diff -u --recursive --new-file v2.3.20/linux/Documentation/Changes linux/Documentation/Changes
--- v2.3.20/linux/Documentation/Changes	Tue Aug 31 17:29:12 1999
+++ linux/Documentation/Changes	Sun Oct 10 08:47:02 1999
@@ -392,6 +392,8 @@
    Due to changes in the PPP driver and routing code, those of you
 using PPP networking will need to upgrade your pppd.
 
+See ftp://cs.anu.edu.au/pub/software/ppp/ for newest versions.
+
 iBCS
 ====
 
diff -u --recursive --new-file v2.3.20/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.3.20/linux/Documentation/Configure.help	Sat Oct  9 11:47:49 1999
+++ linux/Documentation/Configure.help	Sat Oct  9 18:51:41 1999
@@ -1976,8 +1976,9 @@
    - "386" for the AMD/Cyrix/Intel 386DX/DXL/SL/SLC/SX, Cyrix/TI
      486DLC/DLC2 and UMC 486SX-S. Only "386" kernels will run on a 386
      class machine.
-   - "486" for the AMD/Cyrix/IBM/Intel DX4 or 486DX/DX2/SL/SX/SX2,
-     AMD/Cyrix 5x86, NexGen Nx586 and UMC U5D or U5S.
+   - "486" for the AMD/Cyrix/IBM/Intel 486DX/DX2/DX4 or
+     SL/SLC/SLC2/SLC3/SX/SX2, AMD/Cyrix 5x86, NexGen Nx586 and
+     UMC U5D or U5S.
    - "586" for generic Pentium CPUs, possibly lacking the TSC 
      (time stamp counter) register.
    - "Pentium" for the Intel Pentium/Pentium MMX, AMD K5, K6 and 
@@ -2120,7 +2121,7 @@
   Say N unless you have such a graphics board or plan to get one
   before you next recompile the kernel.
 
-Permedia2 support (experimental)
+Permedia2 support (EXPERIMENTAL)
 CONFIG_FB_PM2
   Say Y here if this is your graphics board.
 
@@ -8063,7 +8064,7 @@
   The module will be called ntfs.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
-NTFS read-write support (experimental)
+NTFS read-write support (EXPERIMENTAL)
 CONFIG_NTFS_RW
   If you say Y here, you will (hopefully) be able to write to NTFS
   file systems as well as read from them. The read-write support
@@ -8128,7 +8129,7 @@
   The module is called affs.o. If you want to compile it as a module,
   say M here and read Documentation/modules.txt. If unsure, say N.
 
-Apple Macintosh filesystem support (experimental)
+Apple Macintosh filesystem support (EXPERIMENTAL)
 CONFIG_HFS_FS
   If you say Y here, you will be able to mount Macintosh-formatted
   floppy disks and hard drive partitions with full read-write access.
@@ -8192,7 +8193,7 @@
   If you are not a part of a fairly large, distributed network, you
   probably do not need an automounter, and can say N here.
 
-EFS filesystem support (experimental)
+EFS filesystem support (EXPERIMENTAL)
 CONFIG_EFS_FS
   EFS is an older filesystem used for non-ISO9660 CDROMs and hard disk
   partitions by SGI's IRIX operating system (IRIX 6.0 and newer uses
@@ -8202,7 +8203,7 @@
   what all this is about, it's safe to say N. For more information
   about EFS see its home page at http://aeschi.ch.eu.org/efs/ .
 
-  If you want to compile the UFS filesystem support as a module ( =
+  If you want to compile the EFS filesystem support 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 efs.o. 
@@ -8242,7 +8243,7 @@
 
   If you haven't heard about all of this before, it's safe to say N.
 
-UFS filesystem write support (experimental)
+UFS filesystem write support (EXPERIMENTAL)
 CONFIG_UFS_FS_WRITE
   Say Y here if you want to try writing to UFS partitions. This is
   experimental, so you should back up your UFS partitions beforehand.
@@ -12593,7 +12594,7 @@
 
   If unsure, say N.
 
-Kernel httpd acceleration (experimental)
+Kernel httpd acceleration (EXPERIMENTAL)
 CONFIG_KHTTPD
   The kernel httpd acceleration daemon (kHTTPd) is a (limited) 
   web server build into the kernel. It is limited since it can only
diff -u --recursive --new-file v2.3.20/linux/Documentation/fb/clgenfb.txt linux/Documentation/fb/clgenfb.txt
--- v2.3.20/linux/Documentation/fb/clgenfb.txt	Fri Sep 10 23:57:27 1999
+++ linux/Documentation/fb/clgenfb.txt	Mon Oct 11 10:06:33 1999
@@ -45,9 +45,7 @@
 Version 1.9.4.4
 ---------------
 * Preliminary Laguna support
-* Overhaul color register routines.  Shifts are now based on offset
-  values in var.cmap, so as long as those are correctly set for PReP
-  things should work (knock on wood).
+* Overhaul color register routines.
 * Associated with the above, console colors are now obtained from a LUT
   called 'palette' instead of from the VGA registers.  This code was
   modeled after that in atyfb and matroxfb.
diff -u --recursive --new-file v2.3.20/linux/Documentation/fb/framebuffer.txt linux/Documentation/fb/framebuffer.txt
--- v2.3.20/linux/Documentation/fb/framebuffer.txt	Thu Aug 26 13:05:34 1999
+++ linux/Documentation/fb/framebuffer.txt	Mon Oct 11 13:53:09 1999
@@ -2,7 +2,7 @@
 			-----------------------
 
 Maintained by Geert Uytterhoeven <geert@linux-m68k.org>
-Last revised: November 7, 1998
+Last revised: October 7, 1999
 
 
 0. Introduction
@@ -304,7 +304,20 @@
       o linux/include/video/
 
 
-8. Downloading
+
+8. Mailing list
+---------------
+
+There's a _development_ mailing list at linux-fbdev@vuser.vu.union.edu,
+controlled by majordomo. Send an email with `help' in the message body to
+majordomo@vuser.vu.union.edu for subscription information.
+
+The mailing list is archived at
+
+    http://www.mail-archive.com/linux-fbdev@vuser.vu.union.edu/
+
+
+9. Downloading
 --------------
 
 All necessary files can be found at
@@ -313,8 +326,12 @@
 
 and on its mirrors.
 
+The latest version of fbset can be found at
+
+    http://www.cs.kuleuven.ac.be/~geert/bin/
+
   
-9. Credits                                                       
+10. Credits                                                       
 ----------                                                       
                 
 This readme was written by Geert Uytterhoeven, partly based on the original
diff -u --recursive --new-file v2.3.20/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt
--- v2.3.20/linux/Documentation/ioctl-number.txt	Fri Sep 10 23:57:27 1999
+++ linux/Documentation/ioctl-number.txt	Mon Oct 11 10:18:07 1999
@@ -1,5 +1,5 @@
 Ioctl Numbers
-2 September 1999
+10 October 1999
 Michael Elizabeth Chastain
 <mec@shout.net>
 
@@ -114,6 +114,8 @@
 'e'	00-1F	linux/video_encoder.h	conflict!
 'e'	00-1F	net/irda/irtty.h	conflict!
 'f'	00-1F	linux/ext2_fs.h
+'h'	00-7F				Charon filesystem
+					<mailto:zapman@interlan.net>
 'i'	00-3F	linux/i2o.h
 'j'	00-3F	linux/joystick.h
 'k'	all	asm-sparc/kbio.h
@@ -140,6 +142,8 @@
 'v'	00-1F	linux/ext2_fs.h		conflict!
 'v'	all	linux/videodev.h	conflict!
 'w'	all				CERN SCI driver
+'y'	00-1F				packet based user level communications
+					<mailto:zapman@interlan.net>
 'z'	00-3F				CAN bus card
 					<mailto:hdstich@connectu.ulm.circular.de>
 'z'	40-7F				CAN bus card
diff -u --recursive --new-file v2.3.20/linux/Makefile linux/Makefile
--- v2.3.20/linux/Makefile	Sat Oct  9 11:47:50 1999
+++ linux/Makefile	Mon Oct 11 10:13:24 1999
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 20
+SUBLEVEL = 21
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
@@ -125,6 +125,18 @@
 endif
 
 DRIVERS := $(DRIVERS) drivers/net/net.a
+
+ifdef CONFIG_NET_FC
+DRIVERS := $(DRIVERS) drivers/net/fc/fc.a
+endif
+
+ifdef CONFIG_TR
+DRIVERS := $(DRIVERS) drivers/net/tokenring/tr.a
+endif
+
+ifdef CONFIG_WAN
+DRIVERS := $(DRIVERS) drivers/net/wan/wan.a
+endif
 
 ifdef CONFIG_ATM
 DRIVERS := $(DRIVERS) drivers/atm/atm.a
diff -u --recursive --new-file v2.3.20/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c
--- v2.3.20/linux/arch/alpha/kernel/alpha_ksyms.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/alpha/kernel/alpha_ksyms.c	Mon Oct 11 10:06:34 1999
@@ -139,7 +139,7 @@
 EXPORT_SYMBOL_NOVERS(__copy_user);
 EXPORT_SYMBOL_NOVERS(__do_clear_user);
 EXPORT_SYMBOL(__strncpy_from_user);
-EXPORT_SYMBOL(__strlen_user);
+EXPORT_SYMBOL(__strnlen_user);
 
 /*
  * The following are specially called from the semaphore assembly stubs.
diff -u --recursive --new-file v2.3.20/linux/arch/alpha/lib/strlen_user.S linux/arch/alpha/lib/strlen_user.S
--- v2.3.20/linux/arch/alpha/lib/strlen_user.S	Sat Apr 24 17:54:08 1999
+++ linux/arch/alpha/lib/strlen_user.S	Mon Oct 11 10:06:34 1999
@@ -3,6 +3,13 @@
  *
  * Return the length of the string including the NUL terminator
  * (strlen+1) or zero if an error occurred.
+ *
+ * In places where it is critical to limit the processing time,
+ * and the data is not trusted, strnlen_user() should be used.
+ * It will return a value greater than its second argument if
+ * that limit would be exceeded. This implementation is allowed
+ * to access memory beyond the limit, but will not cross a page
+ * boundary when doing so.
  */
 
 #include <alpha/regdef.h>
@@ -27,6 +34,14 @@
 
 	.align 3
 __strlen_user:
+	ldah	a1, 32767(zero)	# do not use plain strlen_user() for strings
+				# that might be almost 2 GB long; you should
+				# be using strnlen_user() instead
+
+	.globl __strnlen_user
+
+	.align 3
+__strnlen_user:
 	ldgp	$29,0($27)	# we do exceptions -- we need the gp.
 	.prologue 1
 
@@ -37,9 +52,17 @@
 	or      t1, t0, t0
 	subq	a0, 1, a0	# get our +1 for the return 
 	cmpbge  zero, t0, t1	# t1 <- bitmask: bit i == 1 <==> i-th byte == 0
+	subq	a1, 7, t2
+	subq	a0, v0, t0
 	bne     t1, $found
 
-$loop:	EX( ldq t0, 8(v0) )
+	addq	t2, t0, t2
+	addq	a1, 1, a1
+
+	.align 3
+$loop:	ble	t2, $limit
+	EX( ldq t0, 8(v0) )
+	subq	t2, 8, t2
 	addq    v0, 8, v0	# addr += 8
 	cmpbge  zero, t0, t1
 	beq     t1, $loop
@@ -59,6 +82,11 @@
 	nop			# dual issue next two on ev4 and ev5
 	subq    v0, a0, v0
 $exception:
+	ret
+
+	.align 3		# currently redundant
+$limit:
+	subq	a1, t2, v0
 	ret
 
 	.end __strlen_user
diff -u --recursive --new-file v2.3.20/linux/arch/i386/boot/Makefile linux/arch/i386/boot/Makefile
--- v2.3.20/linux/arch/i386/boot/Makefile	Tue Aug 31 17:29:12 1999
+++ linux/arch/i386/boot/Makefile	Mon Oct 11 14:06:10 1999
@@ -8,9 +8,6 @@
 # Copyright (C) 1994 by Linus Torvalds
 #
 
-AS86	=$(CROSS_COMPILE)as86 -0 -a
-LD86	=$(CROSS_COMPILE)ld86 -0
-
 BOOT_INCL =	$(TOPDIR)/include/linux/config.h \
 		$(TOPDIR)/include/linux/autoconf.h \
 		$(TOPDIR)/include/asm/boot.h
@@ -45,40 +42,40 @@
 tools/build: tools/build.c
 	$(HOSTCC) $(HOSTCFLAGS) -o $@ $< -I$(TOPDIR)/include
 
-setup: setup.o
-	$(LD86) -s -o $@ $<
+bootsect: bootsect.o
+	$(LD) -Ttext 0x0 -s -oformat binary -o $@ $<
 
-setup.o: setup.s
-	$(AS86) -o $@ $<
+bootsect.o: bootsect.s
+	$(AS) -o $@ $<
 
-setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
+bootsect.s: bootsect.S Makefile $(BOOT_INCL)
 	$(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
-bsetup: bsetup.o
-	$(LD86) -s -o $@ $<
+bbootsect: bbootsect.o bsetup
+	$(LD) -Ttext 0x0 -s -oformat binary $< -R bsetup.o -o $@
 
-bsetup.o: bsetup.s
-	$(AS86) -o $@ $<
+bbootsect.o: bbootsect.s
+	$(AS) -o $@ $<
 
-bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
+bbootsect.s: bootsect.S Makefile $(BOOT_INCL)
 	$(CPP) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
-bootsect: bootsect.o
-	$(LD86) -s -o $@ $<
+setup: setup.o
+	$(LD) -Ttext 0x0 -s -oformat binary -e begtext -o $@ $<
 
-bootsect.o: bootsect.s
-	$(AS86) -o $@ $<
+setup.o: setup.s
+	$(AS) -o $@ $<
 
-bootsect.s: bootsect.S Makefile $(BOOT_INCL)
+setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
 	$(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
-bbootsect: bbootsect.o
-	$(LD86) -s -o $@ $<
+bsetup: bsetup.o
+	$(LD) -Ttext 0x0 -s -oformat binary -e begtext -o $@ $<
 
-bbootsect.o: bbootsect.s
-	$(AS86) -o $@ $<
+bsetup.o: bsetup.s
+	$(AS) -o $@ $<
 
-bbootsect.s: bootsect.S Makefile $(BOOT_INCL)
+bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
 	$(CPP) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
 dep:
diff -u --recursive --new-file v2.3.20/linux/arch/i386/boot/bootsect.S linux/arch/i386/boot/bootsect.S
--- v2.3.20/linux/arch/i386/boot/bootsect.S	Thu Aug 26 13:05:34 1999
+++ linux/arch/i386/boot/bootsect.S	Mon Oct 11 14:06:10 1999
@@ -1,464 +1,423 @@
-!
-!	bootsect.s		Copyright (C) 1991, 1992 Linus Torvalds
-!	modified by Drew Eckhardt
-!	modified by Bruce Evans (bde)
-!
-! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
-! itself out of the way to address 0x90000, and jumps there.
-!
-! bde - should not jump blindly, there may be systems with only 512K low
-! memory.  Use int 0x12 to get the top of memory, etc.
-!
-! It then loads 'setup' directly after itself (0x90200), and the system
-! at 0x10000, using BIOS interrupts. 
-!
-! NOTE! currently system is at most (8*65536-4096) bytes long. This should 
-! be no problem, even in the future. I want to keep it simple. This 508 kB
-! kernel size should be enough, especially as this doesn't contain the
-! buffer cache as in minix (and especially now that the kernel is 
-! compressed :-)
-!
-! The loader has been made as simple as possible, and continuous
-! read errors will result in a unbreakable loop. Reboot by hand. It
-! loads pretty fast by getting whole tracks at a time whenever possible.
+/*
+ *	bootsect.S		Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ *	modified by Drew Eckhardt
+ *	modified by Bruce Evans (bde)
+ *	modified by Chris Noe (May 1999) (as86 -> gas)
+ *
+ * bootsect is loaded at 0x7c00 by the bios-startup routines, and moves
+ * itself out of the way to address 0x90000, and jumps there.
+ *
+ * bde - should not jump blindly, there may be systems with only 512K low
+ * memory.  Use int 0x12 to get the top of memory, etc.
+ *
+ * It then loads 'setup' directly after itself (0x90200), and the system
+ * at 0x10000, using BIOS interrupts. 
+ *
+ * NOTE! currently system is at most (8*65536-4096) bytes long. This should 
+ * be no problem, even in the future. I want to keep it simple. This 508 kB
+ * kernel size should be enough, especially as this doesn't contain the
+ * buffer cache as in minix (and especially now that the kernel is 
+ * compressed :-)
+ *
+ * The loader has been made as simple as possible, and continuous
+ * read errors will result in a unbreakable loop. Reboot by hand. It
+ * loads pretty fast by getting whole tracks at a time whenever possible.
+ */
 
-#include <linux/config.h> /* for CONFIG_ROOT_RDONLY */
+#include <linux/config.h>		/* for CONFIG_ROOT_RDONLY */
 #include <asm/boot.h>
 
-.text
+SETUPSECS	= 4			/* default nr of setup-sectors */
+BOOTSEG		= 0x07C0		/* original address of boot-sector */
+INITSEG		= DEF_INITSEG		/* we move boot here - out of the way */
+SETUPSEG	= DEF_SETUPSEG		/* setup starts here */
+SYSSEG		= DEF_SYSSEG		/* system loaded at 0x10000 (65536) */
+SYSSIZE		= DEF_SYSSIZE		/* system size: # of 16-byte clicks */
+					/* to be loaded */
+ROOT_DEV	= 0 			/* ROOT_DEV is now written by "build" */
+SWAP_DEV	= 0			/* SWAP_DEV is now written by "build" */
 
-SETUPSECS = 4				! default nr of setup-sectors
-BOOTSEG   = 0x07C0			! original address of boot-sector
-INITSEG   = DEF_INITSEG			! we move boot here - out of the way
-SETUPSEG  = DEF_SETUPSEG		! setup starts here
-SYSSEG    = DEF_SYSSEG			! system loaded at 0x10000 (65536).
-SYSSIZE	  = DEF_SYSSIZE			! system size: number of 16-byte clicks
-					! to be loaded
-
-! ROOT_DEV & SWAP_DEV are now written by "build".
-ROOT_DEV = 0
-SWAP_DEV = 0
 #ifndef SVGA_MODE
 #define SVGA_MODE ASK_VGA
 #endif
+
 #ifndef RAMDISK
 #define RAMDISK 0
 #endif 
+
 #ifndef CONFIG_ROOT_RDONLY
 #define CONFIG_ROOT_RDONLY 1
 #endif
 
-! ld86 requires an entry symbol. This may as well be the usual one.
-.globl	_main
-_main:
+.code16
+.text
+
+.global _start
+_start:
+
 #if 0 /* hook for debugger, harmless unless BIOS is fussy (old HP) */
-	int	3
+	int	$0x3
 #endif
-	mov	ax,#BOOTSEG
-	mov	ds,ax
-	mov	ax,#INITSEG
-	mov	es,ax
-	mov	cx,#128
-	sub	si,si
-	sub	di,di
+
+	movw	$BOOTSEG, %ax
+	movw	%ax, %ds
+	movw	$INITSEG, %ax
+	movw	%ax, %es
+	movw	$128, %cx
+	subw	%si, %si
+	subw	%di, %di
 	cld
 	rep
-	movsd
-	jmpi	go,INITSEG
-
-! ax and es already contain INITSEG
-
-go:	mov	di,#0x4000-12	! 0x4000 is arbitrary value >= length of
-				! bootsect + length of setup + room for stack
-				! 12 is disk parm size
-
-! bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde).  We
-! wouldn't have to worry about this if we checked the top of memory.  Also
-! my BIOS can be configured to put the wini drive tables in high memory
-! instead of in the vector table.  The old stack might have clobbered the
-! drive table.
-
-	mov	ds,ax
-	mov	ss,ax		! put stack at INITSEG:0x4000-12.
-	mov	sp,di
-/*
- *	Many BIOS's default disk parameter tables will not 
- *	recognize multi-sector reads beyond the maximum sector number
- *	specified in the default diskette parameter tables - this may
- *	mean 7 sectors in some cases.
- *
- *	Since single sector reads are slow and out of the question,
- *	we must take care of this by creating new parameter tables
- *	(for the first disk) in RAM.  We will set the maximum sector
- *	count to 36 - the most we will encounter on an ED 2.88.  
- *
- *	High doesn't hurt.  Low does.
- *
- *	Segments are as follows: ds=es=ss=cs - INITSEG,
- *		fs = 0, gs is unused.
- */
-
-! cx contains 0 from rep movsd above
+	movsl
+	ljmp	$INITSEG, $go
 
-	mov	fs,cx
-	mov	bx,#0x78		! fs:bx is parameter table address
-	push	ds
-	seg fs
-	lds	si,(bx)			! ds:si is source
-
-	mov	cl,#3			! copy 12 bytes
+# bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde).  We
+# wouldn't have to worry about this if we checked the top of memory.  Also
+# my BIOS can be configured to put the wini drive tables in high memory
+# instead of in the vector table.  The old stack might have clobbered the
+# drive table.
+
+go:	movw	$0x4000-12, %di		# 0x4000 is an arbitrary value >=
+					# length of bootsect + length of
+					# setup + room for stack;
+					# 12 is disk parm size.
+	movw	%ax, %ds		# ax and es already contain INITSEG
+	movw	%ax, %ss
+	movw	%di, %sp		# put stack at INITSEG:0x4000-12.
+
+# Many BIOS's default disk parameter tables will not recognize
+# multi-sector reads beyond the maximum sector number specified
+# in the default diskette parameter tables - this may mean 7
+# sectors in some cases.
+#
+# Since single sector reads are slow and out of the question,
+# we must take care of this by creating new parameter tables
+# (for the first disk) in RAM.  We will set the maximum sector
+# count to 36 - the most we will encounter on an ED 2.88.  
+#
+# High doesn't hurt.  Low does.
+#
+# Segments are as follows: ds = es = ss = cs - INITSEG, fs = 0,
+# and gs is unused.
+
+	movw	%cx, %fs		# set fs to 0
+	movw	$0x78, %bx		# fs:bx is parameter table address
+	pushw	%ds
+	ldsw	%fs:(%bx), %si		# ds:si is source
+	movb	$3, %cl			# copy 12 bytes
 	cld
-	push	di
-
+	pushw	%di			# di = 0x4000-12.
 	rep
-	movsd
-
-	pop	di
-	pop	ds
-
-	movb	4(di),*36		! patch sector count
-
-	seg fs
-	mov	(bx),di
-	seg fs
-	mov	2(bx),es
-
-! load the setup-sectors directly after the bootblock.
-! Note that 'es' is already set up.
-! Also cx is 0 from rep movsd above.
+	movsl
+	popw	%di
+	popw	%ds
+	movb	$36, 0x4(%di)		# patch sector count
+	movw	%di, %fs:(%bx)
+	movw	%es, %fs:2(%bx)
+
+# Load the setup-sectors directly after the bootblock.
+# Note that 'es' is already set up.
+# Also, cx = 0 from rep movsl above.
 
 load_setup:
-	xor	ah,ah			! reset FDC 
-	xor	dl,dl
-	int 	0x13	
-
-	xor	dx, dx			! drive 0, head 0
-	mov	cl,#0x02		! sector 2, track 0
-	mov	bx,#0x0200		! address = 512, in INITSEG
-	mov	ah,#0x02		! service 2, nr of sectors
-	mov	al,setup_sects		! (assume all on head 0, track 0)
-	int	0x13			! read it
-	jnc	ok_load_setup		! ok - continue
+	xorb	%ah, %ah		# reset FDC 
+	xorb	%dl, %dl
+	int 	$0x13	
+	xorw	%dx, %dx		# drive 0, head 0
+	movb	$0x02, %cl		# sector 2, track 0
+	movw	$0x0200, %bx		# address = 512, in INITSEG
+	movb	$0x02, %ah		# service 2, "read sector(s)"
+	movb	setup_sects, %al	# (assume all on head 0, track 0)
+	int	$0x13			# read it
+	jnc	ok_load_setup		# ok - continue
 
-	push	ax			! dump error code
+	pushw	%ax			# dump error code
 	call	print_nl
-	mov	bp, sp
+	movw	%sp, %bp
 	call	print_hex
-	pop	ax	
-	
+	popw	%ax	
 	jmp	load_setup
 
 ok_load_setup:
-
-! Get disk drive parameters, specifically nr of sectors/track
+# Get disk drive parameters, specifically nr of sectors/track.
 
 #if 0
 
-! bde - the Phoenix BIOS manual says function 0x08 only works for fixed
-! disks.  It doesn't work for one of my BIOS's (1987 Award).  It was
-! fatal not to check the error code.
-
-	xor	dl,dl
-	mov	ah,#0x08		! AH=8 is get drive parameters
-	int	0x13
-	xor	ch,ch
-#else
+# bde - the Phoenix BIOS manual says function 0x08 only works for fixed
+# disks.  It doesn't work for one of my BIOS's (1987 Award).  It was
+# fatal not to check the error code.
+
+	xorb	%dl, %dl
+	movb	$0x08, %ah		# AH=8 is get drive parameters
+	int	$0x13
+	xorb	%ch, %ch
 
-! It seems that there is no BIOS call to get the number of sectors.  Guess
-! 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
-! 15 if sector 15 can be read.  Otherwise guess 9.
+#else
 
-	mov	si,#disksizes		! table of sizes to try
+# It seems that there is no BIOS call to get the number of sectors.
+# Guess 36 sectors if sector 36 can be read, 18 sectors if sector 18
+# can be read, 15 if sector 15 can be read.  Otherwise guess 9.
 
+	movw	$disksizes, %si		# table of sizes to try
 probe_loop:
 	lodsb
-	cbw				! extend to word
-	mov	sectors, ax
-	cmp	si,#disksizes+4
-	jae	got_sectors		! if all else fails, try 9
-	xchg	ax, cx			! cx = track and sector
-	xor	dx, dx			! drive 0, head 0
-	xor	bl, bl
-	mov	bh,setup_sects
-	inc	bh
-	shl	bh,#1			! address after setup (es = cs)
-	mov	ax,#0x0201		! service 2, 1 sector
-	int	0x13
-	jc	probe_loop		! try next value
-
+	cbtw				# extend to word
+	movw	%ax, sectors
+	cmpw	$disksizes+4, %si
+	jae	got_sectors		# if all else fails, try 9
+	
+	xchgw	%cx, %ax		# cx = track and sector
+	xorw	%dx, %dx		# drive 0, head 0
+	xorb	%bl, %bl
+	movb	setup_sects, %bh
+	incb	%bh
+	shlb	%bh			# address after setup (es = cs) 
+	movw	$0x0201, %ax		# service 2, 1 sector
+	int	$0x13
+	jc	probe_loop		# try next value
 #endif
 
 got_sectors:
-
-! Restore es
-
-	mov	ax,#INITSEG
-	mov	es,ax
-
-! Print some inane message
-
-	mov	ah,#0x03		! read cursor pos
-	xor	bh,bh
-	int	0x10
-	
-	mov	cx,#9
-	mov	bx,#0x0007		! page 0, attribute 7 (normal)
-	mov	bp,#msg1
-	mov	ax,#0x1301		! write string, move cursor
-	int	0x10
-
-! ok, we've written the message, now
-! we want to load the system (at 0x10000)
-
-	mov	ax,#SYSSEG
-	mov	es,ax		! segment of 0x010000
+	movw	$INITSEG, %ax
+	movw	%ax, %es		# set up es
+	movb	$0x03, %ah		# read cursor pos
+	xorb	%bh, %bh
+	int	$0x10
+	movw	$9, %cx
+	movw	$0x0007, %bx		# page 0, attribute 7 (normal)
+	movw    $msg1, %bp
+	movw    $0x1301, %ax		# write string, move cursor
+	int	$0x10			# tell the user we're loading..
+	movw	$SYSSEG, %ax		# ok, we've written the message, now
+	movw	%ax, %es		# we want to load system (at 0x10000)
 	call	read_it
 	call	kill_motor
 	call	print_nl
 
-! After that we check which root-device to use. If the device is
-! defined (!= 0), nothing is done and the given device is used.
-! Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8),
-! depending on the number of sectors we pretend to know we have.
-
-	seg cs
-	mov	ax,root_dev
-	or	ax,ax
+# After that we check which root-device to use. If the device is
+# defined (!= 0), nothing is done and the given device is used.
+# Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8)
+# depending on the number of sectors we pretend to know we have.
+
+	movw	%cs:root_dev, %ax
+	orw	%ax, %ax
 	jne	root_defined
-	seg cs
-	mov	bx,sectors
-	mov	ax,#0x0208		! /dev/ps0 - 1.2Mb
-	cmp	bx,#15
+	
+	movw	%cs:sectors, %bx
+	movw	$0x0208, %ax		# /dev/ps0 - 1.2Mb
+	cmpw	$15, %bx
 	je	root_defined
-	mov	al,#0x1c		! /dev/PS0 - 1.44Mb
-	cmp	bx,#18
+	
+	movb	$0x1c, %al		# /dev/PS0 - 1.44Mb
+	cmpw	$18, %bx
 	je	root_defined
-	mov	al,#0x20		! /dev/fd0H2880 - 2.88Mb
-	cmp	bx,#36
+	
+	movb	$0x20, %al		# /dev/fd0H2880 - 2.88Mb
+	cmpw	$36, %bx
 	je	root_defined
-	mov	al,#0			! /dev/fd0 - autodetect
+	
+	movb	$0, %al			# /dev/fd0 - autodetect
 root_defined:
-	seg cs
-	mov	root_dev,ax
+	movw	%ax, %cs:root_dev
+
+# After that (everything loaded), we jump to the setup-routine
+# loaded directly after the bootblock:
+
+	ljmp	$SETUPSEG, $0
+
+# This routine loads the system at address 0x10000, making sure
+# no 64kB boundaries are crossed. We try to load it as fast as
+# possible, loading whole tracks whenever we can.
 
-! after that (everything loaded), we jump to
-! the setup-routine loaded directly after
-! the bootblock:
-
-	jmpi	0,SETUPSEG
-
-! This routine loads the system at address 0x10000, making sure
-! no 64kB boundaries are crossed. We try to load it as fast as
-! possible, loading whole tracks whenever we can.
-!
-! in:	es - starting address segment (normally 0x1000)
-!
-sread:	.word 0			! sectors read of current track
-head:	.word 0			! current head
-track:	.word 0			! current track
+# es = starting address segment (normally 0x1000)
+
+sread:	.word 0				# sectors read of current track
+head:	.word 0				# current head
+track:	.word 0				# current track
 
 read_it:
-	mov	al,setup_sects
-	inc	al
-	mov	sread,al
-	mov ax,es
-	test ax,#0x0fff
-die:	jne die			! es must be at 64kB boundary
-	xor bx,bx		! bx is starting address within segment
+	movb	setup_sects, %al
+	incb	%al
+	movb	%al, sread
+	movw	%es, %ax
+	testw	$0x0fff, %ax
+die:	jne	die			# es must be at 64kB boundary
+
+	xorw	%bx, %bx		# bx is starting address within segment
 rp_read:
 #ifdef __BIG_KERNEL__
-#define CALL_HIGHLOAD_KLUDGE .word 0x1eff,0x220 ! call far * bootsect_kludge
-				! NOTE: as86 can't assemble this
-	CALL_HIGHLOAD_KLUDGE	! this is within setup.S
+	lcall	bootsect_kludge		# in setup.S
 #else
-	mov ax,es
-	sub ax,#SYSSEG
+	movw	%es, %ax
+	subw	$SYSSEG, %ax
 #endif
-	cmp ax,syssize		! have we loaded all yet?
-	jbe ok1_read
+	cmpw	syssize, %ax		# have we loaded all yet?
+	jbe	ok1_read
+
 	ret
+
 ok1_read:
-	mov ax,sectors
-	sub ax,sread
-	mov cx,ax
-	shl cx,#9
-	add cx,bx
-	jnc ok2_read
-	je ok2_read
-	xor ax,ax
-	sub ax,bx
-	shr ax,#9
+	movw	sectors, %ax
+	subw	sread, %ax
+	movw	%ax, %cx
+	shlw	$9, %cx
+	addw	%bx, %cx
+	jnc	ok2_read
+	
+	je	ok2_read
+
+	xorw	%ax, %ax
+	subw	%bx, %ax
+	shrw	$9, %ax
 ok2_read:
-	call read_track
-	mov cx,ax
-	add ax,sread
-	cmp ax,sectors
-	jne ok3_read
-	mov ax,#1
-	sub ax,head
-	jne ok4_read
-	inc track
+	call	read_track
+	movw	%ax, %cx
+	addw	sread, %ax
+	cmpw	sectors, %ax
+	jne	ok3_read
+	
+	movw	$1, %ax
+	subw	head, %ax
+	jne	ok4_read
+	
+	incw	track
 ok4_read:
-	mov head,ax
-	xor ax,ax
+	movw	%ax, head
+	xorw	%ax, %ax
 ok3_read:
-	mov sread,ax
-	shl cx,#9
-	add bx,cx
-	jnc rp_read
-	mov ax,es
-	add ah,#0x10
-	mov es,ax
-	xor bx,bx
-	jmp rp_read
+	movw	%ax, sread
+	shlw	$9, %cx
+	addw	%cx, %bx
+	jnc	rp_read
+	
+	movw	%es, %ax
+	addb	$0x10, %ah
+	movw	%ax, %es
+	xorw	%bx, %bx
+	jmp	rp_read
 
 read_track:
 	pusha
 	pusha	
-	mov	ax, #0xe2e 	! loading... message 2e = .
-	mov	bx, #7
- 	int	0x10
+	movw	$0xe2e, %ax 			# loading... message 2e = .
+	movw	$7, %bx
+ 	int	$0x10
 	popa		
-
-	mov	dx,track
-	mov	cx,sread
-	inc	cx
-	mov	ch,dl
-	mov	dx,head
-	mov	dh,dl
-	and	dx,#0x0100
-	mov	ah,#2
-	
-	push	dx				! save for error dump
-	push	cx
-	push	bx
-	push	ax
-
-	int	0x13
+	movw	track, %dx
+	movw	sread, %cx
+	incw	%cx
+	movb	%dl, %ch
+	movw	head, %dx
+	movb	%dl, %dh
+	andw	$0x0100, %dx
+	movb	$2, %ah
+	pushw	%dx				# save for error dump
+	pushw	%cx
+	pushw	%bx
+	pushw	%ax
+	int	$0x13
 	jc	bad_rt
-	add	sp, #8
+	
+	addw	$8, %sp
 	popa
 	ret
 
-bad_rt:	push	ax				! save error code
-	call	print_all			! ah = error, al = read
-	
-	
-	xor ah,ah
-	xor dl,dl
-	int 0x13
-	
-
-	add	sp, #10
-	popa	
+bad_rt:
+	pushw	%ax				# save error code
+	call	print_all			# ah = error, al = read
+	xorb	%ah, %ah
+	xorb	%dl, %dl
+	int	$0x13
+	addw	$10, %sp
+	popa
 	jmp read_track
 
-/*
- *	print_all is for debugging purposes.  
- *	It will print out all of the registers.  The assumption is that this is
- *	called from a routine, with a stack frame like
- *	dx 
- *	cx
- *	bx
- *	ax
- *	error
- *	ret <- sp
- *
-*/
+# print_all is for debugging purposes.  
+#
+# it will print out all of the registers.  The assumption is that this is
+# called from a routine, with a stack frame like
+#
+#	%dx 
+#	%cx
+#	%bx
+#	%ax
+#	(error)
+#	ret <- %sp
  
 print_all:
-	mov	cx, #5		! error code + 4 registers
-	mov	bp, sp	
-
+	movw	$5, %cx				# error code + 4 registers
+	movw	%sp, %bp
 print_loop:
-	push	cx		! save count left
-	call	print_nl	! nl for readability
-
-	cmp	cl, #5
-	jae	no_reg		! see if register name is needed
+	pushw	%cx				# save count left
+	call	print_nl			# nl for readability
+	cmpb	$5, %cl
+	jae	no_reg				# see if register name is needed
 	
-	mov	ax, #0xe05 + 'A - 1
-	sub	al, cl
-	int	0x10
-
-	mov	al, #'X
-	int	0x10
-
-	mov	al, #':
-	int	0x10
-
+	movw	$0xe05 + 'A' - 1, %ax
+	subb	%cl, %al
+	int	$0x10
+	movb	$'X', %al
+	int	$0x10
+	movb	$':', %al
+	int	$0x10
 no_reg:
-	add	bp, #2		! next register
-	call	print_hex	! print it
-	pop	cx
+	addw	$2, %bp				# next register
+	call	print_hex			# print it
+	popw	%cx
 	loop	print_loop
 	ret
 
 print_nl:
-	mov	ax, #0xe0d	! CR
-	int	0x10
-	mov	al, #0xa	! LF
-	int 	0x10
+	movw	$0xe0d, %ax			# CR
+	int	$0x10
+	movb	$0xa, %al			# LF
+	int 	$0x10
 	ret
 
-/*
- *	print_hex is for debugging purposes, and prints the word
- *	pointed to by ss:bp in hexadecimal.
-*/
+# print_hex is for debugging purposes, and prints the word
+# pointed to by ss:bp in hexadecimal.
 
 print_hex:
-	mov	cx, #4		! 4 hex digits
-	mov	dx, (bp)	! load word into dx
+	movw	$4, %cx				# 4 hex digits
+	movw	(%bp), %dx			# load word into dx
 print_digit:
-	rol	dx, #4		! rotate so that lowest 4 bits are used
-	mov	ax, #0xe0f	! ah = request, al = mask for nybble
-	and	al, dl
-	add	al, #0x90	! convert al to ASCII hex (four instructions)
+	rolw	$4, %dx				# rotate to use low 4 bits
+	movw	$0xe0f, %ax			# ah = request
+	andb	%dl, %al			# al = mask for nybble
+	addb	$0x90, %al			# convert al to ascii hex
+	daa					# in only four instructions!
+	adc	$0x40, %al
 	daa
-	adc	al, #0x40
-	daa
-	int	0x10
+	int	$0x10
 	loop	print_digit
 	ret
 
+# This procedure turns off the floppy drive motor, so
+# that we enter the kernel in a known state, and
+# don't have to worry about it later.
 
-/*
- * This procedure turns off the floppy drive motor, so
- * that we enter the kernel in a known state, and
- * don't have to worry about it later.
- */
 kill_motor:
-	push dx
-	mov dx,#0x3f2
-	xor al, al
-	outb
-	pop dx
+	pushw	%dx
+	movw	$0x3f2, %dx
+	xorb	%al, %al
+	outw	%al, %dx
+	popw	%dx
 	ret
 
-sectors:
-	.word 0
-
-disksizes:
-	.byte 36,18,15,9
+sectors:	.word 0
+disksizes:	.byte 36, 18, 15, 9
+msg1:		.byte 13, 10
+		.ascii "Loading"
 
-msg1:
-	.byte 13,10
-	.ascii "Loading"
+# XXX: This is a *very* snug fit.
 
 .org 497
-setup_sects:
-	.byte SETUPSECS
-root_flags:
-	.word CONFIG_ROOT_RDONLY
-syssize:
-	.word SYSSIZE
-swap_dev:
-	.word SWAP_DEV
-ram_size:
-	.word RAMDISK
-vid_mode:
-	.word SVGA_MODE
-root_dev:
-	.word ROOT_DEV
-boot_flag:
-	.word 0xAA55
+setup_sects:	.byte SETUPSECS
+root_flags:	.word CONFIG_ROOT_RDONLY
+syssize:	.word SYSSIZE
+swap_dev:	.word SWAP_DEV
+ram_size:	.word RAMDISK
+vid_mode:	.word SVGA_MODE
+root_dev:	.word ROOT_DEV
+boot_flag:	.word 0xAA55
diff -u --recursive --new-file v2.3.20/linux/arch/i386/boot/compressed/Makefile linux/arch/i386/boot/compressed/Makefile
--- v2.3.20/linux/arch/i386/boot/compressed/Makefile	Sun Jul 11 09:48:05 1999
+++ linux/arch/i386/boot/compressed/Makefile	Mon Oct 11 14:06:10 1999
@@ -39,7 +39,7 @@
 	$(OBJCOPY) $(SYSTEM) $$tmppiggy; \
 	gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
 	echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \
-	$(LD) -m elf_i386 -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \
+	$(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \
 	rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk
 
 clean:
diff -u --recursive --new-file v2.3.20/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- v2.3.20/linux/arch/i386/boot/setup.S	Sat Oct  9 11:47:50 1999
+++ linux/arch/i386/boot/setup.S	Mon Oct 11 14:06:10 1999
@@ -1,35 +1,38 @@
-!
-!	setup.S		Copyright (C) 1991, 1992 Linus Torvalds
-!
-! setup.s is responsible for getting the system data from the BIOS,
-! and putting them into the appropriate places in system memory.
-! both setup.s and system has been loaded by the bootblock.
-!
-! This code asks the bios for memory/disk/other parameters, and
-! puts them in a "safe" place: 0x90000-0x901FF, ie where the
-! boot-block used to be. It is then up to the protected mode
-! system to read them from there before the area is overwritten
-! for buffer-blocks.
-!
-! Move PS/2 aux init code to psaux.c
-! (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
-!
-! some changes and additional features by Christoph Niemann,
-! March 1993/June 1994 (Christoph.Niemann@linux.org)
-!
-! add APM BIOS checking by Stephen Rothwell, May 1994
-! (Stephen.Rothwell@canb.auug.org.au)
-!
-! High load stuff, initrd support and position independency
-! by Hans Lermen & Werner Almesberger, February 1996
-! <lermen@elserv.ffm.fgan.de>, <almesber@lrc.epfl.ch>
-!
-! Video handling moved to video.S by Martin Mares, March 1996
-! <mj@k332.feld.cvut.cz>
-!
-! Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david
-! parsons) to avoid loadlin confusion, July 1997
-!
+/*
+ *	setup.S		Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * setup.s is responsible for getting the system data from the BIOS,
+ * and putting them into the appropriate places in system memory.
+ * both setup.s and system has been loaded by the bootblock.
+ *
+ * This code asks the bios for memory/disk/other parameters, and
+ * puts them in a "safe" place: 0x90000-0x901FF, ie where the
+ * boot-block used to be. It is then up to the protected mode
+ * system to read them from there before the area is overwritten
+ * for buffer-blocks.
+ *
+ * Move PS/2 aux init code to psaux.c
+ * (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
+ *
+ * some changes and additional features by Christoph Niemann,
+ * March 1993/June 1994 (Christoph.Niemann@linux.org)
+ *
+ * add APM BIOS checking by Stephen Rothwell, May 1994
+ * (Stephen.Rothwell@canb.auug.org.au)
+ *
+ * High load stuff, initrd support and position independency
+ * by Hans Lermen & Werner Almesberger, February 1996
+ * <lermen@elserv.ffm.fgan.de>, <almesber@lrc.epfl.ch>
+ *
+ * Video handling moved to video.S by Martin Mares, March 1996
+ * <mj@k332.feld.cvut.cz>
+ *
+ * Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david
+ * parsons) to avoid loadlin confusion, July 1997
+ *
+ * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
+ * <stiker@northlink.com>
+ */
 
 #define __ASSEMBLY__
 #include <linux/config.h>
@@ -39,17 +42,20 @@
 #include <asm/boot.h>
 #include <asm/e820.h>
 
-! Signature words to ensure LILO loaded us right
+/* Signature words to ensure LILO loaded us right */
 #define SIG1	0xAA55
 #define SIG2	0x5A5A
 
-INITSEG  = DEF_INITSEG	! 0x9000, we move boot here - out of the way
-SYSSEG   = DEF_SYSSEG	! 0x1000, system loaded at 0x10000 (65536).
-SETUPSEG = DEF_SETUPSEG	! 0x9020, this is the current segment
-			! ... and the former contents of CS
-DELTA_INITSEG = SETUPSEG - INITSEG ! 0x0020
+INITSEG  = DEF_INITSEG		# 0x9000, we move boot here, out of the way
+SYSSEG   = DEF_SYSSEG		# 0x1000, system loaded at 0x10000 (65536).
+SETUPSEG = DEF_SETUPSEG		# 0x9020, this is the current segment
+				# ... and the former contents of CS
 
+DELTA_INITSEG = SETUPSEG - INITSEG	# 0x0020
+
+.code16
 .globl begtext, begdata, begbss, endtext, enddata, endbss
+
 .text
 begtext:
 .data
@@ -58,631 +64,617 @@
 begbss:
 .text
 
-entry start
 start:
 	jmp	trampoline
-! ------------------------ start of header --------------------------------
-!
-! SETUP-header, must start at CS:2 (old 0x9020:2)
-!
-		.ascii	"HdrS"		! Signature for SETUP-header
-		.word	0x0201		! Version number of header format
-					! (must be >= 0x0105
-					! else old loadlin-1.5 will fail)
-realmode_swtch:	.word	0,0		! default_switch,SETUPSEG
+
+# This is the setup header, and it must start at %cs:2 (old 0x9020:2)
+
+		.ascii	"HdrS"		# header signature
+		.word	0x0201		# header version number (>= 0x0105)
+					# or else old loadlin-1.5 will fail)
+realmode_swtch:	.word	0, 0		# default_switch, SETUPSEG
 start_sys_seg:	.word	SYSSEG
-		.word	kernel_version	! pointing to kernel version string
-  ! note: above part of header is compatible with loadlin-1.5 (header v1.5),
-  !        must not change it
-
-type_of_loader:	.byte	0		! = 0, old one (LILO, Loadlin,
-					!      Bootlin, SYSLX, bootsect...)
-					! else it is set by the loader:
-					! 0xTV: T=0 for LILO
-					!	T=1 for Loadlin
-					!	T=2 for bootsect-loader
-					!	T=3 for SYSLX
-					!	T=4 for ETHERBOOT
-					!       V = version
-loadflags:			! flags, unused bits must be zero (RFU)
-LOADED_HIGH	= 1		! bit within loadflags,
-				! if set, then the kernel is loaded high
-CAN_USE_HEAP	= 0x80		! if set, the loader also has set heap_end_ptr
-				! to tell how much space behind setup.S
-				| can be used for heap purposes.
-				! Only the loader knows what is free!
+		.word	kernel_version	# pointing to kernel version string
+					# above section of header is compatible
+					# with loadlin-1.5 (header v1.5). Don't
+					# change it.
+
+type_of_loader:	.byte	0		# = 0, old one (LILO, Loadlin,
+					#      Bootlin, SYSLX, bootsect...)
+					# else it is set by the loader:
+					# 0xTV: T=0 for LILO
+					#	T=1 for Loadlin
+					#	T=2 for bootsect-loader
+					#	T=3 for SYSLX
+					#	T=4 for ETHERBOOT
+					#       V = version
+
+# flags, unused bits must be zero (RFU) bit within loadflags
+loadflags:
+LOADED_HIGH	= 1			# if set, the kernel is loaded high
+CAN_USE_HEAP	= 0x80			# if set, the loader also has set
+					# heap_end_ptr to tell how much
+					# space behind setup.S can be used for
+					# heap purposes.
+					# Only the loader knows what is free
 #ifndef __BIG_KERNEL__
-		.byte	0x00
+		.byte	0
 #else
 		.byte	LOADED_HIGH
 #endif
 
-setup_move_size: .word  0x8000	! size to move, when we (setup) are not
-				! loaded at 0x90000. We will move ourselves
-				! to 0x90000 then just before jumping into
-				! the kernel. However, only the loader
-				! know how much of data behind us also needs
-				! to be loaded.
-code32_start:				! here loaders can put a different
-					! start address for 32-bit code.
+setup_move_size: .word  0x8000		# size to move, when setup is not
+					# loaded at 0x90000. We will move setup 
+					# to 0x90000 then just before jumping
+					# into the kernel. However, only the
+					# loader knows how much data behind
+					# us also needs to be loaded.
+
+code32_start:				# here loaders can put a different
+					# start address for 32-bit code.
 #ifndef __BIG_KERNEL__
-		.long	0x1000		!   0x1000 = default for zImage
+		.long	0x1000		#   0x1000 = default for zImage
 #else
-		.long	0x100000	! 0x100000 = default for big kernel
+		.long	0x100000	# 0x100000 = default for big kernel
 #endif
-ramdisk_image:	.long	0	! address of loaded ramdisk image
-				! Here the loader (or kernel generator) puts
-				! the 32-bit address were it loaded the image.
-				! This only will be interpreted by the kernel.
-ramdisk_size:	.long	0	! its size in bytes
+
+ramdisk_image:	.long	0		# address of loaded ramdisk image
+					# Here the loader puts the 32-bit
+					# address where it loaded the image.
+					# This only will be read by the kernel.
+
+ramdisk_size:	.long	0		# its size in bytes
+
+.global bootsect_kludge			# so that we can see it in bootsect.S
 bootsect_kludge:
-		.word   bootsect_helper,SETUPSEG
-heap_end_ptr:	.word	modelist+1024	! space from here (exclusive) down to
-				! end of setup code can be used by setup
-				! for local heap purposes.
+		.word  bootsect_helper, SETUPSEG
+
+heap_end_ptr:	.word	modelist+1024	# space from here (exclusive) down to
+					# end of setup code can be used by setup
+					# for local heap purposes.
 trampoline:	call	start_of_setup
 		.space	1024
-! ------------------------ end of header ----------------------------------
+# End of setup header #####################################################
 
 start_of_setup:
-! Bootlin depends on this being done early
-	mov	ax,#0x01500
-	mov	dl,#0x81
-	int	0x13
+# Bootlin depends on this being done early
+	movw	$0x01500, %ax
+	movb	$0x81, %dl
+	int	$0x13
 
 #ifdef SAFE_RESET_DISK_CONTROLLER
-! Reset the disk controller.
-	mov	ax,#0x0000
-	mov	dl,#0x80
-	int	0x13
+# Reset the disk controller.
+	movw	$0x0000, %ax
+	movb	$0x80, $dl
+	int	$0x13
 #endif
 
-! set DS=CS, we know that SETUPSEG == CS at this point
-	mov	ax,cs		! aka #SETUPSEG
-	mov	ds,ax
-
-! Check signature at end of setup
-	cmp	setup_sig1,#SIG1
+# Set %ds = %cs, we know that SETUPSEG = %cs at this point
+	movw	%cs, %ax		# aka SETUPSEG
+	movw	%ax, %ds
+# Check signature at end of setup
+	cmpw	$SIG1, setup_sig1
 	jne	bad_sig
-	cmp	setup_sig2,#SIG2
+
+	cmpw	$SIG2, setup_sig2
 	jne	bad_sig
-	jmp	good_sig1
 
-! Routine to print ASCIIz string at DS:SI
+	jmp	good_sig1
 
-prtstr:	lodsb
-	and	al,al
+# Routine to print asciiz string at ds:si
+prtstr:
+	lodsb
+	andb	%al, %al
 	jz	fin
+
 	call	prtchr
 	jmp	prtstr
-fin:	ret
 
-! Space printing
-
-prtsp2:	call	prtspc		! Print double space
-prtspc:	mov	al,#0x20	! Print single space (fall-thru!)
-
-! Part of above routine, this one just prints ASCII al
+fin:	ret
 
-prtchr:	push	ax
-	push	cx
-	xor	bh,bh
-	mov	cx,#0x01
-	mov	ah,#0x0e
-	int	0x10
-	pop	cx
-	pop	ax
+# Space printing
+prtsp2:	call	prtspc		# Print double space
+prtspc:	movb	$0x20, %al	# Print single space (note: fall-thru)
+
+# Part of above routine, this one just prints ascii al
+prtchr:	pushw	%ax
+	pushw	%cx
+	xorb	%bh, %bh
+	movw	$0x01, %cx
+	movb	$0x0e, %ah
+	int	$0x10
+	popw	%cx
+	popw	%ax
 	ret
 
-beep:	mov	al,#0x07
+beep:	movb	$0x07, %al
 	jmp	prtchr
 	
-no_sig_mess:	.ascii	"No setup signature found ..."
-		db	0x00
+no_sig_mess: .string	"No setup signature found ..."
 
 good_sig1:
 	jmp	good_sig
 
-! We now have to find the rest of the setup code/data
+# We now have to find the rest of the setup code/data
 bad_sig:
-	mov	ax,cs		! aka #SETUPSEG
-	sub	ax,#DELTA_INITSEG ! aka #INITSEG
-	mov	ds,ax
-	xor	bh,bh
-	mov	bl,[497]	! get setup sects from boot sector
-	sub	bx,#4		! LILO loads 4 sectors of setup
-	shl	bx,#7		! convert to dwords (1sect=2^7 dwords)
-	mov	cx,bx
-	shr	bx,#2		! convert to segment
-	add	bx,#SYSSEG
-	seg cs
-	mov	start_sys_seg,bx
-
-! Move rest of setup code/data to here
-	mov	di,#2048	! four sectors loaded by LILO
-	sub	si,si
-	mov	ax,cs		! aka #SETUPSEG
-	mov	es,ax
-	mov	ax,#SYSSEG
-	mov	ds,ax
+	movw	%cs, %ax			# SETUPSEG
+	subw	$DELTA_INITSEG, %ax		# INITSEG
+	movw	%ax, %ds
+	xorb	%bh, %bh
+	movb	(497), %bl			# get setup sect from bootsect
+	subw	$4, %bx				# LILO loads 4 sectors of setup
+	shlw	$7, %bx				# convert to dwords (1sect=2^7 dwords)
+	movw	%bx, %cx
+	shrw	$2, %bx				# convert to segment
+	addw	$SYSSEG, %bx
+	movw	%bx, %cs:start_sys_seg
+# Move rest of setup code/data to here
+	movw	$2048, %di			# four sectors loaded by LILO
+	subw	%si, %si
+	movw	%cs, %ax			# aka SETUPSEG
+	movw	%ax, %es
+	movw	$SYSSEG, %ax
+	movw	%ax, %ds
 	rep
-	movsd
-
-	mov	ax,cs		! aka #SETUPSEG
-	mov	ds,ax
-	cmp	setup_sig1,#SIG1
+	movsl
+	movw	%cs, %ax			# aka SETUPSEG
+	movw	%ax, %ds
+	cmpw	$SIG1, setup_sig1
 	jne	no_sig
-	cmp	setup_sig2,#SIG2
+
+	cmpw	$SIG2, setup_sig2
 	jne	no_sig
+
 	jmp	good_sig
 
 no_sig:
-	lea	si,no_sig_mess
+	lea	no_sig_mess, %si
 	call	prtstr
+
 no_sig_loop:
 	jmp	no_sig_loop
 
 good_sig:
-	mov	ax,cs		! aka #SETUPSEG
-	sub	ax,#DELTA_INITSEG ! aka #INITSEG
-	mov	ds,ax
-
-! check if an old loader tries to load a big-kernel
-	seg cs
-	test	byte ptr loadflags,#LOADED_HIGH ! Have we a big kernel?
-	jz	loader_ok	! NO, no danger even for old loaders
-				! YES, we have a big-kernel
-	seg cs
-	cmp	byte ptr type_of_loader,#0 ! Have we one of the new loaders?
-	jnz	loader_ok	! YES, OK
-				! NO, we have an old loader, must give up
-	push    cs
-	pop	ds
-	lea	si,loader_panic_mess
+	movw	%cs, %ax			# aka SETUPSEG
+	subw	$DELTA_INITSEG, %ax 		# aka INITSEG
+	movw	%ax, %ds
+# Check if an old loader tries to load a big-kernel
+	testb	$LOADED_HIGH, %cs:loadflags	# Do we have a big kernel?
+	jz	loader_ok			# No, no danger for old loaders.
+
+	cmpb	$0, %cs:type_of_loader 		# Do we have a loader that
+						# can deal with us?
+	jnz	loader_ok			# Yes, continue.
+
+	pushw	%cs				# No, we have an old loader,
+	popw	%ds				# die. 
+	lea	loader_panic_mess, %si
 	call	prtstr
+
 	jmp	no_sig_loop
-loader_panic_mess: 
-	.ascii	"Wrong loader:  giving up."
-	db	0
+
+loader_panic_mess: .string "Wrong loader, giving up..."
 
 loader_ok:
-! Get memory size (extended mem, kB)
+# Get memory size (extended mem, kB)
 
-	xor	eax, eax
-	mov	dword ptr [0x1e0], eax
+	xorl	%eax, %eax
+	movl	%eax, (0x1e0)
 #ifndef STANDARD_MEMORY_BIOS_CALL
-
-	mov	byte ptr [E820NR], al
-
-! Try three different memory detection schemes.  First, try
-! e820h, which lets us assemble a memory map, then try e801h,
-! which returns a 32-bit memory size, and finally 88h, which
-! returns 0-64m
-
-! method E820H:
-! the memory map from hell.  e820h returns memory classified into
-! a whole bunch of different types, and allows memory holes and
-! everything.  We scan through this memory map and build a list
-! of the first 32 memory areas, which we return at [E820MAP].
-! 
+	movb	%al, (E820NR)
+# Try three different memory detection schemes.  First, try
+# e820h, which lets us assemble a memory map, then try e801h,
+# which returns a 32-bit memory size, and finally 88h, which
+# returns 0-64m
+
+# method E820H:
+# the memory map from hell.  e820h returns memory classified into
+# a whole bunch of different types, and allows memory holes and
+# everything.  We scan through this memory map and build a list
+# of the first 32 memory areas, which we return at [E820MAP].
+#
 
 meme820:
-	mov	edx, #0x534d4150		! ascii `SMAP'
-	xor	ebx, ebx			! continuation counter
-
-	mov	di, #E820MAP			! point into the whitelist
-						! so we can have the bios
-						! directly write into it.
+	movl	$0x534d4150, %edx		# ascii `SMAP'
+	xorl	%ebx, %ebx			# continuation counter
+	movw	$E820MAP, %di			# point into the whitelist
+						# so we can have the bios
+						# directly write into it.
 
 jmpe820:
-	mov	eax, #0x0000e820		! e820, upper word zeroed
-	mov	ecx, #20			! size of the e820rec
-
-	push	ds				! data record.
-	pop	es
-	int	0x15				! make the call
-	jc	bail820				! fall to e801 if it fails
-
-	cmp	eax, #0x534d4150		! check the return is `SMAP'
-	jne	bail820				! fall to e801 if it fails
-
-!	cmp	dword ptr [16+di], #1		! is this usable memory?
-!	jne	again820
-	
-	! If this is usable memory, we save it by simply advancing di by
-	! sizeof(e820rec).
-	!
+	movl	$0x0000e820, %eax		# e820, upper word zeroed
+	movl	$20, %ecx			# size of the e820rec
+	pushw	%ds				# data record.
+	popw	%es
+	int	$0x15				# make the call
+	jc	bail820				# fall to e801 if it fails
+
+	cmpl	$0x534d4150, %eax		# check the return is `SMAP'
+	jne	bail820				# fall to e801 if it fails
+
+#	cmpl	$1, 16(%di)			# is this usable memory?
+#	jne	again820
+
+	# If this is usable memory, we save it by simply advancing %di by
+	# sizeof(e820rec).
+	#
 good820:
-	mov	al, byte ptr [E820NR]	! up to 32 good entries, that is
-	cmp	al, #E820MAX
+	movb	(E820NR), %al			# up to 32 entries
+	cmpb	$E820MAX, %al
 	jnl	bail820
-	inc	byte ptr [E820NR]
-	mov	ax, di
-	add	ax, #20
-	mov	di, ax
 
+	incb	(E820NR)
+	movw	%di, %ax
+	addw	$20, %ax
+	movw	%ax, %di
 again820:
-	cmp	ebx, #0			! check to see if ebx is
-	jne	jmpe820			! set to EOF
-
+	cmpl	$0, %ebx			# check to see if
+	jne	jmpe820				# %ebx is set to EOF
 bail820:
 
 
-! method E801H:
-! memory size is in 1k chunksizes, to avoid confusing loadlin.
-! we store the 0xe801 memory size in a completely different place,
-! because it will most likely be longer than 16 bits.
-! (use 1e0 because that's what Larry Augustine uses in his
-! alternative new memory detection scheme, and it's sensible
-! to write everything into the same place.)
+# method E801H:
+# memory size is in 1k chunksizes, to avoid confusing loadlin.
+# we store the 0xe801 memory size in a completely different place,
+# because it will most likely be longer than 16 bits.
+# (use 1e0 because that's what Larry Augustine uses in his
+# alternative new memory detection scheme, and it's sensible
+# to write everything into the same place.)
 
 meme801:
-
-        mov     ax,#0xe801
-	int     0x15
+	movw	$0xe801, %ax
+	int	$0x15
 	jc	mem88
 
-	and     edx, #0xffff    ! clear sign extend
-	shl     edx, 6          ! and go from 64k to 1k chunks
-	mov     [0x1e0],edx     ! store extended memory size
+	andl	$0xffff, %edx			# clear sign extend
+	shll	$6, %edx			# and go from 64k to 1k chunks
+	movl	%edx, (0x1e0)			# store extended memory size
+	andl	$0xffff, %ecx			# clear sign extend
+ 	addl	%ecx, (0x1e0)			# and add lower memory into
+						# total size.
 
-	and     ecx, #0xffff    ! clear sign extend
-	add     [0x1e0],ecx     ! and add lower memory into total size.
-
-! Ye Olde Traditional Methode.  Returns the memory size (up to 16mb or
-! 64mb, depending on the bios) in ax.
+# Ye Olde Traditional Methode.  Returns the memory size (up to 16mb or
+# 64mb, depending on the bios) in ax.
 mem88:
 
 #endif
-	mov	ah,#0x88
-	int	0x15
-	mov	[2],ax
-
-! Set the keyboard repeat rate to the max
-
-	mov	ax,#0x0305
-	xor	bx,bx		! clear bx
-	int	0x16
-
-! Check for video adapter and its parameters and allow the
-! user to browse video modes.
-
-	call	video	! NOTE: we need DS pointing to boot sector
-
-! Get hd0 data
-
-	xor	ax,ax		! clear ax
-	mov	ds,ax
-	lds	si,[4*0x41]
-	mov	ax,cs		! aka #SETUPSEG
-	sub	ax,#DELTA_INITSEG ! aka #INITSEG
-	push	ax
-	mov	es,ax
-	mov	di,#0x0080
-	mov	cx,#0x10
-	push	cx
+	movb	$0x88, %ah
+	int	$0x15
+	movw	%ax, (2)
+
+# Set the keyboard repeat rate to the max
+	movw	$0x0305, %ax
+	xorw	%bx, %bx
+	int	$0x16
+
+# Check for video adapter and its parameters and allow the
+# user to browse video modes.
+	call	video				# NOTE: we need %ds pointing
+						# to bootsector
+
+# Get hd0 data...
+	xorw	%ax, %ax
+	movw	%ax, %ds
+	ldsw	(4 * 0x41), %si
+	movw	%cs, %ax			# aka SETUPSEG
+	subw	$DELTA_INITSEG, %ax		# aka INITSEG
+	pushw	%ax
+	movw	%ax, %es
+	movw	$0x0080, %di
+	movw	$0x10, %cx
+	pushw	%cx
 	cld
 	rep
-	movsb
-
-! Get hd1 data
-
-	xor	ax,ax		! clear ax
-	mov	ds,ax
-	lds	si,[4*0x46]
-	pop	cx
-	pop	es
-	mov	di,#0x0090
+ 	movsb
+# Get hd1 data...
+	xorw	%ax, %ax
+	movw	%ax, %ds
+	ldsw	(4 * 0x46), %si
+	popw	%cx
+	popw	%es
+	movw	$0x0090, %di
 	rep
 	movsb
-
-! Check that there IS a hd1 :-)
-
-	mov	ax,#0x01500
-	mov	dl,#0x81
-	int	0x13
+# Check that there IS a hd1 :-)
+	movw	$0x01500, %ax
+	movb	$0x81, %dl
+	int	$0x13
 	jc	no_disk1
-	cmp	ah,#3
+	
+	cmpb	$3, %ah
 	je	is_disk1
+
 no_disk1:
-	mov	ax,cs		! aka #SETUPSEG
-	sub	ax,#DELTA_INITSEG ! aka #INITSEG
-	mov	es,ax
-	mov	di,#0x0090
-	mov	cx,#0x10
-	xor	ax,ax		! clear ax
+	movw	%cs, %ax			# aka SETUPSEG
+	subw	$DELTA_INITSEG, %ax 		# aka INITSEG
+	movw	%ax, %es
+	movw	$0x0090, %di
+	movw	$0x10, %cx
+	xorw	%ax, %ax
 	cld
 	rep
 	stosb
 is_disk1:
-
-! check for Micro Channel (MCA) bus
-	mov ax,cs		! aka #SETUPSEG
-	sub ax,#DELTA_INITSEG	! aka #INITSEG
-	mov ds,ax
-	mov ds,ax
-	xor ax,ax
-	mov [0xa0], ax		! set table length to 0
-	mov ah, #0xc0
+# check for Micro Channel (MCA) bus
+	movw	%cs, %ax			# aka SETUPSEG
+	subw	$DELTA_INITSEG, %ax		# aka INITSEG
+	movw	%ax, %ds
+	xorw	%ax, %ax
+	movw	%ax, 0xa0			# set table length to 0
+	movb	$0xc0, %ah
 	stc
-	int 0x15		! puts feature table at es:bx
-	jc no_mca
-	push ds
-	mov ax,es
-	mov ds,ax
-	mov ax,cs		! aka #SETUPSEG
-	sub ax, #DELTA_INITSEG	! aka #INITSEG
-	mov es,ax
-	mov si,bx
-	mov di,#0xa0
-	mov cx,(si)
-	add cx,#2		! table length is a short
-	cmp cx,#0x10
-	jc sysdesc_ok
-	mov cx,#0x10		! we keep only first 16 bytes
+	int	$0x15				# moves feature table to es:bx
+	jc	no_mca
+
+	pushw	%ds
+	movw	%es, %ax
+	movw	%ax, %ds
+	movw	%cs, %ax			# aka SETUPSEG
+	subw	$DELTA_INITSEG, %ax		# aka INITSEG
+	movw	%ax, %es
+	movw	%bx, %si
+	movw	$0xa0, %di
+	movw	(%si), %cx
+	addw	$2, %cx				# table length is a short
+	cmpw	$0x10, %cx
+	jc	sysdesc_ok
+
+	movw	$0x10, %cx			# we keep only first 16 bytes
 sysdesc_ok:
 	rep
 	movsb
-	pop ds
-
+	popw	%ds
 no_mca:
-
-! Check for PS/2 pointing device
-
-	mov	ax,cs		! aka #SETUPSEG
-	sub	ax,#DELTA_INITSEG ! aka #INITSEG
-	mov	ds,ax
-	mov	[0x1ff],#0	! default is no pointing device
-	int	0x11		! int 0x11: equipment determination
-	test	al,#0x04	! check if pointing device installed
+# Check for PS/2 pointing device
+	movw	%cs, %ax			# aka SETUPSEG
+	subw	$DELTA_INITSEG, %ax		# aka INITSEG
+	movw	%ax, %ds
+	movw	$0, (0x1ff)			# default is no pointing device
+	int	$0x11				# int 0x11: equipment list
+	testb	$0x04, %al			# check if mouse installed
 	jz	no_psmouse
-	mov	[0x1ff],#0xaa	! device present
+
+	movw	$0xAA, (0x1ff)			# device present
 no_psmouse:
 
 #ifdef CONFIG_APM
-! check for APM BIOS
-		! NOTE:	DS is pointing to the boot sector
-		!
-	mov	[64],#0		! version == 0 means no APM BIOS
-
-	mov	ax,#0x05300	! APM BIOS installation check
-	xor	bx,bx
-	int	0x15
-	jc	done_apm_bios	! error -> no APM BIOS
-
-	cmp	bx,#0x0504d	! check for "PM" signature
-	jne	done_apm_bios	! no signature -> no APM BIOS
-
-	and	cx,#0x02	! Is 32 bit supported?
-	je	done_apm_bios	!	no ...
-
-	mov	ax,#0x05304	! Disconnect first just in case
-	xor	bx,bx
-	int	0x15		! ignore return code
-
-	mov	ax,#0x05303	! 32 bit connect
-	xor	ebx,ebx
-	int	0x15
-	jc	no_32_apm_bios	! error
-
-	mov	[66],ax		! BIOS code segment
-	mov	[68],ebx	! BIOS entry point offset
-	mov	[72],cx		! BIOS 16 bit code segment
-	mov	[74],dx		! BIOS data segment
-	mov	[78],esi	! BIOS code segment length
-	mov	[82],di		! BIOS data segment length
-!
-! Redo the installation check as the 32 bit connect
-! modifies the flags returned on some BIOSs
-!
-	mov	ax,#0x05300	! APM BIOS installation check
-	xor	bx,bx
-	int	0x15
-	jc	apm_disconnect	! error -> should not happen, tidy up
+# Then check for an APM BIOS...
+						# %ds points to the bootsector
+	movw	$0, 0x40			# version = 0 means no APM BIOS
+	movw	$0x05300, %ax			# APM BIOS installation check
+	xorw	%bx, %bx
+	int	$0x15
+	jc	done_apm_bios			# Nope, no APM BIOS
+	
+	cmpw	$0x0504d, %bx			# Check for "PM" signature
+	jne	done_apm_bios			# No signature, no APM BIOS
+
+	andw	$0x02, %cx			# Is 32 bit supported?
+	je	done_apm_bios			# No 32-bit, no (good) APM BIOS
+
+	movw	$0x05304, %ax			# Disconnect first just in case
+	xorw	%bx, %bx
+	int	$0x15				# ignore return code
+	movw	$0x05303, %ax			# 32 bit connect
+	xorw	%ebx, %ebx
+	int	$0x15
+	jc	no_32_apm_bios			# Ack, error. 
+
+	movw	%ax,  (66)			# BIOS code segment
+	movl	%ebx, (68)			# BIOS entry point offset
+	movw	%cx,  (72)			# BIOS 16 bit code segment
+	movw	%dx,  (74)			# BIOS data segment
+	movl	%esi, (78)			# BIOS code segment length
+	movw	%di,  (82)			# BIOS data segment length
+# Redo the installation check as the 32 bit connect
+# modifies the flags returned on some BIOSs
+	movw	$0x05300, %ax			# APM BIOS installation check
+	xorw	%bx, %bx
+	int	$0x15
+	jc	apm_disconnect			# error -> shouldn't happen
 
-	cmp	bx,#0x0504d	! check for "PM" signature
-	jne	apm_disconnect	! no signature -> should not happen, tidy up
+	cmpw	$0x0504d, %bx			# check for "PM" signature
+	jne	apm_disconnect			# no sig -> shouldn't happen
 
-	mov	[64],ax		! record the APM BIOS version
-	mov	[76],cx		!	and flags
+	movw	%ax, (64)			# record the APM BIOS version
+	movw	%cx, (76)			# and flags
 	jmp	done_apm_bios
 
-apm_disconnect:
-	mov	ax,#0x05304	! Disconnect
-	xor	bx,bx
-	int	0x15		! ignore return code
+apm_disconnect:					# Tidy up
+	movw	$0x05304, %ax			# Disconnect
+	xorw	%bx, %bx
+	int	$0x15				# ignore return code
+
 	jmp	done_apm_bios
 
 no_32_apm_bios:
-	and	[76], #0xfffd	! remove 32 bit support bit
-
+	andw	$0xfffd, (76)			# remove 32 bit support bit
 done_apm_bios:
 #endif
 
-! Now we want to move to protected mode ...
-
-	seg cs
-	cmp	realmode_swtch,#0
+# Now we want to move to protected mode ...
+	cmpw	$0, %cs:realmode_swtch
 	jz	rmodeswtch_normal
-	seg cs
-	callf	far * realmode_swtch
+
+	call	*%cs:realmode_swtch
+
 	jmp	rmodeswtch_end
+
 rmodeswtch_normal:
-        push	cs
+        pushw	%cs
 	call	default_switch
-rmodeswtch_end:
 
-! we get the code32 start address and modify the below 'jmpi'
-! (loader may have changed it)
-	seg cs
-	mov	eax,code32_start
-	seg cs
-	mov	code32,eax
-
-! Now we move the system to its rightful place
-! ...but we check, if we have a big-kernel.
-! in this case we *must* not move it ...
-	seg cs
-	test	byte ptr loadflags,#LOADED_HIGH
-	jz	do_move0	! we have a normal low loaded zImage
-				! we have a high loaded big kernel
-	jmp	end_move	! ... and we skip moving
+rmodeswtch_end:
+# we get the code32 start address and modify the below 'jmpi'
+# (loader may have changed it)
+	movl	%cs:code32_start, %eax
+	movl	%eax, %cs:code32
+
+# Now we move the system to its rightful place ... but we check if we have a
+# big-kernel. In that case we *must* not move it ...
+	testb	$LOADED_HIGH, %cs:loadflags
+	jz	do_move0			# .. then we have a normal low
+						# loaded zImage
+						# .. or else we have a high
+						# loaded bzImage
+	jmp	end_move			# ... and we skip moving
 
 do_move0:
-	mov	ax,#0x100	! start of destination segment
-	mov	bp,cs		! aka #SETUPSEG
-	sub	bp,#DELTA_INITSEG ! aka #INITSEG
-	seg cs
-	mov	bx,start_sys_seg	! start of source segment
-	cld			! 'direction'=0, movs moves forward
+	movw	$0x100, %ax			# start of destination segment
+	movw	%cs, %bp			# aka SETUPSEG
+	subw	$DELTA_INITSEG, %bp		# aka INITSEG
+	movw	%cs:start_sys_seg, %bx		# start of source segment
+	cld
 do_move:
-	mov	es,ax		! destination segment
-	inc	ah		! instead of add ax,#0x100
-	mov	ds,bx		! source segment
-	add	bx,#0x100
-	sub	di,di
-	sub	si,si
-	mov 	cx,#0x400
+	movw	%ax, %es			# destination segment
+	incb	%ah				# instead of add ax,#0x100
+	movw	%bx, %ds			# source segment
+	addw	$0x100, %bx
+	subw	%di, %di
+	subw	%si, %si
+	movw 	$0x400, %cx
 	rep
-	movsd
-	cmp	bx,bp		! we assume start_sys_seg > 0x200,
-				! so we will perhaps read one page more then
-				! needed, but never overwrite INITSEG because
-				! destination is minimum one page below source
+	movsl
+	cmpw	%bp, %bx			# assume start_sys_seg > 0x200,
+						# so we will perhaps read one
+						# page more than needed, but
+						# never overwrite INITSEG
+						# because destination is a
+						# minimum one page below source
 	jb	do_move
 
-! then we load the segment descriptors
-
 end_move:
-	mov	ax,cs ! aka #SETUPSEG	! right, forgot this at first. didn't work :-)
-	mov	ds,ax
-
-! If we have our code not at 0x90000, we need to move it there now.
-! We also then need to move the parameters behind it (command line)
-! Because we would overwrite the code on the current IP, we move
-! it in two steps, jumping high after the first one.
-	mov	ax,cs
-	cmp	ax,#SETUPSEG
+# then we load the segment descriptors
+	movw	%cs, %ax			# aka SETUPSEG
+	movw	%ax, %ds
+
+# If we have our code not at 0x90000, we need to move it there now.
+# We also then need to move the params behind it (commandline)
+# Because we would overwrite the code on the current IP, we move
+# it in two steps, jumping high after the first one.
+	movw	%cs, %ax
+	cmpw	$SETUPSEG, %ax
 	je	end_move_self
-	cli	! make sure we really have interrupts disabled !
-		! because after this the stack should not be used
-	sub	ax,#DELTA_INITSEG ! aka #INITSEG
-	mov	dx,ss
-	cmp	dx,ax
+
+	cli					# make sure we really have
+						# interrupts disabled !
+						# because after this the stack
+						# should not be used
+	subw	$DELTA_INITSEG, %ax		# aka INITSEG
+	movw	%ss, %dx
+	cmpw	%ax, %dx
 	jb	move_self_1
-	add	dx,#INITSEG
-	sub	dx,ax		! this will be SS after the move
+
+	addw	$INITSEG, %dx
+	subw	%ax, %dx			# this will go into %ss after
+						# the move
 move_self_1:
-	mov	ds,ax
-	mov	ax,#INITSEG	! real INITSEG
-	mov	es,ax
-	seg cs
-	mov	cx,setup_move_size
-	std		! we have to move up, so we use direction down
-			! because the areas may overlap
-	mov	di,cx
-	dec	di
-	mov	si,di
-	sub	cx,#move_self_here+0x200
+	movw	%ax, %ds
+	movw	$INITSEG, %ax			# real INITSEG
+	movw	%ax, %es
+	movw	%cs:setup_move_size, %cx
+	std					# we have to move up, so we use
+						# direction down because the
+						# areas may overlap
+	movw	%cx, %di
+	decw	%di
+	movw	%di, %si
+	subw	$move_self_here+0x200, %cx
 	rep
 	movsb
-	jmpi	move_self_here,SETUPSEG ! jump to our final place
+	ljmp	$SETUPSEG, $move_self_here
+
 move_self_here:
-	mov	cx,#move_self_here+0x200
+	movw	$move_self_here+0x200, %cx
 	rep
 	movsb
-	mov	ax,#SETUPSEG
-	mov	ds,ax
-	mov	ss,dx
-			! now we are at the right place
-end_move_self:
-
-	lidt	idt_48		! load idt with 0,0
-	lgdt	gdt_48		! load gdt with whatever appropriate
-
-! that was painless, now we enable A20
+	movw	$SETUPSEG, %ax
+	movw	%ax, %ds
+	movw	%dx, %ss
+end_move_self:					# now we are at the right place
+	lidt	idt_48				# load idt with 0,0
+	lgdt	gdt_48				# load gdt with whatever is
+						# appropriate
 
+# that was painless, now we enable a20
 	call	empty_8042
-	mov	al,#0xD1		! command write
-	out	#0x64,al
+
+	movb	$0xD1, %al			# command write
+	outb	%al, $0x64
 	call	empty_8042
-	mov	al,#0xDF		! A20 on
-	out	#0x60,al
+
+	movb	$0xDF, %al			# A20 on
+	outb	%al, $0x60
 	call	empty_8042
 
-! wait until a20 really *is* enabled; it can take a fair amount of
-! time on certain systems; Toshiba Tecras are known to have this
-! problem.  The memory location used here is the int 0x1f vector,
-! which should be safe to use; any *unused* memory location < 0xfff0
-! should work here.  
-
-#define	TEST_ADDR 0x7c
-
-	push	ds
-	xor	ax,ax			! segment 0x0000
-	mov	ds,ax
-	dec	ax			! segment 0xffff (HMA)
-	mov	gs,ax
-	mov	bx,[TEST_ADDR]		! we want to restore the value later
+# wait until a20 really *is* enabled; it can take a fair amount of
+# time on certain systems; Toshiba Tecras are known to have this
+# problem.  The memory location used here (0x200) is the int 0x80
+# vector, which should be safe to use.
+	push    %ds
+	push    %es
+	xorw	%ax, %ax			# segment 0x0000
+	movw	%ax, %fs
+	decw	%ax				# segment 0xffff (HMA)
+	movw	%ax, %gs
 a20_wait:
-	inc	ax
-	mov	[TEST_ADDR],ax
-	seg	gs
-	cmp	ax,[TEST_ADDR+0x10]
-	je	a20_wait		! loop until no longer aliased
-	mov	[TEST_ADDR],bx		! restore original value
-	pop	ds
-		
-! make sure any possible coprocessor is properly reset..
-
-	xor	ax,ax
-	out	#0xf0,al
-	call	delay
-	out	#0xf1,al
+	incw	%ax				# unused memory location <0xfff0
+	movw	%ax, %fs:(0x200)		# we use the "int 0x80" vector
+	cmpw	%gs:(0x210), %ax		# and its corresponding HMA addr
+	je	a20_wait			# loop until no longer aliased
+
+# make sure any possible coprocessor is properly reset..
+	xorw	%ax, %ax
+	outb	%al, $0xf0
 	call	delay
 
-! well, that went ok, I hope. Now we mask all interrupts - the rest
-! is done in init_IRQ().
+	outb	%al, $0xf1
+	call	delay
 
-	mov	al,#0xFF		! mask off all interrupts for now
-	out	#0xA1,al
+# well, that went ok, I hope. Now we mask all interrupts - the rest
+# is done in init_IRQ().
+	movb	$0xFF, %al			# mask all interrupts for now
+	outb	%al, $0xA1
 	call	delay
-	mov	al,#0xFB		! mask all irq's but irq2 which
-	out	#0x21,al		! is cascaded
+	
+	movb	$0xFB, %al			# mask all irq's but irq2 which
+	outb	%al, $0x21			# is cascaded
 
-! Well, that certainly wasn't fun :-(. Hopefully it works, and we don't
-! need no steenking BIOS anyway (except for the initial loading :-).
-! The BIOS routine wants lots of unnecessary data, and it's less
-! "interesting" anyway. This is how REAL programmers do it.
-!
-! Well, now's the time to actually move into protected mode. To make
-! things as simple as possible, we do no register set-up or anything,
-! we let the GNU-compiled 32-bit programs do that. We just jump to
-! absolute address 0x1000 (or the loader supplied one),
-! in 32-bit protected mode.
-!
-! Note that the short jump isn't strictly needed, although there are
-! reasons why it might be a good idea. It won't hurt in any case.
-!
-	mov	ax,#1		! protected mode (PE) bit
-	lmsw	ax		! This is it!
+# Well, that certainly wasn't fun :-(. Hopefully it works, and we don't
+# need no steenking BIOS anyway (except for the initial loading :-).
+# The BIOS-routine wants lots of unnecessary data, and it's less
+# "interesting" anyway. This is how REAL programmers do it.
+#
+# Well, now's the time to actually move into protected mode. To make
+# things as simple as possible, we do no register set-up or anything,
+# we let the gnu-compiled 32-bit programs do that. We just jump to
+# absolute address 0x1000 (or the loader supplied one),
+# in 32-bit protected mode.
+#
+# Note that the short jump isn't strictly needed, although there are
+# reasons why it might be a good idea. It won't hurt in any case.
+	movw	$1, %ax				# protected mode (PE) bit
+	lmsw	%ax				# This is it!
 	jmp	flush_instr
-flush_instr:
-	xor	bx,bx		! Flag to indicate a boot
 
-! NOTE: For high loaded big kernels we need a
-!	jmpi    0x100000,__KERNEL_CS
-!
-!	but we yet haven't reloaded the CS register, so the default size 
-!	of the target offset still is 16 bit.
-!       However, using an operant prefix (0x66), the CPU will properly
-!	take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
-!	Manual, Mixing 16-bit and 32-bit code, page 16-6)
-	db	0x66,0xea	! prefix + jmpi-opcode
-code32:	dd	0x1000		! will be set to 0x100000 for big kernels
-	dw	__KERNEL_CS
+flush_instr:
+	xorw	%bx, %bx			# Flag to indicate a boot
 
+# NOTE: For high loaded big kernels we need a
+#	jmpi    0x100000,__KERNEL_CS
+#
+#	but we yet haven't reloaded the CS register, so the default size 
+#	of the target offset still is 16 bit.
+#       However, using an operant prefix (0x66), the CPU will properly
+#	take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
+#	Manual, Mixing 16-bit and 32-bit code, page 16-6)
+
+	.byte 0x66, 0xea			# prefix + jmpi-opcode
+code32:	.long	0x1000				# will be set to 0x100000
+						# for big kernels
+	.word	__KERNEL_CS
 
+# Here's a bunch of information about your current kernel..
 kernel_version:	.ascii	UTS_RELEASE
 		.ascii	" ("
 		.ascii	LINUX_COMPILE_BY
@@ -690,191 +682,184 @@
 		.ascii	LINUX_COMPILE_HOST
 		.ascii	") "
 		.ascii	UTS_VERSION
-		db	0
-
-! This is the default real mode switch routine.
-! to be called just before protected mode transition
+		.byte	0
 
+# This is the default real mode switch routine.
+# to be called just before protected mode transition
 default_switch:
-	cli			! no interrupts allowed !
-	mov	al,#0x80	! disable NMI for the bootup sequence
-	out	#0x70,al
-	retf
-
-! This routine only gets called, if we get loaded by the simple
-! bootsect loader _and_ have a bzImage to load.
-! Because there is no place left in the 512 bytes of the boot sector,
-! we must emigrate to code space here.
-!
+	cli					# no interrupts allowed !
+	movb	$0x80, %al			# disable NMI for bootup
+						# sequence
+	outb	%al, $0x70
+	lret
+
+# This routine only gets called, if we get loaded by the simple
+# bootsect loader _and_ have a bzImage to load.
+# Because there is no place left in the 512 bytes of the boot sector,
+# we must emigrate to code space here.
 bootsect_helper:
-	seg cs
-	cmp	word ptr bootsect_es,#0
+	cmpw	$0, %cs:bootsect_es
 	jnz	bootsect_second
-	seg cs
-	mov	byte ptr type_of_loader,#0x20
-	mov	ax,es
-	shr	ax,#4
-	seg	cs
-	mov	byte ptr bootsect_src_base+2,ah
-	mov	ax,es
-	seg cs
-	mov	bootsect_es,ax
-	sub	ax,#SYSSEG
-	retf			! nothing else to do for now
+
+	movb	$0x20, %cs:type_of_loader
+	movw	%es, %ax
+	shrw	$4, %ax
+	movb	%ah, %cs:bootsect_src_base+2
+	movw	%es, %ax
+	movw	%ax, %cs:bootsect_es
+	subw	$SYSSEG, %ax
+	lret					# nothing else to do for now
+
 bootsect_second:
-	push	cx
-	push	si
-	push	bx
-	test	bx,bx	! 64K full ?
+	pushw	%cx
+	pushw	%si
+	pushw	%bx
+	testw	%bx, %bx			# 64K full?
 	jne	bootsect_ex
-	mov	cx,#0x8000	! full 64K move, INT15 moves words
-	push	cs
-	pop	es
-	mov	si,#bootsect_gdt
-	mov	ax,#0x8700
-	int	0x15
-	jc	bootsect_panic	! this, if INT15 fails
-	seg cs
-	mov	es,bootsect_es	! we reset es to always point to 0x10000
-	seg cs
-	inc	byte ptr bootsect_dst_base+2
+
+	movw	$0x8000, %cx			# full 64K, INT15 moves words
+	pushw	%cs
+	popw	%es
+	movw	$bootsect_gdt, %si
+	movw	$0x8700, %ax
+	int	$0x15
+	jc	bootsect_panic			# this, if INT15 fails
+
+	movw	%cs:bootsect_es, %es		# we reset %es to always point
+	incb	%cs:bootsect_dst_base+2		# to 0x10000
 bootsect_ex:
-	seg cs
-	mov	ah, byte ptr bootsect_dst_base+2
-	shl	ah,4	! we now have the number of moved frames in ax
-	xor	al,al
-	pop	bx
-	pop	si
-	pop	cx
-	retf
+	movb	%cs:bootsect_dst_base+2, %ah
+	shlb	$4, %ah				# we now have the number of
+						# moved frames in %ax
+	xorb	%al, %al
+	popw	%bx
+	popw	%si
+	popw	%cx
+	lret
 
 bootsect_gdt:
-	.word	0,0,0,0
-	.word	0,0,0,0
+	.word	0, 0, 0, 0
+	.word	0, 0, 0, 0
+
 bootsect_src:
 	.word	0xffff
+
 bootsect_src_base:
-	.byte	0,0,1			! base = 0x010000
-	.byte	0x93			! typbyte
-	.word	0			! limit16,base24 =0
+	.byte	0x00, 0x00, 0x01		# base = 0x010000
+	.byte	0x93				# typbyte
+	.word	0				# limit16,base24 =0
+
 bootsect_dst:
 	.word	0xffff
+
 bootsect_dst_base:
-	.byte	0,0,0x10		! base = 0x100000
-	.byte	0x93			! typbyte
-	.word	0			! limit16,base24 =0
-	.word	0,0,0,0			! BIOS CS
-	.word	0,0,0,0			! BIOS DS
+	.byte	0x00, 0x00, 0x10		# base = 0x100000
+	.byte	0x93				# typbyte
+	.word	0				# limit16,base24 =0
+	.word	0, 0, 0, 0			# BIOS CS
+	.word	0, 0, 0, 0			# BIOS DS
+
 bootsect_es:
 	.word	0
 
 bootsect_panic:
-	push	cs
-	pop	ds
+	pushw	%cs
+	popw	%ds
 	cld
-	lea	si,bootsect_panic_mess
+	leaw	bootsect_panic_mess, %si
 	call	prtstr
+	
 bootsect_panic_loop:
 	jmp	bootsect_panic_loop
+
 bootsect_panic_mess:
-	.ascii	"INT15 refuses to access high memory.  Giving up."
-	db	0
+	.string	"INT15 refuses to access high mem, giving up."
 
-! This routine checks that the keyboard command queue is empty
-! (after emptying the output buffers)
-!
-! Some machines have delusions that the keyboard buffer is always full
-! with no keyboard attached...
+# This routine checks that the keyboard command queue is empty
+# (after emptying the output buffers)
+#
+# Some machines have delusions that the keyboard buffer is always full
+# with no keyboard attached...
 
 empty_8042:
-       push    ecx
-       mov     ecx,#0xFFFFFF
+	pushl	%ecx
+	movl	$0xFFFFFF, %ecx
 
 empty_8042_loop:
-       dec     ecx
-       jz      empty_8042_end_loop
+	decl	%ecx
+	jz	empty_8042_end_loop
 
 	call	delay
-	in	al,#0x64	! 8042 status port
-	test	al,#1		! output buffer?
+
+	inb	$0x64, %al			# 8042 status port
+	testb	$1, %al				# output buffer?
 	jz	no_output
+
 	call	delay
-	in	al,#0x60	! read it
+	inb	$0x60, %al			# read it
 	jmp	empty_8042_loop
+
 no_output:
-	test	al,#2		! is input buffer full?
-	jnz	empty_8042_loop	! yes - loop
+	testb	$2, %al				# is input buffer full?
+	jnz	empty_8042_loop			# yes - loop
 empty_8042_end_loop:
-        pop     ecx
+	popl	%ecx
 	ret
 
-!
-! Read the CMOS clock. Return the seconds in al
-!
+# Read the cmos clock. Return the seconds in al
 gettime:
-	push	cx
-	mov	ah,#0x02
-	int	0x1a
-	mov	al,dh			! dh contains the seconds
-	and	al,#0x0f
-	mov	ah,dh
-	mov	cl,#0x04
-	shr	ah,cl
+	pushw	%cx
+	movb	$0x02, %ah
+	int	$0x1a
+	movb	%dh, %al			# %dh contains the seconds
+	andb	$0x0f, %al
+	movb	%dh, %ah
+	movb	$0x04, %cl
+	shrb	%cl, %ah
 	aad
-	pop	cx
+	popw	%cx
 	ret
 
-!
-! Delay is needed after doing I/O
-!
+# Delay is needed after doing I/O
 delay:
-	.word	0x00eb			! jmp $+2
+	jmp	.+2				# jmp $+2
 	ret
 
-!
-! Descriptor tables
-!
-
+# Descriptor tables
 gdt:
-	.word	0,0,0,0		! dummy
-
-	.word	0,0,0,0		! unused
-
-	.word	0xFFFF		! 4Gb - (0x100000*0x1000 = 4Gb)
-	.word	0x0000		! base address=0
-	.word	0x9A00		! code read/exec
-	.word	0x00CF		! granularity=4096, 386 (+5th nibble of limit)
-
-	.word	0xFFFF		! 4Gb - (0x100000*0x1000 = 4Gb)
-	.word	0x0000		! base address=0
-	.word	0x9200		! data read/write
-	.word	0x00CF		! granularity=4096, 386 (+5th nibble of limit)
+	.word	0, 0, 0, 0			# dummy
+	.word	0, 0, 0, 0			# unused
 
+	.word	0xFFFF				# 4Gb - (0x100000*0x1000 = 4Gb)
+	.word	0				# base address = 0
+	.word	0x9A00				# code read/exec
+	.word	0x00CF				# granularity = 4096, 386
+						#  (+5th nibble of limit)
+
+	.word	0xFFFF				# 4Gb - (0x100000*0x1000 = 4Gb)
+	.word	0				# base address = 0
+	.word	0x9200				# data read/write
+	.word	0x00CF				# granularity = 4096, 386
+						#  (+5th nibble of limit)
 idt_48:
-	.word	0			! idt limit=0
-	.word	0,0			! idt base=0L
-
+	.word	0				# idt limit = 0
+	.word	0, 0				# idt base = 0L
 gdt_48:
-	.word	0x800		! gdt limit=2048, 256 GDT entries
-	.word	512+gdt,0x9	! gdt base = 0X9xxxx
+	.word	0x8000				# gdt limit=2048,
+						#  256 GDT entries
 
-!
-! Include video setup & detection code
-!
+	.word	512+gdt, 0x9			# gdt base = 0X9xxxx
 
-#include "video.S"
+# Include video setup & detection code
 
-!
-! Setup signature -- must be last
-!
+#include "video.S"
 
+# Setup signature -- must be last
 setup_sig1:	.word	SIG1
 setup_sig2:	.word	SIG2
 
-!
-! After this point, there is some free space which is used by the video mode
-! handling code to store the temporary mode table (not used by the kernel).
-!
+# After this point, there is some free space which is used by the video mode
+# handling code to store the temporary mode table (not used by the kernel).
 
 modelist:
 
diff -u --recursive --new-file v2.3.20/linux/arch/i386/boot/tools/build.c linux/arch/i386/boot/tools/build.c
--- v2.3.20/linux/arch/i386/boot/tools/build.c	Sun Oct 25 14:16:21 1998
+++ linux/arch/i386/boot/tools/build.c	Mon Oct 11 14:06:10 1999
@@ -58,27 +58,10 @@
 	exit(1);
 }
 
-/* Reading of ld86 output (Minix format) */
-
-#define MINIX_HEADER_LEN 32
-
-void minix_open(const char *name)
+void file_open(const char *name)
 {
-	static byte hdr[] = { 0x01, 0x03, 0x10, 0x04, 0x20, 0x00, 0x00, 0x00 };
-	static u32 *lb = (u32 *) buf;
-
 	if ((fd = open(name, O_RDONLY, 0)) < 0)
 		die("Unable to open `%s': %m", name);
-	if (read(fd, buf, MINIX_HEADER_LEN) != MINIX_HEADER_LEN)
-		die("%s: Unable to read header", name);
-	if (memcmp(buf, hdr, sizeof(hdr)) || lb[5])
-		die("%s: Non-Minix header", name);
-	if (lb[3])
-		die("%s: Illegal data segment");
-	if (lb[4])
-		die("%s: Illegal bss segment");
-	if (lb[7])
-		die("%s: Illegal symbol table");
 }
 
 void usage(void)
@@ -125,7 +108,7 @@
 	}
 	fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
 
-	minix_open(argv[1]);				    /* Copy the boot sector */
+	file_open(argv[1]);
 	i = read(fd, buf, sizeof(buf));
 	fprintf(stderr,"Boot sector %d bytes.\n",i);
 	if (i != 512)
@@ -138,7 +121,7 @@
 		die("Write call failed");
 	close (fd);
 
-	minix_open(argv[2]);				    /* Copy the setup code */
+	file_open(argv[2]);				    /* Copy the setup code */
 	for (i=0 ; (c=read(fd, buf, sizeof(buf)))>0 ; i+=c )
 		if (write(1, buf, c) != c)
 			die("Write call failed");
@@ -146,8 +129,8 @@
 		die("read-error on `setup'");
 	close (fd);
 
-	setup_sectors = (i + 511) / 512;		    /* Pad unused space with zeros */
-	/* for compatibility with ancient versions of LILO */
+	setup_sectors = (i + 511) / 512;	/* Pad unused space with zeros */
+	/* for compatibility with ancient versions of LILO. */
 	if (setup_sectors < SETUP_SECTS)
 		setup_sectors = SETUP_SECTS;
 	fprintf(stderr, "Setup is %d bytes.\n", i);
@@ -161,8 +144,7 @@
 		i += c;
 	}
 
-	if ((fd = open(argv[3], O_RDONLY, 0)) < 0)	    /* Copy the image itself */
-		die("Unable to open `%s': %m", argv[3]);
+	file_open(argv[3]);
 	if (fstat (fd, &sb))
 		die("Unable to stat `%s': %m", argv[3]);
 	sz = sb.st_size;
@@ -187,7 +169,7 @@
 	}
 	close(fd);
 
-	if (lseek(1, 497, SEEK_SET) != 497)		    /* Write sizes to the boot sector */
+	if (lseek(1, 497, SEEK_SET) != 497)		    /* Write sizes to the bootsector */
 		die("Output: seek failed");
 	buf[0] = setup_sectors;
 	if (write(1, buf, 1) != 1)
diff -u --recursive --new-file v2.3.20/linux/arch/i386/boot/video.S linux/arch/i386/boot/video.S
--- v2.3.20/linux/arch/i386/boot/video.S	Fri May 14 12:47:01 1999
+++ linux/arch/i386/boot/video.S	Mon Oct 11 14:06:10 1999
@@ -1,60 +1,62 @@
-!
-!	Display adapter & video mode setup, version 2.13 (14-May-99)
-!
-!	Copyright (C) 1995 -- 1999 Martin Mares <mj@ucw.cz>
-!	Based on the original setup.S code (C) Linus Torvalds and Mats Anderson
-!
-!	For further information, look at Documentation/svga.txt.
-!
+/*	video.S
+ *
+ *	Display adapter & video mode setup, version 2.13 (14-May-99)
+ *
+ *	Copyright (C) 1995 -- 1998 Martin Mares <mj@ucw.cz>
+ *	Based on the original setup.S code (C) Linus Torvalds and Mats Anderson
+ *
+ *	Rewritten to use GNU 'as' by Chris Noe <stiker@northlink.com> May 1999
+ *
+ *	For further information, look at Documentation/svga.txt.
+ *
+ */
 
 #include <linux/config.h> /* for CONFIG_VIDEO_* */
 
-! Enable autodetection of SVGA adapters and modes. If you really need this
-! feature, drop me a mail as I think of removing it some day. You can
-! always enter `scan' to get the video mode table and then use the real
-! video mode numbers (those 4-digit hexadecimal numbers, NOT the menu
-! item numbers) which don't rely on any autodetection.
+/* Enable autodetection of SVGA adapters and modes. */
 #undef CONFIG_VIDEO_SVGA
 
-! Enable autodetection of VESA modes
+/* Enable autodetection of VESA modes */
 #define CONFIG_VIDEO_VESA
 
-! Enable compacting of mode table
+/* Enable compacting of mode table */
 #define CONFIG_VIDEO_COMPACT
 
-! Retain screen contents when switching modes
+/* Retain screen contents when switching modes */
 #define CONFIG_VIDEO_RETAIN
 
-! Enable local mode list
+/* Enable local mode list */
 #undef CONFIG_VIDEO_LOCAL
 
-! Force 400 scan lines for standard modes (hack to fix bad behaviour
-! of certain broken BIOSes -- don't use unless needed)
+/* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */
 #undef CONFIG_VIDEO_400_HACK
 
-! A special hack allowing to force specific BIOS mode ID along with specific
-! dimensions. Especially useful for certain X-Window graphics mode hacks
-! (e.g., 800x600 modes on IBM ThinkPad).
+/* Hack that lets you force specific BIOS mode ID and specific dimensions */
 #undef CONFIG_VIDEO_GFX_HACK
 #define VIDEO_GFX_BIOS_AX 0x4f02	/* 800x600 on ThinkPad */
 #define VIDEO_GFX_BIOS_BX 0x0102
 #define VIDEO_GFX_DUMMY_RESOLUTION 0x6425	/* 100x37 */
 
-! This code uses an extended set of video mode numbers. These include:
-! Aliases for standard modes
-!	NORMAL_VGA (-1)
-!	EXTENDED_VGA (-2)
-!	ASK_VGA (-3)
-! Video modes numbered by menu position -- NOT RECOMMENDED because of lack
-! of compatibility when extending the table. These are between 0x00 and 0xff.
+/* This code uses an extended set of video mode numbers. These include:
+ * Aliases for standard modes
+ *	NORMAL_VGA (-1)
+ *	EXTENDED_VGA (-2)
+ *	ASK_VGA (-3)
+ * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
+ * of compatibility when extending the table. These are between 0x00 and 0xff.
+ */
 #define VIDEO_FIRST_MENU 0x0000
-! Standard BIOS video modes (BIOS number + 0x0100)
+
+/* Standard BIOS video modes (BIOS number + 0x0100) */
 #define VIDEO_FIRST_BIOS 0x0100
-! VESA BIOS video modes (VESA number + 0x0200)
+
+/* VESA BIOS video modes (VESA number + 0x0200) */
 #define VIDEO_FIRST_VESA 0x0200
-! Video7 special modes (BIOS number + 0x0900)
+
+/* Video7 special modes (BIOS number + 0x0900) */
 #define VIDEO_FIRST_V7 0x0900
-! Special video modes
+
+/* Special video modes */
 #define VIDEO_FIRST_SPECIAL 0x0f00
 #define VIDEO_80x25 0x0f00
 #define VIDEO_8POINT 0x0f01
@@ -66,14 +68,15 @@
 #define VIDEO_80x60 0x0f07
 #define VIDEO_GFX_HACK 0x0f08
 #define VIDEO_LAST_SPECIAL 0x0f09
-! Video modes given by resolution
+
+/* Video modes given by resolution */
 #define VIDEO_FIRST_RESOLUTION 0x1000
 
-! The "recalculate timings" flag
+/* The "recalculate timings" flag */
 #define VIDEO_RECALC 0x8000
 
-! Positions of various video parameters passed to the kernel
-! (see also include/linux/tty.h)
+/* Positions of various video parameters passed to the kernel */
+/* (see also include/linux/tty.h) */
 #define PARAM_CURSOR_POS	0x00
 #define PARAM_VIDEO_PAGE	0x04
 #define PARAM_VIDEO_MODE	0x06
@@ -94,530 +97,505 @@
 #define PARAM_VESAPM_OFF	0x30
 #define PARAM_LFB_PAGES		0x32
 
-! Define DO_STORE according to CONFIG_VIDEO_RETAIN
+
+/* Define DO_STORE according to CONFIG_VIDEO_RETAIN */
 #ifdef CONFIG_VIDEO_RETAIN
 #define DO_STORE call store_screen
 #else
 #define DO_STORE
 #endif /* CONFIG_VIDEO_RETAIN */
 
-!
-! This is the main entry point called by setup.S
-!
-! Input:
-!	DS pointing to the boot sector
-
-video:	push	ds		! We use different segments
-	push	ds		! FS contains original DS
-	pop	fs
-	push	cs		! DS is equal to CS
-	pop	ds
-	push	cs		! ES is equal to CS
-	pop	es
-	xor	ax,ax
-	mov	gs,ax		! GS is zero
+# This is the main entry point called by setup.S
+# %ds *must* be pointing to the bootsector
+video:	pushw	%ds		# We use different segments
+	pushw	%ds		# FS contains original DS
+	popw	%fs
+	pushw	%cs		# DS is equal to CS
+	popw	%ds
+	pushw	%cs		# ES is equal to CS
+	popw	%es
+	xorw	%ax, %ax
+	movw	%ax, %gs	# GS is zero
 	cld
-	call	basic_detect	! Basic adapter type testing (EGA/VGA/MDA/CGA)
+	call	basic_detect	# Basic adapter type testing (EGA/VGA/MDA/CGA)
 #ifdef CONFIG_VIDEO_SELECT
-	seg	fs		! User-selected video mode
-	mov	ax,[0x01fa]
-	cmp	ax,#ASK_VGA	! Bring up the menu
+	movw	%fs:(0x01fa), %ax		# User selected video mode
+	cmpw	$ASK_VGA, %ax			# Bring up the menu
 	jz	vid2
-	call	mode_set	! Set the mode
+
+	call	mode_set			# Set the mode
 	jc	vid1
-	lea	si,badmdt	! Invalid mode ID
+
+	leaw	badmdt, %si			# Invalid mode ID
 	call	prtstr
 vid2:	call	mode_menu
 vid1:
 #ifdef CONFIG_VIDEO_RETAIN
-	call	restore_screen	! Restore screen contents
+	call	restore_screen			# Restore screen contents
 #endif /* CONFIG_VIDEO_RETAIN */
 #endif /* CONFIG_VIDEO_SELECT */
-	call	mode_params	! Store mode parameters
-	pop	ds		! Restore original DS
+	call	mode_params			# Store mode parameters
+	popw	%ds				# Restore original DS
 	ret
 
-!
-! Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.
-!
-
+# Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.
 basic_detect:
-	seg	fs		! Default is no VGA
-	movb	[PARAM_HAVE_VGA],#0
-
-	mov	ah,#0x12	! Check EGA/VGA
-	mov	bl,#0x10
-	int	0x10
-	seg	fs
-	mov	[PARAM_VIDEO_EGA_BX],bx	! Used for identification of EGA in the kernel
-	cmp	bl,#0x10	! No, this is a CGA/MDA/HGA card.
+	movb	$0, %fs:(PARAM_HAVE_VGA)
+	movb	$0x12, %ah	# Check EGA/VGA
+	movb	$0x10, %bl
+	int	$0x10
+	movw	%bx, %fs:(PARAM_VIDEO_EGA_BX)	# Identifies EGA to the kernel
+	cmpb	$0x10, %bl			# No, it's a CGA/MDA/HGA card.
 	je	basret
-	incb	[adapter]
-
-	mov	ax,#0x1a00	! Check for EGA/VGA discrimination
-	int	0x10
-	cmp	al,#0x1a	! 1a means VGA, anything else EGA
-	jne	basret
-	seg	fs
-	incb	[PARAM_HAVE_VGA]	! We've detected a VGA
-	incb	[adapter]
 
+	incb	adapter
+	movw	$0x1a00, %ax			# Check EGA or VGA?
+	int	$0x10
+	cmpb	$0x1a, %al			# 1a means VGA...
+	jne	basret				# anything else is EGA.
+	
+	incb	%fs:(PARAM_HAVE_VGA)		# We've detected a VGA
+	incb	adapter
 basret:	ret
 
-!
-! Store the video mode parameters for later usage by the kernel.
-! This is done by asking the BIOS except for the rows/columns
-! parameters in the default 80x25 mode -- these are set directly,
-! because some very obscure BIOSes supply insane values.
-!
-
+# Store the video mode parameters for later usage by the kernel.
+# This is done by asking the BIOS except for the rows/columns
+# parameters in the default 80x25 mode -- these are set directly,
+# because some very obscure BIOSes supply insane values.
 mode_params:
 #ifdef CONFIG_VIDEO_SELECT
-	cmpb	[graphic_mode],#0
+	cmpb	$0, graphic_mode
 	jnz	mopar_gr
 #endif
-
-	mov	ah,#0x03	! Read cursor position
-	xor	bh,bh
-	int	0x10
-	seg	fs
-	mov	[PARAM_CURSOR_POS],dx
-
-	mov	ah,#0x0f	! Read page/mode/width
-	int	0x10
-	seg	fs
-	mov	[PARAM_VIDEO_PAGE],bx
-	seg	fs
-	mov	[PARAM_VIDEO_MODE],ax	! Video mode and screen width
-	cmp	al,#7			! MDA/HGA => segment differs
+	movb	$0x03, %ah			# Read cursor position
+	xorb	%bh, %bh
+	int	$0x10
+	movw	%dx, %fs:(PARAM_CURSOR_POS)
+	movb	$0x0f, %ah			# Read page/mode/width
+	int	$0x10
+	movw	%bx, %fs:(PARAM_VIDEO_PAGE)
+	movw	%ax, %fs:(PARAM_VIDEO_MODE)	# Video mode and screen width
+	cmpb	$0x7, %al			# MDA/HGA => segment differs
 	jnz	mopar0
-	mov	[video_segment],#0xb000
-mopar0:	seg	gs			! Font size
-	mov	ax,[0x485]
-	seg	fs
-	mov	[PARAM_FONT_POINTS],ax	! (valid only on EGA/VGA)
 
-	mov	ax,[force_size]	! Forced size?
-	or	ax,ax
+	movw	$0xb000, video_segment
+mopar0: movw	%gs:(0x485), %ax		# Font size
+	movw	%ax, %fs:(PARAM_FONT_POINTS)	# (valid only on EGA/VGA)
+	movw	force_size, %ax			# Forced size?
+	orw	%ax, %ax
 	jz	mopar1
-	seg	fs
-	mov	[PARAM_VIDEO_COLS],ah
-	seg	fs
-	mov	[PARAM_VIDEO_LINES],al
-	ret
 
-mopar1:	mov	al,#25
-	cmpb	[adapter],#0	! If we are on CGA/MDA/HGA, the screen must
-	jz	mopar2		! have 25 lines.
-	seg	gs		! On EGA/VGA, use the EGA+ BIOS variable
-	mov	al,[0x484]	! containing maximal line number.
-	inc	al
-mopar2:	seg	fs
-	movb	[PARAM_VIDEO_LINES],al
+	movb	%ah, %fs:(PARAM_VIDEO_COLS)
+	movb	%al, %fs:(PARAM_VIDEO_LINES)
 	ret
 
-#ifdef CONFIG_VIDEO_SELECT
+mopar1:	movb	$25, %al
+	cmpb	$0, adapter			# If we are on CGA/MDA/HGA, the
+	jz	mopar2				# screen must have 25 lines.
 
-!
-! Fetching of VESA frame buffer parameters
-!
+	movb	%gs:(0x484), %al		# On EGA/VGA, use the EGA+ BIOS
+	incb	%al				# location of max lines.
+mopar2: movb	%al, %fs:(PARAM_VIDEO_LINES)
+	ret
 
+#ifdef CONFIG_VIDEO_SELECT
+# Fetching of VESA frame buffer parameters
 mopar_gr:
-	lea	di,modelist+1024
-	seg	fs
-	movb	[PARAM_HAVE_VGA],#0x23
-
-	mov	ax,(di+16)
-	seg	fs
-	mov	[PARAM_LFB_LINELENGTH],ax
-
-	mov	ax,(di+18)
-	seg	fs
-	mov	[PARAM_LFB_WIDTH],ax
-
-	mov	ax,(di+20)
-	seg	fs
-	mov	[PARAM_LFB_HEIGHT],ax
-
-	mov	al,(di+25)
-	mov	ah,#0
-	seg	fs
-	mov	[PARAM_LFB_DEPTH],ax
-
-	mov	al,(di+29)
-	mov	ah,#0
-	seg	fs
-	mov	[PARAM_LFB_PAGES],ax
-
-	mov	eax,(di+40)
-	seg	fs
-	mov	[PARAM_LFB_BASE],eax
-
-	mov	eax,(di+31)
-	seg	fs
-	mov	[PARAM_LFB_COLORS],eax
-
-	mov	eax,(di+35)
-	seg	fs
-	mov	[PARAM_LFB_COLORS+4],eax
-
-	! get video mem size
-	lea	di,modelist+1024
-	mov	ax,#0x4f00
-	int	0x10
-
-	xor	eax,eax	
-	mov	ax,(di+18)
-	seg	fs
-	mov	[PARAM_LFB_SIZE],eax
-
-	! get protected mode interface informations	
-	mov	ax,#0x4f0a
-	xor	bx,bx
-	xor	di,di
-	int	0x10
-	cmp	ax,#0x004f
+	leaw	modelist+1024, %di
+	movb	$0x23, %fs:(PARAM_HAVE_VGA)
+	movw	16(%di), %ax
+	movw	%ax, %fs:(PARAM_LFB_LINELENGTH)
+	movw	18(%di), %ax
+	movw	%ax, %fs:(PARAM_LFB_WIDTH)
+	movw	20(%di), %ax
+	movw	%ax, %fs:(PARAM_LFB_HEIGHT)
+	movb	25(%di), %al
+	movb	$0, %ah
+	movw	%ax, %fs:(PARAM_LFB_DEPTH)
+	movb	29(%di), %al	
+	movb	$0, %ah
+	movw	%ax, %fs:(PARAM_LFB_PAGES)
+	movl	40(%di), %eax
+	movl	%eax, %fs:(PARAM_LFB_BASE)
+	movl	31(%di), %eax
+	movl	%eax, %fs:(PARAM_LFB_COLORS)
+	movl	35(%di), %eax
+	movl	%eax, %fs:(PARAM_LFB_COLORS+4)
+
+# get video mem size
+	leaw	modelist+1024, %di
+	movw	$0x4f00, %ax
+	int	$0x10
+	xorl	%eax, %eax
+	movw	18(%di), %ax
+	movl	%eax, %fs:(PARAM_LFB_SIZE)
+# get protected mode interface informations
+	movw	$0x4f0a, %ax
+	xorw	%bx, %bx
+	xorw	%di, %di
+	int	$0x10
+	cmp	$0x004f, %ax
 	jnz	no_pm
-	seg	fs
-	mov	[PARAM_VESAPM_SEG],es
-	seg	fs
-	mov	[PARAM_VESAPM_OFF],di
 
-no_pm:
-	ret
-
-!
-! The video mode menu
-!
+	movw	%es, %fs:(PARAM_VESAPM_SEG)
+	movw	%di, %fs:(PARAM_VESAPM_OFF)
+no_pm:	ret
 
+# The video mode menu
 mode_menu:
-	lea	si,keymsg	! "Return/Space/Timeout" message
+	leaw	keymsg, %si			# "Return/Space/Timeout" message
 	call	prtstr
 	call	flush
 nokey:	call	getkt
-	cmp	al,#0x0d	! ENTER ?
-	je	listm		! yes - manual mode selection
-	cmp	al,#0x20	! SPACE ?
-	je	defmd1		! no - repeat
+
+	cmpb	$0x0d, %al			# ENTER ?
+	je	listm				# yes - manual mode selection
+
+	cmpb	$0x20, %al			# SPACE ?
+	je	defmd1				# no - repeat
+
 	call 	beep
 	jmp	nokey
-defmd1:	ret			! No mode selected => use the 80x25 default
 
-listm:	call	mode_table	! We need a mode table to be listed
-listm0:	lea	si,name_bann	! Print adapter name
+defmd1:	ret					# No mode chosen? Default 80x25
+
+listm:	call	mode_table			# List mode table
+listm0:	leaw	name_bann, %si			# Print adapter name
 	call	prtstr
-	mov	si,[card_name]
-	or	si,si
+	movw	card_name, %si
+	orw	%si, %si
 	jnz	an2
-	mov	al,[adapter]
-	lea	si,old_name
-	or	al,al
+
+	movb	adapter, %al
+	leaw	old_name, %si
+	orb	%al, %al
 	jz	an1
-	lea	si,ega_name
-	dec	al
+
+	leaw	ega_name, %si
+	decb	%al
 	jz	an1
-	lea	si,vga_name
+
+	leaw	vga_name, %si
 	jmp	an1
+
 an2:	call	prtstr
-	lea	si,svga_name
+	leaw	svga_name, %si
 an1:	call	prtstr
-	lea	si,listhdr	! Table header
+	leaw	listhdr, %si			# Table header
 	call	prtstr
-	mov	dl,#0x30	! DL holds mode number
-	lea	si,modelist
-lm1:	cmp	(si),#ASK_VGA	! End?
+	movb	$0x30, %dl			# DL holds mode number
+	leaw	modelist, %si
+lm1:	cmpw	$ASK_VGA, (%si)			# End?
 	jz	lm2
-	mov	al,dl		! Menu selection number
+
+	movb	%dl, %al			# Menu selection number
 	call	prtchr
 	call	prtsp2
 	lodsw
-	call	prthw		! Mode ID
+	call	prthw				# Mode ID
 	call	prtsp2
-	mov	al,(si+1)
-	call	prtdec		! Rows
-	mov	al,#0x78	! 'x'
+	movb	0x1(%si), %al
+	call	prtdec				# Rows
+	movb	$0x78, %al			# the letter 'x'
 	call	prtchr
 	lodsw
-	call	prtdec		! Columns
-	mov	al,#0x0d	! New line
+	call	prtdec				# Columns
+	movb	$0x0d, %al			# New line
 	call	prtchr
-	mov	al,#0x0a
+	movb	$0x0a, %al
 	call	prtchr
-	inc	dl		! Next character
-	cmp	dl,#0x3a
+	incb	%dl				# Next character
+	cmpb	$0x3a, %dl
 	jnz	lm1
-	mov	dl,#0x61
+
+	movb	$0x61, %dl
 	jmp	lm1
 
-lm2:	lea	si,prompt	! Mode prompt
+lm2:	leaw	prompt, %si			# Mode prompt
 	call	prtstr
-	lea	di,edit_buf	! Editor buffer
+	leaw	edit_buf, %di			# Editor buffer
 lm3:	call	getkey
-	cmp	al,#0x0d	! Enter?
+	cmpb	$0x0d, %al			# Enter?
 	jz	lment
-	cmp	al,#0x08	! Backspace?
+
+	cmpb	$0x08, %al			# Backspace?
 	jz	lmbs
-	cmp	al,#0x20	! Printable?
+
+	cmpb	$0x20, %al			# Printable?
 	jc	lm3
-	cmp	di,#edit_buf+4	! Enough space?
+
+	cmpw	$edit_buf+4, %di		# Enough space?
 	jz	lm3
+
 	stosb
 	call	prtchr
 	jmp	lm3
 
-lmbs:	cmp	di,#edit_buf	! Backspace
+lmbs:	cmpw	$edit_buf, %di			# Backspace
 	jz	lm3
-	dec	di
-	mov	al,#0x08
+
+	decw	%di
+	movb	$0x08, %al
 	call	prtchr
 	call	prtspc
-	mov	al,#0x08
+	movb	$0x08, %al
 	call	prtchr
 	jmp	lm3
-
-lment:	movb	(di),#0
-	lea	si,crlft
+	
+lment:	movb	$0, (%di)
+	leaw	crlft, %si
 	call	prtstr
-	lea	si,edit_buf
-	cmpb	(si),#0		! Empty string => use default mode
+	leaw	edit_buf, %si
+	cmpb	$0, (%si)			# Empty string = default mode
 	jz	lmdef
-	cmpb	(si+1),#0	! One character => menu selection
+
+	cmpb	$0, 1(%si)			# One character = menu selection
 	jz	mnusel
-	cmp	(si),#0x6373	! "scan" => mode scanning
+
+	cmpw	$0x6373, (%si)			# "scan" => mode scanning
 	jnz	lmhx
-	cmp	(si+2),#0x6e61
+
+	cmpw	$0x6e61, 2(%si)
 	jz	lmscan
-lmhx:	xor	bx,bx		! Else => mode ID in hex
+
+lmhx:	xorw	%bx, %bx			# Else => mode ID in hex
 lmhex:	lodsb
-	or	al,al
+	orb	%al, %al
 	jz	lmuse1
-	sub	al,#0x30
+
+	subb	$0x30, %al
 	jc	lmbad
-	cmp	al,#10
+
+	cmpb	$10, %al
 	jc	lmhx1
-	sub	al,#7
-	and	al,#0xdf
-	cmp	al,#10
+
+	subb	$7, %al
+	andb	$0xdf, %al
+	cmpb	$10, %al
 	jc	lmbad
-	cmp	al,#16
+
+	cmpb	$16, %al
 	jnc	lmbad
-lmhx1:	shl	bx,#4
-	or	bl,al
+
+lmhx1:	shlw	$4, %bx
+	orb	%al, %bl
 	jmp	lmhex
-lmuse1:	mov	ax,bx
+
+lmuse1:	movw	%bx, %ax
 	jmp	lmuse
 
-mnusel:	lodsb			! Menu selection
-	xor	ah,ah
-	sub	al,#0x30
+mnusel:	lodsb					# Menu selection
+	xorb	%ah, %ah
+	subb	$0x30, %al
 	jc	lmbad
-	cmp	al,#10
+
+	cmpb	$10, %al
 	jc	lmuse
-	cmp	al,#0x61-0x30
+	
+	cmpb	$0x61-0x30, %al
 	jc	lmbad
-	sub	al,#0x61-0x30-10
-	cmp	al,#36
+	
+	subb	$0x61-0x30-10, %al
+	cmpb	$36, %al
 	jnc	lmbad
+
 lmuse:	call	mode_set
 	jc	lmdef
-lmbad:	lea	si,unknt
-	call	prtstr
-	br	lm2
 
-lmscan:	cmpb	[adapter],#0	! Scanning supported only on EGA/VGA
+lmbad:	leaw	unknt, %si
+	call	prtstr
+	jmp	lm2
+lmscan:	cmpb	$0, adapter			# Scanning only on EGA/VGA
 	jz	lmbad
-	mov	[mt_end],#0	! Scanning of modes: done as new autodetection
-	movb	[scanning],#1
-	call	mode_table
-	br	listm0
 
+	movw	$0, mt_end			# Scanning of modes is
+	movb	$1, scanning			# done as new autodetection.
+	call	mode_table
+	jmp	listm0
 lmdef:	ret
 
-!
-! Additional parts of mode_set... (relative jumps, you know)
-!
-
-setv7:				! Video7 extended modes
+# Additional parts of mode_set... (relative jumps, you know)
+setv7:						# Video7 extended modes
 	DO_STORE
-	sub	bh,#VIDEO_FIRST_V7>>8
-	mov	ax,#0x6f05
-	int	0x10
+	subb	$VIDEO_FIRST_V7>>8, %bh
+	movw	$0x6f05, %ax
+	int	$0x10
 	stc
 	ret
 
-_setrec:	br	setrec		! Ugly...
-_set_80x25:	br	set_80x25
-
-!
-! Aliases for backward compatibility.
-!
+_setrec:	jmp	setrec			# Ugly...
+_set_80x25:	jmp	set_80x25
 
+# Aliases for backward compatibility.
 setalias:
-	mov	ax,#VIDEO_80x25
-	inc	bx
+	movw	$VIDEO_80x25, %ax
+	incw	%bx
 	jz	mode_set
-	mov	al,#VIDEO_8POINT-VIDEO_FIRST_SPECIAL
-	inc	bx
-	jnz	setbad
 
-	! Fall-through!
-
-!
-! Setting of user mode (AX=mode ID) => CF=success
-!
+	movb	$VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al
+	incw	%bx
+	jnz	setbad				# Fall-through!
 
+# Setting of user mode (AX=mode ID) => CF=success
 mode_set:
-	mov	bx,ax
-	cmp	ah,#0xff
+	movw	%ax, %bx
+	cmpb	$0xff, %ah
 	jz	setalias
-	test	ah,#VIDEO_RECALC>>8
+
+	testb	$VIDEO_RECALC>>8, %ah
 	jnz	_setrec
-	cmp	ah,#VIDEO_FIRST_RESOLUTION>>8
+
+	cmpb	$VIDEO_FIRST_RESOLUTION>>8, %ah
 	jnc	setres
-	cmp	ah,#VIDEO_FIRST_SPECIAL>>8
+	
+	cmpb	$VIDEO_FIRST_SPECIAL>>8, %ah
 	jz	setspc
-	cmp	ah,#VIDEO_FIRST_V7>>8
+	
+	cmpb	$VIDEO_FIRST_V7>>8, %ah
 	jz	setv7
-	cmp	ah,#VIDEO_FIRST_VESA>>8
+	
+	cmpb	$VIDEO_FIRST_VESA>>8, %ah
 	jnc	check_vesa
-	or	ah,ah
+	
+	orb	%ah, %ah
 	jz	setmenu
-	dec	ah
+	
+	decb	%ah
 	jz	setbios
+
 setbad:	clc
-	movb	[do_restore],#0	! The screen needn't be restored
+	movb	$0, do_restore			# The screen needn't be restored
 	ret
 
 setvesa:
 	DO_STORE
-	sub	bh,#VIDEO_FIRST_VESA>>8
-	mov	ax,#0x4f02	! VESA BIOS mode set call
-	int	0x10
-	cmp	ax,#0x004f	! AL=4f if implemented, AH=0 if OK
-	jnz	setbad
+	subb	$VIDEO_FIRST_VESA>>8, %bh
+	movw	$0x4f02, %ax			# VESA BIOS mode set call
+	int	$0x10
+	cmpw	$0x004f, %ax			# AL=4f if implemented
+	jnz	setbad				# AH=0 if OK
+
 	stc
 	ret
 
 setbios:
 	DO_STORE
-	int	0x10		! Standard BIOS mode set call
-	push	bx
-	mov	ah,#0x0f	! Check if really set
-	int	0x10
-	pop	bx
-	cmp	al,bl
+	int	$0x10				# Standard BIOS mode set call
+	pushw	%bx
+	movb	$0x0f, %ah			# Check if really set
+	int	$0x10
+	popw	%bx
+	cmpb	%bl, %al
 	jnz	setbad
+	
 	stc
 	ret
 
-setspc:	xor	bh,bh		! Set special mode
-	cmp	bl,#VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL
+setspc:	xorb	%bh, %bh			# Set special mode
+	cmpb	$VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl
 	jnc	setbad
-	add	bx,bx
-	.word	0xa7ff, spec_inits	! JMP [BX+spec_inits]
+	
+	addw	%bx, %bx
+	.word	0xa7ff, spec_inits		# JMP [BX+spec_inits]
 
 setmenu:
-	or	al,al		! 80x25 is an exception
+	orb	%al, %al			# 80x25 is an exception
 	jz	_set_80x25
-	push	bx		! Set mode chosen from menu
-	call	mode_table	! Build the mode table
-	pop	ax
-	shl	ax,#2
-	add	si,ax
-	cmp	si,di
+	
+	pushw	%bx				# Set mode chosen from menu
+	call	mode_table			# Build the mode table
+	popw	%ax
+	shlw	$2, %ax
+	addw	%ax, %si
+	cmpw	%di, %si
 	jnc	setbad
-	mov	ax,(si)		! Fetch mode ID
+	
+	movw	(%si), %ax			# Fetch mode ID
 _m_s:	jmp	mode_set
 
-setres:
-	push	bx		! Set mode chosen by its resolution
+setres:	pushw	%bx				# Set mode chosen by resolution
 	call	mode_table
-	pop	bx
-	xchg	bh,bl
+	popw	%bx
+	xchgb	%bl, %bh
 setr1:	lodsw
-	cmp	ax,#ASK_VGA	! End of the list?
+	cmpw	$ASK_VGA, %ax			# End of the list?
 	jz	setbad
+	
 	lodsw
-	cmp	ax,bx
+	cmpw	%bx, %ax
 	jnz	setr1
-	mov	ax,(si-4)	! Fetch mode ID
+	
+	movw	-4(%si), %ax			# Fetch mode ID
 	jmp	_m_s
 
-
 check_vesa:
-	lea	di,modelist+1024
-	sub	bh,#VIDEO_FIRST_VESA>>8
-	mov	cx,bx		! Get mode information structure
-	mov	ax,#0x4f01
-	int	0x10
-	add	bh,#VIDEO_FIRST_VESA>>8
-	cmp	ax,#0x004f
+	leaw	modelist+1024, %di
+	subb	$VIDEO_FIRST_VESA>>8, %bh
+	movw	%bx, %cx			# Get mode information structure
+	movw	$0x4f01, %ax
+	int	$0x10
+	addb	$VIDEO_FIRST_VESA>>8, %bh
+	cmpw	$0x004f, %ax
 	jnz	setbad
 
-	mov	al,(di)		! Check capabilities.
-	and	al,#0x19
-	cmp	al,#0x09
-	jz	setvesa		! this is a text mode
-
-	mov	al,(di)		! Check capabilities.
-	and	al,#0x99
-	cmp	al,#0x99
-	jnz	_setbad		! to bad, no linear frame buffer
-
-	sub	bh,#VIDEO_FIRST_VESA>>8
-	or	bx,#0x4000	! want use linear frame buffer	
-	mov	ax,#0x4f02	! VESA BIOS mode set call
-	int	0x10
-	cmp	ax,#0x004f	! AL=4f if implemented, AH=0 if OK
-	jnz	_setbad
+	movb	(%di), %al			# Check capabilities.
+	andb	$0x19, %al
+	cmpb	$0x09, %al
+	jz	setvesa				# This is a text mode
+
+	movb	(%di), %al			# Check capabilities.
+	andb	$0x99, %al
+	cmpb	$0x99, %al
+	jnz	_setbad				# Doh! No linear frame buffer.
+
+	subb	$VIDEO_FIRST_VESA>>8, %bh
+	orw	$0x4000, %bx			# Use linear frame buffer
+	movw	$0x4f02, %ax			# VESA BIOS mode set call
+	int	$0x10
+	cmpw	$0x004f, %ax			# AL=4f if implemented
+	jnz	_setbad				# AH=0 if OK
 
-	movb	[graphic_mode],#1 ! flag graphic mode
-	movb	[do_restore],#0   ! no screen restore
+	movb	$1, graphic_mode		# flag graphic mode
+	movb	$0, do_restore			# no screen restore
 	stc
 	ret
-	
-_setbad:	br	setbad		! Ugly...
-	
-!
-! Recalculate vertical display end registers -- this fixes various
-! inconsistencies of extended modes on many adapters. Called when
-! the VIDEO_RECALC flag is set in the mode ID.
-!
 
-setrec:	sub	ah,#VIDEO_RECALC>>8	! Set the base mode
+_setbad:	jmp	setbad          	# Ugly...
+
+# Recalculate vertical display end registers -- this fixes various
+# inconsistencies of extended modes on many adapters. Called when
+# the VIDEO_RECALC flag is set in the mode ID.
+
+setrec:	subb	$VIDEO_RECALC>>8, %ah		# Set the base mode
 	call	mode_set
 	jnc	rct3
-	seg	gs			! Font size in pixels
-	mov	ax,[0x485]
-	seg	gs			! Number of rows
-	mov	bl,[0x484]
-	inc	bl
-	mul	bl			! Number of visible
-	dec	ax			! scan lines - 1
-	mov	dx,#0x3d4
-	mov	bx,ax
-	mov	al,#0x12		! Lower 8 bits
-	mov	ah,bl
-	out	dx,ax
-	mov	al,#0x07		! Bits 8 and 9 in the overflow register
+
+	movw	%gs:(0x485), %ax		# Font size in pixels
+	movb	%gs:(0x484), %bl		# Number of rows
+	incb	%bl
+	mulb	%bl				# Number of visible
+	decw	%ax				# scan lines - 1
+	movw	$0x3d4, %dx
+	movw	%ax, %bx
+	movb	$0x12, %al			# Lower 8 bits
+	movb	%bl, %ah
+	outw	%ax, %dx
+	movb	$0x07, %al		# Bits 8 and 9 in the overflow register
 	call	inidx
-	xchg	ah,al
-	and	ah,#0xbd
-	shr	bh,#1
+	xchgb	%al, %ah
+	andb	$0xbd, %ah
+	shrb	%bh
 	jnc	rct1
-	or	ah,#0x02
-rct1:	shr	bh,#1
+	orb	$0x02, %ah
+rct1:	shrb	%bh
 	jnc	rct2
-	or	ah,#0x40
-rct2:	mov	al,#0x07
-	out	dx,ax
+	orb	$0x40, %ah
+rct2:	movb	$0x07, %al
+	outw	%ax, %dx
 	stc
 rct3:	ret
 
-!
-! Table of routines for setting of the special modes.
-!
-
+# Table of routines for setting of the special modes.
 spec_inits:
 	.word	set_80x25
 	.word	set_8pixel
@@ -629,589 +607,575 @@
 	.word	set_80x60
 	.word	set_gfx
 
-!
-! Set the 80x25 mode. If already set, do nothing.
-!
-
+# Set the 80x25 mode. If already set, do nothing.
 set_80x25:
-	mov	[force_size],#0x5019	! Override possibly broken BIOS vars
+	movw	$0x5019, force_size		# Override possibly broken BIOS
 use_80x25:
 #ifdef CONFIG_VIDEO_400_HACK
-	mov	ax,#0x1202	! Force 400 scan lines
-	mov	bl,#0x30
-	int	0x10
+	movw	$0x1202, %ax			# Force 400 scan lines
+	movb	$0x30, %bl
+	int	$0x10
 #else
-	mov	ah,#0x0f	! Get current mode ID
-	int	0x10
-	cmp	ax,#0x5007	! Mode 7 (80x25 mono) is the only one available
-	jz	st80		! on CGA/MDA/HGA and is also available on EGAM
-	cmp	ax,#0x5003	! Unknown mode => force 80x25 color
+	movb	$0x0f, %ah			# Get current mode ID
+	int	$0x10
+	cmpw	$0x5007, %ax	# Mode 7 (80x25 mono) is the only one available
+	jz	st80		# on CGA/MDA/HGA and is also available on EGAM
+
+	cmpw	$0x5003, %ax	# Unknown mode, force 80x25 color
 	jnz	force3
-st80:	cmpb	[adapter],#0	! CGA/MDA/HGA => mode 3/7 is always 80x25
+
+st80:	cmpb	$0, adapter	# CGA/MDA/HGA => mode 3/7 is always 80x25
 	jz	set80
-	seg	gs		! This is EGA+ -- beware of 80x50 etc.
-	mov	al,[0x0484]
-	or	al,al		! Some buggy BIOSes set 0 rows
+
+	movb	%gs:(0x0484), %al	# This is EGA+ -- beware of 80x50 etc.
+	orb	%al, %al		# Some buggy BIOS'es set 0 rows
 	jz	set80
-	cmp	al,#24		! Let's hope this is correct
+	
+	cmpb	$24, %al		# It's hopefully correct
 	jz	set80
 #endif /* CONFIG_VIDEO_400_HACK */
 force3:	DO_STORE
-	mov	ax,#0x0003	! Forced set
-	int	0x10
+	movw	$0x0003, %ax			# Forced set
+	int	$0x10
 set80:	stc
 	ret
 
-!
-! Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
-!
-
+# Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
 set_8pixel:
 	DO_STORE
-	call	use_80x25	! The base is 80x25
+	call	use_80x25			# The base is 80x25
 set_8pt:
-	mov	ax,#0x1112	! Use 8x8 font
-	xor	bl,bl
-	int	0x10
-	mov	ax,#0x1200	! Use alternate print screen
-	mov	bl,#0x20
-	int	0x10
-	mov	ax,#0x1201	! Turn off cursor emulation
-	mov	bl,#0x34
-	int	0x10
-	mov	ah,#0x01	! Define cursor (scan lines 6 to 7)
-	mov	cx,#0x0607
-	int	0x10
+	movw	$0x1112, %ax			# Use 8x8 font
+	xorb	%bl, %bl
+	int	$0x10
+	movw	$0x1200, %ax			# Use alternate print screen
+	movb	$0x20, %bl
+	int	$0x10
+	movw	$0x1201, %ax			# Turn off cursor emulation
+	movb	$0x34, %bl
+	int	$0x10
+	movb	$0x01, %ah			# Define cursor scan lines 6-7
+	movw	$0x0607, %cx
+	int	$0x10
 set_current:
 	stc
 	ret
 
-!
-! Set the 80x28 mode. This mode works on all VGA's, because it's a standard
-! 80x25 mode with 14-point fonts instead of 16-point.
-!
-
+# Set the 80x28 mode. This mode works on all VGA's, because it's a standard
+# 80x25 mode with 14-point fonts instead of 16-point.
 set_80x28:
 	DO_STORE
-	call	use_80x25	! The base is 80x25
-set14:	mov	ax,#0x1111	! Use 9x14 font
-	xor	bl,bl
-	int	0x10
-	mov	ah,#0x01	! Define cursor (scan lines 11 to 12)
-	mov	cx,#0x0b0c
-	int	0x10
+	call	use_80x25			# The base is 80x25
+set14:	movw	$0x1111, %ax			# Use 9x14 font
+	xorb	%bl, %bl
+	int	$0x10
+	movb	$0x01, %ah			# Define cursor scan lines 11-12
+	movw	$0x0b0c, %cx
+	int	$0x10
 	stc
 	ret
 
-!
-! Set the 80x43 mode. This mode is works on all VGA's.
-! It's a 350-scanline mode with 8-pixel font.
-!
-
+# Set the 80x43 mode. This mode is works on all VGA's.
+# It's a 350-scanline mode with 8-pixel font.
 set_80x43:
 	DO_STORE
-	mov	ax,#0x1201	! Set 350 scans
-	mov	bl,#0x30
-	int	0x10
-	mov	ax,#0x0003	! Reset video mode
-	int	0x10
-	jmp	set_8pt		! Use 8-pixel font
-
-!
-! Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font.
-!
+	movw	$0x1201, %ax			# Set 350 scans
+	movb	$0x30, %bl
+	int	$0x10
+	movw	$0x0003, %ax			# Reset video mode
+	int	$0x10
+	jmp	set_8pt				# Use 8-pixel font
 
+# Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font.
 set_80x30:
-	call	use_80x25	! Start with real 80x25
+	call	use_80x25			# Start with real 80x25
 	DO_STORE
-	mov	dx,#0x3cc	! Get CRTC port
-	in	al,dx
-	mov	dl,#0xd4
-	ror	al,#1		! Mono or color?
+	movw	$0x3cc, %dx			# Get CRTC port
+	inb	%dx, %al
+	movb	$0xd4, %dl
+	rorb	%al				# Mono or color?
 	jc	set48a
-	mov	dl,#0xb4
-set48a:	mov	ax,#0x0c11	! Vertical sync end (also unlocks CR0-7)
+
+	movb	$0xb4, %dl
+set48a:	movw	$0x0c11, %ax		# Vertical sync end (also unlocks CR0-7)
  	call	outidx
-	mov	ax,#0x0b06	! Vertical total
+	movw	$0x0b06, %ax			# Vertical total
  	call	outidx
-	mov	ax,#0x3e07	! (Vertical) overflow
+	movw	$0x3e07, %ax			# (Vertical) overflow
  	call	outidx
-	mov	ax,#0xea10	! Vertical sync start
+	movw	$0xea10, %ax			# Vertical sync start
  	call	outidx
-	mov	ax,#0xdf12	! Vertical display end
+	movw	$0xdf12, %ax			# Vertical display end
 	call	outidx
-	mov	ax,#0xe715	! Vertical blank start
+	movw	$0xe715, %ax			# Vertical blank start
  	call	outidx
-	mov	ax,#0x0416	! Vertical blank end
+	movw	$0x0416, %ax			# Vertical blank end
  	call	outidx
-	push	dx
-	mov	dl,#0xcc	! Misc output register (read)
- 	in	al,dx
- 	mov	dl,#0xc2	! (write)
- 	and	al,#0x0d	! Preserve clock select bits and color bit
- 	or	al,#0xe2	! Set correct sync polarity
- 	out	dx,al
-	pop	dx
-	mov	[force_size],#0x501e
-	stc			! That's all.
+	pushw	%dx
+	movb	$0xcc, %dl			# Misc output register (read)
+ 	inb	%dx, %al
+ 	movb	$0xc2, %dl			# (write)
+ 	andb	$0x0d, %al	# Preserve clock select bits and color bit
+ 	orb	$0xe2, %al			# Set correct sync polarity
+ 	outb	%al, %dx
+	popw	%dx
+	movw	$0x501e, force_size
+	stc					# That's all.
 	ret
 
-!
-! Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font.
-!
-
+# Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font.
 set_80x34:
-	call	set_80x30	! Set 480 scans
-	call	set14		! And 14-pt font
-	mov	ax,#0xdb12	! VGA vertical display end
-	mov	[force_size],#0x5022
+	call	set_80x30			# Set 480 scans
+	call	set14				# And 14-pt font
+	movw	$0xdb12, %ax			# VGA vertical display end
+	movw	$0x5022, force_size
 setvde:	call	outidx
 	stc
 	ret
 
-!
-! Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font.
-!
-
+# Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font.
 set_80x60:
-	call	set_80x30	! Set 480 scans
-	call	set_8pt		! And 8-pt font
-	mov	ax,#0xdf12	! VGA vertical display end
-	mov	[force_size],#0x503c
+	call	set_80x30			# Set 480 scans
+	call	set_8pt				# And 8-pt font
+	movw	$0xdf12, %ax			# VGA vertical display end
+	movw	$0x503c, force_size
 	jmp	setvde
 
-!
-! Special hack for ThinkPad graphics
-!
-
+# Special hack for ThinkPad graphics
 set_gfx:
 #ifdef CONFIG_VIDEO_GFX_HACK
-	mov	ax,# VIDEO_GFX_BIOS_AX
-	mov	bx,# VIDEO_GFX_BIOS_BX
-	int	0x10
-	mov	[force_size],# VIDEO_GFX_DUMMY_RESOLUTION
+	movw	$VIDEO_GFX_BIOS_AX, %ax
+	movw	$VIDEO_GFX_BIOS_BX, %bx
+	int	$0x10
+	movw	$VIDEO_GFX_DUMMY_RESOLUTION, force_size
 	stc
 #endif
 	ret
 
 #ifdef CONFIG_VIDEO_RETAIN
 
-!
-! Store screen contents to temporary buffer.
-!
-
+# Store screen contents to temporary buffer.
 store_screen:
-	cmpb	[do_restore],#0		! Already stored?
+	cmpb	$0, do_restore			# Already stored?
 	jnz	stsr
-	testb	[loadflags],#CAN_USE_HEAP	! Have we space for storing?
+
+	testb	$CAN_USE_HEAP, loadflags	# Have we space for storing?
 	jz	stsr
-	push	ax
-	push	bx
-	push	[force_size]		! Don't force specific size
-	mov	[force_size],#0
-	call	mode_params		! Obtain params of current mode
-	pop	[force_size]
-
-	seg	fs
-	mov	ah,[PARAM_VIDEO_LINES]
-	seg	fs
-	mov	al,[PARAM_VIDEO_COLS]
-	mov	bx,ax			! BX=dimensions
-	mul	ah
-	mov	cx,ax			! CX=number of characters to store
-	add	ax,ax			! Calculate image size
-	add	ax,#modelist+1024+4
-	cmp	ax,[heap_end_ptr]
-	jnc	sts1			! Unfortunately, out of memory
-
-	seg	fs			! Store mode params
-	mov	ax,[PARAM_CURSOR_POS]
-	lea	di,modelist+1024
+	
+	pushw	%ax
+	pushw	%bx
+	pushw	force_size			# Don't force specific size
+	movw	$0, force_size
+	call	mode_params			# Obtain params of current mode
+	popw	force_size
+	movb	%fs:(PARAM_VIDEO_LINES), %ah
+	movb	%fs:(PARAM_VIDEO_COLS), %al
+	movw	%ax, %bx			# BX=dimensions
+	mulb	%ah
+	movw	%ax, %cx			# CX=number of characters
+	addw	%ax, %ax			# Calculate image size
+	addw	$modelist+1024+4, %ax
+	cmpw	heap_end_ptr, %ax
+	jnc	sts1				# Unfortunately, out of memory
+
+	movw	%fs:(PARAM_CURSOR_POS), %ax	# Store mode params
+	leaw	modelist+1024, %di
 	stosw
-	mov	ax,bx
+	movw	%bx, %ax
 	stosw
-
-	push	ds			! Store the screen
-	mov	ds,[video_segment]
-	xor	si,si
+	pushw	%ds				# Store the screen
+	movw	video_segment, %ds
+	xorw	%si, %si
 	rep
 	movsw
-	pop	ds
-	incb	[do_restore]		! Screen will be restored later
-sts1:	pop	bx
-	pop	ax
+	popw	%ds
+	incb	do_restore			# Screen will be restored later
+sts1:	popw	%bx
+	popw	%ax
 stsr:	ret
 
-!
-! Restore screen contents from temporary buffer.
-!
-
+# Restore screen contents from temporary buffer.
 restore_screen:
-	cmpb	[do_restore],#0		! Has the screen been stored?
+	cmpb	$0, do_restore			# Has the screen been stored?
 	jz	res1
-	call	mode_params		! Get parameters of current mode
-	seg	fs
-	mov	cl,[PARAM_VIDEO_LINES]
-	seg	fs
-	mov	ch,[PARAM_VIDEO_COLS]
-	lea	si,modelist+1024	! Screen buffer
-	lodsw				! Set cursor position
-	mov	dx,ax
-	cmp	dh,cl
+
+	call	mode_params			# Get parameters of current mode
+	movb	%fs:(PARAM_VIDEO_LINES), %cl
+	movb	%fs:(PARAM_VIDEO_COLS), %ch
+	leaw	modelist+1024, %si		# Screen buffer
+	lodsw					# Set cursor position
+	movw	%ax, %dx
+	cmpb	%cl, %dh
 	jc	res2
-	mov	dh,cl
-	dec	dh
-res2:	cmp	dl,ch
+	
+	movb	%cl, %dh
+	decb	%dh
+res2:	cmpb	%ch, %dl
 	jc	res3
-	mov	dl,ch
-	dec	dl
-res3:	mov	ah,#0x02
-	mov	bh,#0x00
-	int	0x10
-	lodsw				! Display size
-	mov	dl,ah			! DL=number of lines
-	mov	ah,#0			! BX=physical length of orig. line
-	mov	bx,ax
-	cmp	dl,cl			! Too many?
+	
+	movb	%ch, %dl
+	decb	%dl
+res3:	movb	$0x02, %ah
+	movb	$0x00, %bh
+	int	$0x10
+	lodsw					# Display size
+	movb	%ah, %dl			# DL=number of lines
+	movb	$0, %ah				# BX=phys. length of orig. line
+	movw	%ax, %bx
+	cmpb	%cl, %dl			# Too many?
 	jc	res4
-	push	ax
-	mov	al,dl
-	sub	al,cl
-	mul	bl
-	add	si,ax
-	add	si,ax
-	pop	ax
-	mov	dl,cl
-res4:	cmp	al,ch			! Too wide?
+
+	pushw	%ax
+	movb	%dl, %al
+	subb	%cl, %al
+	mulb	%bl
+	addw	%ax, %si
+	addw	%ax, %si
+	popw	%ax
+	movb	%cl, %dl
+res4:	cmpb	%ch, %al			# Too wide?
 	jc	res5
-	mov	al,ch			! AX=width of src. line
-res5:	mov	cl,#0
-	xchg	cl,ch
-	mov	bp,cx			! BP=width of dest. line
-	push	es
-	mov	es,[video_segment]
-	xor	di,di			! Move the data
-	add	bx,bx			! Convert BX and BP to _bytes_
-	add	bp,bp
-res6:	push	si
-	push	di
-	mov	cx,ax
+	
+	movb	%ch, %al			# AX=width of src. line
+res5:	movb	$0, %cl
+	xchgb	%ch, %cl
+	movw	%cx, %bp			# BP=width of dest. line
+	pushw	%es
+	movw	video_segment, %es
+	xorw	%di, %di			# Move the data
+	addw	%bx, %bx			# Convert BX and BP to _bytes_
+	addw	%bp, %bp
+res6:	pushw	%si
+	pushw	%di
+	movw	%ax, %cx
 	rep
 	movsw
-	pop	di
-	pop	si
-	add	di,bp
-	add	si,bx
-	dec	dl
+	popw	%di
+	popw	%si
+	addw	%bp, %di
+	addw	%bx, %si
+	decb	%dl
 	jnz	res6
-	pop	es			! Done
+	
+	popw	%es				# Done
 res1:	ret
-
 #endif /* CONFIG_VIDEO_RETAIN */
 
-!
-! Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
-!
-
-outidx:	out	dx,al
-	push	ax
-	mov	al,ah
-	inc	dx
-	out	dx,al
-	dec	dx
-	pop	ax
-	ret
-
-!
-! Build the table of video modes (stored after the setup.S code at the
-! `modelist' label. Each video mode record looks like:
-!	.word	MODE-ID		(our special mode ID (see above))
-!	.byte	rows		(number of rows)
-!	.byte	columns		(number of columns)
-! Returns address of the end of the table in DI, the end is marked
-! with a ASK_VGA ID.
-!
-
+# Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
+outidx:	outb	%al, %dx
+	pushw	%ax
+	movb	%ah, %al
+	incw	%dx
+	outb	%al, %dx
+	decw	%dx
+	popw	%ax
+	ret
+
+# Build the table of video modes (stored after the setup.S code at the
+# `modelist' label. Each video mode record looks like:
+#	.word	MODE-ID		(our special mode ID (see above))
+#	.byte	rows		(number of rows)
+#	.byte	columns		(number of columns)
+# Returns address of the end of the table in DI, the end is marked
+# with a ASK_VGA ID.
 mode_table:
-	mov	di,[mt_end]	! Already filled?
-	or	di,di
+	movw	mt_end, %di			# Already filled?
+	orw	%di, %di
 	jnz	mtab1x
-	lea	di,modelist	! Store standard modes:
-
-	mov	eax,#VIDEO_80x25 + 0x50190000	! The 80x25 mode (ALL)
-	stosd
-	mov	al,[adapter]	! CGA/MDA/HGA -- no more modes
-	or	al,al
+	
+	leaw	modelist, %di			# Store standard modes:
+	movl	$VIDEO_80x25 + 0x50190000, %eax	# The 80x25 mode (ALL)
+	stosl
+	movb	adapter, %al			# CGA/MDA/HGA -- no more modes
+	orb	%al, %al
 	jz	mtabe
-	dec	al
+	
+	decb	%al
 	jnz	mtabv
-	mov	eax,#VIDEO_8POINT + 0x502b0000	! The 80x43 EGA mode
-	stosd
+	
+	movl	$VIDEO_8POINT + 0x502b0000, %eax	# The 80x43 EGA mode
+	stosl
 	jmp	mtabe
+
 mtab1x:	jmp	mtab1
 
-mtabv:	lea	si,vga_modes			! All modes for std VGA
-	mov	cx,#vga_modes_end-vga_modes
-	rep	! I'm unable to use movsw as I don't know how to store a half
-	movsb	! of the expression above to cx without using explicit shr.
+mtabv:	leaw	vga_modes, %si			# All modes for std VGA
+	movw	$vga_modes_end-vga_modes, %cx
+	rep	# I'm unable to use movsw as I don't know how to store a half
+	movsb	# of the expression above to cx without using explicit shr.
 
-	cmpb	[scanning],#0			! Mode scan requested?
+	cmpb	$0, scanning			# Mode scan requested?
 	jz	mscan1
+	
 	call	mode_scan
 mscan1:
 
 #ifdef CONFIG_VIDEO_LOCAL
 	call	local_modes
 #endif /* CONFIG_VIDEO_LOCAL */
+
 #ifdef CONFIG_VIDEO_VESA
-	call	vesa_modes			! Detect VESA VGA modes
+	call	vesa_modes			# Detect VESA VGA modes
 #endif /* CONFIG_VIDEO_VESA */
+
 #ifdef CONFIG_VIDEO_SVGA
-	cmpb	[scanning],#0			! Bypass when scanning
+	cmpb	$0, scanning			# Bypass when scanning
 	jnz	mscan2
-	call	svga_modes			! Detect SVGA cards & modes
+	
+	call	svga_modes			# Detect SVGA cards & modes
 mscan2:
 #endif /* CONFIG_VIDEO_SVGA */
 
 mtabe:
 
 #ifdef CONFIG_VIDEO_COMPACT
-	lea	si,modelist	! Compact video mode list if requested.
-	mov	dx,di
-	mov	di,si
-cmt1:	cmp	si,dx		! Scan all modes
+	leaw	modelist, %si
+	movw	%di, %dx
+	movw	%si, %di
+cmt1:	cmpw	%dx, %si			# Scan all modes
 	jz	cmt2
-	lea	bx,modelist	! Find in previous entries
-	mov	cx,(si+2)
-cmt3:	cmp	si,bx
+
+	leaw	modelist, %bx			# Find in previous entries
+	movw	2(%si), %cx
+cmt3:	cmpw	%bx, %si
 	jz	cmt4
-	cmp	cx,(bx+2)	! Found => don't copy this entry
+
+	cmpw	2(%bx), %cx			# Found => don't copy this entry
 	jz	cmt5
-	add	bx,#4
+
+	addw	$4, %bx
 	jmp	cmt3
 
-cmt4:	movsd			! Copy entry
+cmt4:	movsl					# Copy entry
 	jmp	cmt1
 
-cmt5:	add	si,#4		! Skip entry
+cmt5:	addw	$4, %si				# Skip entry
 	jmp	cmt1
 
 cmt2:
 #endif	/* CONFIG_VIDEO_COMPACT */
 
-	mov	(di),#ASK_VGA	! End marker
-	mov	[mt_end],di
-mtab1:	lea	si,modelist	! Returning: SI=mode list, DI=list end
+	movw	$ASK_VGA, (%di)			# End marker
+	movw	%di, mt_end
+mtab1:	leaw	modelist, %si			# SI=mode list, DI=list end
 ret0:	ret
 
-! Modes usable on all standard VGAs
-
+# Modes usable on all standard VGAs
 vga_modes:
 	.word	VIDEO_8POINT
-	.word	0x5032		! 80x50
+	.word	0x5032				# 80x50
 	.word	VIDEO_80x43
-	.word	0x502b		! 80x43
+	.word	0x502b				# 80x43
 	.word	VIDEO_80x28
-	.word	0x501c		! 80x28
+	.word	0x501c				# 80x28
 	.word	VIDEO_80x30
-	.word	0x501e		! 80x30
+	.word	0x501e				# 80x30
 	.word	VIDEO_80x34
-	.word	0x5022		! 80x34
+	.word	0x5022				# 80x34
 	.word	VIDEO_80x60
-	.word	0x503c		! 80x60
+	.word	0x503c				# 80x60
 #ifdef CONFIG_VIDEO_GFX_HACK
 	.word	VIDEO_GFX_HACK
 	.word	VIDEO_GFX_DUMMY_RESOLUTION
 #endif
-vga_modes_end:
 
-!
-! Detect VESA modes.
-!
+vga_modes_end:
+# Detect VESA modes.
 
 #ifdef CONFIG_VIDEO_VESA
-
 vesa_modes:
-	cmpb	[adapter],#2	! VGA only
+	cmpb	$2, adapter			# VGA only
 	jnz	ret0
-	mov	bp,di		! BP=original mode table end
-	add	di,#0x200	! Buffer space
-	mov	ax,#0x4f00	! VESA Get card info call
-	int	#0x10
-	mov	di,bp
-	cmp	ax,#0x004f	! Successful?
+
+	movw	%di, %bp			# BP=original mode table end
+	addw	$0x200, %di			# Buffer space
+	movw	$0x4f00, %ax			# VESA Get card info call
+	int	$0x10
+	movw	%bp, %di
+	cmpw	$0x004f, %ax			# Successful?
 	jnz	ret0
-	cmp	(di+0x200),#0x4556
+	
+	cmpw	$0x4556, 0x200(%di)
 	jnz	ret0
-	cmp	(di+0x202),#0x4153
+	
+	cmpw	$0x4153, 0x202(%di)
 	jnz	ret0
-	mov	[card_name],#vesa_name	! Set name to "VESA VGA"
-	push	gs
-	lgs	si,(di+0x20e)	! GS:SI=mode list
-	mov	cx,#128		! Iteration limit
-vesa1:	seg	gs		! Get next mode in the list
-	lodsw
-	cmp	ax,#0xffff	! End of the table?
+	
+	movw	$vesa_name, card_name		# Set name to "VESA VGA"
+	pushw	%gs
+	lgsw	0x20e(%di), %si			# GS:SI=mode list
+	movw	$128, %cx			# Iteration limit
+vesa1:
+# gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst.
+# XXX:	lodsw	%gs:(%si), %ax			# Get next mode in the list
+	.byte 0x66, 0x65, 0xAD
+	cmpw	$0xffff, %ax			# End of the table?
 	jz	vesar
-	cmp	ax,#0x0080	! Check validity of mode ID
+	
+	cmpw	$0x0080, %ax			# Check validity of mode ID
 	jc	vesa2
-	or	ah,ah		! Valid IDs are 0x0000-0x007f and 0x0100-0x07ff
-	jz	vesan		! [Certain BIOSes erroneously report 0x80-0xff]
-	cmp	ax,#0x0800
+	
+	orb	%ah, %ah		# Valid IDs: 0x0000-0x007f/0x0100-0x07ff
+	jz	vesan			# Certain BIOSes report 0x80-0xff!
+
+	cmpw	$0x0800, %ax
 	jnc	vesae
-vesa2:	push	cx
-	mov	cx,ax		! Get mode information structure
-	mov	ax,#0x4f01
-	int	0x10
-	mov	bx,cx		! BX=mode number
-	add	bh,#VIDEO_FIRST_VESA>>8
-	pop	cx
-	cmp	ax,#0x004f
-	jnz	vesan		! Don't report errors (buggy BIOSES :-[ )
-	mov	al,(di)		! Check capabilities. We require
-	and	al,#0x19	! a color text mode.
-	cmp	al,#0x09
+
+vesa2:	pushw	%cx
+	movw	%ax, %cx			# Get mode information structure
+	movw	$0x4f01, %ax
+	int	$0x10
+	movw	%cx, %bx			# BX=mode number
+	addb	$VIDEO_FIRST_VESA>>8, %bh
+	popw	%cx
+	cmpw	$0x004f, %ax
+	jnz	vesan			# Don't report errors (buggy BIOSES)
+
+	movb	(%di), %al			# Check capabilities. We require
+	andb	$0x19, %al			# a color text mode.
+	cmpb	$0x09, %al
 	jnz	vesan
-	cmp	(di+8),#0xb800	! Standard video memory address required
+	
+	cmpw	$0xb800, 8(%di)		# Standard video memory address required
 	jnz	vesan
-	testb	(di),#2		! Mode characteristics supplied?
-	mov	(di),bx		! Store mode number
+
+	testb	$2, (%di)			# Mode characteristics supplied?
+	movw	%bx, (%di)			# Store mode number
 	jz	vesa3
-	xor	dx,dx
-	mov	bx,(di+0x12)	! Width
-	or	bh,bh
+	
+	xorw	%dx, %dx
+	movw	0x12(%di), %bx			# Width
+	orb	%bh, %bh
 	jnz	vesan
-	mov	(di+3),bl
-	mov	ax,(di+0x14)	! Height
-	or	ah,ah
+	
+	movb	%bl, 0x3(%di)
+	movw	0x14(%di), %ax			# Height
+	orb	%ah, %ah
 	jnz	vesan
-	mov	(di+2),al
-	mul	bl
-	cmp	ax,#8193	! Small enough for Linux console driver?
+	
+	movb	%al, 2(%di)
+	mulb	%bl
+	cmpw	$8193, %ax		# Small enough for Linux console driver?
 	jnc	vesan
+
 	jmp	vesaok
 
-vesa3:	sub	bx,#0x8108	! This mode has no detailed info specified,
-	jc	vesan		! so it must be a standard VESA mode.
-	cmp	bx,#5
+vesa3:	subw	$0x8108, %bx	# This mode has no detailed info specified,
+	jc	vesan		# so it must be a standard VESA mode.
+
+	cmpw	$5, %bx
 	jnc	vesan
-	mov	ax,(bx+vesa_text_mode_table)
-	mov	(di+2),ax
-vesaok:	add	di,#4		! The mode is valid. Store it.
-vesan:	loop	vesa1		! Next mode. Limit exceeded => error
-vesae:	lea	si,vesaer
+
+	movw	vesa_text_mode_table(%bx), %ax
+	movw	%ax, 2(%di)
+vesaok:	addw	$4, %di				# The mode is valid. Store it.
+vesan:	loop	vesa1			# Next mode. Limit exceeded => error
+vesae:	leaw	vesaer, %si
 	call	prtstr
-	mov	di,bp		! Discard already found modes.
-vesar:	pop	gs
+	movw	%bp, %di			# Discard already found modes.
+vesar:	popw	%gs
 	ret
 
-!
-! Dimensions of standard VESA text modes
-!
-
+# Dimensions of standard VESA text modes
 vesa_text_mode_table:
-	db	60, 80		! 0108
-	db	25, 132		! 0109
-	db	43, 132		! 010A
-	db	50, 132		! 010B
-	db	60, 132		! 010C
-
+	.byte	60, 80				# 0108
+	.byte	25, 132				# 0109
+	.byte	43, 132				# 010A
+	.byte	50, 132				# 010B
+	.byte	60, 132				# 010C
 #endif	/* CONFIG_VIDEO_VESA */
 
-!
-! Scan for video modes. A bit dirty, but should work.
-!
-
+# Scan for video modes. A bit dirty, but should work.
 mode_scan:
-	mov	cx,#0x0100	! Start with mode 0
-scm1:	mov	ah,#0		! Test the mode
-	mov	al,cl
-	int	0x10
-	mov	ah,#0x0f
-	int	0x10
-	cmp	al,cl
-	jnz	scm2		! Mode not set
-	mov	dx,#0x3c0	! Test if it's a text mode
-	mov	al,#0x10		! Mode bits
+	movw	$0x0100, %cx			# Start with mode 0
+scm1:	movb	$0, %ah				# Test the mode
+	movb	%cl, %al
+	int	$0x10
+	movb	$0x0f, %ah
+	int	$0x10
+	cmpb	%cl, %al
+	jnz	scm2				# Mode not set
+
+	movw	$0x3c0, %dx			# Test if it's a text mode
+	movb	$0x10, %al			# Mode bits
 	call	inidx
-	and	al,#0x03
+	andb	$0x03, %al
 	jnz	scm2
-	mov	dl,#0xce		! Another set of mode bits
-	mov	al,#0x06
+	
+	movb	$0xce, %dl			# Another set of mode bits
+	movb	$0x06, %al
 	call	inidx
-	shr	al,#1
+	shrb	%al
 	jc	scm2
-	mov	dl,#0xd4		! Cursor location
-	mov	al,#0x0f
+	
+	movb	$0xd4, %dl			# Cursor location
+	movb	$0x0f, %al
 	call	inidx
-	or	al,al
+	orb	%al, %al
 	jnz	scm2
-	mov	ax,cx		! OK, store the mode
+	
+	movw	%cx, %ax			# Ok, store the mode
 	stosw
-	seg	gs		! Number of rows
-	mov	al,[0x484]
-	inc	al
+	movb	%gs:(0x484), %al		# Number of rows
+	incb	%al
 	stosb
-	seg	gs		! Number of columns
-	mov	ax,[0x44a]
+	movw	%gs:(0x44a), %ax		# Number of columns
 	stosb
-scm2:	inc	cl
+scm2:	incb	%cl
 	jns	scm1
-	mov	ax,#0x0003	! Return back to mode 3
-	int	0x10
+	
+	movw	$0x0003, %ax			# Return back to mode 3
+	int	$0x10
 	ret
 
-tstidx:	out	dx,ax		! OUT DX,AX and inidx
-inidx:	out	dx,al		! Read from indexed VGA register
-	inc	dx		! AL=index, DX=index reg port -> AL=data
-	in	al,dx
-	dec	dx
+tstidx:	outw	%ax, %dx			# OUT DX,AX and inidx
+inidx:	outb	%al, %dx			# Read from indexed VGA register
+	incw	%dx			# AL=index, DX=index reg port -> AL=data
+	inb	%dx, %al
+	decw	%dx
 	ret
 
-!
-! Try to detect type of SVGA card and supply (usually approximate) video
-! mode table for it.
-!
+# Try to detect type of SVGA card and supply (usually approximate) video
+# mode table for it.
 
 #ifdef CONFIG_VIDEO_SVGA
-
 svga_modes:
-	lea	si,svga_table	! Test all known SVGA adapters
+	leaw	svga_table, %si			# Test all known SVGA adapters
 dosvga:	lodsw
-	mov	bp,ax		! Default mode table
-	or	ax,ax
+	movw	%ax, %bp			# Default mode table
+	orw	%ax, %ax
 	jz	didsv1
-	lodsw			! Pointer to test routine
-	push	si
-	push	di
-	push	es
-	mov	bx,#0xc000
-	mov	es,bx
-	call	ax		! Call test routine
-	pop	es
-	pop	di
-	pop	si
-	or	bp,bp
+
+	lodsw					# Pointer to test routine
+	pushw	%si
+	pushw	%di
+	pushw	%es
+	movw	$0xc000, %bx
+	movw	%bx, %es
+	call	ax				# Call test routine
+	popw	%es
+	popw	%di
+	popw	%si
+	orw	%bp, %bp
 	jz	dosvga
-	mov	si,bp		! Found, copy the modes
-	mov	ah,[svga_prefix]
+	
+	movw	%bp, %si			# Found, copy the modes
+	movb	svga_prefix, %ah
 cpsvga:	lodsb
-	or	al,al
+	orb	%al, %al
 	jz	didsv
+	
 	stosw
 	movsw
 	jmp	cpsvga
 
-didsv:	mov	[card_name],si	! Store pointer to card name
+didsv:	movw	%si, card_name			# Store pointer to card name
 didsv1:	ret
 
-!
-! Table of all known SVGA cards. For each card, we store a pointer to
-! a table of video modes supported by the card and a pointer to a routine
-! used for testing of presence of the card. The video mode table is always
-! followed by the name of the card or the chipset.
-!
-
+# Table of all known SVGA cards. For each card, we store a pointer to
+# a table of video modes supported by the card and a pointer to a routine
+# used for testing of presence of the card. The video mode table is always
+# followed by the name of the card or the chipset.
 svga_table:
 	.word	ati_md, ati_test
 	.word	oak_md, oak_test
@@ -1230,88 +1194,91 @@
 	.word	tseng_md, tseng_test
 	.word	0
 
-!
-! Test routines and mode tables:
-!
-
-! S3 - The test algorithm was taken from the SuperProbe package
-! for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org
+# Test routines and mode tables:
 
+# S3 - The test algorithm was taken from the SuperProbe package
+# for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org
 s3_test:
-	mov	cx,#0x0f35	! we store some constants in cl/ch
-	mov	dx,#0x03d4
-	movb	al,#0x38
+	movw	$0x0f35, %cx	# we store some constants in cl/ch
+	movw	$0x03d4, %dx
+	movb	$0x38, %al
 	call	inidx
-	mov	bh,al		! store current value of CRT-register 0x38
-	mov	ax,#0x0038
-	call	outidx		! disable writing to special regs
-	movb	al,cl		! check whether we can write special reg 0x35
+	movb	%al, %bh	# store current CRT-register 0x38
+	movw	$0x0038, %ax
+	call	outidx		# disable writing to special regs
+	movb	%cl, %al	# check whether we can write special reg 0x35
 	call	inidx
-	movb	bl,al		! save the current value of CRT reg 0x35
-	andb	al,#0xf0	! clear bits 0-3
-	movb	ah,al
-	movb	al,cl		! and write it to CRT reg 0x35
+	movb	%al, %bl	# save the current value of CRT reg 0x35
+	andb	$0xf0, %al	# clear bits 0-3
+	movb	%al, %ah
+	movb	%cl, %al	# and write it to CRT reg 0x35
 	call	outidx
-	call	inidx		! now read it back
-	andb	al,ch		! clear the upper 4 bits
-	jz	s3_2		! the first test failed. But we have a
-	movb	ah,bl		! second chance
-	mov	al,cl
+	call	inidx		# now read it back
+	andb	%ch, %al	# clear the upper 4 bits
+	jz	s3_2		# the first test failed. But we have a
+
+	movb	%bl, %ah	# second chance
+	movb	%cl, %al
 	call	outidx
-	jmp	s3_1		! do the other tests
-s3_2:	mov	ax,cx		! load ah with 0xf and al with 0x35
-	orb	ah,bl		! set the upper 4 bits of ah with the orig value
-	call	outidx		! write ...
-	call	inidx		! ... and reread 
-	andb	al,cl		! turn off the upper 4 bits
-	push	ax
-	movb	ah,bl		! restore old value in register 0x35
-	movb	al,cl
+	jmp	s3_1		# do the other tests
+
+s3_2:	movw	%cx, %ax	# load ah with 0xf and al with 0x35
+	orb	%bl, %ah	# set the upper 4 bits of ah with the orig value
+	call	outidx		# write ...
+	call	inidx		# ... and reread 
+	andb	%cl, %al	# turn off the upper 4 bits
+	pushw	%ax
+	movb	%bl, %ah	# restore old value in register 0x35
+	movb	%cl, %al
 	call	outidx
-	pop	ax
-	cmp	al,ch		! setting lower 4 bits was successful => bad
-	je	no_s3		! writing is allowed => this is not an S3
-s3_1:	mov	ax,#0x4838	! allow writing to special regs by putting
-	call	outidx		! magic number into CRT-register 0x38
-	movb	al,cl		! check whether we can write special reg 0x35
+	popw	%ax
+	cmpb	%ch, %al	# setting lower 4 bits was successful => bad
+	je	no_s3		# writing is allowed => this is not an S3
+
+s3_1:	movw	$0x4838, %ax	# allow writing to special regs by putting
+	call	outidx		# magic number into CRT-register 0x38
+	movb	%cl, %al	# check whether we can write special reg 0x35
 	call	inidx
-	movb	bl,al
-	andb	al,#0xf0
-	movb	ah,al
-	movb	al,cl
+	movb	%al, %bl
+	andb	$0xf0, %al
+	movb	%al, %ah
+	movb	%cl, %al
 	call	outidx
 	call	inidx
-	andb	al,ch
-	jnz	no_s3		! no, we can't write => no S3
-	mov	ax,cx
-	orb	ah,bl
+	andb	%ch, %al
+	jnz	no_s3		# no, we can't write => no S3
+
+	movw	%cx, %ax
+	orb	%bl, %ah
 	call	outidx
 	call	inidx
-	andb	al,ch
-	push	ax
-	movb	ah,bl		! restore old value in register 0x35
-	movb	al,cl
+	andb	%ch, %al
+	pushw	%ax
+	movb	%bl, %ah	# restore old value in register 0x35
+	movb	%cl, %al
 	call	outidx
-	pop	ax
-	cmp	al,ch
-	jne	no_s31		! writing not possible => no S3
-	movb	al,#0x30
-	call	inidx		! now get the S3 id ...
-	lea	di,idS3
-	mov	cx,#0x10
+	popw	%ax
+	cmpb	%ch, %al
+	jne	no_s31		# writing not possible => no S3
+	movb	$0x30, %al
+	call	inidx		# now get the S3 id ...
+	leaw	idS3, %di
+	movw	$0x10, %cx
 	repne
 	scasb
 	je	no_s31
-	movb	ah,bh
-	movb	al,#0x38
+
+	movb	%bh, %ah
+	movb	$0x38, %al
 	jmp	s3rest
-no_s3:	movb	al,#0x35	! restore CRT register 0x35
-	movb	ah,bl
+
+no_s3:	movb	$0x35, %al	# restore CRT register 0x35
+	movb	%bl, %ah
+	call	outidx
+no_s31:	xorw	%bp, %bp	# Detection failed
+s3rest:	movb	%bh, %ah
+	movb	$0x38, %al	# restore old value of CRT register 0x38
 	call	outidx
-no_s31:	xor	bp,bp		! Detection failed
-s3rest:	movb	ah,bh
-	movb	al,#0x38	! restore old value of CRT register 0x38
-	br	outidx
 
 idS3:	.byte	0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95
 	.byte	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0
@@ -1322,16 +1289,16 @@
 	.ascii	"S3"
 	.byte	0
 
-! ATI cards.
-
+# ATI cards.
 ati_test:
-	lea 	si,idati
-	mov	di,#0x31
-	mov 	cx,#0x09
+	leaw 	idati, %si
+	movw	$0x31, %di
+	movw	$0x09, %cx
 	repe
 	cmpsb
 	je	atiok
-	xor	bp,bp
+
+	xorw	%bp, %bp
 atiok:	ret
 
 idati:	.ascii	"761295520"
@@ -1346,19 +1313,20 @@
 	.ascii	"ATI"
 	.byte	0
 
-! AHEAD
-
+# AHEAD
 ahead_test:
-	mov	ax,#0x200f
-	mov	dx,#0x3ce
-	out	dx,ax
-	inc	dx
-	in	al,dx
-	cmp	al,#0x20
+	movw	$0x200f, %ax
+	movw	$0x3ce, %dx
+	outw	%ax, %dx
+	incw	%dx
+	inb	%dx, %al
+	cmpb	$0x20, %al
 	je	isahed
-	cmp	al,#0x21
+
+	cmpb	$0x21, %al
 	je	isahed
-	xor	bp,bp
+	
+	xorw	%bp, %bp
 isahed:	ret
 
 ahead_md:
@@ -1372,23 +1340,23 @@
 	.ascii	"Ahead"
 	.byte	0
 
-! Chips & Tech.
-
+# Chips & Tech.
 chips_test:
-	mov	dx,#0x3c3
-	in	al,dx
-	or	al,#0x10
-	out	dx,al
-	mov	dx,#0x104		
-	in	al,dx
-	mov	bl,al
-	mov	dx,#0x3c3
-	in	al,dx
-	and	al,#0xef
-	out	dx,al
-	cmp	bl,#0xa5
+	movw	$0x3c3, %dx
+	inb	%dx, %al
+	orb	$0x10, %al
+	outb	%al, %dx
+	movw	$0x104, %dx
+	inb	%dx, %al
+	movb	%al, %bl
+	movw	$0x3c3, %dx
+	inb	%dx, %al
+	andb	$0xef, %al
+	outb	%al, %dx
+	cmpb	$0xa5, %bl
 	je	cantok
-	xor	bp,bp
+	
+	xorw	%bp, %bp
 cantok:	ret
 
 chips_md:
@@ -1398,50 +1366,51 @@
 	.ascii	"Chips & Technologies"
 	.byte	0
 
-! Cirrus Logic 5X0
-
+# Cirrus Logic 5X0
 cirrus1_test:
-	mov	dx,#0x3d4
-	mov	al,#0x0c
-	out	dx,al
-	inc	dx
-	in	al,dx
-	mov	bl,al
-	xor	al,al
-	out	dx,al
-	dec	dx
-	mov	al,#0x1f
-	out	dx,al
-	inc	dx
-	in	al,dx
-	mov	bh,al
-	xor	ah,ah
-	shl	al,#4
-	mov	cx,ax
-	mov	al,bh
-	shr	al,#4
-	add	cx,ax
-	shl	cx,#8
-	add	cx,#6
-	mov	ax,cx
-	mov	dx,#0x3c4
-	out	dx,ax
-	inc	dx
-	in	al,dx
-	and	al,al
+	movw	$0x3d4, %dx
+	movb	$0x0c, %al
+	outb	%al, %dx
+	incw	%dx
+	inb	%dx, %al
+	movb	%al, %bl
+	xorb	%al, %al
+	outb	%al, %dx
+	decw	%dx
+	movb	$0x1f, %al
+	outb	%al, %dx
+	incw	%dx
+	inb	%dx, %al
+	movb	%al, %bh
+	xorb	%ah, %ah
+	shlb	$4, %al
+	movw	%ax, %cx
+	movb	%bh, %al
+	shrb	$4, %al
+	addw	%ax, %cx
+	shlw	$8, %cx
+	addw	$6, %cx
+	movw	%cx, %ax
+	movw	$0x3c4, %dx
+	outw	%ax, %dx
+	incw	%dx
+	inb	%dx, %al
+	andb	%al, %al
 	jnz	nocirr
-	mov	al,bh
-	out	dx,al
-	in	al,dx
-	cmp	al,#0x01
+	
+	movb	%bh, %al
+	outb	%al, %dx
+	inb	%dx, %al
+	cmpb	$0x01, %al
 	je	iscirr
-nocirr:	xor	bp,bp
-iscirr: mov	dx,#0x3d4
-	mov	al,bl
-	xor	ah,ah
-	shl	ax,#8
-	add	ax,#0x0c
-	out	dx,ax
+
+nocirr:	xorw	%bp, %bp
+iscirr: movw	$0x3d4, %dx
+	movb	%bl, %al
+	xorb	%ah, %ah
+	shlw	$8, %ax
+	addw	$0x0c, %ax
+	outw	%ax, %dx
 	ret
 
 cirrus1_md:
@@ -1453,46 +1422,49 @@
 	.ascii	"Cirrus Logic 5X0"
 	.byte	0
 
-! Cirrus Logic 54XX
-
+# Cirrus Logic 54XX
 cirrus5_test:
-	mov	dx,#0x3c4
-	mov	al,#6
+	movw	$0x3c4, %dx
+	movb	$6, %al
 	call	inidx
-	mov	bl,al			! BL=backup
-	mov	ax,#6
+	movb	%al, %bl			# BL=backup
+	movw	$6, %ax
 	call	tstidx
-	cmp	al,#0x0f
+	cmpb	$0x0f, %al
 	jne	c5fail
-	mov	ax,#0x1206
+	
+	movw	$0x1206, %ax
 	call	tstidx
-	cmp	al,#0x12
+	cmpb	$0x12, %al
 	jne	c5fail
-	mov	al,#0x1e
+	
+	movb	$0x1e, %al
 	call	inidx
-	mov	bh,al
-	mov	ah,bh
-	and	ah,#0xc0
-	mov	al,#0x1e
+	movb	%al, %bh
+	movb	%bh, %ah
+	andb	$0xc0, %ah
+	movb	$0x1e, %al
 	call	tstidx
-	and	al,#0x3f
+	andb	$0x3f, %al
 	jne	c5xx
-	mov	al,#0x1e
-	mov	ah,bh
-	or	ah,#0x3f
+	
+	movb	$0x1e, %al
+	movb	%bh, %ah
+	orb	$0x3f, %ah
 	call	tstidx
-	xor	al,#0x3f
-	and	al,#0x3f
+	xorb	$0x3f, %al
+	andb	$0x3f, %al
 c5xx:	pushf
-	mov	al,#0x1e
-	mov	ah,bh
-	out	dx,ax
+	movb	$0x1e, %al
+	movb	%bh, %ah
+	outw	%ax, %dx
 	popf
 	je	c5done
-c5fail:	xor	bp,bp
-c5done:	mov	al,#6
-	mov	ah,bl
-	out	dx,ax
+
+c5fail:	xorw	%bp, %bp
+c5done:	movb	$6, %al
+	movb	%bl, %ah
+	outw	%ax, %dx
 	ret
 
 cirrus5_md:
@@ -1502,37 +1474,42 @@
 	.ascii	"Cirrus Logic 54XX"
 	.byte	0
 
-! Cirrus Logic 64XX -- no known extra modes, but must be identified, because
-! it's misidentified by the Ahead test.
-
+# Cirrus Logic 64XX -- no known extra modes, but must be identified, because
+# it's misidentified by the Ahead test.
 cirrus6_test:
-	mov	dx,#0x3ce
-	mov	al,#0x0a
+	movw	$0x3ce, %dx
+	movb	$0x0a, %al
 	call	inidx
-	mov	bl,al			! BL=backup
-	mov	ax,#0xce0a
+	movb	%al, %bl	# BL=backup
+	movw	$0xce0a, %ax
 	call	tstidx
-	or	al,al
+	orb	%al, %al
 	jne	c2fail
-	mov	ax,#0xec0a
+	
+	movw	$0xec0a, %ax
 	call	tstidx
-	cmp	al,#0x01
+	cmpb	$0x01, %al
 	jne	c2fail
-	mov	al,#0xaa
-	call	inidx	! 4X, 5X, 7X and 8X are valid 64XX chip IDs
-	shr	al,#4
-	sub	al,#4
+	
+	movb	$0xaa, %al
+	call	inidx		# 4X, 5X, 7X and 8X are valid 64XX chip ID's. 
+	shrb	$4, %al
+	subb	$4, %al
 	jz	c6done
-	dec	al
+	
+	decb	%al
 	jz	c6done
-	sub	al,#2
+	
+	subb	$2, %al
 	jz	c6done
-	dec	al
+	
+	decb	%al
 	jz	c6done
-c2fail:	xor	bp,bp
-c6done:	mov	al,#0x0a
-	mov	ah,bl
-	out	dx,ax
+	
+c2fail:	xorw	%bp, %bp
+c6done:	movb	$0x0a, %al
+	movb	%bl, %ah
+	outw	%ax, %dx
 	ret
 
 cirrus6_md:
@@ -1540,23 +1517,25 @@
 	.ascii	"Cirrus Logic 64XX"
 	.byte	0
 
-! Everex / Trident
-
+# Everex / Trident
 everex_test:
-	mov	ax,#0x7000
-	xor	bx,bx
-	int	0x10
-	cmp	al,#0x70
+	movw	$0x7000, %ax
+	xorw	%bx, %bx
+	int	$0x10
+	cmpb	$0x70, %al
 	jne	noevrx
-	shr	dx,#4
-	cmp	dx,#0x678
+	
+	shrw	$4, %dx
+	cmpw	$0x678, %dx
 	je	evtrid
-	cmp	dx,#0x236
+	
+	cmpw	$0x236, %dx
 	jne	evrxok
-evtrid:	lea	bp,trident_md
+
+evtrid:	leaw	trident_md, %bp
 evrxok:	ret
 
-noevrx:	xor	bp,bp
+noevrx:	xorw	%bp, %bp
 	ret
 
 everex_md:
@@ -1574,28 +1553,27 @@
 	.ascii	"Everex/Trident"
 	.byte	0
 
-! Genoa.
-
+# Genoa.
 genoa_test:
-	lea	si,idgenoa		! Check Genoa 'clues'
-	xor 	ax,ax
-	seg es
-	mov	al,[0x37]
-	mov	di,ax
-	mov	cx,#0x04
-	dec	si
-	dec	di
-l1:	inc	si
-	inc	di
-	mov	al,(si)
-	test	al,al
+	leaw	idgenoa, %si			# Check Genoa 'clues'
+	xorw	%ax, %ax
+	movb	%es:(0x37), %al
+	movw	%ax, %di
+	movw	$0x04, %cx
+	decw	%si
+	decw	%di
+l1:	incw	%si
+	incw	%di
+	movb	(%si), %al
+	testb	%al, %al
 	jz	l2
-	seg es
-	cmp	al,(di)
+
+	cmpb	%es:(%di), %al
 l2:	loope 	l1
-	or	cx,cx
+	orw	%cx, %cx
 	je	isgen
-	xor	bp,bp
+	
+	xorw	%bp, %bp
 isgen:	ret
 
 idgenoa: .byte	0x77, 0x00, 0x99, 0x66
@@ -1616,16 +1594,16 @@
 	.ascii	"Genoa"
 	.byte	0
 
-! OAK
-
+# OAK
 oak_test:
-	lea	si,idoakvga
-	mov	di,#0x08
-	mov	cx,#0x08
+	leaw	idoakvga, %si
+	movw	$0x08, %di
+	movw	$0x08, %cx
 	repe
 	cmpsb
 	je	isoak
-	xor	bp,bp
+	
+	xorw	%bp, %bp
 isoak:	ret
 
 idoakvga: .ascii  "OAK VGA "
@@ -1638,16 +1616,16 @@
 	.ascii	"OAK"
 	.byte	0
 
-! WD Paradise.
-
+# WD Paradise.
 paradise_test:
-	lea	si,idparadise
-	mov	di,#0x7d
-	mov	cx,#0x04
+	leaw	idparadise, %si
+	movw	$0x7d, %di
+	movw	$0x04, %cx
 	repe
 	cmpsb
 	je	ispara
-	xor	bp,bp
+	
+	xorw	%bp, %bp
 ispara:	ret
 
 idparadise:	.ascii	"VGA="
@@ -1661,30 +1639,32 @@
 	.ascii	"Paradise"
 	.byte	0
 
-! Trident.
-
+# Trident.
 trident_test:
-	mov	dx,#0x3c4
-	mov	al,#0x0e
-	out	dx,al
-	inc	dx
-	in	al,dx
-	xchg	ah,al
-	xor	al,al
-	out	dx,al
-	in	al,dx
-	xchg	al,ah
-	mov	bl,al		! Strange thing ... in the book this wasn't
-	and	bl,#0x02	! necessary but it worked on my card which
-	jz	setb2		! is a trident. Without it the screen goes
-	and	al,#0xfd	! blurred ...
-	jmp	clrb2		!
-setb2:	or	al,#0x02	!
-clrb2:	out	dx,al
-	and	ah,#0x0f
-	cmp	ah,#0x02
+	movw	$0x3c4, %dx
+	movb	$0x0e, %al
+	outb	%al, %dx
+	incw	%dx
+	inb	%dx, %al
+	xchgb	%al, %ah
+	xorb	%al, %al
+	outb	%al, %dx
+	inb	%dx, %al
+	xchgb	%ah, %al
+	movb	%al, %bl	# Strange thing ... in the book this wasn't
+	andb	$0x02, %bl	# necessary but it worked on my card which
+	jz	setb2		# is a trident. Without it the screen goes
+				# blurred ...
+	andb	$0xfd, %al
+	jmp	clrb2		
+
+setb2:	orb	$0x02, %al	
+clrb2:	outb	%al, %dx
+	andb	$0x0f, %ah
+	cmpb	$0x02, %ah
 	je	istrid
-	xor	bp,bp
+
+	xorw	%bp, %bp
 istrid:	ret
 
 trident_md:
@@ -1699,21 +1679,21 @@
 	.ascii	"Trident"
 	.byte	0
 
-! Tseng.
-
+# Tseng.
 tseng_test:
-	mov	dx,#0x3cd
-	in	al,dx			! Could things be this simple? :-)
-	mov	bl,al
-	mov	al,#0x55
-	out	dx,al
-	in	al,dx
-	mov	ah,al
-	mov	al,bl
-	out	dx,al
-	cmp	ah,#0x55
+	movw	$0x3cd, %dx
+	inb	%dx, %al	# Could things be this simple ! :-)
+	movb	%al, %bl
+	movb	$0x55, %al
+	outb	%al, %dx
+	inb	%dx, %al
+	movb	%al, %ah
+	movb	%bl, %al
+	outb	%al, %dx
+	cmpb	$0x55, %ah
  	je	istsen
-isnot:	xor	bp,bp
+
+isnot:	xorw	%bp, %bp
 istsen:	ret
 
 tseng_md:
@@ -1727,40 +1707,41 @@
 	.ascii	"Tseng"
 	.byte	0
 
-! Video7.
-
+# Video7.
 video7_test:
-	mov	dx,#0x3cc
-	in	al,dx
-	mov	dx,#0x3b4
-	and	al,#0x01
+	movw	$0x3cc, %dx
+	inb	%dx, %al
+	movw	$0x3b4, %dx
+	andb	$0x01, %al
 	jz	even7
-	mov	dx,#0x3d4
-even7:	mov	al,#0x0c
-	out	dx,al
-	inc	dx
-	in	al,dx
-	mov	bl,al
-	mov	al,#0x55
-	out	dx,al
-	in	al,dx
-	dec	dx
-	mov	al,#0x1f
-	out	dx,al
-	inc	dx
-	in	al,dx
-	mov	bh,al
-	dec	dx
-	mov	al,#0x0c
-	out	dx,al
-	inc	dx
-	mov	al,bl
-	out	dx,al
-	mov	al,#0x55
-	xor	al,#0xea
-	cmp	al,bh
+
+	movw	$0x3d4, %dx
+even7:	movb	$0x0c, %al
+	outb	%al, %dx
+	incw	%dx
+	inb	%dx, %al
+	movb	%al, %bl
+	movb	$0x55, %al
+	outb	%al, %dx
+	inb	%dx, %al
+	decw	%dx
+	movb	$0x1f, %al
+	outb	%al, %dx
+	incw	%dx
+	inb	%dx, %al
+	movb	%al, %bh
+	decw	%dx
+	movb	$0x0c, %al
+	outb	%al, %dx
+	incw	%dx
+	movb	%bl, %al
+	outb	%al, %dx
+	movb	$0x55, %al
+	xorb	$0xea, %al
+	cmpb	%bh, %al
 	jne	isnot
-	movb	[svga_prefix],#VIDEO_FIRST_V7>>8	! Use special mode switching
+	
+	movb	$VIDEO_FIRST_V7>>8, $svga_prefix # Use special mode switching
 	ret
 
 video7_md:
@@ -1774,16 +1755,16 @@
 	.ascii	"Video 7"
 	.byte	0
 
-! Realtek VGA
-
+# Realtek VGA
 realtek_test:
-	lea	si,idrtvga
-	mov	di,#0x45
-	mov	cx,#0x0b
+	leaw	idrtvga, %si
+	movw	$0x45, %di
+	movw	$0x0b, %cx
 	repe
 	cmpsb
 	je	isrt
-	xor	bp,bp
+	
+	xorw	%bp, %bp
 isrt:	ret
 
 idrtvga:	.ascii	"REALTEK VGA"
@@ -1800,170 +1781,154 @@
 
 #endif	/* CONFIG_VIDEO_SVGA */
 
-!
-! User-defined local mode table (VGA only)
-!
-
+# User-defined local mode table (VGA only)
 #ifdef CONFIG_VIDEO_LOCAL
-
 local_modes:
-	lea	si,local_mode_table
+	leaw	local_mode_table, %si
 locm1:	lodsw
-	or	ax,ax
+	orw	%ax, %ax
 	jz	locm2
+	
 	stosw
 	movsw
 	jmp	locm1
-locm2:	ret
 
-! This is the table of local video modes which can be supplied manually
-! by the user. Each entry consists of mode ID (word) and dimensions
-! (byte for column count and another byte for row count). These modes
-! are placed before all SVGA and VESA modes and override them if table
-! compacting is enabled. The table must end with a zero word followed
-! by NUL-terminated video adapter name.
+locm2:	ret
 
+# This is the table of local video modes which can be supplied manually
+# by the user. Each entry consists of mode ID (word) and dimensions
+# (byte for column count and another byte for row count). These modes
+# are placed before all SVGA and VESA modes and override them if table
+# compacting is enabled. The table must end with a zero word followed
+# by NUL-terminated video adapter name.
 local_mode_table:
-	.word	0x0100		! Example: 40x25
+	.word	0x0100				# Example: 40x25
 	.byte	25,40
 	.word	0
 	.ascii	"Local"
 	.byte	0
-
 #endif	/* CONFIG_VIDEO_LOCAL */
 
-!
-! Read a key and return the ASCII code in al, scan code in ah
-!
-
-getkey:	xor	ah,ah
-	int	0x16
+# Read a key and return the ASCII code in al, scan code in ah
+getkey:	xorb	%ah, %ah
+	int	$0x16
 	ret
 
-!
-! Read a key with a timeout of 30 seconds. The hardware clock is used to get
-! the time.
-!
-
+# Read a key with a timeout of 30 seconds.
+# The hardware clock is used to get the time.
 getkt:	call	gettime
-	add	al,#30		! Wait 30 seconds
-	cmp	al,#60
+	addb	$30, %al			# Wait 30 seconds
+	cmpb	$60, %al
 	jl	lminute
-	sub	al,#60
+
+	subb	$60, %al
 lminute:
-	mov	cl,al
-again:	mov	ah,#0x01
-	int	0x16
-	jnz	getkey		! key pressed, so get it
+	movb	%al, %cl
+again:	movb	$0x01, %ah
+	int	$0x16
+	jnz	getkey				# key pressed, so get it
+
 	call	gettime
-	cmp	al,cl
+	cmpb	%cl, %al
 	jne	again
-	mov	al,#0x20	! timeout, return default char `space'
-	ret
 
-!
-! Flush the keyboard buffer
-!
+	movb	$0x20, %al			# timeout, return `space'
+	ret
 
-flush:	mov	ah,#0x01
-	int	0x16
+# Flush the keyboard buffer
+flush:	movb	$0x01, %ah
+	int	$0x16
 	jz	empty
-	xor	ah,ah
-	int	0x16
+	
+	xorb	%ah, %ah
+	int	$0x16
 	jmp	flush
-empty:	ret
 
-!
-! Print hexadecimal number.
-!
+empty:	ret
 
-prthw:	push	ax
-	mov	al,ah
+# Print hexadecimal number.
+prthw:	pushw	%ax
+	movb	%ah, %al
 	call	prthb
-	pop	ax
-prthb:	push	ax
-	shr	al,#4
+	popw	%ax
+prthb:	pushw	%ax
+	shrb	$4, %al
 	call	prthn
-	pop	ax
-	and	al,#0x0f
-prthn:	cmp	al,#0x0a
+	popw	%ax
+	andb	$0x0f, %al
+prthn:	cmpb	$0x0a, %al
 	jc	prth1
-	add	al,#0x07
-prth1:	add	al,#0x30
-	br	prtchr
-
-!
-! Print decimal number (AL).
-!
-
-prtdec:	push	ax
-	push	cx
-	xor	ah,ah		! Clear ah
-	mov	cl,#0x0a
-	idiv	cl
-	cmp	al,#0x09
+
+	addb	$0x07, %al
+prth1:	addb	$0x30, %al
+	jmp	prtchr
+
+# Print decimal number in al
+prtdec:	pushw	%ax
+	pushw	%cx
+	xorb	%ah, %ah
+	movb	$0x0a, %cl
+	idivb	%cl
+	cmpb	$0x09, %al
 	jbe	lt100
+
 	call	prtdec
 	jmp	skip10
-lt100:	add	al,#0x30
+
+lt100:	addb	$0x30, %al
 	call	prtchr
-skip10:	mov	al,ah
-	add	al,#0x30
+skip10:	movb	%ah, %al
+	addb	$0x30, %al
 	call	prtchr	
-	pop	cx
-	pop	ax
+	popw	%cx
+	popw	%ax
 	ret
 
-!
-! VIDEO_SELECT-only variables
-!
-
-mt_end:		.word	0	! End of video mode table if built
-edit_buf:	.space	6	! Line editor buffer
-card_name:	.word	0	! Pointer to adapter name
-scanning:	.byte	0	! Performing mode scan
-do_restore:	.byte	0	! Screen contents altered during mode change
-svga_prefix:	.byte	VIDEO_FIRST_BIOS>>8	! Default prefix for BIOS modes
-graphic_mode:	.byte	0	! Graphic mode with a linear frame buffer
-
-!
-! Messages:
-!
+# VIDEO_SELECT-only variables
+mt_end:		.word	0	# End of video mode table if built
+edit_buf:	.space	6	# Line editor buffer
+card_name:	.word	0	# Pointer to adapter name
+scanning:	.byte	0	# Performing mode scan
+do_restore:	.byte	0	# Screen contents altered during mode change
+svga_prefix:	.byte	VIDEO_FIRST_BIOS>>8	# Default prefix for BIOS modes
+graphic_mode:	.byte	0	# Graphic mode with a linear frame buffer
 
+# Status messages
 keymsg:		.ascii	"Press <RETURN> to see video modes available, "
 		.ascii	"<SPACE> to continue or wait 30 secs"
-		db	0x0d, 0x0a, 0
-listhdr:	db	0x0d, 0x0a
+		.byte	0x0d, 0x0a, 0
+
+listhdr:	.byte	0x0d, 0x0a
 		.ascii	"Mode:    COLSxROWS:"
-crlft:		db	0x0d, 0x0a, 0
-prompt:		db	0x0d, 0x0a
-		.ascii	"Enter mode number or `scan': "
-		db	0
-unknt:		.ascii	"Unknown mode ID. Try again."
-		db	0
+
+crlft:		.byte	0x0d, 0x0a, 0
+
+prompt:		.byte	0x0d, 0x0a
+		.asciz	"Enter mode number or `scan': "
+
+unknt:		.asciz	"Unknown mode ID. Try again."
+
 badmdt:		.ascii	"You passed an undefined mode number."
-		db	0x0d, 0x0a, 0
+		.byte	0x0d, 0x0a, 0
+
 vesaer:		.ascii	"Error: Scanning of VESA modes failed. Please "
 		.ascii	"report to <mj@ucw.cz>."
-		db	0x0d, 0x0a, 0
-old_name:	.ascii	"CGA/MDA/HGA"
-		db	0
-ega_name:	.ascii	"EGA"
-		db	0
+		.byte	0x0d, 0x0a, 0
+
+old_name:	.asciz	"CGA/MDA/HGA"
+
+ega_name:	.asciz	"EGA"
+
 svga_name:	.ascii	" "
-vga_name:	.ascii	"VGA"
-		db	0
-vesa_name:	.ascii	"VESA"
-		db	0
-name_bann:	.ascii	"Video adapter: "
-		db	0
 
+vga_name:	.asciz	"VGA"
+
+vesa_name:	.asciz	"VESA"
+
+name_bann:	.asciz	"Video adapter: "
 #endif /* CONFIG_VIDEO_SELECT */
 
-!
-! Other variables:
-!
-
-adapter:	.byte	0	! Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA
-video_segment:	.word	0xb800	! Video memory segment
-force_size:	.word	0	! Use this size instead of the one in BIOS vars
+# Other variables:
+adapter:	.byte	0	# Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA
+video_segment:	.word	0xb800	# Video memory segment
+force_size:	.word	0	# Use this size instead of the one in BIOS vars
diff -u --recursive --new-file v2.3.20/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.3.20/linux/arch/i386/config.in	Sat Oct  9 11:47:50 1999
+++ linux/arch/i386/config.in	Mon Oct 11 10:37:44 1999
@@ -183,9 +183,8 @@
   bool 'Video mode selection support' CONFIG_VIDEO_SELECT
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
     tristate 'MDA text console (dual-headed) (EXPERIMENTAL)' CONFIG_MDA_CONSOLE
-    bool 'Support for frame buffer devices (EXPERIMENTAL)' CONFIG_FB
+    source drivers/video/Config.in
   fi
-  source drivers/video/Config.in
   endmenu
 fi
 
diff -u --recursive --new-file v2.3.20/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.3.20/linux/arch/i386/defconfig	Sat Oct  9 11:47:50 1999
+++ linux/arch/i386/defconfig	Mon Oct 11 14:57:23 1999
@@ -41,6 +41,9 @@
 #
 # CONFIG_BIGMEM is not set
 CONFIG_NET=y
+# CONFIG_VISWS is not set
+CONFIG_X86_IO_APIC=y
+CONFIG_X86_LOCAL_APIC=y
 CONFIG_PCI=y
 # CONFIG_PCI_GOBIOS is not set
 # CONFIG_PCI_GODIRECT is not set
@@ -48,9 +51,6 @@
 CONFIG_PCI_BIOS=y
 CONFIG_PCI_DIRECT=y
 # CONFIG_MCA is not set
-# CONFIG_VISWS is not set
-CONFIG_X86_IO_APIC=y
-CONFIG_X86_LOCAL_APIC=y
 
 #
 # PCMCIA/Cardbus support
@@ -95,10 +95,13 @@
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 CONFIG_BLK_DEV_IDECD=y
-# CONFIG_IDECD_SLOTS is not set
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
+#
 CONFIG_BLK_DEV_CMD640=y
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 CONFIG_BLK_DEV_RZ1000=y
@@ -106,8 +109,6 @@
 # CONFIG_BLK_DEV_IDEDMA_PCI is not set
 # CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_BLK_DEV_AEC6210 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_BLK_DEV_HPT366 is not set
 CONFIG_BLK_DEV_PIIX=y
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_IDE_CHIPSETS is not set
@@ -245,9 +246,11 @@
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_DEPCA is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
 # CONFIG_PCNET32 is not set
+# CONFIG_ACENIC is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 # CONFIG_DE4X5 is not set
@@ -257,15 +260,18 @@
 # CONFIG_NE2K_PCI is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
 # CONFIG_NET_RADIO is not set
 
 #
-# Token ring devices
+# Token Ring driver support
 #
 # CONFIG_TR is not set
 # CONFIG_NET_FC is not set
@@ -273,18 +279,12 @@
 #
 # Wan interfaces
 #
-# CONFIG_HOSTESS_SV11 is not set
-# CONFIG_COSA is not set
-# CONFIG_SEALEVEL_4021 is not set
-# CONFIG_DLCI is not set
-# CONFIG_WAN_DRIVERS is not set
-# CONFIG_LAPBETHER is not set
-# CONFIG_X25_ASY is not set
+# CONFIG_WAN is not set
 
 #
 # PCMCIA network devices
 #
-# CONFIG_PCMCIA_PCNET is not set
+CONFIG_PCMCIA_PCNET=y
 # CONFIG_PCMCIA_3C589 is not set
 CONFIG_PCMCIA_RAYCS=y
 CONFIG_PCMCIA_NETCARD=y
@@ -327,7 +327,7 @@
 # CONFIG_BUSMOUSE is not set
 CONFIG_MOUSE=y
 CONFIG_PSMOUSE=y
-CONFIG_82C710_MOUSE=y
+# CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
diff -u --recursive --new-file v2.3.20/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c
--- v2.3.20/linux/arch/i386/kernel/apm.c	Fri Sep 10 23:57:27 1999
+++ linux/arch/i386/kernel/apm.c	Mon Oct 11 10:06:34 1999
@@ -643,33 +643,6 @@
 	return APM_SUCCESS;
 }
 
-static int apm_get_battery_status(u_short which, u_short *status,
-				  u_short *bat, u_short *life, u_short *nbat)
-{
-	u32	eax;
-	u32	ebx;
-	u32	ecx;
-	u32	edx;
-	u32	esi;
-
-	if (apm_bios_info.version < 0x0102) {
-		/* pretend we only have one battery. */
-		if (which != 1)
-			return APM_BAD_DEVICE;
-		*nbat = 1;
-		return apm_get_power_status(status, bat, life);
-	}
-
-	if (apm_bios_call(0x530a, (0x8000 | (which)), 0, &eax,
-			&ebx, &ecx, &edx, &esi))
-		return (eax >> 8) & 0xff;
-	*status = ebx;
-	*bat = ecx;
-	*life = edx;
-	*nbat = esi;
-	return APM_SUCCESS;
-}
-
 static int __init apm_engage_power_management(u_short device)
 {
 	u32	eax;
@@ -1263,7 +1236,6 @@
 	unsigned short	bx;
 	unsigned short	cx;
 	unsigned short	dx;
-	unsigned short	nbat;
 	unsigned short	error;
 	unsigned short  ac_line_status = 0xff;
 	unsigned short  battery_status = 0xff;
@@ -1473,7 +1445,7 @@
 
 	if (apm_bios_info.version == 0) {
 		printk(KERN_INFO "apm: BIOS not found.\n");
-		return;
+		return -1;
 	}
 	printk(KERN_INFO
 		"apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n",
@@ -1483,7 +1455,7 @@
 		driver_version);
 	if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) {
 		printk(KERN_INFO "apm: no 32 bit BIOS support\n");
-		return;
+		return -1;
 	}
 
 	/*
@@ -1512,7 +1484,7 @@
 
 	if (apm_disabled) {
 		printk(KERN_NOTICE "apm: disabled on user request.\n");
-		return;
+		return -1;
 	}
 
 #ifdef CONFIG_SMP
@@ -1571,6 +1543,7 @@
 	misc_register(&apm_device);
 
 	kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
+	return 0;
 }
 
 module_init(apm_init)
diff -u --recursive --new-file v2.3.20/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c
--- v2.3.20/linux/arch/i386/kernel/i386_ksyms.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/i386/kernel/i386_ksyms.c	Mon Oct 11 10:06:34 1999
@@ -18,6 +18,7 @@
 #include <asm/hardirq.h>
 #include <asm/delay.h>
 #include <asm/irq.h>
+#include <asm/mmx.h>
 
 extern void dump_thread(struct pt_regs *, struct user *);
 extern int dump_fpu(elf_fpregset_t *);
@@ -73,7 +74,13 @@
 EXPORT_SYMBOL(__clear_user);
 EXPORT_SYMBOL(__generic_copy_from_user);
 EXPORT_SYMBOL(__generic_copy_to_user);
-EXPORT_SYMBOL(strlen_user);
+EXPORT_SYMBOL(strnlen_user);
+
+#ifdef CONFIG_X86_USE_3DNOW
+EXPORT_SYMBOL(_mmx_memcpy);
+EXPORT_SYMBOL(mmx_clear_page);
+EXPORT_SYMBOL(mmx_copy_page);
+#endif
 
 #ifdef __SMP__
 EXPORT_SYMBOL(cpu_data);
@@ -119,3 +126,4 @@
 #ifdef CONFIG_VT
 EXPORT_SYMBOL(screen_info);
 #endif
+
diff -u --recursive --new-file v2.3.20/linux/arch/i386/lib/Makefile linux/arch/i386/lib/Makefile
--- v2.3.20/linux/arch/i386/lib/Makefile	Thu Aug 26 13:05:34 1999
+++ linux/arch/i386/lib/Makefile	Mon Oct 11 10:06:34 1999
@@ -9,4 +9,8 @@
 L_OBJS  = checksum.o old-checksum.o delay.o \
 	usercopy.o getuser.o putuser.o
 
+ifdef CONFIG_X86_USE_3DNOW
+L_OBJS += mmx.o
+endif
+
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.20/linux/arch/i386/lib/mmx.c linux/arch/i386/lib/mmx.c
--- v2.3.20/linux/arch/i386/lib/mmx.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/i386/lib/mmx.c	Mon Oct 11 10:06:34 1999
@@ -0,0 +1,236 @@
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+
+/*
+ *	MMX 3DNow! library helper functions
+ *
+ *	To do:
+ *	We can use MMX just for prefetch in IRQ's. This may be a win. 
+ *		(reported so on K6-III)
+ *	We should use a better code neutral filler for the short jump
+ *		leal ebx. [ebx] is apparently best for K6-2, but Cyrix ??
+ *	We also want to clobber the filler register so we dont get any
+ *		register forwarding stalls on the filler. 
+ *
+ *	Add *user handling. Checksums are not a win with MMX on any CPU
+ *	tested so far for any MMX solution figured.
+ *
+ */
+ 
+void *_mmx_memcpy(void *to, const void *from, size_t len)
+{
+	void *p=to;
+	int i= len >> 6;	/* len/64 */
+
+	if (!(current->flags & PF_USEDFPU))
+		clts();
+	else
+	{
+		__asm__ __volatile__ ( " fnsave %0; fwait\n"::"m"(current->thread.i387));
+		current->flags &= ~PF_USEDFPU;
+	}
+
+	__asm__ __volatile__ (
+		"1: prefetch (%0)\n"		/* This set is 28 bytes */
+		"   prefetch 64(%0)\n"
+		"   prefetch 128(%0)\n"
+		"   prefetch 192(%0)\n"
+		"   prefetch 256(%0)\n"
+		"2:  \n"
+		".section .fixup, \"ax\"\n"
+		"3: movw $0x1AEB, 1b\n"	/* jmp on 26 bytes */
+		"   jmp 2b\n"
+		".previous\n"
+		".section __ex_table,\"a\"\n"
+		"	.align 4\n"
+		"	.long 1b, 3b\n"
+		".previous"
+		: : "r" (from) );
+		
+	
+	for(; i>0; i--)
+	{
+		__asm__ __volatile__ (
+		"1:  prefetch 320(%0)\n"
+		"2:  movq (%0), %%mm0\n"
+		"  movq 8(%0), %%mm1\n"
+		"  movq 16(%0), %%mm2\n"
+		"  movq 24(%0), %%mm3\n"
+		"  movq %%mm0, (%1)\n"
+		"  movq %%mm1, 8(%1)\n"
+		"  movq %%mm2, 16(%1)\n"
+		"  movq %%mm3, 24(%1)\n"
+		"  movq 32(%0), %%mm0\n"
+		"  movq 40(%0), %%mm1\n"
+		"  movq 48(%0), %%mm2\n"
+		"  movq 56(%0), %%mm3\n"
+		"  movq %%mm0, 32(%1)\n"
+		"  movq %%mm1, 40(%1)\n"
+		"  movq %%mm2, 48(%1)\n"
+		"  movq %%mm3, 56(%1)\n"
+		".section .fixup, \"ax\"\n"
+		"3: movw $0x05EB, 1b\n"	/* jmp on 5 bytes */
+		"   jmp 2b\n"
+		".previous\n"
+		".section __ex_table,\"a\"\n"
+		"	.align 4\n"
+		"	.long 1b, 3b\n"
+		".previous"
+		: : "r" (from), "r" (to) : "memory");
+		from+=64;
+		to+=64;
+	}
+	/*
+	 *	Now do the tail of the block
+	 */
+	__memcpy(to, from, len&63);
+	stts();
+	return p;
+}
+
+static void fast_clear_page(long page)
+{
+	int i;
+	if (!(current->flags & PF_USEDFPU))
+		clts();
+	else
+	{
+		__asm__ __volatile__ ( " fnsave %0; fwait\n"::"m"(current->thread.i387));
+		current->flags &= ~PF_USEDFPU;
+	}
+	
+	__asm__ __volatile__ (
+		"  pxor %%mm0, %%mm0\n" : :
+	);
+
+	for(i=0;i<4096/128;i++)
+	{
+		__asm__ __volatile__ (
+		"  movq %%mm0, (%0)\n"
+		"  movq %%mm0, 8(%0)\n"
+		"  movq %%mm0, 16(%0)\n"
+		"  movq %%mm0, 24(%0)\n"
+		"  movq %%mm0, 32(%0)\n"
+		"  movq %%mm0, 40(%0)\n"
+		"  movq %%mm0, 48(%0)\n"
+		"  movq %%mm0, 56(%0)\n"
+		"  movq %%mm0, 64(%0)\n"
+		"  movq %%mm0, 72(%0)\n"
+		"  movq %%mm0, 80(%0)\n"
+		"  movq %%mm0, 88(%0)\n"
+		"  movq %%mm0, 96(%0)\n"
+		"  movq %%mm0, 104(%0)\n"
+		"  movq %%mm0, 112(%0)\n"
+		"  movq %%mm0, 120(%0)\n"
+		: : "r" (page) : "memory");
+		page+=128;
+	}
+	stts();
+}
+
+static void fast_copy_page(long to, long from)
+{
+	int i;
+	if (!(current->flags & PF_USEDFPU))
+		clts();
+	else
+	{
+		__asm__ __volatile__ ( " fnsave %0; fwait\n"::"m"(current->thread.i387));
+		current->flags &= ~PF_USEDFPU;
+	}
+
+	__asm__ __volatile__ (
+		"1: prefetch (%0)\n"
+		"   prefetch 64(%0)\n"
+		"   prefetch 128(%0)\n"
+		"   prefetch 192(%0)\n"
+		"   prefetch 256(%0)\n"
+		"2:  \n"
+		".section .fixup, \"ax\"\n"
+		"3: movw $0x1AEB, 1b\n"	/* jmp on 26 bytes */
+		"   jmp 2b\n"
+		".previous\n"
+		".section __ex_table,\"a\"\n"
+		"	.align 4\n"
+		"	.long 1b, 3b\n"
+		".previous"
+		: : "r" (from) );
+
+	for(i=0; i<4096/64; i++)
+	{
+		__asm__ __volatile__ (
+		"1: prefetch 320(%0)\n"
+		"2: movq (%0), %%mm0\n"
+		"   movq 8(%0), %%mm1\n"
+		"   movq 16(%0), %%mm2\n"
+		"   movq 24(%0), %%mm3\n"
+		"   movq %%mm0, (%1)\n"
+		"   movq %%mm1, 8(%1)\n"
+		"   movq %%mm2, 16(%1)\n"
+		"   movq %%mm3, 24(%1)\n"
+		"   movq 32(%0), %%mm0\n"
+		"   movq 40(%0), %%mm1\n"
+		"   movq 48(%0), %%mm2\n"
+		"   movq 56(%0), %%mm3\n"
+		"   movq %%mm0, 32(%1)\n"
+		"   movq %%mm1, 40(%1)\n"
+		"   movq %%mm2, 48(%1)\n"
+		"   movq %%mm3, 56(%1)\n"
+		".section .fixup, \"ax\"\n"
+		"3: movw $0x05EB, 1b\n"	/* jmp on 5 bytes */
+		"   jmp 2b\n"
+		".previous\n"
+		".section __ex_table,\"a\"\n"
+		"	.align 4\n"
+		"	.long 1b, 3b\n"
+		".previous"
+		: : "r" (from), "r" (to) : "memory");
+		from+=64;
+		to+=64;
+	}
+	stts();
+}
+
+/*
+ *	Favour MMX for page clear and copy. 
+ */
+
+static void slow_zero_page(long page)
+{
+	int d0, d1;
+	__asm__ __volatile__( \
+		"cld\n\t" \
+		"rep ; stosl" \
+		: "=&c" (d0), "=&D" (d1)
+		:"a" (0),"1" (page),"0" (1024)
+		:"memory");
+}
+ 
+void mmx_clear_page(long page)
+{
+	if(in_interrupt())
+		slow_zero_page(page);
+	else
+		fast_clear_page(page);
+}
+
+static void slow_copy_page(long to, long from)
+{
+	int d0, d1, d2;
+	__asm__ __volatile__( \
+		"cld\n\t" \
+		"rep ; movsl" \
+		: "=&c" (d0), "=&D" (d1), "=&S" (d2) \
+		: "0" (1024),"1" ((long) to),"2" ((long) from) \
+		: "memory");
+}
+  
+
+void mmx_copy_page(long to, long from)
+{
+	if(in_interrupt())
+		slow_copy_page(to, from);
+	else
+		fast_copy_page(to, from);
+}
diff -u --recursive --new-file v2.3.20/linux/arch/i386/lib/usercopy.c linux/arch/i386/lib/usercopy.c
--- v2.3.20/linux/arch/i386/lib/usercopy.c	Sun Dec 27 10:36:38 1998
+++ linux/arch/i386/lib/usercopy.c	Mon Oct 11 10:06:34 1999
@@ -6,6 +6,37 @@
  * Copyright 1997 Linus Torvalds
  */
 #include <asm/uaccess.h>
+#include <asm/mmx.h>
+
+#ifdef CONFIG_X86_USE_3DNOW_AND_WORKS
+
+unsigned long
+__generic_copy_to_user(void *to, const void *from, unsigned long n)
+{
+	if (access_ok(VERIFY_WRITE, to, n))
+	{
+		if(n<512)
+			__copy_user(to,from,n);
+		else
+			mmx_copy_user(to,from,n);
+	}
+	return n;
+}
+
+unsigned long
+__generic_copy_from_user(void *to, const void *from, unsigned long n)
+{
+	if (access_ok(VERIFY_READ, from, n))
+	{
+		if(n<512)
+			__copy_user_zeroing(to,from,n);
+		else
+			mmx_copy_user_zeroing(to, from, n);
+	}
+	return n;
+}
+
+#else
 
 unsigned long
 __generic_copy_to_user(void *to, const void *from, unsigned long n)
@@ -23,6 +54,7 @@
 	return n;
 }
 
+#endif
 
 /*
  * Copy a null terminated string from userspace.
@@ -117,26 +149,31 @@
 /*
  * Return the size of a string (including the ending 0)
  *
- * Return 0 for error
+ * Return 0 on exception, a value greater than N if too long
  */
 
-long strlen_user(const char *s)
+long strnlen_user(const char *s, long n)
 {
-	unsigned long res;
+	unsigned long mask = -__addr_ok(s);
+	unsigned long res, tmp;
 
 	__asm__ __volatile__(
+		"	andl %0,%%ecx\n"
 		"0:	repne; scasb\n"
-		"	notl %0\n"
+		"	setne %%al\n"
+		"	subl %%ecx,%0\n"
+		"	addl %0,%%eax\n"
 		"1:\n"
 		".section .fixup,\"ax\"\n"
-		"2:	xorl %0,%0\n"
+		"2:	xorl %%eax,%%eax\n"
 		"	jmp 1b\n"
 		".previous\n"
 		".section __ex_table,\"a\"\n"
 		"	.align 4\n"
 		"	.long 0b,2b\n"
 		".previous"
-		:"=c" (res), "=D" (s)
-		:"1" (s), "a" (0), "0" (-__addr_ok(s)));
-	return res & -__addr_ok(s);
+		:"=r" (n), "=D" (s), "=a" (res), "=c" (tmp)
+		:"0" (n), "1" (s), "2" (0), "3" (mask)
+		:"cc");
+	return res & mask;
 }
diff -u --recursive --new-file v2.3.20/linux/arch/sh/config.in linux/arch/sh/config.in
--- v2.3.20/linux/arch/sh/config.in	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/config.in	Mon Oct 11 10:06:34 1999
@@ -22,8 +22,8 @@
 comment 'Loadable module support'
 bool 'Enable loadable module support' CONFIG_MODULES
 if [ "$CONFIG_MODULES" = "y" ]; then
-  bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
-  bool 'Kernel module loader' CONFIG_KMOD
+   bool '  Set version information on all symbols for modules' CONFIG_MODVERSIONS
+   bool '  Kernel module loader' CONFIG_KMOD
 fi
 endmenu
 
@@ -44,7 +44,7 @@
 
 tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
 if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
-  bool '   Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
+   bool '  Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
 fi
 
 tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
@@ -52,14 +52,14 @@
 endmenu
 
 if [ "$CONFIG_NET" = "y" ]; then
-	source net/Config.in
+   source net/Config.in
 fi
 
 mainmenu_option next_comment
 comment 'Unix 98 PTY support'
 bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
 if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
-	int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
+   int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
 fi
 endmenu
 
diff -u --recursive --new-file v2.3.20/linux/arch/sparc64/solaris/timod.c linux/arch/sparc64/solaris/timod.c
--- v2.3.20/linux/arch/sparc64/solaris/timod.c	Fri Sep 10 23:57:28 1999
+++ linux/arch/sparc64/solaris/timod.c	Mon Oct 11 10:15:40 1999
@@ -152,7 +152,7 @@
 	sock = &current->files->fd[fd]->f_dentry->d_inode->u.socket_i;
 	wake_up_interruptible(&sock->wait);
 	if (sock->fasync_list && !(sock->flags & SO_WAITDATA))
-		kill_fasync(sock->fasync_list, SIGIO);
+		kill_fasync(sock->fasync_list, SIGIO, POLL_IN);
 	SOLD("done");
 }
 
diff -u --recursive --new-file v2.3.20/linux/drivers/acorn/block/Config.in linux/drivers/acorn/block/Config.in
--- v2.3.20/linux/drivers/acorn/block/Config.in	Thu Jun 17 01:11:35 1999
+++ linux/drivers/acorn/block/Config.in	Mon Oct 11 10:06:34 1999
@@ -5,11 +5,11 @@
 comment 'Acorn-specific block devices'
 
 if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then
-  tristate 'Old Archimedes floppy (1772) support' CONFIG_BLK_DEV_FD1772
-  tristate 'MFM harddisk support' CONFIG_BLK_DEV_MFM
-  if [ "$CONFIG_BLK_DEV_MFM" != "n" ]; then
-    bool '   Autodetect hard drive geometry' CONFIG_BLK_DEV_MFM_AUTODETECT
-  fi
+   tristate 'Old Archimedes floppy (1772) support' CONFIG_BLK_DEV_FD1772
+   tristate 'MFM harddisk support' CONFIG_BLK_DEV_MFM
+   if [ "$CONFIG_BLK_DEV_MFM" != "n" ]; then
+      bool '  Autodetect hard drive geometry' CONFIG_BLK_DEV_MFM_AUTODETECT
+   fi
 fi
 
 endmenu
diff -u --recursive --new-file v2.3.20/linux/drivers/acorn/scsi/Config.in linux/drivers/acorn/scsi/Config.in
--- v2.3.20/linux/drivers/acorn/scsi/Config.in	Thu Jun 17 01:11:35 1999
+++ linux/drivers/acorn/scsi/Config.in	Mon Oct 11 10:06:34 1999
@@ -3,21 +3,21 @@
 #
 dep_tristate 'Acorn SCSI card (aka30) support' CONFIG_SCSI_ACORNSCSI_3 $CONFIG_SCSI
 if [ "$CONFIG_SCSI_ACORNSCSI_3" != "n" ]; then
-  bool '  Support SCSI 2 Tagged queueing' CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
-  bool '  Support SCSI 2 Synchronous Transfers' CONFIG_SCSI_ACORNSCSI_SYNC
+   bool '  Support SCSI 2 Tagged queueing' CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
+   bool '  Support SCSI 2 Synchronous Transfers' CONFIG_SCSI_ACORNSCSI_SYNC
 fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  dep_tristate 'ARXE SCSI support (Experimental)' CONFIG_SCSI_ARXESCSI $CONFIG_SCSI
-  dep_tristate 'CumanaSCSI II support (Experimental)' CONFIG_SCSI_CUMANA_2 $CONFIG_SCSI
-  dep_tristate 'EESOX support (Experimental)' CONFIG_SCSI_EESOXSCSI $CONFIG_SCSI
-  dep_tristate 'PowerTec support (Experimental)' CONFIG_SCSI_POWERTECSCSI $CONFIG_SCSI
+   dep_tristate 'ARXE SCSI support (EXPERIMENTAL)' CONFIG_SCSI_ARXESCSI $CONFIG_SCSI
+   dep_tristate 'CumanaSCSI II support (EXPERIMENTAL)' CONFIG_SCSI_CUMANA_2 $CONFIG_SCSI
+   dep_tristate 'EESOX support (EXPERIMENTAL)' CONFIG_SCSI_EESOXSCSI $CONFIG_SCSI
+   dep_tristate 'PowerTec support (EXPERIMENTAL)' CONFIG_SCSI_POWERTECSCSI $CONFIG_SCSI
 
-  comment 'The following drivers are not fully supported'
+   comment 'The following drivers are not fully supported'
 
-  dep_tristate 'CumanaSCSI I support' CONFIG_SCSI_CUMANA_1 $CONFIG_SCSI
-  if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then
-    dep_tristate 'EcoScsi support' CONFIG_SCSI_ECOSCSI $CONFIG_SCSI
-  fi
-  dep_tristate 'Oak SCSI support' CONFIG_SCSI_OAK1 $CONFIG_SCSI
+   dep_tristate 'CumanaSCSI I support' CONFIG_SCSI_CUMANA_1 $CONFIG_SCSI
+   if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then
+      dep_tristate 'EcoScsi support' CONFIG_SCSI_ECOSCSI $CONFIG_SCSI
+   fi
+   dep_tristate 'Oak SCSI support' CONFIG_SCSI_OAK1 $CONFIG_SCSI
 fi
 
diff -u --recursive --new-file v2.3.20/linux/drivers/block/Config.in linux/drivers/block/Config.in
--- v2.3.20/linux/drivers/block/Config.in	Tue Sep  7 12:14:06 1999
+++ linux/drivers/block/Config.in	Mon Oct 11 10:10:19 1999
@@ -6,198 +6,200 @@
 
 tristate 'Normal PC floppy disk support' CONFIG_BLK_DEV_FD
 if [ "$CONFIG_AMIGA" = "y" ]; then
-  tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY
+   tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
-  tristate 'Atari floppy support' CONFIG_ATARI_FLOPPY
+   tristate 'Atari floppy support' CONFIG_ATARI_FLOPPY
 fi
 if [ "$CONFIG_MAC" = "y" ]; then
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    bool 'Macintosh IIfx/Quadra 900/Quadra 950 floppy support (EXPERIMENTAL)' CONFIG_BLK_DEV_SWIM_IOP
-  fi
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      bool 'Macintosh IIfx/Quadra 900/Quadra 950 floppy support (EXPERIMENTAL)' CONFIG_BLK_DEV_SWIM_IOP
+   fi
 fi
 
 tristate 'Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE
 comment 'Please see Documentation/ide.txt for help/info on IDE drives'
 if [ "$CONFIG_BLK_DEV_IDE" = "n" ]; then
-  bool 'Old hard disk (MFM/RLL/IDE) driver' CONFIG_BLK_DEV_HD_ONLY
+   bool 'Old hard disk (MFM/RLL/IDE) driver' CONFIG_BLK_DEV_HD_ONLY
 else
-  bool '   Use old disk-only driver on primary interface' CONFIG_BLK_DEV_HD_IDE
-  dep_tristate '   Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
-  if [ "$CONFIG_BLK_DEV_IDEDISK" != "n" ]; then
-    bool '     Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE
-  fi
-  dep_tristate '   Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE
-  if [ "$CONFIG_BLK_DEV_IDECD" = "y" ]; then
-    bool '     Include CD-Changer Reporting' CONFIG_IDECD_SLOTS
-  fi
-  dep_tristate '   Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE
-  dep_tristate '   Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
-  dep_tristate '   SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE
-  if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
-    bool '   CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640
-    if [ "$CONFIG_BLK_DEV_CMD640" = "y" ]; then
-      bool '     CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED
-    fi
-    if [ "$CONFIG_PCI" = "y" ]; then
-      bool '   RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000
-      bool '   Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI
-      if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
-        bool '     Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI
-        if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
-          bool '     Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO
-          if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-            bool '       Good-Bad DMA Model-Firmware (EXPERIMENTAL)' IDEDMA_NEW_DRIVE_LISTINGS
-            define_bool IDEDMA_PCI_EXPERIMENTAL y
-          else
-            define_bool IDEDMA_PCI_EXPERIMENTAL n
-          fi
-        fi
-        bool '     Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
-        bool '     AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210
-        if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
-          if [ "$CONFIG_X86" = "y" ]; then
-            bool '     ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3
-          fi
-          bool '     CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646
-          bool '     CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693
-        fi
-        bool '     HPT34X chipset support' CONFIG_BLK_DEV_HPT34X
-        if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" -a \
-             "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then
-          bool '       HPT34X DMA support (DANGEROUS)' CONFIG_BLK_DEV_HPT34X_DMA
-        fi
-        bool '     HPT366 chipset support' CONFIG_BLK_DEV_HPT366
-        if [ "$CONFIG_X86" = "y" ]; then
-          bool '     Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX
-          if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" -a \
-               "$CONFIG_BLK_DEV_PIIX" = "y" ]; then
-            bool '       PIIXn Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TUNING
-          fi
-        fi
-        if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
-          bool '     NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415
-        fi
-        if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-          bool '     OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621
-        fi
-        if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
-          bool '     PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX
-          if [ "$CONFIG_EXPERIMENTAL" = "y" -a \
-               "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then
-            bool '       Special UDMA Feature (EXPERIMENTAL)' PDC202XX_FORCE_BURST_BIT
-            bool '       Special Mode Feature (DANGEROUS)' PDC202XX_FORCE_MASTER_MODE
-          fi
-        fi
-        if [ "$CONFIG_X86" = "y" ]; then
-          bool '     SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513
-        fi
-        if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
-          bool '     Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
-          if [ "$CONFIG_X86" = "y" ]; then
-            bool '     VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586
-          fi
-        fi
-      fi
-      if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
-          bool '   Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
-      fi
-    fi
-    if [ "$CONFIG_PMAC" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then
-      bool '   Builtin PowerMac IDE support' CONFIG_BLK_DEV_IDE_PMAC
-        if [ "$CONFIG_BLK_DEV_IDE_PMAC" != "n" ]; then
-          bool '     PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC
-          if [ "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" ]; then
-            bool '     Use DMA by default' CONFIG_IDEDMA_PMAC_AUTO
-          fi
-       fi
-    fi
-    if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
-        bool '   ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE
-        if [ "$CONFIG_BLK_DEV_IDE_ICSIDE" = "y" ]; then
-          bool '     ICS DMA support' CONFIG_BLK_DEV_IDEDMA_ICS
-          if [ "$CONFIG_BLK_DEV_IDEDMA_ICS" = "y" ]; then
-            bool '     Use ICS DMA by default' CONFIG_IDEDMA_ICS_AUTO
-          fi
-        fi
-        bool '   RapIDE interface support' CONFIG_BLK_DEV_IDE_RAPIDE
-    fi
-    if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" -o \
-         "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" -o \
-         "$CONFIG_BLK_DEV_IDEDMA_ICS" = "y" ]; then
-      define_bool CONFIG_BLK_DEV_IDEDMA y
-      if [ "$CONFIG_IDEDMA_PCI_AUTO" = "y" -o \
-           "$CONFIG_IDEDMA_PMAC_AUTO" = "y" -o \
-           "$CONFIG_IDEDMA_ICS_AUTO" = "y" ]; then
-        define_bool CONFIG_IDEDMA_AUTO y
-      fi
-    fi
-    bool '   Other IDE chipset support' CONFIG_IDE_CHIPSETS
-    if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
-      comment 'Note: most of these also require special kernel boot parameters'
-      bool '     Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES
-      bool '     ALI M14xx support' CONFIG_BLK_DEV_ALI14XX
-      bool '     DTC-2278 support' CONFIG_BLK_DEV_DTC2278
-      bool '     Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B
-      if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a \
-           "$CONFIG_EXPERIMENTAL" = "y" ]; then
-        bool '     PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
-      fi
-      bool '     QDI QD6580 support' CONFIG_BLK_DEV_QD6580
-      bool '     UMC-8672 support' CONFIG_BLK_DEV_UMC8672
-    fi
-    if [ "$CONFIG_AMIGA" = "y" ]; then
-      bool '   Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE
-      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-        bool '   Amiga IDE Doubler support' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE
-      fi
-    fi
-    if [ "$CONFIG_ZORRO" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-        bool '   Buddha/Catweasel IDE interface support' CONFIG_BLK_DEV_BUDDHA
-    fi
-    if [ "$CONFIG_ATARI" = "y" ]; then
-      bool '   Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE
-    fi
-    if [ "$CONFIG_MAC" = "y" ]; then
-      bool '   Macintosh Quadra/Powerbook IDE interface support' CONFIG_BLK_DEV_MAC_IDE
-    fi
-  fi
+   bool '  Use old disk-only driver on primary interface' CONFIG_BLK_DEV_HD_IDE
+   dep_tristate '  Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
+   if [ "$CONFIG_BLK_DEV_IDEDISK" != "n" ]; then
+      bool '    Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE
+   fi
+   dep_tristate '  Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE
+   dep_tristate '  Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE
+   dep_tristate '  Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
+   dep_tristate '  SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE
+   comment 'IDE chipset support/bugfixes'
+   if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
+      bool '  CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640
+      if [ "$CONFIG_BLK_DEV_CMD640" = "y" ]; then
+	 bool '    CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED
+      fi
+      if [ "$CONFIG_PCI" = "y" ]; then
+	 bool '  RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000
+	 bool '  Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI
+	 if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
+	    bool '    Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI
+	    if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
+	       bool '      Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO
+	       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+		  bool '      Good-Bad DMA Model-Firmware (EXPERIMENTAL)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
+		  define_bool CONFIG_IDEDMA_PCI_EXPERIMENTAL y
+	       else
+		  define_bool CONFIG_IDEDMA_PCI_EXPERIMENTAL n
+	       fi
+	    fi
+	    bool '    Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
+	    bool '    AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210
+	    if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
+	       if [ "$CONFIG_X86" = "y" ]; then
+		  bool '    ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3
+	       fi
+	       bool '    CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646
+	       bool '    CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693
+	    fi
+	    if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
+  	       bool '    HPT34X chipset support' CONFIG_BLK_DEV_HPT34X
+	       if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a \
+	 	     "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then
+	       bool '      HPT34X DMA support (DANGEROUS)' CONFIG_BLK_DEV_HPT34X_DMA
+	       fi
+  	       bool '    HPT366 chipset support' CONFIG_BLK_DEV_HPT366
+	    fi
+	    if [ "$CONFIG_X86" = "y" ]; then
+	       bool '    Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX
+	       if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a \
+		    "$CONFIG_BLK_DEV_PIIX" = "y" ]; then
+		  bool '      PIIXn Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TUNING
+	       fi
+	    fi
+	    if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
+	       bool '    NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415
+	    fi
+	    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	       bool '    OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621
+	    fi
+	    if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
+	       bool '    PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX
+	       if [ "$CONFIG_EXPERIMENTAL" = "y" -a \
+		    "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then
+		  bool '      Special UDMA Feature (EXPERIMENTAL)' CONFIG_PDC202XX_FORCE_BURST_BIT
+		  bool '      Special Mode Feature (DANGEROUS)' CONFIG_PDC202XX_FORCE_MASTER_MODE
+	       fi
+	    fi
+	    if [ "$CONFIG_X86" = "y" ]; then
+	       bool '    SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513
+	    fi
+	    if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
+	       bool '    Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
+	       if [ "$CONFIG_X86" = "y" ]; then
+		  bool '     VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586
+	       fi
+	    fi
+         fi
+	 if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
+	    bool '    Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
+	 fi
+      fi
+      if [ "$CONFIG_PMAC" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then
+	 bool '    Builtin PowerMac IDE support' CONFIG_BLK_DEV_IDE_PMAC
+	 if [ "$CONFIG_BLK_DEV_IDE_PMAC" != "n" ]; then
+	    bool '      PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC
+	    if [ "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" ]; then
+	       bool '        Use DMA by default' CONFIG_IDEDMA_PMAC_AUTO
+	    fi
+	 fi
+      fi
+      if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+	 bool '    ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE
+	 if [ "$CONFIG_BLK_DEV_IDE_ICSIDE" = "y" ]; then
+	    bool '      ICS DMA support' CONFIG_BLK_DEV_IDEDMA_ICS
+	    if [ "$CONFIG_BLK_DEV_IDEDMA_ICS" = "y" ]; then
+	       bool '        Use ICS DMA by default' CONFIG_IDEDMA_ICS_AUTO
+	    fi
+	 fi
+	 bool '    RapIDE interface support' CONFIG_BLK_DEV_IDE_RAPIDE
+      fi
+      if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" -o \
+	   "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" -o \
+	   "$CONFIG_BLK_DEV_IDEDMA_ICS" = "y" ]; then
+	 define_bool CONFIG_BLK_DEV_IDEDMA y
+	 if [ "$CONFIG_IDEDMA_PCI_AUTO" = "y" -o \
+	      "$CONFIG_IDEDMA_PMAC_AUTO" = "y" -o \
+	      "$CONFIG_IDEDMA_ICS_AUTO" = "y" ]; then
+	    define_bool CONFIG_IDEDMA_AUTO y
+	 fi
+      fi
+      bool '  Other IDE chipset support' CONFIG_IDE_CHIPSETS
+      if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
+	 comment 'Note: most of these also require special kernel boot parameters'
+	 bool '    Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES
+	 bool '    ALI M14xx support' CONFIG_BLK_DEV_ALI14XX
+	 bool '    DTC-2278 support' CONFIG_BLK_DEV_DTC2278
+	 bool '    Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B
+	 if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a \
+	      "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	    bool '    PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
+	 fi
+	 bool '    QDI QD6580 support' CONFIG_BLK_DEV_QD6580
+	 bool '    UMC-8672 support' CONFIG_BLK_DEV_UMC8672
+      fi
+      if [ "$CONFIG_AMIGA" = "y" ]; then
+	 bool '    Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE
+	 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	    dep_tristate '      Amiga IDE Doubler support (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE
+	 fi
+      fi
+      if [ "$CONFIG_ZORRO" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	 bool '    Buddha/Catweasel IDE interface support (EXPERIMENTAL)' CONFIG_BLK_DEV_BUDDHA
+      fi
+      if [ "$CONFIG_ATARI" = "y" ]; then
+	 bool '    Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE
+      fi
+      if [ "$CONFIG_MAC" = "y" ]; then
+	 bool '    Macintosh Quadra/Powerbook IDE interface support' CONFIG_BLK_DEV_MAC_IDE
+      fi
+   fi
 fi
 if [ "$CONFIG_MCA" = "y" ]; then
-  tristate 'PS/2 ESDI hard disk support' CONFIG_BLK_DEV_PS2
+   tristate 'PS/2 ESDI hard disk support' CONFIG_BLK_DEV_PS2
 fi
 if [ "$CONFIG_ZORRO" = "y" ]; then
-  tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM
+   tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
-  tristate 'Atari ACSI support' CONFIG_ATARI_ACSI
-  if [ "$CONFIG_ATARI_ACSI" != "n" ]; then
-    comment 'Some devices (e.g. CD jukebox) support multiple LUNs'
-    bool 'Probe all LUNs on each ACSI device' CONFIG_ACSI_MULTI_LUN
-    dep_tristate 'Atari SLM laser printer support' CONFIG_ATARI_SLM $CONFIG_ATARI_ACSI
-  fi
+   tristate 'Atari ACSI support' CONFIG_ATARI_ACSI
+   if [ "$CONFIG_ATARI_ACSI" != "n" ]; then
+      comment 'Some devices (e.g. CD jukebox) support multiple LUNs'
+      bool '  Probe all LUNs on each ACSI device' CONFIG_ACSI_MULTI_LUN
+      tristate '  Atari SLM laser printer support' CONFIG_ATARI_SLM
+   fi
+fi
+if [ "$CONFIG_PCI" = "y" ]; then
+   tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA
 fi
-tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA
 
 comment 'Additional Block Devices'
 
 tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
 if [ "$CONFIG_NET" = "y" ]; then
-  tristate 'Network block device support' CONFIG_BLK_DEV_NBD
+   tristate 'Network block device support' CONFIG_BLK_DEV_NBD
 fi
 bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
 if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
-  tristate '   Linear (append) mode' CONFIG_MD_LINEAR
-  tristate '   RAID-0 (striping) mode' CONFIG_MD_STRIPED
-  tristate '   RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING
-  tristate '   RAID-4/RAID-5 mode' CONFIG_MD_RAID5
+   tristate '  Linear (append) mode' CONFIG_MD_LINEAR
+   tristate '  RAID-0 (striping) mode' CONFIG_MD_STRIPED
+   tristate '  RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING
+   tristate '  RAID-4/RAID-5 mode' CONFIG_MD_RAID5
 fi
 if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then
-  bool '      Boot support (linear, striped)' CONFIG_MD_BOOT
+   bool '    Boot support (linear, striped)' CONFIG_MD_BOOT
 fi
 tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
 if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
-  bool '   Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
+   bool '  Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
 fi
 tristate 'XT hard disk support' CONFIG_BLK_DEV_XD
 
@@ -205,14 +207,14 @@
 # PARIDE must also be a module.  The bogus CONFIG_PARIDE_PARPORT option
 # controls the choices given to the user ...
 
-if [ "$CONFIG_PARPORT" = "y" -o "$CONFIG_PARPORT" = "n" ] ; then
+if [ "$CONFIG_PARPORT" = "y" -o "$CONFIG_PARPORT" = "n" ]; then
    define_bool CONFIG_PARIDE_PARPORT y
 else
    define_bool CONFIG_PARIDE_PARPORT m
 fi
 dep_tristate 'Parallel port IDE device support' CONFIG_PARIDE $CONFIG_PARIDE_PARPORT
 if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then
-  source drivers/block/paride/Config.in
+   source drivers/block/paride/Config.in
 fi
 
 if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
@@ -226,15 +228,15 @@
      "$CONFIG_BLK_DEV_PIIX" = "y" -o \
      "$CONFIG_BLK_DEV_SIS5513" = "y" -o \
      "$CONFIG_BLK_DEV_SL82C105" = "y" ]; then
-  define_bool CONFIG_BLK_DEV_IDE_MODES y
+   define_bool CONFIG_BLK_DEV_IDE_MODES y
 else
-  define_bool CONFIG_BLK_DEV_IDE_MODES n
+   define_bool CONFIG_BLK_DEV_IDE_MODES n
 fi
 
 if [ "$CONFIG_BLK_DEV_HD_IDE" = "y" -o "$CONFIG_BLK_DEV_HD_ONLY" = "y" ]; then
-  define_bool CONFIG_BLK_DEV_HD y
+   define_bool CONFIG_BLK_DEV_HD y
 else
-  define_bool CONFIG_BLK_DEV_HD n
+   define_bool CONFIG_BLK_DEV_HD n
 fi
 
 endmenu
diff -u --recursive --new-file v2.3.20/linux/drivers/block/Makefile linux/drivers/block/Makefile
--- v2.3.20/linux/drivers/block/Makefile	Tue Sep  7 12:14:06 1999
+++ linux/drivers/block/Makefile	Mon Oct 11 10:06:34 1999
@@ -20,7 +20,7 @@
 
 
 L_TARGET := block.a
-L_OBJS   := genhd.o cmos-probe.o
+L_OBJS   := genhd.o ide-geometry.o
 M_OBJS   :=
 MOD_LIST_NAME := BLOCK_MODULES
 LX_OBJS := ll_rw_blk.o blkpg.o
@@ -248,7 +248,7 @@
 else
   ifeq ($(CONFIG_BLK_DEV_IDE),m)
   MIX_OBJS += ide.o $(IDE_OBJS)
-  M_OBJS += ide-mod.o ide-probe.o
+  M_OBJS += ide-mod.o ide-probe-mod.o
   endif
 endif
 
@@ -376,3 +376,7 @@
 
 ide-mod.o: ide.o $(IDE_OBJS)
 	$(LD) $(LD_RFLAG) -r -o $@ ide.o $(IDE_OBJS)
+
+ide-probe-mod.o: ide-probe.o ide-geometry.o
+	$(LD) $(LD_RFLAG) -r -o $@ ide-probe.o ide-geometry.o
+
diff -u --recursive --new-file v2.3.20/linux/drivers/block/cmos-probe.c linux/drivers/block/cmos-probe.c
--- v2.3.20/linux/drivers/block/cmos-probe.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/cmos-probe.c	Wed Dec 31 16:00:00 1969
@@ -1,78 +0,0 @@
-/*
- *  linux/drivers/block/cmos-probe.c	Version 1.00  August 16, 1999
- *
- *  Copyright (C) 1994-1999  Linus Torvalds & authors (see below)
- */
-
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/malloc.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-
-
-#include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-/*
- * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc
- * controller that is BIOS compatible with ST-506, and thus showing up in our
- * BIOS table, but not register compatible, and therefore not present in CMOS.
- *
- * Furthermore, we will assume that our ST-506 drives <if any> are the primary
- * drives in the system -- the ones reflected as drive 1 or 2.  The first
- * drive is stored in the high nibble of CMOS byte 0x12, the second in the low
- * nibble.  This will be either a 4 bit drive type or 0xf indicating use byte
- * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.  A non-zero value
- * means we have an AT controller hard disk for that drive.
- *
- * Of course, there is no guarantee that either drive is actually on the
- * "primary" IDE interface, but we don't bother trying to sort that out here.
- * If a drive is not actually on the primary interface, then these parameters
- * will be ignored.  This results in the user having to supply the logical
- * drive geometry as a boot parameter for each drive not on the primary i/f.
- *
- * The only "perfect" way to handle this would be to modify the setup.[cS] code
- * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info
- * for us during initialization.  I have the necessary docs -- any takers?  -ml
- */
-void probe_cmos_for_drives (ide_hwif_t *hwif)
-{
-#ifdef __i386__
-	extern struct drive_info_struct drive_info;
-	byte cmos_disks, *BIOS = (byte *) &drive_info;
-	int unit;
-
-#ifdef CONFIG_BLK_DEV_PDC4030
-	if (hwif->chipset == ide_pdc4030 && hwif->channel != 0)
-		return;
-#endif /* CONFIG_BLK_DEV_PDC4030 */
-	outb_p(0x12,0x70);		/* specify CMOS address 0x12 */
-	cmos_disks = inb_p(0x71);	/* read the data from 0x12 */
-	/* Extract drive geometry from CMOS+BIOS if not already setup */
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		ide_drive_t *drive = &hwif->drives[unit];
-		if ((cmos_disks & (0xf0 >> (unit*4))) && !drive->present && !drive->nobios) {
-			drive->cyl   = drive->bios_cyl  = *(unsigned short *)BIOS;
-			drive->head  = drive->bios_head = *(BIOS+2);
-			drive->sect  = drive->bios_sect = *(BIOS+14);
-			drive->ctl   = *(BIOS+8);
-			drive->present = 1;
-		}
-		BIOS += 16;
-	}
-#endif
-}
diff -u --recursive --new-file v2.3.20/linux/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c
--- v2.3.20/linux/drivers/block/cpqarray.c	Fri Sep 10 23:57:29 1999
+++ linux/drivers/block/cpqarray.c	Mon Oct 11 10:10:19 1999
@@ -212,6 +212,7 @@
  */
 static void ida_procinit(int i)
 {
+#ifdef CONFIG_PROC_FS
 	struct proc_dir_entry *pd;
 
 	if (proc_array == NULL) {
@@ -224,6 +225,7 @@
 	if (!pd) return;
 	pd->read_proc = ida_proc_get_info;
 	pd->data = hba[i];
+#endif	
 }
 
 /*
@@ -356,7 +358,9 @@
 			}
 		}
 	}
+#ifdef CONFIG_PROC_FS
 	remove_proc_entry("array", &proc_root);
+#endif
 	kfree(ida);
 	kfree(ida_sizes);
 	kfree(ida_hardsizes);
diff -u --recursive --new-file v2.3.20/linux/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c
--- v2.3.20/linux/drivers/block/ide-disk.c	Mon Jul  5 20:13:59 1999
+++ linux/drivers/block/ide-disk.c	Mon Oct 11 10:06:34 1999
@@ -94,42 +94,40 @@
  *
  * Returns:	1 if lba_capacity looks sensible
  *		0 otherwise
+ *
+ * It is called only once for each drive.
  */
 static int lba_capacity_is_ok (struct hd_driveid *id)
 {
-	unsigned long lba_sects   = id->lba_capacity;
-	unsigned long chs_sects   = id->cyls * id->heads * id->sectors;
-	unsigned long _10_percent = chs_sects / 10;
+	unsigned long lba_sects, chs_sects, head, tail;
 
 	/*
-	 * very large drives (8GB+) may lie about the number of cylinders
-	 * This is a split test for drives 8 Gig and Bigger only.
+	 * The ATA spec tells large drives to return
+	 * C/H/S = 16383/16/63 independent of their size.
+	 * Some drives can be jumpered to use 15 heads instead of 16.
 	 */
-	if ((id->lba_capacity >= 16514064) && (id->cyls == 0x3fff) &&
-	    (id->heads == 16) && (id->sectors == 63)) {
-		id->cyls = lba_sects / (16 * 63); /* correct cyls */
-		return 1;	/* lba_capacity is our only option */
-	}
-	/*
-	 * ... and at least one TLA VBC has POS instead of brain and can't
-	 * tell 16 from 15.
-	 */
-	if ((id->lba_capacity >= 15481935) && (id->cyls == 0x3fff) &&
-	    (id->heads == 15) && (id->sectors == 63)) {
-		id->cyls = lba_sects / (15 * 63); /* correct cyls */
-		return 1;	/* lba_capacity is our only option */
-	}
-	/* perform a rough sanity check on lba_sects:  within 10% is "okay" */
-	if ((lba_sects - chs_sects) < _10_percent) {
-		return 1;	/* lba_capacity is good */
-	}
+	if (id->cyls == 16383 && id->sectors == 63 &&
+	    (id->heads == 15 || id->heads == 16) &&
+	    id->lba_capacity >= 16383*63*id->heads)
+		return 1;
+
+	lba_sects   = id->lba_capacity;
+	chs_sects   = id->cyls * id->heads * id->sectors;
+
+	/* perform a rough sanity check on lba_sects:  within 10% is OK */
+	if ((lba_sects - chs_sects) < chs_sects/10)
+		return 1;
+
 	/* some drives have the word order reversed */
-	lba_sects = (lba_sects << 16) | (lba_sects >> 16);
-	if ((lba_sects - chs_sects) < _10_percent) {
-		id->lba_capacity = lba_sects;	/* fix it */
+	head = ((lba_sects >> 16) & 0xffff);
+	tail = (lba_sects & 0xffff);
+	lba_sects = (head | (tail << 16));
+	if ((lba_sects - chs_sects) < chs_sects/10) {
+		id->lba_capacity = lba_sects;
 		return 1;	/* lba_capacity is (now) good */
 	}
-	return 0;	/* lba_capacity value is bad */
+
+	return 0;	/* lba_capacity value may be bad */
 }
 
 /*
@@ -450,24 +448,28 @@
 }
 
 /*
- * current_capacity() returns the capacity (in sectors) of a drive
- * according to its current geometry/LBA settings.
+ * Compute drive->capacity, the full capacity of the drive
+ * Called with drive->id != NULL.
  */
-static unsigned long idedisk_capacity (ide_drive_t  *drive)
+static void init_idedisk_capacity (ide_drive_t  *drive)
 {
 	struct hd_driveid *id = drive->id;
 	unsigned long capacity = drive->cyl * drive->head * drive->sect;
 
 	drive->select.b.lba = 0;
+
 	/* Determine capacity, and use LBA if the drive properly supports it */
-	if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) {
-		if (id->lba_capacity >= capacity) {
-			drive->cyl = id->lba_capacity / (drive->head * drive->sect);
-			capacity = id->lba_capacity;
-			drive->select.b.lba = 1;
-		}
+	if ((id->capability & 2) && lba_capacity_is_ok(id)) {
+		capacity = id->lba_capacity;
+		drive->cyl = capacity / (drive->head * drive->sect);
+		drive->select.b.lba = 1;
 	}
-	return (capacity - drive->sect0);
+	drive->capacity = capacity;
+}
+
+static unsigned long idedisk_capacity (ide_drive_t  *drive)
+{
+	return (drive->capacity - drive->sect0);
 }
 
 static void idedisk_special (ide_drive_t *drive)
@@ -628,7 +630,7 @@
 	int major = HWIF(drive)->major;
 	int minor = drive->select.b.unit << PARTN_BITS;
 
-	ide_add_setting(drive,	"bios_cyl",		SETTING_RW,					-1,			-1,			TYPE_SHORT,	0,	65535,				1,	1,	&drive->bios_cyl,		NULL);
+	ide_add_setting(drive,	"bios_cyl",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->bios_cyl,		NULL);
 	ide_add_setting(drive,	"bios_head",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&drive->bios_head,		NULL);
 	ide_add_setting(drive,	"bios_sect",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	63,				1,	1,	&drive->bios_sect,		NULL);
 	ide_add_setting(drive,	"bswap",		SETTING_READ,					-1,			-1,			TYPE_BYTE,	0,	1,				1,	1,	&drive->bswap,			NULL);
@@ -679,7 +681,7 @@
 static void idedisk_setup (ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
-	unsigned long capacity, check;
+	unsigned long capacity;
 	
 	idedisk_add_settings(drive);
 
@@ -705,66 +707,33 @@
 		drive->head    = drive->bios_head = id->heads;
 		drive->sect    = drive->bios_sect = id->sectors;
 	}
+
 	/* Handle logical geometry translation by the drive */
 	if ((id->field_valid & 1) && id->cur_cyls &&
 	    id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) {
-		/*
-		 * Extract the physical drive geometry for our use.
-		 * Note that we purposely do *not* update the bios info.
-		 * This way, programs that use it (like fdisk) will
-		 * still have the same logical view as the BIOS does,
-		 * which keeps the partition table from being screwed.
-		 *
-		 * An exception to this is the cylinder count,
-		 * which we reexamine later on to correct for 1024 limitations.
-		 */
 		drive->cyl  = id->cur_cyls;
 		drive->head = id->cur_heads;
 		drive->sect = id->cur_sectors;
-
-		/* check for word-swapped "capacity" field in id information */
-		capacity = drive->cyl * drive->head * drive->sect;
-		check = (id->cur_capacity0 << 16) | id->cur_capacity1;
-		if (check == capacity) {	/* was it swapped? */
-			/* yes, bring it into little-endian order: */
-			id->cur_capacity0 = (capacity >>  0) & 0xffff;
-			id->cur_capacity1 = (capacity >> 16) & 0xffff;
-		}
 	}
+
 	/* Use physical geometry if what we have still makes no sense */
-	if ((!drive->head || drive->head > 16) &&
-	    id->heads && id->heads <= 16) {
-		if ((id->lba_capacity > 16514064) || (id->cyls == 0x3fff)) {
-			id->cyls = ((int)(id->lba_capacity/(id->heads * id->sectors)));
-		}
-		drive->cyl  = id->cur_cyls    = id->cyls;
-		drive->head = id->cur_heads   = id->heads;
-		drive->sect = id->cur_sectors = id->sectors;
+	if (drive->head > 16 && id->heads && id->heads <= 16) {
+		drive->cyl  = id->cyls;
+		drive->head = id->heads;
+		drive->sect = id->sectors;
 	}
 
 	/* calculate drive capacity, and select LBA if possible */
-	capacity = idedisk_capacity (drive);
+	init_idedisk_capacity (drive);
 
 	/*
 	 * if possible, give fdisk access to more of the drive,
 	 * by correcting bios_cyls:
 	 */
+	capacity = idedisk_capacity (drive);
 	if ((capacity >= (drive->bios_cyl * drive->bios_sect * drive->bios_head)) &&
-	    (!drive->forced_geom) && drive->bios_sect && drive->bios_head) {
+	    (!drive->forced_geom) && drive->bios_sect && drive->bios_head)
 		drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head;
-#ifdef DEBUG
-		printk("Fixing Geometry :: CHS=%d/%d/%d to CHS=%d/%d/%d\n",
-			drive->id->cur_cyls,
-			drive->id->cur_heads,
-			drive->id->cur_sectors,
-			drive->bios_cyl,
-			drive->bios_head,
-			drive->bios_sect);
-#endif
-		drive->id->cur_cyls    = drive->bios_cyl;
-		drive->id->cur_heads   = drive->bios_head;
-		drive->id->cur_sectors = drive->bios_sect;
-	}
 
 #if 0	/* done instead for entire identify block in arch/ide.h stuff */
 	/* fix byte-ordering of buffer size field */
@@ -790,19 +759,6 @@
 		}
 	}
 	printk("\n");
-
-	if (drive->select.b.lba) {
-		if (*(int *)&id->cur_capacity0 < id->lba_capacity) {
-#ifdef DEBUG
-			printk("     CurSects=%d, LBASects=%d, ",
-				*(int *)&id->cur_capacity0, id->lba_capacity);
-#endif
-			*(int *)&id->cur_capacity0 = id->lba_capacity;
-#ifdef DEBUG
-			printk( "Fixed CurSects=%d\n", *(int *)&id->cur_capacity0);
-#endif
-		}
-	}
 
 	drive->mult_count = 0;
 	if (id->max_multsect) {
diff -u --recursive --new-file v2.3.20/linux/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c
--- v2.3.20/linux/drivers/block/ide-dma.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/ide-dma.c	Mon Oct 11 10:06:34 1999
@@ -91,7 +91,7 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#ifdef IDEDMA_NEW_DRIVE_LISTINGS
+#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
 
 struct drive_list_entry {
 	char * id_model;
@@ -130,7 +130,7 @@
 	return 0;
 }
 
-#else /* !IDEDMA_NEW_DRIVE_LISTINGS */
+#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
 
 /*
  * good_dma_drives() lists the model names (from "hdparm -i")
@@ -162,7 +162,7 @@
 				"WDC AC31600H",
  				NULL};
 
-#endif /* IDEDMA_NEW_DRIVE_LISTINGS */
+#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
 
 /*
  * Our Physical Region Descriptor (PRD) table should be large enough
@@ -314,7 +314,7 @@
 {
 	struct hd_driveid *id = drive->id;
 
-#ifdef IDEDMA_NEW_DRIVE_LISTINGS
+#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
 	if (good_bad) {
 		return in_drive_list(id, drive_whitelist);
 	} else {
@@ -323,7 +323,7 @@
 			printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model);
 		return(blacklist);
 	}
-#else /* !IDEDMA_NEW_DRIVE_LISTINGS */
+#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
 	const char **list;
 
 	if (good_bad) {
@@ -344,7 +344,7 @@
 			}
 		}
 	}
-#endif /* IDEDMA_NEW_DRIVE_LISTINGS */
+#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.20/linux/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c
--- v2.3.20/linux/drivers/block/ide-floppy.c	Thu Aug  5 14:34:01 1999
+++ linux/drivers/block/ide-floppy.c	Mon Oct 11 10:06:34 1999
@@ -1498,7 +1498,7 @@
 	int major = HWIF(drive)->major;
 	int minor = drive->select.b.unit << PARTN_BITS;
 
-	ide_add_setting(drive,	"bios_cyl",		SETTING_RW,					-1,			-1,			TYPE_SHORT,	0,	1023,				1,	1,	&drive->bios_cyl,		NULL);
+	ide_add_setting(drive,	"bios_cyl",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	1023,				1,	1,	&drive->bios_cyl,		NULL);
 	ide_add_setting(drive,	"bios_head",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&drive->bios_head,		NULL);
 	ide_add_setting(drive,	"bios_sect",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	63,				1,	1,	&drive->bios_sect,		NULL);
 	ide_add_setting(drive,	"breada_readahead",	SETTING_RW,					BLKRAGET,		BLKRASET,		TYPE_INT,	0,	255,				1,	2,	&read_ahead[major],		NULL);
diff -u --recursive --new-file v2.3.20/linux/drivers/block/ide-geometry.c linux/drivers/block/ide-geometry.c
--- v2.3.20/linux/drivers/block/ide-geometry.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/ide-geometry.c	Mon Oct 11 10:06:34 1999
@@ -0,0 +1,225 @@
+/*
+ * linux/drivers/block/ide-geometry.c
+ */
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+/*
+ * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc
+ * controller that is BIOS compatible with ST-506, and thus showing up in our
+ * BIOS table, but not register compatible, and therefore not present in CMOS.
+ *
+ * Furthermore, we will assume that our ST-506 drives <if any> are the primary
+ * drives in the system -- the ones reflected as drive 1 or 2.  The first
+ * drive is stored in the high nibble of CMOS byte 0x12, the second in the low
+ * nibble.  This will be either a 4 bit drive type or 0xf indicating use byte
+ * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.  A non-zero value
+ * means we have an AT controller hard disk for that drive.
+ *
+ * Of course, there is no guarantee that either drive is actually on the
+ * "primary" IDE interface, but we don't bother trying to sort that out here.
+ * If a drive is not actually on the primary interface, then these parameters
+ * will be ignored.  This results in the user having to supply the logical
+ * drive geometry as a boot parameter for each drive not on the primary i/f.
+ */
+/*
+ * The only "perfect" way to handle this would be to modify the setup.[cS] code
+ * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info
+ * for us during initialization.  I have the necessary docs -- any takers?  -ml
+ */
+/*
+ * I did this, but it doesnt work - there is no reasonable way to find the
+ * correspondence between the BIOS numbering of the disks and the Linux
+ * numbering. -aeb
+ *
+ * The code below is bad. One of the problems is that drives 1 and 2
+ * may be SCSI disks (even when IDE disks are present), so that
+ * the geometry we read here from BIOS is attributed to the wrong disks.
+ * Consequently, also the "drive->present = 1" below is a mistake.
+ *
+ * Eventually the entire routine below should be removed.
+ */
+void probe_cmos_for_drives (ide_hwif_t *hwif)
+{
+#ifdef __i386__
+	extern struct drive_info_struct drive_info;
+	byte cmos_disks, *BIOS = (byte *) &drive_info;
+	int unit;
+
+#ifdef CONFIG_BLK_DEV_PDC4030
+	if (hwif->chipset == ide_pdc4030 && hwif->channel != 0)
+		return;
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+	outb_p(0x12,0x70);		/* specify CMOS address 0x12 */
+	cmos_disks = inb_p(0x71);	/* read the data from 0x12 */
+	/* Extract drive geometry from CMOS+BIOS if not already setup */
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		ide_drive_t *drive = &hwif->drives[unit];
+		if ((cmos_disks & (0xf0 >> (unit*4))) &&
+		    !drive->present && !drive->nobios) {
+			drive->cyl   = drive->bios_cyl  = *(unsigned short *)BIOS;
+			drive->head  = drive->bios_head = *(BIOS+2);
+			drive->sect  = drive->bios_sect = *(BIOS+14);
+			drive->ctl   = *(BIOS+8);
+#if 0
+			drive->present = 1;
+#endif
+		}
+		BIOS += 16;
+	}
+#endif
+}
+
+
+/*
+ * If heads is nonzero: find a translation with this many heads and S=63.
+ * Otherwise: find out how OnTrack Disk Manager would translate the disk.
+ */
+static void
+ontrack(ide_drive_t *drive, int heads, int *c, int *h, int *s) {
+	struct hd_driveid *id = drive->id;
+	static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
+	const byte *headp = dm_head_vals;
+	unsigned long total, tracks;
+
+	/*
+	 * The specs say: take geometry as obtained from Identify,
+	 * compute total capacity C*H*S from that, and truncate to
+	 * 1024*255*63. Now take S=63, H the first in the sequence
+	 * 4, 8, 16, 32, 64, 128, 255 such that 63*H*1024 >= total.
+	 */
+	if (id)
+		total = id->cyls * id->heads * id->sectors;
+	else
+		total = drive->cyl * drive->head * drive->sect;
+
+	*s = 63;
+
+	if (heads) {
+		*h = heads;
+		*c = total / (63 * heads);
+		return;
+	}
+
+#if 0
+	while (63 * headp[0] * 1024 < total && headp[1] != 0)
+		 headp++;
+	*h = headp[0];
+	*c = total / (63 * headp[0]);
+#else
+	/* The code below differs in two aspects:
+	   (i) It will not produce geometries like C/H/S = 1024/64/63
+		because of the `>='. This follows OnTracks text (which
+		claims that 512 <= C <= 1023), but not OnTracks code.
+	   (ii) It starts dividing by 63, so that a rounding down occurs.
+		For example, with C=11159, H=10, S=37 we find total=4128830
+		and DM would make C=512, H=128, S=63, but we make 1024/64/63
+		if `>=' is replaced by `>'.
+	   The reason we use this code is mainly that we have done so for
+	   a long time without getting complaints.
+	*/
+
+	tracks = total / 63;
+	while (*c >= 1024) {
+		*h = *headp;
+		*c = tracks / *h;
+		if (*++headp == 0)
+			break;
+	}
+#endif
+}
+
+/*
+ * This routine is called from the partition-table code in pt/msdos.c.
+ * It has two tasks:
+ * (i) to handle Ontrack DiskManager by offsetting everything by 63 sectors,
+ *  or to handle EZdrive by remapping sector 0 to sector 1.
+ * (ii) to invent a translated geometry.
+ * Part (i) is suppressed if the user specifies the "noremap" option
+ * on the command line.
+ * Part (ii) is suppressed if the user specifies an explicit geometry.
+ *
+ * The ptheads parameter is either 0 or tells about the number of
+ * heads shown by the end of the first nonempty partition.
+ * If this is either 16, 32, 64, 128, 240 or 255 we'll believe it.
+ *
+ * The xparm parameter has the following meaning:
+ *	 0 = convert to CHS with fewer than 1024 cyls
+ *	     using the same method as Ontrack DiskManager.
+ *	 1 = same as "0", plus offset everything by 63 sectors.
+ *	-1 = similar to "0", plus redirect sector 0 to sector 1.
+ *	 2 = convert to a CHS geometry with "ptheads" heads.
+ *
+ * Returns 0 if the translation was not possible, if the device was not 
+ * an IDE disk drive, or if a geometry was "forced" on the commandline.
+ * Returns 1 if the geometry translation was successful.
+ */
+int ide_xlate_1024 (kdev_t i_rdev, int xparm, int ptheads, const char *msg)
+{
+	ide_drive_t *drive;
+	const char *msg1 = "";
+	int heads = 0;
+	int c, h, s;
+	int transl = 1;		/* try translation */
+	int ret = 0;
+
+	drive = get_info_ptr(i_rdev);
+	if (!drive)
+		return 0;
+
+	/* remap? */
+	if (drive->remap_0_to_1 != 2) {
+		if (xparm == 1) {		/* DM */
+			drive->sect0 = 63;
+			msg1 = " [remap +63]";
+			ret = 1;
+		} else if (xparm == -1) {	/* EZ-Drive */
+			if (drive->remap_0_to_1 == 0) {
+				drive->remap_0_to_1 = 1;
+				msg1 = " [remap 0->1]";
+				ret = 1;
+			}
+		}
+	}
+
+	/* There used to be code here that assigned drive->id->CHS
+	   to drive->CHS and that to drive->bios_CHS. However,
+	   some disks have id->C/H/S = 4092/16/63 but are larger than 2.1 GB.
+	   In such cases that code was wrong.  Moreover,
+	   there seems to be no reason to do any of these things. */
+
+	/* translate? */
+	if (drive->forced_geom)
+		transl = 0;
+
+	/* does ptheads look reasonable? */
+	if (ptheads == 32 || ptheads == 64 || ptheads == 128 ||
+	    ptheads == 240 || ptheads == 255)
+		heads = ptheads;
+
+	if (xparm == 2) {
+		if (!heads ||
+		   (drive->bios_head >= heads && drive->bios_sect == 63))
+			transl = 0;
+	}
+	if (xparm == -1) {
+		if (drive->bios_head > 16)
+			transl = 0;     /* we already have a translation */
+	}
+
+	if (transl) {
+		ontrack(drive, heads, &c, &h, &s);
+		drive->bios_cyl = c;
+		drive->bios_head = h;
+		drive->bios_sect = s;
+		ret = 1;
+	}
+
+	drive->part[0].nr_sects = current_capacity(drive);
+
+	if (ret)
+		printk("%s%s [%d/%d/%d]", msg, msg1,
+		       drive->bios_cyl, drive->bios_head, drive->bios_sect);
+	return ret;
+}
diff -u --recursive --new-file v2.3.20/linux/drivers/block/ide-pmac.c linux/drivers/block/ide-pmac.c
--- v2.3.20/linux/drivers/block/ide-pmac.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/ide-pmac.c	Mon Oct 11 10:10:19 1999
@@ -30,8 +30,9 @@
 #include <asm/mediabay.h>
 #include <asm/feature.h>
 #ifdef CONFIG_PMAC_PBOOK
-#include <asm/adb.h>
-#include <asm/pmu.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <asm/irq.h>
 #endif
 #include "ide_modes.h"
 
@@ -50,9 +51,9 @@
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 
 #ifdef CONFIG_PMAC_PBOOK
-static int idepmac_notify(struct notifier_block *, unsigned long, void *);
-struct notifier_block idepmac_sleep_notifier = {
-	idepmac_notify
+static int idepmac_notify(struct pmu_sleep_notifier *self, int when);
+struct pmu_sleep_notifier idepmac_sleep_notifier = {
+	idepmac_notify, SLEEP_LEVEL_BLOCK,
 };
 #endif /* CONFIG_PMAC_PBOOK */
 
@@ -224,7 +225,7 @@
 	pmac_ide_count = i;
 
 #ifdef CONFIG_PMAC_PBOOK
-	notifier_chain_register(&sleep_notifier_list, &idepmac_sleep_notifier);
+	pmu_register_sleep_notifier(&idepmac_sleep_notifier);
 #endif /* CONFIG_PMAC_PBOOK */
 }
 
@@ -384,29 +385,107 @@
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 
 #ifdef CONFIG_PMAC_PBOOK
-static int idepmac_notify(struct notifier_block *this,
-			  unsigned long code, void *p)
+static void idepmac_sleep_disk(int i, unsigned long base)
 {
-	int i, timeout;
+	int j;
 
-	switch (code) {
-	case PBOOK_SLEEP:
-		/* do anything here?? */
+	/* Reset to PIO 0 */
+	out_le32((unsigned *)(base + 0x200 + _IO_BASE), 0x2f8526);
+
+	/* FIXME: We only handle the master IDE */
+	if (ide_hwifs[i].drives[0].media == ide_disk) {
+		/* Spin down the drive */
+		outb(0xa0, base+0x60);
+		outb(0x0, base+0x30);
+		outb(0x0, base+0x20);
+		outb(0x0, base+0x40);
+		outb(0x0, base+0x50);
+		outb(0xe0, base+0x70);
+		outb(0x2, base+0x160);   
+		for (j = 0; j < 10; j++) {
+			int status;
+			mdelay(100);
+			status = inb(base+0x70);
+			if (!(status & BUSY_STAT) && (status & DRQ_STAT))
+				break;
+		}
+	}
+}
+
+static void idepmac_wake_disk(int i, unsigned long base)
+{
+	int j;
+
+	/* Revive IDE disk and controller */
+	feature_set(pmac_ide_node[i], FEATURE_IDE_enable);
+	mdelay(1);
+	feature_set(pmac_ide_node[i], FEATURE_IDE_DiskPower);
+	mdelay(100);
+	feature_set(pmac_ide_node[i], FEATURE_IDE_Reset);
+	mdelay(1);
+	/* Make sure we are still PIO0 */
+	out_le32((unsigned *)(base + 0x200 + _IO_BASE), 0x2f8526);
+	mdelay(100);
+
+	/* Wait up to 10 seconds (enough for recent drives) */
+	for (j = 0; j < 100; j++) {
+		int status;
+		mdelay(100);
+		status = inb(base + 0x70);
+		if (!(status & BUSY_STAT))
+			break;
+	}
+}
+
+/* Here we handle media bay devices */
+static void
+idepmac_wake_bay(int i, unsigned long base)
+{
+	int timeout;
+
+	timeout = 5000;
+	while ((inb(base + 0x70) & BUSY_STAT) && timeout) {
+		mdelay(1);
+		--timeout;
+	}
+}
+
+static int idepmac_notify(struct pmu_sleep_notifier *self, int when)
+{
+	int i, ret;
+	unsigned long base;
+
+	switch (when) {
+	case PBOOK_SLEEP_REQUEST:
+		break;
+	case PBOOK_SLEEP_REJECT:
+		break;
+	case PBOOK_SLEEP_NOW:
+		for (i = 0; i < pmac_ide_count; ++i) {
+			if ((base = pmac_ide_regbase[i]) == 0)
+				continue;
+			/* Disable irq during sleep */
+			disable_irq(pmac_ide_irq[i]);
+			ret = check_media_bay_by_base(base, MB_CD);
+			if (ret == -ENODEV)
+				/* not media bay - put the disk to sleep */
+				idepmac_sleep_disk(i, base);
+		}
 		break;
 	case PBOOK_WAKE:
-		/* wait for the controller(s) to become ready */
-		timeout = 5000;
 		for (i = 0; i < pmac_ide_count; ++i) {
-			unsigned long base = pmac_ide_regbase[i];
-			if (check_media_bay_by_base(base, MB_CD) == -EINVAL)
+			if ((base = pmac_ide_regbase[i]) == 0)
 				continue;
-			while ((inb(base + 0x70) & BUSY_STAT) && timeout) {
-				mdelay(1);
-				--timeout;
-			}
+		        /* We don't handle media bay devices this way */
+			ret = check_media_bay_by_base(base, MB_CD);
+			if (ret == -ENODEV)
+				idepmac_wake_disk(i, base);
+			else if (ret == 0)
+				idepmac_wake_bay(i, base);
+			enable_irq(pmac_ide_irq[i]);
 		}
 		break;
 	}
-	return NOTIFY_DONE;
+	return PBOOK_SLEEP_OK;
 }
 #endif /* CONFIG_PMAC_PBOOK */
diff -u --recursive --new-file v2.3.20/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.3.20/linux/drivers/block/ide.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/ide.c	Mon Oct 11 10:06:34 1999
@@ -526,7 +526,7 @@
  * current_capacity() returns the capacity (in sectors) of a drive
  * according to its current geometry/LBA settings.
  */
-static unsigned long current_capacity (ide_drive_t *drive)
+unsigned long current_capacity (ide_drive_t *drive)
 {
 	if (!drive->present)
 		return 0;
@@ -1067,13 +1067,16 @@
 		goto kill_rq;
 	}
 	block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0;
-#if FAKE_FDISK_FOR_EZDRIVE
-	if (block == 0 && drive->remap_0_to_1)
+
+	/* Yecch - this will shift the entire interval,
+	   possibly killing some innocent following sector */
+	if (block == 0 && drive->remap_0_to_1 == 1)
 		block = 1;  /* redirect MBR access to EZ-Drive partn table */
-#endif /* FAKE_FDISK_FOR_EZDRIVE */
+
 #if (DISK_RECOVERY_TIME > 0)
 	while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
 #endif
+
 	SELECT_DRIVE(hwif, drive);
 	if (ide_wait_stat(drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
 		printk("%s: drive not ready for command\n", drive->name);
@@ -1513,7 +1516,7 @@
  * get_info_ptr() returns the (ide_drive_t *) for a given device number.
  * It returns NULL if the given device number does not match any present drives.
  */
-static ide_drive_t *get_info_ptr (kdev_t i_rdev)
+ide_drive_t *get_info_ptr (kdev_t i_rdev)
 {
 	int		major = MAJOR(i_rdev);
 	unsigned int	h;
@@ -1609,11 +1612,8 @@
 	}
 	spin_unlock_irqrestore(&io_request_lock, flags);
 	do_hwgroup_request(hwgroup);
-	save_flags(flags);	/* all CPUs; overkill? */
-	cli();			/* all CPUs; overkill? */
 	if (action == ide_wait && rq->rq_status != RQ_INACTIVE)
 		down(&sem);	/* wait for it to be serviced */
-	restore_flags(flags);	/* all CPUs; overkill? */
 	return rq->errors ? -EIO : 0;	/* return -EIO if errors */
 }
 
@@ -2321,10 +2321,11 @@
 		case HDIO_GETGEO:
 		{
 			struct hd_geometry *loc = (struct hd_geometry *) arg;
+			unsigned short bios_cyl = drive->bios_cyl; /* truncate */
 			if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
 			if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
 			if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
-			if (put_user(drive->bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
+			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
 			if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
 				(unsigned long *) &loc->start)) return -EFAULT;
 			return 0;
@@ -2343,7 +2344,8 @@
 				return -EINVAL;
 			if (drive->id == NULL)
 				return -ENOMSG;
-			if (copy_to_user((char *)arg, (char *)drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142))
+			if (copy_to_user((char *)arg, (char *)drive->id,
+					 (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142))
 				return -EFAULT;
 			return 0;
 
@@ -2629,6 +2631,7 @@
  * "hdx=nowerr"		: ignore the WRERR_STAT bit on this drive
  * "hdx=cdrom"		: drive is present, and is a cdrom drive
  * "hdx=cyl,head,sect"	: disk drive is present, with specified geometry
+ * "hdx=noremap"        : do not remap 0->1 even though EZD was detected
  * "hdx=autotune"	: driver will attempt to tune interface speed
  *				to the fastest PIO mode supported,
  *				if possible for this drive only.
@@ -2735,7 +2738,8 @@
 	if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
 		const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom",
 				"serialize", "autotune", "noautotune",
-				"slow", "swapdata", "bswap", "flash", NULL};
+				"slow", "swapdata", "bswap", "flash",
+				"remap", "noremap", NULL};
 		unit = s[2] - 'a';
 		hw   = unit / MAX_DRIVES;
 		unit = unit % MAX_DRIVES;
@@ -2772,13 +2776,19 @@
 			case -8: /* "slow" */
 				drive->slow = 1;
 				goto done;
-			case -9: /* swapdata or bswap */
+			case -9: /* "swapdata" or "bswap" */
 			case -10:
 				drive->bswap = 1;
 				goto done;
-			case -11:
+			case -11: /* "flash" */
 				drive->ata_flash = 1;
 				goto done;
+			case -12: /* "remap" */
+				drive->remap_0_to_1 = 1;
+				goto done;
+			case -13: /* "noremap" */
+				drive->remap_0_to_1 = 2;
+				goto done;
 			case 3: /* cyl,head,sect */
 				drive->media	= ide_disk;
 				drive->cyl	= drive->bios_cyl  = vals[0];
@@ -3023,113 +3033,6 @@
 }
 
 /*
- * This routine is called from the partition-table code in genhd.c
- * to "convert" a drive to a logical geometry with fewer than 1024 cyls.
- *
- * The second parameter, "xparm", determines exactly how the translation 
- * will be handled:
- *		 0 = convert to CHS with fewer than 1024 cyls
- *			using the same method as Ontrack DiskManager.
- *		 1 = same as "0", plus offset everything by 63 sectors.
- *		-1 = similar to "0", plus redirect sector 0 to sector 1.
- *		>1 = convert to a CHS geometry with "xparm" heads.
- *
- * Returns 0 if the translation was not possible, if the device was not 
- * an IDE disk drive, or if a geometry was "forced" on the commandline.
- * Returns 1 if the geometry translation was successful.
- */
-
-int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg)
-{
-	ide_drive_t *drive;
-
-	static const byte head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
-	const byte *heads = head_vals;
-	unsigned long tracks;
-
-	drive = get_info_ptr(i_rdev);
-	if (!drive)
-		return 0;
-
-	if (drive->forced_geom) {
-		/*
-		 * Update the current 3D drive values.
-		 */
-		drive->id->cur_cyls	= drive->bios_cyl;
-		drive->id->cur_heads	= drive->bios_head;
-		drive->id->cur_sectors	= drive->bios_sect;
-		return 0;
-	}
-
-	if (xparm > 1 && xparm <= drive->bios_head && drive->bios_sect == 63) {
-		/*
-		 * Update the current 3D drive values.
-		 */
-		drive->id->cur_cyls	= drive->bios_cyl;
-		drive->id->cur_heads	= drive->bios_head;
-		drive->id->cur_sectors	= drive->bios_sect;
-		return 0;		/* we already have a translation */
-	}
-
-	printk("%s ", msg);
-
-	if (xparm < 0 && (drive->bios_cyl * drive->bios_head * drive->bios_sect) < (1024 * 16 * 63)) {
-		/*
-		 * Update the current 3D drive values.
-		 */
-		drive->id->cur_cyls	= drive->bios_cyl;
-		drive->id->cur_heads	= drive->bios_head;
-		drive->id->cur_sectors	= drive->bios_sect;
-		return 0;		/* small disk: no translation needed */
-	}
-
-	if (drive->id) {
-		drive->cyl  = drive->id->cyls;
-		drive->head = drive->id->heads;
-		drive->sect = drive->id->sectors;
-	}
-	drive->bios_cyl  = drive->cyl;
-	drive->bios_head = drive->head;
-	drive->bios_sect = drive->sect;
-	drive->special.b.set_geometry = 1;
-
-	tracks = drive->bios_cyl * drive->bios_head * drive->bios_sect / 63;
-	drive->bios_sect = 63;
-	if (xparm > 1) {
-		drive->bios_head = xparm;
-		drive->bios_cyl = tracks / drive->bios_head;
-	} else {
-		while (drive->bios_cyl >= 1024) {
-			drive->bios_head = *heads;
-			drive->bios_cyl = tracks / drive->bios_head;
-			if (0 == *++heads)
-				break;
-		}
-#if FAKE_FDISK_FOR_EZDRIVE
-		if (xparm == -1) {
-			drive->remap_0_to_1 = 1;
-			printk("[remap 0->1] ");
-		} else
-#endif /* FAKE_FDISK_FOR_EZDRIVE */
-		if (xparm == 1) {
-			drive->sect0 = 63;
-			drive->bios_cyl = (tracks - 1) / drive->bios_head;
-			printk("[remap +63] ");
-		}
-	}
-
-	drive->part[0].nr_sects = current_capacity(drive);
-	printk("[%d/%d/%d]", drive->bios_cyl, drive->bios_head, drive->bios_sect);
-	/*
-	 * Update the current 3D drive values.
-	 */
-	drive->id->cur_cyls	= drive->bios_cyl;
-	drive->id->cur_heads	= drive->bios_head;
-	drive->id->cur_sectors	= drive->bios_sect;
-	return 1;
-}
-
-/*
  * probe_for_hwifs() finds/initializes "known" IDE interfaces
  */
 static void __init probe_for_hwifs (void)
@@ -3523,6 +3426,9 @@
 EXPORT_SYMBOL(ide_register);
 EXPORT_SYMBOL(ide_unregister);
 EXPORT_SYMBOL(ide_setup_ports);
+
+EXPORT_SYMBOL(get_info_ptr);
+EXPORT_SYMBOL(current_capacity);
 
 /*
  * This is gets invoked once during initialization, to set *everything* up
diff -u --recursive --new-file v2.3.20/linux/drivers/block/pdc202xx.c linux/drivers/block/pdc202xx.c
--- v2.3.20/linux/drivers/block/pdc202xx.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/pdc202xx.c	Mon Oct 11 10:10:19 1999
@@ -14,7 +14,7 @@
  *  8 are UDMA supported and 4 are limited to DMA mode 2 multi-word.
  *  The 8/4 ratio is a BIOS code limit by promise.
  *
- *  UNLESS you enable "PDC202XX_FORCE_BURST_BIT"
+ *  UNLESS you enable "CONFIG_PDC202XX_FORCE_BURST_BIT"
  *
  *  There is only one BIOS in the three contollers.
  *
@@ -521,15 +521,15 @@
 		(primary_mode & 1) ? "MASTER" : "PCI",
 		(secondary_mode & 1) ? "MASTER" : "PCI" );
 
-#ifdef PDC202XX_FORCE_BURST_BIT
+#ifdef CONFIG_PDC202XX_FORCE_BURST_BIT
 	if (!(udma_speed_flag & 1)) {
 		printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1));
 		outb(udma_speed_flag|1, high_16 + 0x001f);
 		printk("%sCTIVE\n", (inb(high_16 + 0x001f) & 1) ? "A" : "INA");
 	}
-#endif /* PDC202XX_FORCE_BURST_BIT */
+#endif /* CONFIG_PDC202XX_FORCE_BURST_BIT */
 
-#ifdef PDC202XX_FORCE_MASTER_MODE
+#ifdef CONFIG_PDC202XX_FORCE_MASTER_MODE
 	if (!(primary_mode & 1)) {
 		printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ",
 			name, primary_mode, (primary_mode|1));
@@ -543,7 +543,7 @@
 		outb(secondary_mode|1, high_16 + 0x001b);
 		printk("%s\n", (inb(high_16 + 0x001b) & 1) ? "MASTER" : "PCI");
 	}
-#endif /* PDC202XX_FORCE_MASTER_MODE */
+#endif /* CONFIG_PDC202XX_FORCE_MASTER_MODE */
 	return dev->irq;
 }
 
diff -u --recursive --new-file v2.3.20/linux/drivers/char/adbmouse.c linux/drivers/char/adbmouse.c
--- v2.3.20/linux/drivers/char/adbmouse.c	Fri Sep 10 23:57:29 1999
+++ linux/drivers/char/adbmouse.c	Mon Oct 11 10:10:19 1999
@@ -35,8 +35,8 @@
 #include <linux/random.h>
 #include <linux/poll.h>
 #include <linux/init.h>
+#include <linux/adb_mouse.h>
 
-#include <asm/adb_mouse.h>
 #ifdef __powerpc__
 #include <asm/processor.h>
 #endif
diff -u --recursive --new-file v2.3.20/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c
--- v2.3.20/linux/drivers/char/busmouse.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/busmouse.c	Mon Oct 11 10:10:19 1999
@@ -144,7 +144,7 @@
 		wake_up(&mse->wait);
 
 		if (mse->fasyncptr)
-			kill_fasync(mse->fasyncptr, SIGIO);
+			kill_fasync(mse->fasyncptr, SIGIO, POLL_IN);
 	}
 }
 
@@ -450,13 +450,10 @@
 #ifdef CONFIG_ATARIMOUSE
 	atari_mouse_init();
 #endif
-#ifdef CONFIG_MAC_MOUSE
-	mac_mouse_init();
-#endif
 #ifdef CONFIG_SUN_MOUSE
 	sun_mouse_init();
 #endif
-#ifdef CONFIG_ADBMOUSE
+#ifdef CONFIG_ADB_MOUSE
 	adb_mouse_init();
 #endif
 #ifdef CONFIG_RPCMOUSE
diff -u --recursive --new-file v2.3.20/linux/drivers/char/console.c linux/drivers/char/console.c
--- v2.3.20/linux/drivers/char/console.c	Thu Aug 26 13:05:35 1999
+++ linux/drivers/char/console.c	Mon Oct 11 10:10:19 1999
@@ -681,7 +681,7 @@
 		else {
 			unsigned short *p = (unsigned short *) kmalloc(ss, GFP_USER);
 			if (!p) {
-				for (i = 0; i< currcons; i++)
+				for (i = first; i < currcons; i++)
 					if (newscreens[i])
 						kfree_s(newscreens[i], ss);
 				return -ENOMEM;
diff -u --recursive --new-file v2.3.20/linux/drivers/char/dn_keyb.c linux/drivers/char/dn_keyb.c
--- v2.3.20/linux/drivers/char/dn_keyb.c	Mon Aug  9 12:32:28 1999
+++ linux/drivers/char/dn_keyb.c	Mon Oct 11 10:10:19 1999
@@ -469,7 +469,7 @@
           		if (mouse_dy >  2048)
               		mouse_dy =  2048;
 				if (mouse_fasyncptr)
-              		kill_fasync(mouse_fasyncptr, SIGIO);
+              		kill_fasync(mouse_fasyncptr, SIGIO, POLL_IN);
 			}
 			mouse_byte_count=0;
 /*			printk("mouse: %d, %d, %x\n",mouse_x,mouse_y,buttons); */
diff -u --recursive --new-file v2.3.20/linux/drivers/char/drm/fops.c linux/drivers/char/drm/fops.c
--- v2.3.20/linux/drivers/char/drm/fops.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/char/drm/fops.c	Mon Oct 11 10:10:19 1999
@@ -197,7 +197,7 @@
 		send -= count;
 	}
 
-	if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO);
+	if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO, POLL_OUT);
 	DRM_DEBUG("waking\n");
 	wake_up_interruptible(&dev->buf_readers);
 	return 0;
diff -u --recursive --new-file v2.3.20/linux/drivers/char/ftape/Config.in linux/drivers/char/ftape/Config.in
--- v2.3.20/linux/drivers/char/ftape/Config.in	Tue Dec  2 13:47:33 1997
+++ linux/drivers/char/ftape/Config.in	Mon Oct 11 10:10:19 1999
@@ -1,17 +1,17 @@
 #
 # Ftape configuration
 #
-dep_tristate 'Zftape, the VFS interface' CONFIG_ZFTAPE $CONFIG_FTAPE
+dep_tristate '  Zftape, the VFS interface' CONFIG_ZFTAPE $CONFIG_FTAPE
 if [ "$CONFIG_ZFTAPE" != "n" ]; then
-  int 'Default block size' CONFIG_ZFT_DFLT_BLK_SZ 10240
-  comment 'The compressor will be built as a module only!'
-  define_bool CONFIG_ZFT_COMPRESSOR m
+   int '  Default block size' CONFIG_ZFT_DFLT_BLK_SZ 10240
+   comment '  The compressor will be built as a module only!'
+   define_bool CONFIG_ZFT_COMPRESSOR m
 fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  int 'Number of ftape buffers (EXPERIMENTAL)' CONFIG_FT_NR_BUFFERS 3
+   int '  Number of ftape buffers (EXPERIMENTAL)' CONFIG_FT_NR_BUFFERS 3
 fi
 if [ "$CONFIG_PROC_FS" = "y" ]; then
-  bool 'Enable procfs status report (+2kb)' CONFIG_FT_PROC_FS y
+   bool '  Enable procfs status report (+2kb)' CONFIG_FT_PROC_FS
 fi
 choice 'Debugging output'			\
 	"Normal		CONFIG_FT_NORMAL_DEBUG	\
@@ -25,14 +25,14 @@
 	 FC-10/FC-20			CONFIG_FT_PROBE_FC10	\
 	 Alt/82078			CONFIG_FT_ALT_FDC" Standard
 if [ "$CONFIG_FT_STD_FDC" != "y" ]; then
-  comment '   Consult the manuals of your tape drive for the correct settings!'
-  hex ' IO base of the floppy disk controller' CONFIG_FT_FDC_BASE 0
-  int '   IRQ channel of the floppy disk controller' CONFIG_FT_FDC_IRQ 0
-  int '   DMA channel of the floppy disk controller' CONFIG_FT_FDC_DMA 0
+   comment '   Consult the manuals of your tape drive for the correct settings!'
+   hex '  IO base of the floppy disk controller' CONFIG_FT_FDC_BASE 0
+   int '  IRQ channel of the floppy disk controller' CONFIG_FT_FDC_IRQ 0
+   int '  DMA channel of the floppy disk controller' CONFIG_FT_FDC_DMA 0
 fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   int 'Default FIFO threshold (EXPERIMENTAL)' CONFIG_FT_FDC_THR 8
-   int 'Maximal data rate to use (EXPERIMENTAL)' CONFIG_FT_FDC_MAX_RATE 2000
+   int '  Default FIFO threshold (EXPERIMENTAL)' CONFIG_FT_FDC_THR 8
+   int '  Maximal data rate to use (EXPERIMENTAL)' CONFIG_FT_FDC_MAX_RATE 2000
 fi
 comment 'ONLY for DEC Alpha architectures'
-int 'CPU clock frequency of your DEC Alpha' CONFIG_FT_ALPHA_CLOCK 0
+int '  CPU clock frequency of your DEC Alpha' CONFIG_FT_ALPHA_CLOCK 0
diff -u --recursive --new-file v2.3.20/linux/drivers/char/joystick/Config.in linux/drivers/char/joystick/Config.in
--- v2.3.20/linux/drivers/char/joystick/Config.in	Wed Dec 16 13:38:18 1998
+++ linux/drivers/char/joystick/Config.in	Mon Oct 11 10:10:19 1999
@@ -2,18 +2,18 @@
 # Joystick lowlevel driver configuration
 #
 
-dep_tristate '   Classic PC analog joysticks and gamepads' CONFIG_JOY_ANALOG $CONFIG_JOYSTICK
-dep_tristate '   FPGaming and MadCatz A3D controllers' CONFIG_JOY_ASSASIN $CONFIG_JOYSTICK
-dep_tristate '   Gravis GrIP joysticks and gamepads' CONFIG_JOY_GRAVIS $CONFIG_JOYSTICK
-dep_tristate '   Logitech Digital joysticks and gamepads' CONFIG_JOY_LOGITECH $CONFIG_JOYSTICK
-dep_tristate '   Microsoft SideWinder, Genius Digital joysticks and gamepads' CONFIG_JOY_SIDEWINDER $CONFIG_JOYSTICK
-dep_tristate '   ThrustMaster DirectConnect joysticks and gamepads' CONFIG_JOY_THRUSTMASTER $CONFIG_JOYSTICK
-dep_tristate '   PDPI Lightning 4 gamecards' CONFIG_JOY_LIGHTNING $CONFIG_JOYSTICK
+dep_tristate '  Classic PC analog joysticks and gamepads' CONFIG_JOY_ANALOG $CONFIG_JOYSTICK
+dep_tristate '  FPGaming and MadCatz A3D controllers' CONFIG_JOY_ASSASIN $CONFIG_JOYSTICK
+dep_tristate '  Gravis GrIP joysticks and gamepads' CONFIG_JOY_GRAVIS $CONFIG_JOYSTICK
+dep_tristate '  Logitech Digital joysticks and gamepads' CONFIG_JOY_LOGITECH $CONFIG_JOYSTICK
+dep_tristate '  Microsoft SideWinder, Genius Digital joysticks and gamepads' CONFIG_JOY_SIDEWINDER $CONFIG_JOYSTICK
+dep_tristate '  ThrustMaster DirectConnect joysticks and gamepads' CONFIG_JOY_THRUSTMASTER $CONFIG_JOYSTICK
+dep_tristate '  PDPI Lightning 4 gamecards' CONFIG_JOY_LIGHTNING $CONFIG_JOYSTICK
 if [ "$CONFIG_PARPORT" != "n" ]; then
-  dep_tristate '   NES, SNES, PSX, Multisystem joysticks and gamepads' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK $CONFIG_PARPORT
-  dep_tristate '   Sega, Multisystem joysticks and gamepads' CONFIG_JOY_DB9 $CONFIG_JOYSTICK $CONFIG_PARPORT
-  dep_tristate '   TurboGraFX Multisystem joystick interface' CONFIG_JOY_TURBOGRAFX $CONFIG_JOYSTICK $CONFIG_PARPORT
+   dep_tristate '  NES, SNES, PSX, Multisystem joysticks and gamepads' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK $CONFIG_PARPORT
+   dep_tristate '  Sega, Multisystem joysticks and gamepads' CONFIG_JOY_DB9 $CONFIG_JOYSTICK $CONFIG_PARPORT
+   dep_tristate '  TurboGraFX Multisystem joystick interface' CONFIG_JOY_TURBOGRAFX $CONFIG_JOYSTICK $CONFIG_PARPORT
 fi  
 if [ "$CONFIG_AMIGA" = "y" ]; then
-  dep_tristate '   Amiga joysticks' CONFIG_JOY_AMIGA $CONFIG_JOYSTICK
+   dep_tristate '  Amiga joysticks' CONFIG_JOY_AMIGA $CONFIG_JOYSTICK
 fi
diff -u --recursive --new-file v2.3.20/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- v2.3.20/linux/drivers/char/keyboard.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/keyboard.c	Mon Oct 11 10:15:40 1999
@@ -32,6 +32,7 @@
 #include <linux/string.h>
 #include <linux/random.h>
 #include <linux/init.h>
+#include <linux/module.h>
 
 #include <asm/keyboard.h>
 #include <asm/bitops.h>
@@ -155,7 +156,6 @@
 
 #ifdef CONFIG_MAGIC_SYSRQ
 static int sysrq_pressed;
-int sysrq_enabled = 1;
 #endif
 
 /*
diff -u --recursive --new-file v2.3.20/linux/drivers/char/misc.c linux/drivers/char/misc.c
--- v2.3.20/linux/drivers/char/misc.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/misc.c	Mon Oct 11 10:15:40 1999
@@ -259,6 +259,12 @@
 #ifdef CONFIG_NWFLASH
 	nwflash_init();
 #endif
+#ifdef CONFIG_SGI_NEWPORT_GFX
+	gfx_register ();
+#endif
+#ifdef CONFIG_SGI
+	streamable_init ();
+#endif
 	if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
 		printk("unable to get major %d for misc devices\n",
 		       MISC_MAJOR);
diff -u --recursive --new-file v2.3.20/linux/drivers/char/n_hdlc.c linux/drivers/char/n_hdlc.c
--- v2.3.20/linux/drivers/char/n_hdlc.c	Mon Jul  5 20:35:18 1999
+++ linux/drivers/char/n_hdlc.c	Mon Oct 11 10:10:19 1999
@@ -9,7 +9,7 @@
  *	Al Longyear <longyear@netcom.com>, Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
  *
  * Original release 01/11/99
- * ==FILEDATE 19990524==
+ * ==FILEDATE 19990901==
  *
  * This code is released under the GNU General Public License (GPL)
  *
@@ -21,8 +21,13 @@
  * 1. tty write calls represent one complete transmit frame of data
  *    The device driver should accept the complete frame or none of 
  *    the frame (busy) in the write method. Each write call should have
- *    a byte count in the range of 2-4096 bytes (2 is min HDLC frame
- *    with 1 addr byte and 1 ctrl byte).
+ *    a byte count in the range of 2-65535 bytes (2 is min HDLC frame
+ *    with 1 addr byte and 1 ctrl byte). The max byte count of 65535
+ *    should include any crc bytes required. For example, when using
+ *    CCITT CRC32, 4 crc bytes are required, so the maximum size frame
+ *    the application may transmit is limited to 65531 bytes. For CCITT
+ *    CRC16, the maximum application frame size would be 65533.
+ *
  *
  * 2. receive callbacks from the device driver represents
  *    one received frame. The device driver should bypass
@@ -73,7 +78,7 @@
  */
 
 #define HDLC_MAGIC 0x239e
-#define HDLC_VERSION "1.2"
+#define HDLC_VERSION "1.11"
 
 #include <linux/version.h>
 #include <linux/config.h>
@@ -100,6 +105,7 @@
 #include <linux/malloc.h>
 #include <linux/tty.h>
 #include <linux/errno.h>
+#include <linux/sched.h>	/* to get the struct task_struct */
 #include <linux/string.h>	/* used in new tty drivers */
 #include <linux/signal.h>	/* used in new tty drivers */
 #include <asm/system.h>
@@ -113,6 +119,13 @@
 #include <linux/kerneld.h>
 #endif
 
+#if LINUX_VERSION_CODE < VERSION(2,3,0) 
+typedef struct wait_queue *wait_queue_head_t;
+#define DECLARE_WAITQUEUE(name,task) struct wait_queue (name) = {(task),NULL}
+#define init_waitqueue_head(head) *(head) = NULL
+#define set_current_state(a) current->state = (a)
+#endif
+
 #if LINUX_VERSION_CODE >= VERSION(2,1,4)
 #include <asm/segment.h>
 #define GET_USER(error,value,addr) error = get_user(value,addr)
@@ -189,18 +202,21 @@
 /*
  * Buffers for individual HDLC frames
  */
-#define MAX_HDLC_FRAME_SIZE 4096
+#define MAX_HDLC_FRAME_SIZE 65535 
 #define DEFAULT_RX_BUF_COUNT 10
-#define MAX_RX_BUF_COUNT 30
+#define MAX_RX_BUF_COUNT 60
 #define DEFAULT_TX_BUF_COUNT 1
 
+
 typedef struct _n_hdlc_buf
 {
 	struct _n_hdlc_buf *link;
 	int count;
-	char buf[MAX_HDLC_FRAME_SIZE];
+	char buf[1];
 } N_HDLC_BUF;
 
+#define	N_HDLC_BUF_SIZE	(sizeof(N_HDLC_BUF)+maxframe)
+
 typedef struct _n_hdlc_buf_list
 {
 	N_HDLC_BUF *head;
@@ -246,12 +262,16 @@
 
 #if LINUX_VERSION_CODE >= VERSION(2,1,19) 
 MODULE_PARM(debuglevel, "i");
+MODULE_PARM(maxframe, "i");
 #endif
 
 /* debug level can be set by insmod for debugging purposes */
 #define DEBUG_LEVEL_INFO	1
 int debuglevel=0;
 
+/* max frame size for memory allocations */
+ssize_t	maxframe=4096;
+
 /* TTY callbacks */
 
 static rw_ret_t n_hdlc_tty_read(struct tty_struct *,
@@ -353,6 +373,9 @@
 			printk (KERN_WARNING"n_hdlc: trying to close unopened tty!\n");
 			return;
 		}
+#if defined(TTY_NO_WRITE_SPLIT)
+		clear_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
+#endif
 		tty->disc_data = NULL;
 		if (tty == n_hdlc->backup_tty)
 			n_hdlc->backup_tty = 0;
@@ -383,7 +406,9 @@
 	struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
 
 	if (debuglevel >= DEBUG_LEVEL_INFO)	
-		printk("%s(%d)n_hdlc_tty_open() called\n",__FILE__,__LINE__);
+		printk("%s(%d)n_hdlc_tty_open() called (major=%u,minor=%u)\n",
+		__FILE__,__LINE__,
+		MAJOR(tty->device), MINOR(tty->device));
 		
 	/* There should not be an existing table for this slot. */
 	if (n_hdlc) {
@@ -399,9 +424,14 @@
 		
 	tty->disc_data = n_hdlc;
 	n_hdlc->tty    = tty;
-		
+	
 	MOD_INC_USE_COUNT;
 	
+#if defined(TTY_NO_WRITE_SPLIT)
+	/* change tty_io write() to not split large writes into 8K chunks */
+	set_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
+#endif
+	
 	/* Flush any pending characters in the driver and discipline. */
 	
 	if (tty->ldisc.flush_buffer)
@@ -597,18 +627,26 @@
 		return;
 	}
 	
+	if ( count>maxframe ) {
+		if (debuglevel >= DEBUG_LEVEL_INFO)	
+			printk("%s(%d) rx count>maxframesize, data discarded\n",
+			       __FILE__,__LINE__);
+		return;
+	}
+
 	/* get a free HDLC buffer */	
 	buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
 	if (!buf) {
 		/* no buffers in free list, attempt to allocate another rx buffer */
 		/* unless the maximum count has been reached */
 		if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT)
-			buf = (N_HDLC_BUF*)kmalloc(sizeof(N_HDLC_BUF),GFP_ATOMIC);
+			buf = (N_HDLC_BUF*)kmalloc(N_HDLC_BUF_SIZE,GFP_ATOMIC);
 	}
 	
 	if (!buf) {
-		printk("%s(%d) no more rx buffers, data discarded\n",
-			__FILE__,__LINE__);
+		if (debuglevel >= DEBUG_LEVEL_INFO)	
+			printk("%s(%d) no more rx buffers, data discarded\n",
+			       __FILE__,__LINE__);
 		return;
 	}
 		
@@ -622,7 +660,7 @@
 	/* wake up any blocked reads and perform async signalling */
 	wake_up_interruptible (&n_hdlc->read_wait);
 	if (n_hdlc->tty->fasync != NULL)
-		kill_fasync (n_hdlc->tty->fasync, SIGIO);
+		kill_fasync (n_hdlc->tty->fasync, SIGIO, POLL_IN);
 
 }	/* end of n_hdlc_tty_receive() */
 
@@ -678,12 +716,11 @@
 		if (file->f_flags & O_NONBLOCK)
 			return -EAGAIN;
 			
-		/* TODO: no timeout? current->timeout = 0;*/
 		interruptible_sleep_on (&n_hdlc->read_wait);
 		if (signal_pending(current))
 			return -EINTR;
 	}
-
+		
 	if (rbuf->count > nr) {
 		/* frame too large for caller's buffer (discard frame) */
 		ret = (rw_ret_t)-EOVERFLOW;
@@ -739,13 +776,13 @@
 		return -EIO;
 
 	/* verify frame size */
-	if (count > MAX_HDLC_FRAME_SIZE) {
+	if (count > maxframe ) {
 		if (debuglevel & DEBUG_LEVEL_INFO)
 			printk (KERN_WARNING
 				"n_hdlc_tty_write: truncating user packet "
 				"from %lu to %d\n", (unsigned long) count,
-				MAX_HDLC_FRAME_SIZE);
-		count = MAX_HDLC_FRAME_SIZE;
+				maxframe );
+		count = maxframe;
 	}
 	
 	/* Allocate transmit buffer */
@@ -754,8 +791,7 @@
 		/* sleep until transmit buffer available */		
 		add_wait_queue(&n_hdlc->write_wait, &wait);
 		while (!tbuf) {
-			/* TODO: no timeout? current->timeout = 0;*/
-			current->state = TASK_INTERRUPTIBLE;
+			set_current_state(TASK_INTERRUPTIBLE);
 			schedule();
 
 			n_hdlc = tty2n_hdlc (tty);
@@ -773,7 +809,7 @@
 			
 			tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list);
 		}
-		current->state = TASK_RUNNING;
+		set_current_state(TASK_RUNNING);
 		remove_wait_queue(&n_hdlc->write_wait, &wait);
 	}
 
@@ -1000,16 +1036,20 @@
 	
 	/* allocate free rx buffer list */
 	for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) {
-		buf = (N_HDLC_BUF*)kmalloc(sizeof(N_HDLC_BUF),GFP_KERNEL);
+		buf = (N_HDLC_BUF*)kmalloc(N_HDLC_BUF_SIZE,GFP_KERNEL);
 		if (buf)
 			n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,buf);
+		else if (debuglevel >= DEBUG_LEVEL_INFO)	
+			printk("%s(%d)n_hdlc_alloc(), kalloc() failed for rx buffer %d\n",__FILE__,__LINE__, i);
 	}
 	
-	/* allocate free rx buffer list */
+	/* allocate free tx buffer list */
 	for(i=0;i<DEFAULT_TX_BUF_COUNT;i++) {
-		buf = (N_HDLC_BUF*)kmalloc(sizeof(N_HDLC_BUF),GFP_KERNEL);
+		buf = (N_HDLC_BUF*)kmalloc(N_HDLC_BUF_SIZE,GFP_KERNEL);
 		if (buf)
 			n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,buf);
+		else if (debuglevel >= DEBUG_LEVEL_INFO)	
+			printk("%s(%d)n_hdlc_alloc(), kalloc() failed for tx buffer %d\n",__FILE__,__LINE__, i);
 	}
 	
 	/* Initialize the control block */
@@ -1108,7 +1148,14 @@
 	static struct tty_ldisc	n_hdlc_ldisc;
 	int    status;
 
-	printk("HDLC line discipline: version %s\n", szVersion);
+	/* range check maxframe arg */
+	if ( maxframe<4096)
+		maxframe=4096;
+	else if ( maxframe>65535)
+		maxframe=65535;
+
+	printk("HDLC line discipline: version %s, maxframe=%u\n", 
+		szVersion, maxframe);
 
 	/* Register the tty discipline */
 	
diff -u --recursive --new-file v2.3.20/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- v2.3.20/linux/drivers/char/n_tty.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/n_tty.c	Mon Oct 11 10:10:19 1999
@@ -604,7 +604,7 @@
 			tty->canon_head = tty->read_head;
 			tty->canon_data++;
 			if (tty->fasync)
-				kill_fasync(tty->fasync, SIGIO);
+				kill_fasync(tty->fasync, SIGIO, POLL_IN);
 			if (waitqueue_active(&tty->read_wait))
 				wake_up_interruptible(&tty->read_wait);
 			return;
@@ -706,7 +706,7 @@
 
 	if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) {
 		if (tty->fasync)
-			kill_fasync(tty->fasync, SIGIO);
+			kill_fasync(tty->fasync, SIGIO, POLL_IN);
 		if (waitqueue_active(&tty->read_wait))
 			wake_up_interruptible(&tty->read_wait);
 	}
@@ -854,6 +854,7 @@
 	retval = 0;
 	n = MIN(*nr, MIN(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail));
 	if (n) {
+		mb();
 		retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
 		n -= retval;
 		tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
diff -u --recursive --new-file v2.3.20/linux/drivers/char/pc110pad.c linux/drivers/char/pc110pad.c
--- v2.3.20/linux/drivers/char/pc110pad.c	Wed Jun  2 11:29:13 1999
+++ linux/drivers/char/pc110pad.c	Mon Oct 11 10:10:19 1999
@@ -30,6 +30,8 @@
 #include <asm/signal.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/semaphore.h>
+#include <linux/spinlock.h>
 #include <asm/uaccess.h>
 
 #include "pc110pad.h"
@@ -51,7 +53,7 @@
 static wait_queue_head_t queue;
 static struct fasync_struct *asyncptr;
 static int active=0;	/* number of concurrent open()s */
-
+static struct semaphore read_lock;
 
 /*
  * Utility to reset a timer to go off some time in the future.
@@ -75,7 +77,7 @@
 {
 	wake_up_interruptible(&queue);
 	if(asyncptr)
-		kill_fasync(asyncptr, SIGIO);
+		kill_fasync(asyncptr, SIGIO, POLL_IN);
 }
 
 
@@ -503,10 +505,13 @@
  */
 static int open_pad(struct inode * inode, struct file * file)
 {
+	unsigned long flags;
+	
 	if (active++)
 		return 0;
 	MOD_INC_USE_COUNT;
 
+	save_flags(flags);
 	cli();
 	outb(0x30, current_params.io+2);	/* switch off digitiser */
 	pad_irq(0,0,0);		/* read to flush any pending bytes */
@@ -522,7 +527,7 @@
 	synthesize_tap=0;
 	del_timer(&bounce_timer);
 	del_timer(&tap_timer);
-	sti();
+	restore_flags(flags);
 
 	return 0;
 }
@@ -556,14 +561,19 @@
 {
 	int r;
 
+	down(&read_lock);
 	for(r=0; r<count; r++)
 	{
 		if(!read_byte_count)
 			new_sample(read_bytes);
 		if(put_user(read_bytes[read_byte_count], buffer+r))
-			return -EFAULT;
+		{
+			r = -EFAULT;
+			break;
+		}
 		read_byte_count = (read_byte_count+1)%3;
 	}
+	up(&read_lock);
 	return r;
 }
 
@@ -681,6 +691,7 @@
 
 int init_module(void)
 {
+	init_MUTEX(&read_lock);
 	return pc110pad_init();
 }
 
diff -u --recursive --new-file v2.3.20/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c
--- v2.3.20/linux/drivers/char/pc_keyb.c	Fri Sep 10 23:57:29 1999
+++ linux/drivers/char/pc_keyb.c	Mon Oct 11 10:15:40 1999
@@ -23,7 +23,6 @@
 #include <linux/tty.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
-#include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/kbd_ll.h>
 #include <linux/delay.h>
@@ -34,14 +33,15 @@
 
 #include <asm/keyboard.h>
 #include <asm/bitops.h>
-#include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 
+#include <asm/io.h>
+
 /* Some configuration switches are present in the include file... */
 
-#include "pc_keyb.h"
+#include <linux/pc_keyb.h>
 
 /* Simple translation table for the SysRq keys */
 
@@ -56,10 +56,11 @@
 	"\r\000/";					/* 0x60 - 0x6f */
 #endif
 
-static void kbd_write(int address, int data);
-static unsigned char handle_kbd_event(void);
+static void kbd_write_command_w(int data);
+static void kbd_write_output_w(int data);
 
 spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
+static unsigned char handle_kbd_event(void);
 
 /* used only by send_data - set by keyboard_interrupt */
 static volatile unsigned char reply_expected = 0;
@@ -83,11 +84,6 @@
 #define AUX_INTS_ON  (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT)
 
 #define MAX_RETRIES	60		/* some aux operations take long time*/
-
-#ifndef AUX_IRQ
-# define AUX_IRQ	12
-#endif
-
 #endif /* CONFIG_PSMOUSE */
 
 /*
@@ -409,7 +405,7 @@
 		if (head != queue->tail) {
 			queue->head = head;
 			if (queue->fasync)
-				kill_fasync(queue->fasync, SIGIO);
+				kill_fasync(queue->fasync, SIGIO, POLL_IN);
 			wake_up_interruptible(&queue->proc_list);
 		}
 	}
@@ -425,22 +421,31 @@
  */
 static unsigned char handle_kbd_event(void)
 {
-	unsigned char status = inb(KBD_STATUS_REG);
+	unsigned char status = kbd_read_status();
+	unsigned int work = 10000;
 
 	while (status & KBD_STAT_OBF) {
 		unsigned char scancode;
 
-		scancode = inb(KBD_DATA_REG);
-
+		scancode = kbd_read_input();
 		if (status & KBD_STAT_MOUSE_OBF) {
 			handle_mouse_event(scancode);
 		} else {
+#ifdef CONFIG_VT
 			if (do_acknowledge(scancode))
 				handle_scancode(scancode, !(scancode & 0x80));
+#endif				
 			mark_bh(KEYBOARD_BH);
 		}
 
-		status = inb(KBD_STATUS_REG);
+		status = kbd_read_status();
+		
+		if(!work--)
+		{
+			printk(KERN_ERR "pc_keyb: controller jammed (0x%02X).\n",
+				status);
+			break;
+		}
 	}
 
 	return status;
@@ -451,8 +456,9 @@
 {
 	unsigned long flags;
 
+#ifdef CONFIG_VT
 	kbd_pt_regs = regs;
-
+#endif
 	spin_lock_irqsave(&kbd_controller_lock, flags);
 	handle_kbd_event();
 	spin_unlock_irqrestore(&kbd_controller_lock, flags);
@@ -475,7 +481,7 @@
 		acknowledge = 0; /* Set by interrupt routine on receipt of ACK. */
 		resend = 0;
 		reply_expected = 1;
-		kbd_write(KBD_DATA_REG, data);
+		kbd_write_output_w(data);
 		for (;;) {
 			if (acknowledge)
 				return 1;
@@ -529,14 +535,14 @@
 #define KBD_NO_DATA	(-1)	/* No data */
 #define KBD_BAD_DATA	(-2)	/* Parity or other error */
 
-static int __init kbd_read_input(void)
+static int __init kbd_read_data(void)
 {
 	int retval = KBD_NO_DATA;
 	unsigned char status;
 
-	status = inb(KBD_STATUS_REG);
+	status = kbd_read_status();
 	if (status & KBD_STAT_OBF) {
-		unsigned char data = inb(KBD_DATA_REG);
+		unsigned char data = kbd_read_input();
 
 		retval = data;
 		if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
@@ -550,7 +556,7 @@
 	int maxread = 100;	/* Random number */
 
 	do {
-		if (kbd_read_input() == KBD_NO_DATA)
+		if (kbd_read_data() == KBD_NO_DATA)
 			break;
 	} while (--maxread);
 }
@@ -560,7 +566,7 @@
 	long timeout = KBD_INIT_TIMEOUT;
 
 	do {
-		int retval = kbd_read_input();
+		int retval = kbd_read_data();
 		if (retval >= 0)
 			return retval;
 		mdelay(1);
@@ -568,13 +574,23 @@
 	return -1;
 }
 
-static void kbd_write(int address, int data)
+static void kbd_write_command_w(int data)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&kbd_controller_lock, flags);
 	kb_wait();
-	outb(data, address);
+	kbd_write_command(data);
+	spin_unlock_irqrestore(&kbd_controller_lock, flags);
+}
+
+static void kbd_write_output_w(int data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&kbd_controller_lock, flags);
+	kb_wait();
+	kbd_write_output(data);
 	spin_unlock_irqrestore(&kbd_controller_lock, flags);
 }
 
@@ -585,9 +601,9 @@
 
 	spin_lock_irqsave(&kbd_controller_lock, flags);
 	kb_wait();
-	outb(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG);
+	kbd_write_command(KBD_CCMD_WRITE_MODE);
 	kb_wait();
-	outb(cmd, KBD_DATA_REG);
+	kbd_write_output(cmd);
 	spin_unlock_irqrestore(&kbd_controller_lock, flags);
 }
 #endif /* CONFIG_PSMOUSE */
@@ -601,7 +617,7 @@
 	 * This seems to be the only way to get it going.
 	 * If the test is successful a x55 is placed in the input buffer.
 	 */
-	kbd_write(KBD_CNTL_REG, KBD_CCMD_SELF_TEST);
+	kbd_write_command_w(KBD_CCMD_SELF_TEST);
 	if (kbd_wait_for_input() != 0x55)
 		return "Keyboard failed self test";
 
@@ -610,14 +626,14 @@
 	 * to test the keyboard clock and data lines.  The results of the
 	 * test are placed in the input buffer.
 	 */
-	kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_TEST);
+	kbd_write_command_w(KBD_CCMD_KBD_TEST);
 	if (kbd_wait_for_input() != 0x00)
 		return "Keyboard interface failed self test";
 
 	/*
 	 * Enable the keyboard by allowing the keyboard clock to run.
 	 */
-	kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_ENABLE);
+	kbd_write_command_w(KBD_CCMD_KBD_ENABLE);
 
 	/*
 	 * Reset keyboard. If the read times out
@@ -628,7 +644,7 @@
 	 * Set up to try again if the keyboard asks for RESEND.
 	 */
 	do {
-		kbd_write(KBD_DATA_REG, KBD_CMD_RESET);
+		kbd_write_output_w(KBD_CMD_RESET);
 		status = kbd_wait_for_input();
 		if (status == KBD_REPLY_ACK)
 			break;
@@ -646,7 +662,7 @@
 	 * Set up to try again if the keyboard asks for RESEND.
 	 */
 	do {
-		kbd_write(KBD_DATA_REG, KBD_CMD_DISABLE);
+		kbd_write_output_w(KBD_CMD_DISABLE);
 		status = kbd_wait_for_input();
 		if (status == KBD_REPLY_ACK)
 			break;
@@ -654,37 +670,37 @@
 			return "Disable keyboard: no ACK";
 	} while (1);
 
-	kbd_write(KBD_CNTL_REG, KBD_CCMD_WRITE_MODE);
-	kbd_write(KBD_DATA_REG, KBD_MODE_KBD_INT
+	kbd_write_command_w(KBD_CCMD_WRITE_MODE);
+	kbd_write_output_w(KBD_MODE_KBD_INT
 			      | KBD_MODE_SYS
 			      | KBD_MODE_DISABLE_MOUSE
 			      | KBD_MODE_KCC);
 
 	/* ibm powerpc portables need this to use scan-code set 1 -- Cort */
-	kbd_write(KBD_CNTL_REG, KBD_CCMD_READ_MODE);
+	kbd_write_command_w(KBD_CCMD_READ_MODE);
 	if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
 		/*
 		 * If the controller does not support conversion,
 		 * Set the keyboard to scan-code set 1.
 		 */
-		kbd_write(KBD_DATA_REG, 0xF0);
+		kbd_write_output_w(0xF0);
 		kbd_wait_for_input();
-		kbd_write(KBD_DATA_REG, 0x01);
+		kbd_write_output_w(0x01);
 		kbd_wait_for_input();
 	}
 
 	
-	kbd_write(KBD_DATA_REG, KBD_CMD_ENABLE);
+	kbd_write_output_w(KBD_CMD_ENABLE);
 	if (kbd_wait_for_input() != KBD_REPLY_ACK)
 		return "Enable keyboard: no ACK";
 
 	/*
 	 * Finally, set the typematic rate to maximum.
 	 */
-	kbd_write(KBD_DATA_REG, KBD_CMD_SET_RATE);
+	kbd_write_output_w(KBD_CMD_SET_RATE);
 	if (kbd_wait_for_input() != KBD_REPLY_ACK)
 		return "Set rate: no ACK";
-	kbd_write(KBD_DATA_REG, 0x00);
+	kbd_write_output_w(0x00);
 	if (kbd_wait_for_input() != KBD_REPLY_ACK)
 		return "Set rate: no ACK";
 
@@ -693,6 +709,8 @@
 
 void __init pckbd_init_hw(void)
 {
+	kbd_request_region();
+
 	/* Flush any pending input. */
 	kbd_clear_input();
 
@@ -707,7 +725,7 @@
 #endif
 
 	/* Ok, finally allocate the IRQ, and off we go.. */
-	request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
+	kbd_request_irq(keyboard_interrupt);
 }
 
 #if defined CONFIG_PSMOUSE
@@ -731,16 +749,16 @@
 	 * controller has an Auxiliary Port (a.k.a. Mouse Port).
 	 */
 	kb_wait();
-	outb(KBD_CCMD_WRITE_AUX_OBUF, KBD_CNTL_REG);
+	kbd_write_command(KBD_CCMD_WRITE_AUX_OBUF);
 
 	kb_wait();
-	outb(0x5a, KBD_DATA_REG); /* 0x5a is a random dummy value. */
+	kbd_write_output(0x5a); /* 0x5a is a random dummy value. */
 
 	do {
-		unsigned char status = inb(KBD_STATUS_REG);
+		unsigned char status = kbd_read_status();
 
 		if (status & KBD_STAT_OBF) {
-			(void) inb(KBD_DATA_REG);
+			(void) kbd_read_input();
 			if (status & KBD_STAT_MOUSE_OBF) {
 				printk(KERN_INFO "Detected PS/2 Mouse Port.\n");
 				retval = 1;
@@ -763,9 +781,9 @@
 
 	spin_lock_irqsave(&kbd_controller_lock, flags);
 	kb_wait();
-	outb(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG);
+	kbd_write_command(KBD_CCMD_WRITE_MOUSE);
 	kb_wait();
-	outb(val, KBD_DATA_REG);
+	kbd_write_output(val);
 	spin_unlock_irqrestore(&kbd_controller_lock, flags);
 }
 
@@ -778,9 +796,9 @@
 
 	spin_lock_irqsave(&kbd_controller_lock, flags);
 	kb_wait();
-	outb(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG);
+	kbd_write_command(KBD_CCMD_WRITE_MOUSE);
 	kb_wait();
-	outb(val, KBD_DATA_REG);
+	kbd_write_output(val);
 	/* we expect an ACK in response. */
 	mouse_reply_expected++;
 	kb_wait();
@@ -827,8 +845,8 @@
 	if (--aux_count)
 		return 0;
 	kbd_write_cmd(AUX_INTS_OFF);			    /* Disable controller ints */
-	kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_DISABLE);
-	free_irq(AUX_IRQ, AUX_DEV);
+	kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE);
+	aux_free_irq(AUX_DEV);
 	return 0;
 }
 
@@ -843,11 +861,11 @@
 		return 0;
 	}
 	queue->head = queue->tail = 0;		/* Flush input queue */
-	if (request_irq(AUX_IRQ, keyboard_interrupt, SA_SHIRQ, "PS/2 Mouse", AUX_DEV)) {
+	if (aux_request_irq(keyboard_interrupt, AUX_DEV)) {
 		aux_count--;
 		return -EBUSY;
 	}
-	kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_ENABLE);	/* Enable the
+	kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE);	/* Enable the
 							   auxiliary port on
 							   controller. */
 	aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */
@@ -966,14 +984,14 @@
 	init_waitqueue_head(&queue->proc_list);
 
 #ifdef INITIALIZE_MOUSE
-	kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_ENABLE);	/* Enable Aux. */
+	kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */
 	aux_write_ack(AUX_SET_SAMPLE);
 	aux_write_ack(100);			/* 100 samples/sec */
 	aux_write_ack(AUX_SET_RES);
 	aux_write_ack(3);			/* 8 counts per mm */
 	aux_write_ack(AUX_SET_SCALE21);		/* 2:1 scaling */
 #endif /* INITIALIZE_MOUSE */
-	kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */
+	kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */
 	kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */
 
 	return 0;
diff -u --recursive --new-file v2.3.20/linux/drivers/char/pc_keyb.h linux/drivers/char/pc_keyb.h
--- v2.3.20/linux/drivers/char/pc_keyb.h	Tue May 11 14:37:40 1999
+++ linux/drivers/char/pc_keyb.h	Wed Dec 31 16:00:00 1969
@@ -1,130 +0,0 @@
-/*
- *	linux/drivers/char/pc_keyb.h
- *
- *	PC Keyboard And Keyboard Controller
- *
- *	(c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
- */
-
-/*
- *	Configuration Switches
- */
-
-#undef KBD_REPORT_ERR			/* Report keyboard errors */
-#define KBD_REPORT_UNKN			/* Report unknown scan codes */
-#define KBD_REPORT_TIMEOUTS		/* Report keyboard timeouts */
-#undef KBD_IS_FOCUS_9000		/* We have the brain-damaged FOCUS-9000 keyboard */
-#undef INITIALIZE_MOUSE			/* Define if your PS/2 mouse needs initialization. */
-
-
-
-#define KBD_INIT_TIMEOUT 1000		/* Timeout in ms for initializing the keyboard */
-#define KBC_TIMEOUT 250			/* Timeout in ms for sending to keyboard controller */
-#define KBD_TIMEOUT 1000		/* Timeout in ms for keyboard command acknowledge */
-
-/*
- *	Internal variables of the driver
- */
-
-extern unsigned char pckbd_read_mask;
-extern unsigned char aux_device_present;
-
-/*
- *	Keyboard Controller Registers
- */
-
-#define KBD_STATUS_REG		0x64	/* Status register (R) */
-#define KBD_CNTL_REG		0x64	/* Controller command register (W) */
-#define KBD_DATA_REG		0x60	/* Keyboard data register (R/W) */
-
-/*
- *	Keyboard Controller Commands
- */
-
-#define KBD_CCMD_READ_MODE	0x20	/* Read mode bits */
-#define KBD_CCMD_WRITE_MODE	0x60	/* Write mode bits */
-#define KBD_CCMD_GET_VERSION	0xA1	/* Get controller version */
-#define KBD_CCMD_MOUSE_DISABLE	0xA7	/* Disable mouse interface */
-#define KBD_CCMD_MOUSE_ENABLE	0xA8	/* Enable mouse interface */
-#define KBD_CCMD_TEST_MOUSE	0xA9	/* Mouse interface test */
-#define KBD_CCMD_SELF_TEST	0xAA	/* Controller self test */
-#define KBD_CCMD_KBD_TEST	0xAB	/* Keyboard interface test */
-#define KBD_CCMD_KBD_DISABLE	0xAD	/* Keyboard interface disable */
-#define KBD_CCMD_KBD_ENABLE	0xAE	/* Keyboard interface enable */
-#define KBD_CCMD_WRITE_AUX_OBUF	0xD3    /* Write to output buffer as if
-					   initiated by the auxiliary device */
-#define KBD_CCMD_WRITE_MOUSE	0xD4	/* Write the following byte to the mouse */
-
-/*
- *	Keyboard Commands
- */
-
-#define KBD_CMD_SET_LEDS	0xED	/* Set keyboard leds */
-#define KBD_CMD_SET_RATE	0xF3	/* Set typematic rate */
-#define KBD_CMD_ENABLE		0xF4	/* Enable scanning */
-#define KBD_CMD_DISABLE		0xF5	/* Disable scanning */
-#define KBD_CMD_RESET		0xFF	/* Reset */
-
-/*
- *	Keyboard Replies
- */
-
-#define KBD_REPLY_POR		0xAA	/* Power on reset */
-#define KBD_REPLY_ACK		0xFA	/* Command ACK */
-#define KBD_REPLY_RESEND	0xFE	/* Command NACK, send the cmd again */
-
-/*
- *	Status Register Bits
- */
-
-#define KBD_STAT_OBF 		0x01	/* Keyboard output buffer full */
-#define KBD_STAT_IBF 		0x02	/* Keyboard input buffer full */
-#define KBD_STAT_SELFTEST	0x04	/* Self test successful */
-#define KBD_STAT_CMD		0x08	/* Last write was a command write (0=data) */
-#define KBD_STAT_UNLOCKED	0x10	/* Zero if keyboard locked */
-#define KBD_STAT_MOUSE_OBF	0x20	/* Mouse output buffer full */
-#define KBD_STAT_GTO 		0x40	/* General receive/xmit timeout */
-#define KBD_STAT_PERR 		0x80	/* Parity error */
-
-#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF)
-
-/*
- *	Controller Mode Register Bits
- */
-
-#define KBD_MODE_KBD_INT	0x01	/* Keyboard data generate IRQ1 */
-#define KBD_MODE_MOUSE_INT	0x02	/* Mouse data generate IRQ12 */
-#define KBD_MODE_SYS 		0x04	/* The system flag (?) */
-#define KBD_MODE_NO_KEYLOCK	0x08	/* The keylock doesn't affect the keyboard if set */
-#define KBD_MODE_DISABLE_KBD	0x10	/* Disable keyboard interface */
-#define KBD_MODE_DISABLE_MOUSE	0x20	/* Disable mouse interface */
-#define KBD_MODE_KCC 		0x40	/* Scan code conversion to PC format */
-#define KBD_MODE_RFU		0x80
-
-/*
- *	Mouse Commands
- */
-
-#define AUX_SET_RES		0xE8	/* Set resolution */
-#define AUX_SET_SCALE11		0xE6	/* Set 1:1 scaling */
-#define AUX_SET_SCALE21		0xE7	/* Set 2:1 scaling */
-#define AUX_GET_SCALE		0xE9	/* Get scaling factor */
-#define AUX_SET_STREAM		0xEA	/* Set stream mode */
-#define AUX_SET_SAMPLE		0xF3	/* Set sample rate */
-#define AUX_ENABLE_DEV		0xF4	/* Enable aux device */
-#define AUX_DISABLE_DEV		0xF5	/* Disable aux device */
-#define AUX_RESET		0xFF	/* Reset aux device */
-#define AUX_ACK			0xFA	/* Command byte ACK. */
-
-#define AUX_BUF_SIZE		2048	/* This might be better divisible by
-					   three to make overruns stay in sync
-					   but then the read function would need
-					   a lock etc - ick */
-
-struct aux_queue {
-	unsigned long head;
-	unsigned long tail;
-	wait_queue_head_t proc_list;
-	struct fasync_struct *fasync;
-	unsigned char buf[AUX_BUF_SIZE];
-};
diff -u --recursive --new-file v2.3.20/linux/drivers/char/ppdev.h linux/drivers/char/ppdev.h
--- v2.3.20/linux/drivers/char/ppdev.h	Sat Oct  9 11:47:50 1999
+++ linux/drivers/char/ppdev.h	Mon Oct 11 10:04:02 1999
@@ -75,7 +75,7 @@
 #define PPSETPHASE	_IOW(PP_IOCTL, 0x94, int)
 
 /* Set and get port timeout (struct timeval's) */
-#define PPGETTIME	_IOW(PP_IOCTL, 0x95, struct timeval)
-#define PPSETTIME	_IOR(PP_IOCTL, 0x96, struct timeval)
+#define PPGETTIME	_IOR(PP_IOCTL, 0x95, struct timeval)
+#define PPSETTIME	_IOW(PP_IOCTL, 0x96, struct timeval)
 
 
diff -u --recursive --new-file v2.3.20/linux/drivers/char/qpmouse.c linux/drivers/char/qpmouse.c
--- v2.3.20/linux/drivers/char/qpmouse.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/qpmouse.c	Mon Oct 11 11:42:59 1999
@@ -42,7 +42,7 @@
 #include <asm/system.h>
 #include <asm/semaphore.h>
 
-#include "pc_keyb.h"		/* mouse enable command.. */
+#include <linux/pc_keyb.h>		/* mouse enable command.. */
 
 
 /*
@@ -134,7 +134,7 @@
 	}
 	queue->head = head;
 	if (queue->fasync)
-		kill_fasync(queue->fasync, SIGIO);
+		kill_fasync(queue->fasync, SIGIO, POLL_IN);
 	wake_up_interruptible(&queue->proc_list);
 }
 
diff -u --recursive --new-file v2.3.20/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.3.20/linux/drivers/char/tty_io.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/tty_io.c	Mon Oct 11 10:10:19 1999
@@ -661,25 +661,31 @@
 	if (down_interruptible(&inode->i_sem)) {
 		return -ERESTARTSYS;
 	}
-	for (;;) {
-		unsigned long size = PAGE_SIZE*2;
-		if (size > count)
-			size = count;
+	if ( test_bit(TTY_NO_WRITE_SPLIT, &tty->flags) ) {
 		lock_kernel();
-		ret = write(tty, file, buf, size);
+		written = write(tty, file, buf, count);
 		unlock_kernel();
-		if (ret <= 0)
-			break;
-		written += ret;
-		buf += ret;
-		count -= ret;
-		if (!count)
-			break;
-		ret = -ERESTARTSYS;
-		if (signal_pending(current))
-			break;
-		if (current->need_resched)
-			schedule();
+	} else {
+		for (;;) {
+			unsigned long size = PAGE_SIZE*2;
+			if (size > count)
+				size = count;
+			lock_kernel();
+			ret = write(tty, file, buf, size);
+			unlock_kernel();
+			if (ret <= 0)
+				break;
+			written += ret;
+			buf += ret;
+			count -= ret;
+			if (!count)
+				break;
+			ret = -ERESTARTSYS;
+			if (signal_pending(current))
+				break;
+			if (current->need_resched)
+				schedule();
+		}
 	}
 	if (written) {
 		file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
@@ -1996,7 +2002,8 @@
 {
 	int	retval;
 	struct tty_driver *p;
-	int	found = 0;
+	int	i, found = 0;
+	struct termios *tp;
 	const char *othername = NULL;
 	
 	if (*driver->refcount)
@@ -2027,6 +2034,23 @@
 	if (driver->next)
 		driver->next->prev = driver->prev;
 
+	/*
+	 * Free the termios and termios_locked structures because
+	 * we don't want to get memory leaks when modular tty
+	 * drivers are removed from the kernel.
+	 */
+	for (i = 0; i < driver->num; i++) {
+		tp = driver->termios[i];
+		if (tp) {
+			driver->termios[i] = NULL;
+			kfree_s(tp, sizeof(struct termios));
+		}
+		tp = driver->termios_locked[i];
+		if (tp) {
+			driver->termios_locked[i] = NULL;
+			kfree_s(tp, sizeof(struct termios));
+		}
+	}
 	proc_tty_unregister_driver(driver);
 	return 0;
 }
diff -u --recursive --new-file v2.3.20/linux/drivers/fc4/Config.in linux/drivers/fc4/Config.in
--- v2.3.20/linux/drivers/fc4/Config.in	Mon Mar 15 16:11:29 1999
+++ linux/drivers/fc4/Config.in	Mon Oct 11 10:10:19 1999
@@ -6,22 +6,22 @@
 
 tristate 'Fibre Channel and FC4 SCSI support' CONFIG_FC4
 if [ ! "$CONFIG_FC4" = "n" ]; then
-  comment 'FC4 drivers'
-  if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
-    tristate 'Sun SOC/Sbus' CONFIG_FC4_SOC
-    tristate 'Sun SOC+ (aka SOCAL)' CONFIG_FC4_SOCAL
-  fi
-  comment 'FC4 targets'
-  dep_tristate 'SparcSTORAGE Array 100 and 200 series' CONFIG_SCSI_PLUTO $CONFIG_SCSI
-  if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
-    dep_tristate 'Sun Enterprise Network Array (A5000 and EX500)' CONFIG_SCSI_FCAL $CONFIG_SCSI
-  else
-    dep_tristate 'Generic FC-AL disk driver' CONFIG_SCSI_FCAL $CONFIG_SCSI
-  fi
+   comment 'FC4 drivers'
+   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+      tristate 'Sun SOC/Sbus' CONFIG_FC4_SOC
+      tristate 'Sun SOC+ (aka SOCAL)' CONFIG_FC4_SOCAL
+   fi
+   comment 'FC4 targets'
+   dep_tristate 'SparcSTORAGE Array 100 and 200 series' CONFIG_SCSI_PLUTO $CONFIG_SCSI
+   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+      dep_tristate 'Sun Enterprise Network Array (A5000 and EX500)' CONFIG_SCSI_FCAL $CONFIG_SCSI
+   else
+      dep_tristate 'Generic FC-AL disk driver' CONFIG_SCSI_FCAL $CONFIG_SCSI
+   fi
 else
-  define_bool CONFIG_FC4_SOC n
-  define_bool CONFIG_FC4_SOCAL n
-  define_bool CONFIG_SCSI_PLUTO n
-  define_bool CONFIG_SCSI_FCAL n
+   define_bool CONFIG_FC4_SOC n
+   define_bool CONFIG_FC4_SOCAL n
+   define_bool CONFIG_SCSI_PLUTO n
+   define_bool CONFIG_SCSI_FCAL n
 fi
 endmenu
diff -u --recursive --new-file v2.3.20/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.3.20/linux/drivers/net/Config.in	Fri Sep 10 23:57:29 1999
+++ linux/drivers/net/Config.in	Mon Oct 11 12:51:33 1999
@@ -7,12 +7,12 @@
 
 tristate 'ARCnet support' CONFIG_ARCNET
 if [ "$CONFIG_ARCNET" != "n" ]; then
-  bool '  Enable arc0e (ARCnet "Ether-Encap" packet format)' CONFIG_ARCNET_ETH
-  bool '  Enable arc0s (ARCnet RFC1051 packet format)' CONFIG_ARCNET_1051
-  dep_tristate '  ARCnet COM90xx (normal) chipset driver' CONFIG_ARCNET_COM90xx $CONFIG_ARCNET
-  dep_tristate '  ARCnet COM90xx (IO mapped) chipset driver' CONFIG_ARCNET_COM90xxIO $CONFIG_ARCNET
-  dep_tristate '  ARCnet COM90xx (RIM I) chipset driver' CONFIG_ARCNET_RIM_I $CONFIG_ARCNET
-  dep_tristate '  ARCnet COM20020 chipset driver' CONFIG_ARCNET_COM20020 $CONFIG_ARCNET
+   bool '  Enable arc0e (ARCnet "Ether-Encap" packet format)' CONFIG_ARCNET_ETH
+   bool '  Enable arc0s (ARCnet RFC1051 packet format)' CONFIG_ARCNET_1051
+   dep_tristate '  ARCnet COM90xx (normal) chipset driver' CONFIG_ARCNET_COM90xx $CONFIG_ARCNET
+   dep_tristate '  ARCnet COM90xx (IO mapped) chipset driver' CONFIG_ARCNET_COM90xxIO $CONFIG_ARCNET
+   dep_tristate '  ARCnet COM90xx (RIM I) chipset driver' CONFIG_ARCNET_RIM_I $CONFIG_ARCNET
+   dep_tristate '  ARCnet COM20020 chipset driver' CONFIG_ARCNET_COM20020 $CONFIG_ARCNET
 fi
 
 endmenu
@@ -20,9 +20,9 @@
 tristate 'Dummy net driver support' CONFIG_DUMMY
 tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  if [ "$CONFIG_NETLINK" = "y" ]; then
-     tristate 'Ethertap network tap' CONFIG_ETHERTAP
-  fi
+   if [ "$CONFIG_NETLINK" = "y" ]; then
+      tristate 'Ethertap network tap (EXPERIMENTAL)' CONFIG_ETHERTAP
+   fi
 fi
 
 tristate 'General Instruments Surfboard 1000' CONFIG_NET_SB1000
@@ -36,145 +36,154 @@
 
 bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
 if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
-  if [ "$CONFIG_ARM" = "y" ]; then
-    if [ "$CONFIG_ARCH_ACORN" != "y" ]; then
-      tristate 'AM79C961A support' CONFIG_ARM_AM79C961A
-    else
-      source drivers/acorn/net/Config.in
-    fi
-  fi
-  if [ "$CONFIG_PPC" = "y" ]; then
-    tristate 'MACE (Power Mac ethernet) support' CONFIG_MACE
-    tristate 'BMAC (G3 ethernet) support' CONFIG_BMAC
-  fi
-  if [ "$CONFIG_ZORRO" = "y" ]; then
-    tristate 'Ariadne support' CONFIG_ARIADNE
-    tristate 'Ariadne II support' CONFIG_ARIADNE2
-    tristate 'A2065 support' CONFIG_A2065
-    tristate 'Hydra support' CONFIG_HYDRA
-  fi
-  if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then
-    tristate 'MIPS JAZZ onboard SONIC Ethernet support' CONFIG_MIPS_JAZZ_SONIC
-  fi
-  bool '3COM cards' CONFIG_NET_VENDOR_3COM
-  if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
-    tristate '3c501 support' CONFIG_EL1
-    tristate '3c503 support' CONFIG_EL2
-    tristate '3c505 support' CONFIG_ELPLUS
-    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate '3c507 support' CONFIG_EL16
+   if [ "$CONFIG_ARM" = "y" ]; then
+      if [ "$CONFIG_ARCH_ACORN" != "y" ]; then
+	 tristate '  AM79C961A support' CONFIG_ARM_AM79C961A
+      else
+	 source drivers/acorn/net/Config.in
+      fi
+   fi
+   if [ "$CONFIG_PPC" = "y" ]; then
+      tristate '  MACE (Power Mac ethernet) support' CONFIG_MACE
+      tristate '  BMAC (G3 ethernet) support' CONFIG_BMAC
+   fi
+   if [ "$CONFIG_ZORRO" = "y" ]; then
+      tristate '  Ariadne support' CONFIG_ARIADNE
+      tristate '  Ariadne II support' CONFIG_ARIADNE2
+      tristate '  A2065 support' CONFIG_A2065
+      tristate '  Hydra support' CONFIG_HYDRA
+   fi
+   if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then
+      tristate '  MIPS JAZZ onboard SONIC Ethernet support' CONFIG_MIPS_JAZZ_SONIC
+   fi
+   bool '  3COM cards' CONFIG_NET_VENDOR_3COM
+   if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
+      tristate '    3c501 support' CONFIG_EL1
+      tristate '    3c503 support' CONFIG_EL2
+      tristate '    3c505 support' CONFIG_ELPLUS
+      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	 tristate '    3c507 support (EXPERIMENTAL)' CONFIG_EL16
+      fi
+      tristate '    3c509/3c529 (MCA)/3c579 support' CONFIG_EL3
+      tristate '    3c515 ISA Fast EtherLink' CONFIG_3C515
       if [ "$CONFIG_MCA" = "y" ]; then
-        tristate '3c523 support' CONFIG_ELMC
-        tristate '3c527 support' CONFIG_ELMC_II
+	 tristate '    3c523 support' CONFIG_ELMC
+	 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	    tristate '    3c527 support (EXPERIMENTAL)' CONFIG_ELMC_II
+	 fi
       fi
-    fi
-    tristate '3c509/3c579 support' CONFIG_EL3
-    tristate '3c515 ISA Fast EtherLink' CONFIG_3C515
-    tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX
-  fi
-  tristate 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE
-  bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC
-  if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
-    tristate 'WD80*3 support' CONFIG_WD80x3
-    if [ "$CONFIG_MCA" = "y" ]; then
-		tristate 'SMC Ultra MCA support' CONFIG_ULTRAMCA
-    fi
-    tristate 'SMC Ultra support' CONFIG_ULTRA
-    tristate 'SMC Ultra32 EISA support' CONFIG_ULTRA32
-    tristate 'SMC 9194 support' CONFIG_SMC9194
+      tristate '    3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX
+   fi
+   tristate '  AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE
+   bool '  Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC
+   if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
+      tristate '    WD80*3 support' CONFIG_WD80x3
+      if [ "$CONFIG_MCA" = "y" ]; then
+	 tristate '    SMC Ultra MCA support' CONFIG_ULTRAMCA
+      fi
+      tristate '    SMC Ultra support' CONFIG_ULTRA
+      tristate '    SMC Ultra32 EISA support' CONFIG_ULTRA32
+      tristate '    SMC 9194 support' CONFIG_SMC9194
   fi
-  bool 'Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL
+  bool '  Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL
   if [ "$CONFIG_NET_VENDOR_RACAL" = "y" ]; then
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate 'NI5010 support' CONFIG_NI5010
+      tristate '    NI5010 support (EXPERIMENTAL)' CONFIG_NI5010
     fi
-    tristate 'NI5210 support' CONFIG_NI52
-    tristate 'NI6510 support' CONFIG_NI65
+    tristate '    NI5210 support' CONFIG_NI52
+    tristate '    NI6510 support' CONFIG_NI65
   fi
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139
-      tristate 'SiS 900 PCI Fast Ethernet Adapter support' CONFIG_SIS900
-      tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN
-      tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC
+      # tristate '  Packet Engines Hamachi GNIC-II support (EXPERIMENTAL)' CONFIG_HAMACHI
+      tristate '  Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN
+      tristate '  RealTek 8129/8139 (not 8019/8029!) support (EXPERIMENTAL)' CONFIG_RTL8139
+      tristate '  SiS 900 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_SIS900
+      tristate '  DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102
+   fi
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate '  AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700
+   fi
+   tristate '  DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA
+   bool '  Other ISA cards' CONFIG_NET_ISA
+   if [ "$CONFIG_NET_ISA" = "y" ]; then
+      tristate '    Cabletron E21xx support' CONFIG_E2100
+      tristate '    EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3
+      tristate '    EtherExpress 16 support' CONFIG_EEXPRESS
+      tristate '    EtherExpressPro support' CONFIG_EEXPRESS_PRO
+      tristate '    FMV-181/182/183/184 support' CONFIG_FMV18X
+      tristate '    HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS
+      tristate '    HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN
+      tristate '    HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100
+      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	 tristate '    ICL EtherTeam 16i/32 support (EXPERIMENTAL)' CONFIG_ETH16I
+      fi
+      tristate '    NE2000/NE1000 support' CONFIG_NE2000
+      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	 tristate '    SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005
+      fi
+      bool '    SK_G16 support' CONFIG_SK_G16
+   fi
+   if [ "$CONFIG_MCA" = "y" ]; then
+      tristate '  SKnet MCA support' CONFIG_SKMC
+      tristate '  NE/2 (ne2000 MCA version) support' CONFIG_NE2_MCA
+   fi
+   bool '  EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA
+   if [ "$CONFIG_NET_EISA" = "y" ]; then
+      tristate '    AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32
+#     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+#	 tristate '    Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE
+#     fi
+      tristate '    Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC
       if [ "$CONFIG_ACENIC" != "n" ]; then
-	  bool 'Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I
+	 bool '      Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I
+      fi
+      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	 tristate '    Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
       fi
-  fi
-  bool 'Other ISA cards' CONFIG_NET_ISA
-  if [ "$CONFIG_NET_ISA" = "y" ]; then
-    tristate 'AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700
-    tristate 'Cabletron E21xx support' CONFIG_E2100
-    tristate 'DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA
-    tristate 'EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3
-    tristate 'EtherExpress 16 support' CONFIG_EEXPRESS
-    tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO
-    tristate 'FMV-181/182/183/184 support' CONFIG_FMV18X
-    tristate 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS
-    tristate 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN
-    tristate 'HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100
-    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I
-    fi
-    tristate 'NE2000/NE1000 support' CONFIG_NE2000
-    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate 'SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005
-    fi
-    bool 'SK_G16 support' CONFIG_SK_G16
-  fi
-  if [ "$CONFIG_MCA" = "y" ]; then
-    tristate 'NE/2 (ne2000 MCA version) support' CONFIG_NE2_MCA
-    tristate 'SKnet MCA support' CONFIG_SKMC
-  fi
-  bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA
-  if [ "$CONFIG_NET_EISA" = "y" ]; then
-    tristate 'AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32
-    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
-    fi
 
-    tristate 'Apricot Xen-II on board Ethernet' CONFIG_APRICOT
-    tristate 'CS89x0 support' CONFIG_CS89x0
-    tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
-    tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP
-    tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
-    tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100
-    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate 'Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390
-      tristate 'Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210
-    fi
-    tristate 'PCI NE2000 support' CONFIG_NE2K_PCI
-    tristate 'TI ThunderLAN support' CONFIG_TLAN
-    tristate 'VIA Rhine support' CONFIG_VIA_RHINE
-    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate 'Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210
-      tristate 'SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100
-      bool 'Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET
-    fi
-    tristate 'Adaptec Starfire support' CONFIG_ADAPTEC_STARFIRE
-  fi
-  bool 'Pocket and portable adaptors' CONFIG_NET_POCKET
-  if [ "$CONFIG_NET_POCKET" = "y" ]; then
-    bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP
-    tristate 'D-Link DE600 pocket adaptor support' CONFIG_DE600
-    tristate 'D-Link DE620 pocket adaptor support' CONFIG_DE620
-  fi
+      tristate '    Apricot Xen-II on board Ethernet' CONFIG_APRICOT
+      tristate '    CS89x0 support' CONFIG_CS89x0
+      tristate '    Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
+      tristate '    DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP
+      tristate '    Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
+      tristate '    EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100
+      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	 tristate '    Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390
+	 tristate '    Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210
+      fi
+      tristate '    PCI NE2000 support' CONFIG_NE2K_PCI
+      # tristate '    Sundance Alta support' CONFIG_ALTA
+      tristate '    TI ThunderLAN support' CONFIG_TLAN
+      tristate '    VIA Rhine support' CONFIG_VIA_RHINE
+      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	 tristate '    Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210
+	 tristate '    SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100
+	 bool '    Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET
+      fi
+   fi
+   bool '  Pocket and portable adapters' CONFIG_NET_POCKET
+   if [ "$CONFIG_NET_POCKET" = "y" ]; then
+      bool '    AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP
+      tristate '    D-Link DE600 pocket adapter support' CONFIG_DE600
+      tristate '    D-Link DE620 pocket adapter support' CONFIG_DE620
+   fi
 fi
 
 endmenu
 
 bool 'FDDI driver support' CONFIG_FDDI
 if [ "$CONFIG_FDDI" = "y" ]; then
-  bool 'Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX
+   bool '  Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX
 fi
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI
-  if [ "$CONFIG_HIPPI" = "y" ]; then
-    tristate 'Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER
-    if [ "$CONFIG_ROADRUNNER" != "n" ]; then
-      bool '  Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS
-    fi
-  fi
+   bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI
+   if [ "$CONFIG_HIPPI" = "y" ]; then
+      tristate '  Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER
+      if [ "$CONFIG_ROADRUNNER" != "n" ]; then
+	 bool '    Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS
+      fi
+   fi
 fi
 
 #
@@ -182,133 +191,66 @@
 #
 
 if [ "$CONFIG_ATALK" != "n" ]; then
-  mainmenu_option next_comment
-  comment 'Appletalk devices'
-  dep_tristate 'Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_ATALK
-  dep_tristate 'COPS LocalTalk PC support' CONFIG_COPS $CONFIG_ATALK
-  if [ "$CONFIG_COPS" != "n" ]; then
-     bool 'Dayna firmware support' CONFIG_COPS_DAYNA
-     bool 'Tangent firmware support' CONFIG_COPS_TANGENT
-  fi
-  dep_tristate 'Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_ATALK
-  if [ "$CONFIG_IPDDP" != "n" ]; then
-     bool 'IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP
-     bool 'Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP
-  fi
-  endmenu
+   mainmenu_option next_comment
+   comment 'Appletalk devices'
+   dep_tristate 'Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_ATALK
+   dep_tristate 'COPS LocalTalk PC support' CONFIG_COPS $CONFIG_ATALK
+   if [ "$CONFIG_COPS" != "n" ]; then
+      bool '  Dayna firmware support' CONFIG_COPS_DAYNA
+      bool '  Tangent firmware support' CONFIG_COPS_TANGENT
+   fi
+   dep_tristate 'Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_ATALK
+   if [ "$CONFIG_IPDDP" != "n" ]; then
+      bool '  IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP
+      bool '  Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP
+   fi
+   endmenu
 fi
 
 if [ ! "$CONFIG_PARPORT" = "n" ]; then
-  dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
+   dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
 fi
 
 tristate 'PPP (point-to-point protocol) support' CONFIG_PPP
 if [ ! "$CONFIG_PPP" = "n" ]; then
-  dep_tristate 'PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP
-  dep_tristate 'PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
-  dep_tristate 'PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP m
+   dep_tristate '  PPP support for async serial ports' CONFIG_PPP_ASYNC $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
-  bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED
-  bool ' Keepalive and linefill' CONFIG_SLIP_SMART
-  bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6
+   bool '  CSLIP compressed headers' CONFIG_SLIP_COMPRESSED
+   bool '  Keepalive and linefill' CONFIG_SLIP_SMART
+   bool '  Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6
 fi
 
+mainmenu_option next_comment
+comment 'Wireless LAN (non-hamradio)'
+
 bool 'Wireless LAN (non-hamradio)' CONFIG_NET_RADIO
 if [ "$CONFIG_NET_RADIO" = "y" ]; then
-  dep_tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET
-  tristate 'AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
-  tristate 'Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN
-
-fi
-
-mainmenu_option next_comment
-comment 'Token ring devices'
+   dep_tristate '  STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET
+   tristate '  AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
+   tristate '  Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN
 
-bool 'Token Ring driver support' CONFIG_TR
-if [ "$CONFIG_TR" = "y" ]; then
-  tristate 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR
-#  tristate 'IBM Lanstreamer PCI adaptor support' CONFIG_IBMLS
-  tristate 'IBM Olympic chipset PCI adapter support' CONFIG_IBMOL
-  tristate 'SysKonnect adapter support' CONFIG_SKTR
 fi
 
 endmenu
 
+source drivers/net/tokenring/Config.in
+
 bool 'Fibre Channel driver support' CONFIG_NET_FC
 if [ "$CONFIG_NET_FC" = "y" ]; then
-  tristate 'Interphase 5526 Tachyon chipset based adaptor support' CONFIG_IPHASE5526
+   dep_tristate '  Interphase 5526 Tachyon chipset based adapter support' CONFIG_IPHASE5526 $CONFIG_SCSI
 fi
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI
-  tristate 'Traffic Shaper (EXPERIMENTAL)' CONFIG_SHAPER
-fi
-
-#
-# WAN drivers support
-#
-
-mainmenu_option next_comment
-comment 'Wan interfaces'
-
-
-# There is no way to detect a comtrol sv11 - force it modular for now.
-#
-dep_tristate 'Comtrol Hostess SV-11 support' CONFIG_HOSTESS_SV11 m
-#
-# The COSA/SRP driver has not been tested as non-modular yet.
-#
-dep_tristate 'COSA/SRP sync serial boards support' CONFIG_COSA m
-#
-# There is no way to detect a Sealevel board. Force it modular
-#
-dep_tristate 'Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m
-
-tristate 'Frame relay DLCI support' CONFIG_DLCI
-if [ "$CONFIG_DLCI" != "n" ]; then
-  int '  Max open DLCI' CONFIG_DLCI_COUNT 24
-  int '  Max DLCI per device' CONFIG_DLCI_MAX 8
-  dep_tristate '  SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI
+   tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI
+   tristate 'Traffic Shaper (EXPERIMENTAL)' CONFIG_SHAPER
 fi
 
-#
-#	Wan router core.
-#
-
-if [ "$CONFIG_WAN_ROUTER" != "n" ]; then
-  bool 'WAN drivers' CONFIG_WAN_DRIVERS
-  if [ "$CONFIG_WAN_DRIVERS" = "y" ]; then
-    dep_tristate 'Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_DRIVERS
-    if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then
-      int  '  Maximum number of cards' CONFIG_WANPIPE_CARDS 1
-      bool '  WANPIPE X.25 support' CONFIG_WANPIPE_X25
-      bool '  WANPIPE Frame Relay support' CONFIG_WANPIPE_FR
-      bool '  WANPIPE PPP support' CONFIG_WANPIPE_PPP
-    fi
-    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      dep_tristate 'Cyclom 2X(tm) multiprotocol cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_DRIVERS
-      if [ "$CONFIG_CYCLADES_SYNC" != "n" ]; then
-        bool '  Cyclom 2X X.25 support (EXPERIMENTAL)' CONFIG_CYCLOMX_X25
-      fi
-    fi
-  fi
-fi
-
-endmenu
-
-
-#
-# X.25 network drivers
-#
-if [ "$CONFIG_X25" != "n" ]; then
-if [ "$CONFIG_LAPB" != "n" ]; then
-    dep_tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER $CONFIG_LAPB
-    dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB
-fi
-fi
+source drivers/net/wan/Config.in
 
 if [ "$CONFIG_PCMCIA" != "n" ]; then
    source drivers/net/pcmcia/Config.in
diff -u --recursive --new-file v2.3.20/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.3.20/linux/drivers/net/Makefile	Fri Sep 10 23:57:29 1999
+++ linux/drivers/net/Makefile	Mon Oct 11 10:10:19 1999
@@ -5,7 +5,7 @@
 
 SUB_DIRS     := 
 MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS) hamradio irda fc pcmcia
+ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan
 
 L_TARGET := net.a
 L_OBJS   := auto_irq.o
@@ -24,10 +24,6 @@
 CONFIG_7990_MODULE :=
 CONFIG_82596_BUILTIN :=
 CONFIG_82596_MODULE :=
-CONFIG_85230_BUILTIN :=
-CONFIG_85230_MODULE  :=
-CONFIG_SYNCPPP_BUILTIN :=
-CONFIG_SYNCPPP_MODULE  :=
 
 ifeq ($(CONFIG_PCMCIA),y)
   SUB_DIRS += pcmcia
@@ -60,38 +56,6 @@
 L_OBJS += seeq8005.o
 endif
 
-ifeq ($(CONFIG_IBMTR),y)
-L_OBJS += ibmtr.o
-else
-  ifeq ($(CONFIG_IBMTR),m)
-  M_OBJS += ibmtr.o
-  endif
-endif
-
-ifeq ($(CONFIG_IBMLS),y)
-L_OBJS += lanstreamer.o
-else
-  ifeq ($(CONFIG_IBMLS),m)
-  M_OBJS += lanstreamer.o
-  endif
-endif
-
-ifeq ($(CONFIG_IBMOL),y)
-L_OBJS += olympic.o
-else
-  ifeq ($(CONFIG_IBMOL),m)
-  M_OBJS += olympic.o
-  endif
-endif
-
-ifeq ($(CONFIG_SKTR),y)
-L_OBJS += sktr.o
-else
-  ifeq ($(CONFIG_SKTR),m)
-  M_OBJS += sktr.o
-  endif
-endif
-
 ifeq ($(CONFIG_ETHERTAP),y)
 L_OBJS += ethertap.o
 else
@@ -123,6 +87,13 @@
   endif
 endif
 
+ifeq ($(CONFIG_PCMCIA_PCNET),y)
+CONFIG_8390_BUILTIN = y
+else
+  ifeq ($(CONFIG_PCMCIA_PCNET),m)
+  CONFIG_8390_MODULE = y
+  endif
+endif
 
 ifeq ($(CONFIG_SHAPER),y)
 L_OBJS += shaper.o
@@ -609,6 +580,15 @@
   endif
 endif
 
+ifeq ($(CONFIG_DM9102),y) 
+L_OBJS += dmfe.o
+else
+  ifeq ($(CONFIG_DM9102),m)
+  M_OBJS += dmfe.o
+  endif
+endif
+
+
 ifeq ($(CONFIG_YELLOWFIN),y)
 L_OBJS += yellowfin.o
 else
@@ -811,14 +791,6 @@
   endif
 endif
 
-ifeq ($(CONFIG_LAPBETHER),y)
-L_OBJS += lapbether.o
-else
-  ifeq ($(CONFIG_LAPBETHER),m)
-  M_OBJS += lapbether.o
-  endif
-endif
-
 ifeq ($(CONFIG_EPIC100),y)
 L_OBJS += epic100.o
 else
@@ -827,63 +799,6 @@
   endif
 endif
 
-ifeq ($(CONFIG_HOSTESS_SV11),y)
-L_OBJS += hostess_sv11.o
-CONFIG_85230_BUILTIN = y
-CONFIG_SYNCPPP_BUILTIN = y
-else
-  ifeq ($(CONFIG_HOSTESS_SV11),m)
-  CONFIG_85230_MODULE = y
-  CONFIG_SYNCPPP_MODULE = y
-  M_OBJS += hostess_sv11.o
-  endif
-endif
-
-ifeq ($(CONFIG_SEALEVEL_4021),y)
-L_OBJS += sealevel.o
-CONFIG_85230_BUILTIN = y
-CONFIG_SYNCPPP_BUILTIN = y
-else
-  ifeq ($(CONFIG_SEALEVEL_4021),m)
-  CONFIG_85230_MODULE = y
-  CONFIG_SYNCPPP_MODULE = y
-  M_OBJS += sealevel.o
-  endif
-endif
-
-
-ifeq ($(CONFIG_COSA),y)
-L_OBJS += cosa.o
-CONFIG_SYNCPPP_BUILTIN = y
-else
-  ifeq ($(CONFIG_COSA),m)
-  CONFIG_SYNCPPP_MODULE = y
-  M_OBJS += cosa.o
-  endif
-endif
-
-# If anything built-in uses syncppp, then build it into the kernel also.
-# If not, but a module uses it, build as a module.
-
-ifdef CONFIG_SYNCPPP_BUILTIN
-LX_OBJS += syncppp.o
-else
-  ifdef CONFIG_SYNCPPP_MODULE
-  MX_OBJS += syncppp.o
-  endif
-endif
-
-# If anything built-in uses Z85230, then build it into the kernel also.
-# If not, but a module uses it, build as a module.
-
-ifdef CONFIG_85230_BUILTIN
-LX_OBJS += z85230.o
-else
-  ifdef CONFIG_85230_MODULE
-  MX_OBJS += z85230.o
-  endif
-endif
-
 # If anything built-in uses slhc, then build it into the kernel also.
 # If not, but a module uses it, build as a module.
 ifdef CONFIG_SLHC_BUILTIN
@@ -914,6 +829,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_PCMCIA_PCNET),y)
+CONFIG_8390_BUILTIN = y
+else
+  ifeq ($(CONFIG_PCMCIA_PCNET),m)
+  CONFIG_8390_MODULE = y
+  endif
+endif
+
 # If anything built-in uses the 8390, then build it into the kernel also.
 # If not, but a module uses it, build as a module.
 ifdef CONFIG_8390_BUILTIN
@@ -1036,22 +959,6 @@
   endif
 endif
 
-ifeq ($(CONFIG_SDLA),y)
-L_OBJS += sdla.o
-else
-  ifeq ($(CONFIG_SDLA),m)
-  M_OBJS += sdla.o
-  endif
-endif
-
-ifeq ($(CONFIG_DLCI),y)
-L_OBJS += dlci.o 
-else
-  ifeq ($(CONFIG_DLCI),m)
-  M_OBJS += dlci.o
-  endif
-endif
-
 ifeq ($(CONFIG_ARIADNE),y)
 L_OBJS += ariadne.o
 else
@@ -1128,68 +1035,6 @@
   endif
 endif
 
-ifeq ($(CONFIG_ADAPTEC_STARFIRE),y)
-L_OBJS += starfire.o
-else
-  ifeq ($(CONFIG_ADAPTEC_STARFIRE),m)
-  M_OBJS += starfire.o
-  endif
-endif
-
-ifeq ($(CONFIG_VENDOR_SANGOMA),y)
-  LX_OBJS += sdladrv.o
-  L_OBJS += sdlamain.o
-  ifeq ($(CONFIG_WANPIPE_X25),y)
-    L_OBJS += sdla_x25.o
-  endif
-  ifeq ($(CONFIG_WANPIPE_FR),y)
-    L_OBJS += sdla_fr.o
-  endif
-  ifeq ($(CONFIG_WANPIPE_PPP),y)
-    L_OBJS += sdla_ppp.o
-  endif
-endif
-
-ifeq ($(CONFIG_VENDOR_SANGOMA),m)
-  MX_OBJS += sdladrv.o
-  M_OBJS += wanpipe.o
-  WANPIPE_OBJS = sdlamain.o
-  ifeq ($(CONFIG_WANPIPE_X25),y)
-    WANPIPE_OBJS += sdla_x25.o
-  endif
-  ifeq ($(CONFIG_WANPIPE_FR),y)
-    WANPIPE_OBJS += sdla_fr.o
-  endif
-  ifeq ($(CONFIG_WANPIPE_PPP),y)
-    WANPIPE_OBJS += sdla_ppp.o
-  endif
-endif
-
-ifeq ($(CONFIG_CYCLADES_SYNC),y)
-  LX_OBJS += cycx_drv.o
-  L_OBJS += cycx_main.o
-  ifeq ($(CONFIG_CYCLOMX_X25),y)
-    L_OBJS += cycx_x25.o
-  endif
-endif
-
-ifeq ($(CONFIG_CYCLADES_SYNC),m)
-  MX_OBJS += cycx_drv.o
-  M_OBJS += cyclomx.o
-  CYCLOMX_OBJS = cycx_main.o
-  ifeq ($(CONFIG_CYCLOMX_X25),y)
-    CYCLOMX_OBJS += cycx_x25.o
-  endif
-endif
-
-ifeq ($(CONFIG_X25_ASY),y)
-L_OBJS += x25_asy.o
-else
-  ifeq ($(CONFIG_X25_ASY),m)
-  M_OBJS += x25_asy.o
-  endif
-endif
-
 #
 # HIPPI adapters
 #
@@ -1211,6 +1056,24 @@
   endif
 endif
 
+ifeq ($(CONFIG_TR),y)
+SUB_DIRS += tokenring
+MOD_IN_SUB_DIRS += tokenring
+else
+  ifeq ($(CONFIG_TR),m)
+  MOD_IN_SUB_DIRS += tokenring
+  endif
+endif
+
+ifeq ($(CONFIG_WAN),y)
+SUB_DIRS += wan
+MOD_IN_SUB_DIRS += wan
+else
+  ifeq ($(CONFIG_WAN),m)
+  MOD_IN_SUB_DIRS += wan
+  endif
+endif
+
 ifeq ($(CONFIG_NET_FC),y)
 SUB_DIRS += fc
 MOD_IN_SUB_DIRS += fc
@@ -1224,12 +1087,6 @@
 
 clean:
 	rm -f core *.o *.a *.s
-
-wanpipe.o: $(WANPIPE_OBJS)
-	ld -r -o $@ $(WANPIPE_OBJS)
-
-cyclomx.o: $(CYCLOMX_OBJS)
-	ld -r -o $@ $(CYCLOMX_OBJS)
 
 rcpci.o: rcpci45.o rclanmtl.o
 	$(LD) -r -o rcpci.o rcpci45.o rclanmtl.o
diff -u --recursive --new-file v2.3.20/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.3.20/linux/drivers/net/Space.c	Fri Sep 10 23:57:29 1999
+++ linux/drivers/net/Space.c	Mon Oct 11 10:13:24 1999
@@ -12,6 +12,8 @@
  *		Donald J. Becker, <becker@super.org>
  *
  * Changelog:
+ *		Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 09/1999
+ *		- fix sbni: s/device/net_device/
  *		Paul Gortmaker (06/98): 
  *		 - sort probes in a sane way, make sure all (safe) probes
  *		   get run once & failed autoprobes don't autoprobe again.
@@ -104,6 +106,7 @@
 extern int tlan_probe(struct net_device *);
 extern int mace_probe(struct net_device *);
 extern int bmac_probe(struct net_device *);
+extern int ncr885e_probe(struct net_device *);
 extern int cs89x0_probe(struct net_device *dev);
 extern int ethertap_probe(struct net_device *dev);
 extern int ether1_probe (struct net_device *dev);
@@ -118,11 +121,12 @@
 extern int dec_lance_probe(struct net_device *);
 extern int mvme147lance_probe(struct net_device *dev);
 extern int via_rhine_probe(struct net_device *dev);
-extern int starfire_probe(struct net_device *dev);
 extern int tc515_probe(struct net_device *dev);
 extern int lance_probe(struct net_device *dev);
+extern int starfire_probe(struct net_device *dev);
 extern int rcpci_probe(struct net_device *);
 extern int mac_onboard_sonic_probe(struct net_device *dev);
+extern int dmfe_reg_board(struct net_device *);
 
 /* Gigabit Ethernet adapters */
 extern int yellowfin_probe(struct net_device *dev);
@@ -143,6 +147,9 @@
 /* Fibre Channel adapters */
 extern int iph5526_probe(struct net_device *dev);
 
+/* SBNI adapters */
+extern int sbni_probe(struct net_device *);
+
 struct devprobe
 {
 	int (*probe)(struct net_device *dev);
@@ -216,6 +223,11 @@
 #ifdef CONFIG_SIS900
 	{sis900_probe, 0},
 #endif
+
+#ifdef CONFIG_DM9102
+	{dmfe_reg_board, 0}, 
+#endif
+
 #ifdef CONFIG_YELLOWFIN
 	{yellowfin_probe, 0},
 #endif
@@ -293,10 +305,10 @@
 
 /*
  * ISA probes that touch addresses < 0x400 (including those that also
- * look for EISA/PCI cards in addition to ISA cards).
+ * look for EISA/PCI/MCA cards in addition to ISA cards).
  */
 struct devprobe isa_probes[] __initdata = {
-#ifdef CONFIG_EL3		/* ISA, EISA (MCA someday) 3c5x9 */
+#ifdef CONFIG_EL3		/* ISA, EISA, MCA 3c5x9 */
 	{el3_probe, 0},
 #endif
 #ifdef CONFIG_HP100 		/* ISA, EISA & PCI */
@@ -458,6 +470,9 @@
 #ifdef CONFIG_BMAC
 	{bmac_probe, 0},
 #endif
+#ifdef CONFIG_NCR885E
+	{ncr885e_probe, 0},
+#endif
 	{NULL, 0},
 };
 
@@ -781,6 +796,7 @@
 /* Token-ring device probe */
 extern int ibmtr_probe(struct net_device *);
 extern int olympic_probe(struct net_device *);
+extern int sktr_probe(struct net_device *);
 
 static int
 trif_probe(struct net_device *dev)
@@ -876,6 +892,29 @@
 #   undef       NEXT_DEV
 #   define      NEXT_DEV        (&fc0_dev)
 #endif
+
+
+#ifdef CONFIG_SBNI
+	static struct net_device sbni7_dev =
+		{"sbni7", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, sbni_probe};
+	static struct net_device sbni6_dev =
+		{"sbni6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni7_dev, sbni_probe};
+	static struct net_device sbni5_dev =
+		{"sbni5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni6_dev, sbni_probe};
+	static struct net_device sbni4_dev =
+		{"sbni4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni5_dev, sbni_probe};
+	static struct net_device sbni3_dev =
+		{"sbni3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni4_dev, sbni_probe};
+	static struct net_device sbni2_dev =
+		{"sbni2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni3_dev, sbni_probe};
+	static struct net_device sbni1_dev =
+		{"sbni1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni2_dev, sbni_probe};
+	static struct net_device sbni0_dev =
+		{"sbni0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni1_dev, sbni_probe};
+
+#undef	NEXT_DEV
+#define	NEXT_DEV	(&sbni0_dev)
+#endif 
 	
 	
 #ifdef CONFIG_NET_SB1000
diff -u --recursive --new-file v2.3.20/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c
--- v2.3.20/linux/drivers/net/arcnet.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/net/arcnet.c	Mon Oct 11 10:10:19 1999
@@ -474,10 +474,12 @@
   lp->sdev=(struct net_device *)kmalloc(sizeof(struct net_device)+10,GFP_KERNEL);
   if(lp->sdev == NULL)
   {
+#ifdef CONFIG_ARCNET_ETH
   	if(lp->edev)
   		kfree(lp->edev);
   	lp->edev=NULL;
   	return -ENOMEM;
+#endif 
   }
   memcpy(lp->sdev,dev,sizeof(struct net_device));
   lp->sdev->name=(char *)(lp+1);
diff -u --recursive --new-file v2.3.20/linux/drivers/net/cosa.c linux/drivers/net/cosa.c
--- v2.3.20/linux/drivers/net/cosa.c	Fri Sep 10 23:57:29 1999
+++ linux/drivers/net/cosa.c	Wed Dec 31 16:00:00 1969
@@ -1,2038 +0,0 @@
-/* $Id: cosa.c,v 1.26 1999/07/09 15:02:37 kas Exp $ */
-
-/*
- *  Copyright (C) 1995-1997  Jan "Yenya" Kasprzak <kas@fi.muni.cz>
- *
- *  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.
- */
-
-/*
- * The driver for the SRP and COSA synchronous serial cards.
- *
- * HARDWARE INFO
- *
- * Both cards are developed at the Institute of Computer Science,
- * Masaryk University (http://www.ics.muni.cz/). The hardware is
- * developed by Jiri Novotny <novotny@ics.muni.cz>. More information
- * and the photo of both cards is available at
- * http://www.pavoucek.cz/cosa.html. The card documentation, firmwares
- * and other goods can be downloaded from ftp://ftp.ics.muni.cz/pub/cosa/.
- * For Linux-specific utilities, see below in the "Software info" section.
- * If you want to order the card, contact Jiri Novotny.
- *
- * The SRP (serial port?, the Czech word "srp" means "sickle") card
- * is a 2-port intelligent (with its own 8-bit CPU) synchronous serial card
- * with V.24 interfaces up to 80kb/s each.
- *
- * The COSA (communication serial adapter?, the Czech word "kosa" means
- * "scythe") is a next-generation sync/async board with two interfaces
- * - currently any of V.24, X.21, V.35 and V.36 can be selected.
- * It has a 16-bit SAB80166 CPU and can do up to 10 Mb/s per channel.
- * The 8-channels version is in development.
- *
- * Both types have downloadable firmware and communicate via ISA DMA.
- * COSA can be also a bus-mastering device.
- *
- * SOFTWARE INFO
- *
- * The homepage of the Linux driver is at http://www.fi.muni.cz/~kas/cosa/.
- * The CVS tree of Linux driver can be viewed there, as well as the
- * firmware binaries and user-space utilities for downloading the firmware
- * into the card and setting up the card.
- *
- * The Linux driver (unlike the present *BSD drivers :-) can work even
- * for the COSA and SRP in one computer and allows each channel to work
- * in one of the three modes (character device, Cisco HDLC, Sync PPP).
- *
- * AUTHOR
- *
- * The Linux driver was written by Jan "Yenya" Kasprzak <kas@fi.muni.cz>.
- *
- * You can mail me bugfixes and even success reports. I am especially
- * interested in the SMP and/or muliti-channel success/failure reports
- * (I wonder if I did the locking properly :-).
- *
- * THE AUTHOR USED THE FOLLOWING SOURCES WHEN PROGRAMMING THE DRIVER
- *
- * The COSA/SRP NetBSD driver by Zdenek Salvet and Ivos Cernohlavek
- * The skeleton.c by Donald Becker
- * The SDL Riscom/N2 driver by Mike Natale
- * The Comtrol Hostess SV11 driver by Alan Cox
- * The Sync PPP/Cisco HDLC layer (syncppp.c) ported to Linux by Alan Cox
- */
-/*
- *     5/25/1999 : Marcelo Tosatti <marcelo@conectiva.com.br>
- *             fixed a deadlock in cosa_sppp_open
- */
-
-/* ---------- Headers, macros, data structures ---------- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/poll.h>
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/netdevice.h>
-#include <linux/spinlock.h>
-
-#undef COSA_SLOW_IO	/* for testing purposes only */
-#undef REALLY_SLOW_IO
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/byteorder.h>
-
-#include "syncppp.h"
-#include "cosa.h"
-
-/* Linux version stuff */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
-typedef struct wait_queue *wait_queue_head_t;
-#define DECLARE_WAITQUEUE(wait, current) \
-	struct wait_queue wait = { current, NULL }
-#endif
-
-/* Maximum length of the identification string. */
-#define COSA_MAX_ID_STRING	128
-
-/* Maximum length of the channel name */
-#define COSA_MAX_NAME		(sizeof("cosaXXXcXXX")+1)
-
-/* Per-channel data structure */
-
-struct channel_data {
-	int usage;	/* Usage count; >0 for chrdev, -1 for netdev */
-	int num;	/* Number of the channel */
-	struct cosa_data *cosa;	/* Pointer to the per-card structure */
-	int txsize;	/* Size of transmitted data */
-	char *txbuf;	/* Transmit buffer */
-	char name[COSA_MAX_NAME];	/* channel name */
-
-	/* The HW layer interface */
-	/* routine called from the RX interrupt */
-	char *(*setup_rx)(struct channel_data *channel, int size);
-	/* routine called when the RX is done (from the EOT interrupt) */
-	int (*rx_done)(struct channel_data *channel);
-	/* routine called when the TX is done (from the EOT interrupt) */
-	int (*tx_done)(struct channel_data *channel, int size);
-
-	/* Character device parts */
-	struct semaphore rsem, wsem;
-	char *rxdata;
-	int rxsize;
-	wait_queue_head_t txwaitq; 
-	wait_queue_head_t rxwaitq;
-	int tx_status, rx_status;
-
-	/* SPPP/HDLC device parts */
-	struct ppp_device pppdev;
-	struct sk_buff *rx_skb, *tx_skb;
-	struct net_device_stats stats;
-};
-
-struct cosa_data {
-	int num;			/* Card number */
-	char name[COSA_MAX_NAME];	/* Card name - e.g "cosa0" */
-	unsigned int datareg, statusreg;	/* I/O ports */
-	unsigned short irq, dma;	/* IRQ and DMA number */
-	unsigned short startaddr;	/* Firmware start address */
-	unsigned short busmaster;	/* Use busmastering? */
-	int nchannels;			/* # of channels on this card */
-	int driver_status;		/* For communicating with firware */
-	int firmware_status;		/* Downloaded, reseted, etc. */
-	int rxbitmap, txbitmap;		/* Bitmap of channels who are willing to send/receive data */
-	int rxtx;			/* RX or TX in progress? */
-	int enabled;
-	int usage;				/* usage count */
-	int txchan, txsize, rxsize;
-	struct channel_data *rxchan;
-	char *bouncebuf;
-	char *txbuf, *rxbuf;
-	struct channel_data *chan;
-	spinlock_t lock;	/* For exclusive operations on this structure */
-	char id_string[COSA_MAX_ID_STRING];	/* ROM monitor ID string */
-	char *type;				/* card type */
-};
-
-/*
- * Define this if you want all the possible ports to be autoprobed.
- * It is here but it probably is not a good idea to use this.
- */
-/* #define COSA_ISA_AUTOPROBE	1 */
-
-/*
- * Character device major number. 117 was allocated for us.
- * The value of 0 means to allocate a first free one.
- */
-static int cosa_major = 117;
-
-/*
- * Encoding of the minor numbers:
- * The lowest CARD_MINOR_BITS bits means the channel on the single card,
- * the highest bits means the card number.
- */
-#define CARD_MINOR_BITS	4	/* How many bits in minor number are reserved
-				 * for the single card */
-/*
- * The following depends on CARD_MINOR_BITS. Unfortunately, the "MODULE_STRING"
- * macro doesn't like anything other than the raw number as an argument :-(
- */
-#define MAX_CARDS	16
-/* #define MAX_CARDS	(1 << (8-CARD_MINOR_BITS)) */
-
-#define DRIVER_RX_READY		0x0001
-#define DRIVER_TX_READY		0x0002
-#define DRIVER_TXMAP_SHIFT	2
-#define DRIVER_TXMAP_MASK	0x0c	/* FIXME: 0xfc for 8-channel version */
-
-/*
- * for cosa->rxtx - indicates whether either transmit or receive is
- * in progress. These values are mean number of the bit.
- */
-#define TXBIT 0
-#define RXBIT 1
-#define IRQBIT 2
-
-#define COSA_MTU 2000	/* FIXME: I don't know this exactly */
-
-#undef DEBUG_DATA 1	/* Dump the data read or written to the channel */
-#undef DEBUG_IRQS 1	/* Print the message when the IRQ is received */
-#undef DEBUG_IO 1	/* Dump the I/O traffic */
-
-/* Maybe the following should be allocated dynamically */
-static struct cosa_data cosa_cards[MAX_CARDS];
-static int nr_cards = 0;
-
-#ifdef COSA_ISA_AUTOPROBE
-static int io[MAX_CARDS+1]  = { 0x220, 0x228, 0x210, 0x218, 0, };
-/* NOTE: DMA is not autoprobed!!! */
-static int dma[MAX_CARDS+1] = { 1, 7, 1, 7, 1, 7, 1, 7, 0, };
-#else
-int io[MAX_CARDS+1]  = { 0, };
-int dma[MAX_CARDS+1] = { 0, };
-#endif
-/* IRQ can be safely autoprobed */
-static int irq[MAX_CARDS+1] = { -1, -1, -1, -1, -1, -1, 0, };
-
-#ifdef MODULE
-MODULE_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i");
-MODULE_PARM_DESC(io, "The I/O bases of the COSA or SRP cards");
-MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CARDS) "i");
-MODULE_PARM_DESC(irq, "The IRQ lines of the COSA or SRP cards");
-MODULE_PARM(dma, "1-" __MODULE_STRING(MAX_CARDS) "i");
-MODULE_PARM_DESC(dma, "The DMA channels of the COSA or SRP cards");
-
-MODULE_AUTHOR("Jan \"Yenya\" Kasprzak, <kas@fi.muni.cz>");
-MODULE_DESCRIPTION("Modular driver for the COSA or SRP synchronous card");
-#endif
-
-/* I use this mainly for testing purposes */
-#ifdef COSA_SLOW_IO
-#define cosa_outb outb_p
-#define cosa_outw outw_p
-#define cosa_inb  inb_p
-#define cosa_inw  inw_p
-#else
-#define cosa_outb outb
-#define cosa_outw outw
-#define cosa_inb  inb
-#define cosa_inw  inw
-#endif
-
-#define is_8bit(cosa)		(!(cosa->datareg & 0x08))
-
-#define cosa_getstatus(cosa)	(cosa_inb(cosa->statusreg))
-#define cosa_putstatus(cosa, stat)	(cosa_outb(stat, cosa->statusreg))
-#define cosa_getdata16(cosa)	(cosa_inw(cosa->datareg))
-#define cosa_getdata8(cosa)	(cosa_inb(cosa->datareg))
-#define cosa_putdata16(cosa, dt)	(cosa_outw(dt, cosa->datareg))
-#define cosa_putdata8(cosa, dt)	(cosa_outb(dt, cosa->datareg))
-
-/* Initialization stuff */
-static int cosa_probe(int ioaddr, int irq, int dma);
-
-/* HW interface */
-static void cosa_enable_rx(struct channel_data *chan);
-static void cosa_disable_rx(struct channel_data *chan);
-static int cosa_start_tx(struct channel_data *channel, char *buf, int size);
-static void cosa_kick(struct cosa_data *cosa);
-static int cosa_dma_able(struct channel_data *chan, char *buf, int data);
-
-/* SPPP/HDLC stuff */
-static void sppp_channel_init(struct channel_data *chan);
-static void sppp_channel_delete(struct channel_data *chan);
-static int cosa_sppp_open(struct net_device *d);
-static int cosa_sppp_close(struct net_device *d);
-static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *d);
-static char *sppp_setup_rx(struct channel_data *channel, int size);
-static int sppp_rx_done(struct channel_data *channel);
-static int sppp_tx_done(struct channel_data *channel, int size);
-static int cosa_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-static struct net_device_stats *cosa_net_stats(struct net_device *dev);
-
-/* Character device */
-static void chardev_channel_init(struct channel_data *chan);
-static char *chrdev_setup_rx(struct channel_data *channel, int size);
-static int chrdev_rx_done(struct channel_data *channel);
-static int chrdev_tx_done(struct channel_data *channel, int size);
-static long long cosa_lseek(struct file *file,
-	long long offset, int origin);
-static ssize_t cosa_read(struct file *file,
-	char *buf, size_t count, loff_t *ppos);
-static ssize_t cosa_write(struct file *file,
-	const char *buf, size_t count, loff_t *ppos);
-static unsigned int cosa_poll(struct file *file, poll_table *poll);
-static int cosa_open(struct inode *inode, struct file *file);
-static int cosa_release(struct inode *inode, struct file *file);
-static int cosa_chardev_ioctl(struct inode *inode, struct file *file,
-	unsigned int cmd, unsigned long arg);
-#ifdef COSA_FASYNC_WORKING
-static int cosa_fasync(struct inode *inode, struct file *file, int on);
-#endif
-
-static struct file_operations cosa_fops = {
-	cosa_lseek,
-	cosa_read,
-	cosa_write,
-	NULL,	/* readdir */
-	cosa_poll,
-	cosa_chardev_ioctl,
-	NULL,	/* mmap */
-	cosa_open,
-	NULL,	/* flush */
-	cosa_release,
-	NULL,	/* fsync */
-#ifdef COSA_FASYNC_WORKING
-	cosa_fasync,
-#else
-	NULL,
-#endif
-	NULL,	/* check media change */
-	NULL,	/* revalidate */
-	NULL	/* lock */
-};
-
-/* Ioctls */
-static int cosa_start(struct cosa_data *cosa, int address);
-static int cosa_reset(struct cosa_data *cosa);
-static int cosa_download(struct cosa_data *cosa, struct cosa_download *d);
-static int cosa_readmem(struct cosa_data *cosa, struct cosa_download *d);
-
-/* COSA/SRP ROM monitor */
-static int download(struct cosa_data *cosa, char *data, int addr, int len);
-static int startmicrocode(struct cosa_data *cosa, int address);
-static int readmem(struct cosa_data *cosa, char *data, int addr, int len);
-static int cosa_reset_and_read_id(struct cosa_data *cosa, char *id);
-
-/* Auxilliary functions */
-static int get_wait_data(struct cosa_data *cosa);
-static int put_wait_data(struct cosa_data *cosa, int data);
-static int puthexnumber(struct cosa_data *cosa, int number);
-static void put_driver_status(struct cosa_data *cosa);
-static void put_driver_status_nolock(struct cosa_data *cosa);
-
-/* Interrupt handling */
-static void cosa_interrupt(int irq, void *cosa, struct pt_regs *regs);
-
-/* I/O ops debugging */
-#ifdef DEBUG_IO
-static void debug_data_in(struct cosa_data *cosa, int data);
-static void debug_data_out(struct cosa_data *cosa, int data);
-static void debug_data_cmd(struct cosa_data *cosa, int data);
-static void debug_status_in(struct cosa_data *cosa, int status);
-static void debug_status_out(struct cosa_data *cosa, int status);
-#endif
-
-
-/* ---------- Initialization stuff ---------- */
-
-#ifdef MODULE
-int init_module(void)
-#else
-static int __init cosa_init(void)
-#endif
-{
-	int i;
-	printk(KERN_INFO "cosa v1.06 (c) 1997-8 Jan Kasprzak <kas@fi.muni.cz>\n");
-#ifdef __SMP__
-	printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n");
-#endif
-	if (cosa_major > 0) {
-		if (register_chrdev(cosa_major, "cosa", &cosa_fops)) {
-			printk(KERN_WARNING "cosa: unable to get major %d\n",
-				cosa_major);
-			return -EIO;
-		}
-	} else {
-		if (!(cosa_major=register_chrdev(0, "cosa", &cosa_fops))) {
-			printk(KERN_WARNING "cosa: unable to register chardev\n");
-			return -EIO;
-		}
-	}
-	for (i=0; i<MAX_CARDS; i++)
-		cosa_cards[i].num = -1;
-	for (i=0; io[i] != 0 && i < MAX_CARDS; i++)
-		cosa_probe(io[i], irq[i], dma[i]);
-	if (!nr_cards) {
-		printk(KERN_WARNING "cosa: no devices found.\n");
-		unregister_chrdev(cosa_major, "cosa");
-		return -ENODEV;
-	}
-	return 0;
-}
-
-#ifdef MODULE
-void cleanup_module (void)
-{
-	struct cosa_data *cosa;
-	printk(KERN_INFO "Unloading the cosa module\n");
-
-	for (cosa=cosa_cards; nr_cards--; cosa++) {
-		int i;
-		/* Clean up the per-channel data */
-		for (i=0; i<cosa->nchannels; i++) {
-			/* Chardev driver has no alloc'd per-channel data */
-			sppp_channel_delete(cosa->chan+i);
-		}
-		/* Clean up the per-card data */
-		kfree(cosa->chan);
-		kfree(cosa->bouncebuf);
-		free_irq(cosa->irq, cosa);
-		free_dma(cosa->dma);
-		release_region(cosa->datareg,is_8bit(cosa)?2:4);
-	}
-	unregister_chrdev(cosa_major, "cosa");
-}
-#endif
-
-/*
- * This function should register all the net devices needed for the
- * single channel.
- */
-static __inline__ void channel_init(struct channel_data *chan)
-{
-	sprintf(chan->name, "cosa%dc%d", chan->cosa->num, chan->num);
-
-	/* Initialize the chardev data structures */
-	chardev_channel_init(chan);
-
-	/* Register the sppp interface */
-	sppp_channel_init(chan);
-}
-	
-static int cosa_probe(int base, int irq, int dma)
-{
-	struct cosa_data *cosa = cosa_cards+nr_cards;
-	int i;
-
-	memset(cosa, 0, sizeof(struct cosa_data));
-
-	/* Checking validity of parameters: */
-	/* IRQ should be 2-7 or 10-15; negative IRQ means autoprobe */
-	if ((irq >= 0  && irq < 2) || irq > 15 || (irq < 10 && irq > 7)) {
-		printk (KERN_INFO "cosa_probe: invalid IRQ %d\n", irq);
-		return -1;
-	}
-	/* I/O address should be between 0x100 and 0x3ff and should be
-	 * multiple of 8. */
-	if (base < 0x100 || base > 0x3ff || base & 0x7) {
-		printk (KERN_INFO "cosa_probe: invalid I/O address 0x%x\n",
-			base);
-		return -1;
-	}
-	/* DMA should be 0,1 or 3-7 */
-	if (dma < 0 || dma == 4 || dma > 7) {
-		printk (KERN_INFO "cosa_probe: invalid DMA %d\n", dma);
-		return -1;
-	}
-	/* and finally, on 16-bit COSA DMA should be 4-7 and 
-	 * I/O base should not be multiple of 0x10 */
-	if (((base & 0x8) && dma < 4) || (!(base & 0x8) && dma > 3)) {
-		printk (KERN_INFO "cosa_probe: 8/16 bit base and DMA mismatch"
-			" (base=0x%x, dma=%d)\n", base, dma);
-		return -1;
-	}
-
-	cosa->dma = dma;
-	cosa->datareg = base;
-	cosa->statusreg = is_8bit(cosa)?base+1:base+2;
-	spin_lock_init(&cosa->lock);
-
-	if (check_region(base, is_8bit(cosa)?2:4))
-		return -1;
-	
-	if (cosa_reset_and_read_id(cosa, cosa->id_string) < 0) {
-		printk(KERN_DEBUG "cosa: probe at 0x%x failed.\n", base);
-		return -1;
-	}
-
-	/* Test the validity of identification string */
-	if (!strncmp(cosa->id_string, "SRP", 3))
-		cosa->type = "srp";
-	else if (!strncmp(cosa->id_string, "COSA", 4))
-		cosa->type = is_8bit(cosa)? "cosa8": "cosa16";
-	else {
-/* Print a warning only if we are not autoprobing */
-#ifndef COSA_ISA_AUTOPROBE
-		printk(KERN_INFO "cosa: valid signature not found at 0x%x.\n",
-			base);
-#endif
-		return -1;
-	}
-
-	/* Now do IRQ autoprobe */
-	if (irq < 0) {
-		unsigned long irqs;
-/*		printk(KERN_INFO "IRQ autoprobe\n"); */
-		sti();
-		irqs = probe_irq_on();
-		/* 
-		 * Enable interrupt on tx buffer empty (it sure is) 
-		 * really sure ?
-		 * FIXME: When this code is not used as module, we should
-		 * probably call udelay() instead of the interruptible sleep.
-		 */
-		current->state = TASK_INTERRUPTIBLE;
-		cosa_putstatus(cosa, SR_TX_INT_ENA);
-		schedule_timeout(30);
-		current->state = TASK_RUNNING;
-		irq = probe_irq_off(irqs);
-		/* Disable all IRQs from the card */
-		cosa_putstatus(cosa, 0);
-		/* Empty the received data register */
-		cosa_getdata8(cosa);
-
-		if (irq < 0) {
-			printk (KERN_INFO "cosa IRQ autoprobe: multiple interrupts obtained (%d, board at 0x%x)\n",
-				irq, cosa->datareg);
-			return -1;
-		}
-		if (irq == 0) {
-			printk (KERN_INFO "cosa IRQ autoprobe: no interrupt obtained (board at 0x%x)\n",
-				cosa->datareg);
-		/*	return -1; */
-		}
-	}
-
-	cosa->irq = irq;
-	cosa->num = nr_cards;
-	cosa->usage = 0;
-	cosa->nchannels = 2;	/* FIXME: how to determine this? */
-
-	request_region(base, is_8bit(cosa)?2:4, cosa->type);
-	if (request_irq(cosa->irq, cosa_interrupt, 0, cosa->type, cosa))
-		goto bad1;
-	if (request_dma(cosa->dma, cosa->type)) {
-		free_irq(cosa->irq, cosa);
-bad1:		release_region(cosa->datareg,is_8bit(cosa)?2:4);
-		printk(KERN_NOTICE "cosa%d: allocating resources failed\n",
-			cosa->num);
-		return -1;
-	}
-	
-	cosa->bouncebuf = kmalloc(COSA_MTU, GFP_KERNEL|GFP_DMA);
-	sprintf(cosa->name, "cosa%d", cosa->num);
-
-	/* Initialize the per-channel data */
-	cosa->chan = kmalloc(sizeof(struct channel_data)*cosa->nchannels,
-		GFP_KERNEL);
-	memset(cosa->chan, 0, sizeof(struct channel_data)*cosa->nchannels);
-	for (i=0; i<cosa->nchannels; i++) {
-		cosa->chan[i].cosa = cosa;
-		cosa->chan[i].num = i;
-		channel_init(cosa->chan+i);
-	}
-
-	printk (KERN_INFO "cosa%d: %s (%s at 0x%x irq %d dma %d), %d channels\n",
-		cosa->num, cosa->id_string, cosa->type,
-		cosa->datareg, cosa->irq, cosa->dma, cosa->nchannels);
-
-	return nr_cards++;
-}
-
-
-/*---------- SPPP/HDLC netdevice ---------- */
-
-static void sppp_channel_init(struct channel_data *chan)
-{
-	struct net_device *d;
-	sppp_attach(&chan->pppdev);
-	d=&chan->pppdev.dev;
-	d->name = chan->name;
-	d->base_addr = chan->cosa->datareg;
-	d->irq = chan->cosa->irq;
-	d->dma = chan->cosa->dma;
-	d->priv = chan;
-	d->init = NULL;
-	d->open = cosa_sppp_open;
-	d->stop = cosa_sppp_close;
-	d->hard_start_xmit = cosa_sppp_tx;
-	d->do_ioctl = cosa_sppp_ioctl;
-	d->get_stats = cosa_net_stats;
-	dev_init_buffers(d);
-	if (register_netdev(d) == -1) {
-		printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
-		sppp_detach(&chan->pppdev.dev);
-		return;
-	}
-}
-
-static void sppp_channel_delete(struct channel_data *chan)
-{
-	sppp_detach(&chan->pppdev.dev);
-	unregister_netdev(&chan->pppdev.dev);
-}
-
-
-static int cosa_sppp_open(struct net_device *d)
-{
-	struct channel_data *chan = d->priv;
-	int err, flags;
-
-	spin_lock_irqsave(&chan->cosa->lock, flags);
-	if (chan->usage != 0) {
-		printk(KERN_WARNING "%s: sppp_open called with usage count %d\n",
-			chan->name, chan->usage);
-		spin_unlock_irqrestore(&chan->cosa->lock, flags);
-		return -EBUSY;
-	}
-	chan->setup_rx = sppp_setup_rx;
-	chan->tx_done = sppp_tx_done;
-	chan->rx_done = sppp_rx_done;
-	chan->usage=-1;
-	chan->cosa->usage++;
-	MOD_INC_USE_COUNT;
-	spin_unlock_irqrestore(&chan->cosa->lock, flags);
-
-	err = sppp_open(d);
-	if (err) {
-		spin_lock_irqsave(&chan->cosa->lock, flags);
-		chan->usage=0;
-		chan->cosa->usage--;
-		MOD_DEC_USE_COUNT;
-		
-		spin_unlock_irqrestore(&chan->cosa->lock, flags);
-		return err;
-	}
-
-	d->tbusy = 0;
-	cosa_enable_rx(chan);
-	return 0;
-}
-
-static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *dev)
-{
-	struct channel_data *chan = dev->priv;
-
-	if (dev->tbusy) { 
-		if (time_before(jiffies, dev->trans_start+2*HZ))
-			return 1;	/* Two seconds timeout */
-		if (test_bit(RXBIT, &chan->cosa->rxtx)) {
-			chan->stats.rx_errors++;
-			chan->stats.rx_missed_errors++;
-		} else {
-			chan->stats.tx_errors++;
-			chan->stats.tx_aborted_errors++;
-		}
-		cosa_kick(chan->cosa);
-		if (chan->tx_skb) {
-			dev_kfree_skb(chan->tx_skb);
-			chan->tx_skb = 0;
-		}
-		dev->tbusy = 0;
-	}
-	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-		printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
-		return 1;
-	}
-	
-	chan->tx_skb = skb;
-	dev->trans_start = jiffies;
-	cosa_start_tx(chan, skb->data, skb->len);
-	return 0;
-}
-
-static int cosa_sppp_close(struct net_device *d)
-{
-	struct channel_data *chan = d->priv;
-	int flags;
-
-	sppp_close(d);
-	d->tbusy = 1;
-	cosa_disable_rx(chan);
-	spin_lock_irqsave(&chan->cosa->lock, flags);
-	if (chan->rx_skb) {
-		kfree_skb(chan->rx_skb);
-		chan->rx_skb = 0;
-	}
-	if (chan->tx_skb) {
-		kfree_skb(chan->tx_skb);
-		chan->tx_skb = 0;
-	}
-	chan->usage=0;
-	chan->cosa->usage--;
-	MOD_DEC_USE_COUNT;
-	spin_unlock_irqrestore(&chan->cosa->lock, flags);
-	return 0;
-}
-
-static char *sppp_setup_rx(struct channel_data *chan, int size)
-{
-	/*
-	 * We can safely fall back to non-dma-able memory, because we have
-	 * the cosa->bouncebuf pre-allocated.
-	 */
-	if (chan->rx_skb)
-		kfree_skb(chan->rx_skb);
-	chan->rx_skb = dev_alloc_skb(size);
-	if (chan->rx_skb == NULL) {
-		printk(KERN_NOTICE "%s: Memory squeeze, dropping packet\n",
-			chan->name);
-		chan->stats.rx_dropped++;
-		return NULL;
-	}
-	chan->pppdev.dev.trans_start = jiffies;
-	return skb_put(chan->rx_skb, size);
-}
-
-static int sppp_rx_done(struct channel_data *chan)
-{
-	if (!chan->rx_skb) {
-		printk(KERN_WARNING "%s: rx_done with empty skb!\n",
-			chan->name);
-		chan->stats.rx_errors++;
-		chan->stats.rx_frame_errors++;
-		return 0;
-	}
-	chan->rx_skb->protocol = htons(ETH_P_WAN_PPP);
-	chan->rx_skb->dev = &chan->pppdev.dev;
-	chan->rx_skb->mac.raw = chan->rx_skb->data;
-	chan->stats.rx_packets++;
-	chan->stats.rx_bytes += chan->cosa->rxsize;
-	netif_rx(chan->rx_skb);
-	chan->rx_skb = 0;
-	chan->pppdev.dev.trans_start = jiffies;
-	return 0;
-}
-
-/* ARGSUSED */
-static int sppp_tx_done(struct channel_data *chan, int size)
-{
-	if (!chan->tx_skb) {
-		printk(KERN_WARNING "%s: tx_done with empty skb!\n",
-			chan->name);
-		chan->stats.tx_errors++;
-		chan->stats.tx_aborted_errors++;
-		return 1;
-	}
-	dev_kfree_skb(chan->tx_skb);
-	chan->tx_skb = 0;
-	chan->stats.tx_packets++;
-	chan->stats.tx_bytes += size;
-	chan->pppdev.dev.tbusy = 0;
-	mark_bh(NET_BH);
-	return 1;
-}
-
-static struct net_device_stats *cosa_net_stats(struct net_device *dev)
-{
-	struct channel_data *chan = dev->priv;
-	return &chan->stats;
-}
-
-
-/*---------- Character device ---------- */
-
-static void chardev_channel_init(struct channel_data *chan)
-{
-	init_MUTEX(&chan->rsem);
-	init_MUTEX(&chan->wsem);
-}
-
-static long long cosa_lseek(struct file * file,
-	long long offset, int origin)
-{
-	return -ESPIPE;
-}
-
-static ssize_t cosa_read(struct file *file,
-	char *buf, size_t count, loff_t *ppos)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	int flags;
-	struct channel_data *chan = (struct channel_data *)file->private_data;
-	struct cosa_data *cosa = chan->cosa;
-	char *kbuf;
-
-	if (down_interruptible(&chan->rsem))
-		return -ERESTARTSYS;
-	
-	if ((chan->rxdata = kmalloc(COSA_MTU, GFP_DMA|GFP_KERNEL)) == NULL) {
-		printk(KERN_INFO "%s: cosa_read() - OOM\n", cosa->name);
-		up(&chan->rsem);
-		return -ENOMEM;
-	}
-
-	chan->rx_status = 0;
-	cosa_enable_rx(chan);
-	spin_lock_irqsave(&cosa->lock, flags);
-	add_wait_queue(&chan->rxwaitq, &wait);
-	while(!chan->rx_status) {
-		current->state = TASK_INTERRUPTIBLE;
-		spin_unlock_irqrestore(&cosa->lock, flags);
-		schedule();
-		spin_lock_irqsave(&cosa->lock, flags);
-		if (signal_pending(current) && chan->rx_status == 0) {
-			chan->rx_status = 1;
-			remove_wait_queue(&chan->rxwaitq, &wait);
-			current->state = TASK_RUNNING;
-			spin_unlock_irqrestore(&cosa->lock, flags);
-			up(&chan->rsem);
-			return -ERESTARTSYS;
-		}
-	}
-	remove_wait_queue(&chan->rxwaitq, &wait);
-	current->state = TASK_RUNNING;
-	kbuf = chan->rxdata;
-	count = chan->rxsize;
-	spin_unlock_irqrestore(&cosa->lock, flags);
-	up(&chan->rsem);
-
-	if (copy_to_user(buf, kbuf, count)) {
-		kfree(buf);
-		return -EFAULT;
-	}
-	kfree(kbuf);
-	return count;
-}
-
-static char *chrdev_setup_rx(struct channel_data *chan, int size)
-{
-	/* Expect size <= COSA_MTU */
-	chan->rxsize = size;
-	return chan->rxdata;
-}
-
-static int chrdev_rx_done(struct channel_data *chan)
-{
-	if (chan->rx_status) { /* Reader has died */
-		kfree(chan->rxdata);
-		up(&chan->wsem);
-	}
-	chan->rx_status = 1;
-	wake_up_interruptible(&chan->rxwaitq);
-	return 1;
-}
-
-
-static ssize_t cosa_write(struct file *file,
-	const char *buf, size_t count, loff_t *ppos)
-{
-	struct channel_data *chan = (struct channel_data *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	struct cosa_data *cosa = chan->cosa;
-	unsigned int flags;
-	char *kbuf;
-
-	if (down_interruptible(&chan->wsem))
-		return -ERESTARTSYS;
-
-	if (count > COSA_MTU)
-		count = COSA_MTU;
-	
-	/* Allocate the buffer */
-	if ((kbuf = kmalloc(count, GFP_KERNEL|GFP_DMA)) == NULL) {
-		printk(KERN_NOTICE "%s: cosa_write() OOM - dropping packet\n",
-			cosa->name);
-		up(&chan->wsem);
-		return -ENOMEM;
-	}
-	if (copy_from_user(kbuf, buf, count)) {
-		up(&chan->wsem);
-		kfree(kbuf);
-		return -EFAULT;
-	}
-	chan->tx_status=0;
-	cosa_start_tx(chan, kbuf, count);
-
-	spin_lock_irqsave(&cosa->lock, flags);
-	add_wait_queue(&chan->txwaitq, &wait);
-	while(!chan->tx_status) {
-		current->state = TASK_INTERRUPTIBLE;
-		spin_unlock_irqrestore(&cosa->lock, flags);
-		schedule();
-		spin_lock_irqsave(&cosa->lock, flags);
-		if (signal_pending(current) && chan->tx_status == 0) {
-			chan->tx_status = 1;
-			remove_wait_queue(&chan->txwaitq, &wait);
-			current->state = TASK_RUNNING;
-			chan->tx_status = 1;
-			spin_unlock_irqrestore(&cosa->lock, flags);
-			return -ERESTARTSYS;
-		}
-	}
-	remove_wait_queue(&chan->txwaitq, &wait);
-	current->state = TASK_RUNNING;
-	up(&chan->wsem);
-	spin_unlock_irqrestore(&cosa->lock, flags);
-	kfree(kbuf);
-	return count;
-}
-
-static int chrdev_tx_done(struct channel_data *chan, int size)
-{
-	if (chan->tx_status) { /* Writer was interrupted */
-		kfree(chan->txbuf);
-		up(&chan->wsem);
-	}
-	chan->tx_status = 1;
-	wake_up_interruptible(&chan->txwaitq);
-	return 1;
-}
-
-static unsigned int cosa_poll(struct file *file, poll_table *poll)
-{
-	printk(KERN_INFO "cosa_poll is here\n");
-	return 0;
-}
-
-static int cosa_open(struct inode *inode, struct file *file)
-{
-	struct cosa_data *cosa;
-	struct channel_data *chan;
-	unsigned long flags;
-	int n;
-
-	if ((n=MINOR(file->f_dentry->d_inode->i_rdev)>>CARD_MINOR_BITS)
-		>= nr_cards)
-		return -ENODEV;
-	cosa = cosa_cards+n;
-
-	if ((n=MINOR(file->f_dentry->d_inode->i_rdev)
-		& ((1<<CARD_MINOR_BITS)-1)) >= cosa->nchannels)
-		return -ENODEV;
-	chan = cosa->chan + n;
-	
-	file->private_data = chan;
-
-	spin_lock_irqsave(&cosa->lock, flags);
-
-	if (chan->usage < 0) { /* in netdev mode */
-		spin_unlock_irqrestore(&cosa->lock, flags);
-		return -EBUSY;
-	}
-	cosa->usage++;
-	chan->usage++;
-
-	chan->tx_done = chrdev_tx_done;
-	chan->setup_rx = chrdev_setup_rx;
-	chan->rx_done = chrdev_rx_done;
-#ifdef MODULE
-	MOD_INC_USE_COUNT;
-#endif
-	spin_unlock_irqrestore(&cosa->lock, flags);
-	return 0;
-}
-
-static int cosa_release(struct inode *inode, struct file *file)
-{
-	struct channel_data *channel = (struct channel_data *)file->private_data;
-	struct cosa_data *cosa = channel->cosa;
-	unsigned long flags;
-
-	spin_lock_irqsave(&cosa->lock, flags);
-	cosa->usage--;
-	channel->usage--;
-#ifdef MODULE
-	MOD_DEC_USE_COUNT;
-#endif
-	spin_unlock_irqrestore(&cosa->lock, flags);
-	return 0;
-}
-
-#ifdef COSA_FASYNC_WORKING
-static struct fasync_struct *fasync[256] = { NULL, };
-
-/* To be done ... */
-static int cosa_fasync(struct inode *inode, struct file *file, int on)
-{
-        int port = MINOR(inode->i_rdev);
-        int rv = fasync_helper(inode, file, on, &fasync[port]);
-        return rv < 0 ? rv : 0;
-}
-#endif
-
-
-/* ---------- Ioctls ---------- */
-
-/*
- * Ioctl subroutines can safely be made inline, because they are called
- * only from cosa_ioctl().
- */
-static inline int cosa_reset(struct cosa_data *cosa)
-{
-	char idstring[COSA_MAX_ID_STRING];
-	if (cosa->usage > 1)
-		printk(KERN_INFO "cosa%d: WARNING: reset requested with cosa->usage > 1 (%d). Odd things may happen.\n",
-			cosa->num, cosa->usage);
-	if (cosa_reset_and_read_id(cosa, idstring) < 0) {
-		printk(KERN_NOTICE "cosa%d: reset failed\n", cosa->num);
-		return -EIO;
-	}
-	printk(KERN_INFO "cosa%d: resetting device: %s\n", cosa->num,
-		idstring);
-	return 0;
-}
-
-/* High-level function to download data into COSA memory. Calls download() */
-static inline int cosa_download(struct cosa_data *cosa, struct cosa_download *d)
-{
-	int i;
-	int addr, len;
-	char *code;
-
-	if (cosa->usage > 1)
-		printk(KERN_INFO "cosa%d: WARNING: download of microcode requested with cosa->usage > 1 (%d). Odd things may happen.\n",
-			cosa->num, cosa->usage);
-#if 0
-	if (cosa->status != CARD_STATUS_RESETED && cosa->status != CARD_STATUS_DOWNLOADED) {
-		printk(KERN_NOTICE "cosa%d: reset the card first (status %d).\n",
-			cosa->num, cosa->status);
-		return -EPERM;
-	}
-#endif
-	get_user_ret(addr, &(d->addr), -EFAULT);
-	get_user_ret(len, &(d->len), -EFAULT);
-	get_user_ret(code, &(d->code), -EFAULT);
-
-	if (d->addr < 0 || d->addr > COSA_MAX_FIRMWARE_SIZE)
-		return -EINVAL;
-	if (d->len < 0 || d->len > COSA_MAX_FIRMWARE_SIZE)
-		return -EINVAL;
-
-	if ((i=download(cosa, d->code, len, addr)) < 0) {
-		printk(KERN_NOTICE "cosa%d: microcode download failed: %d\n",
-			cosa->num, i);
-		return -EIO;
-	}
-	printk(KERN_INFO "cosa%d: downloading microcode - 0x%04x bytes at 0x%04x\n",
-		cosa->num, len, addr);
-	return 0;
-}
-
-/* High-level function to read COSA memory. Calls readmem() */
-static inline int cosa_readmem(struct cosa_data *cosa, struct cosa_download *d)
-{
-	int i;
-	int addr, len;
-	char *code;
-
-	if (cosa->usage > 1)
-		printk(KERN_INFO "cosa%d: WARNING: readmem requested with "
-			"cosa->usage > 1 (%d). Odd things may happen.\n",
-			cosa->num, cosa->usage);
-#if 0
-	if (cosa->status != CARD_STATUS_RESETED &&
-		cosa->status != CARD_STATUS_DOWNLOADED) {
-		printk(KERN_NOTICE "cosa%d: reset the card first (status %d).\n",
-			cosa->num, cosa->status);
-		return -EPERM;
-	}
-#endif
-	get_user_ret(addr, &(d->addr), -EFAULT);
-	get_user_ret(len, &(d->len), -EFAULT);
-	get_user_ret(code, &(d->code), -EFAULT);
-
-	if ((i=readmem(cosa, d->code, len, addr)) < 0) {
-		printk(KERN_NOTICE "cosa%d: reading memory failed: %d\n",
-			cosa->num, i);
-		return -EIO;
-	}
-	printk(KERN_INFO "cosa%d: reading card memory - 0x%04x bytes at 0x%04x\n",
-		cosa->num, len, addr);
-	return 0;
-}
-
-/* High-level function to start microcode. Calls startmicrocode(). */
-static inline int cosa_start(struct cosa_data *cosa, int address)
-{
-	int i;
-
-	if (cosa->usage > 1)
-		printk(KERN_INFO "cosa%d: WARNING: start microcode requested with cosa->usage > 1 (%d). Odd things may happen.\n",
-			cosa->num, cosa->usage);
-#if 0
-	if (cosa->status != CARD_STATUS_DOWNLOADED) {
-		printk(KERN_NOTICE "cosa%d: download the microcode first (status %d).\n",
-			cosa->num, cosa->status);
-		return -EPERM;
-	}
-#endif
-	if ((i=startmicrocode(cosa, address)) < 0) {
-		printk(KERN_NOTICE "cosa%d: start microcode at 0x%04x failed: %d\n",
-			cosa->num, address, i);
-		return -EIO;
-	}
-	printk(KERN_INFO "cosa%d: starting microcode at 0x%04x\n",
-		cosa->num, address);
-	cosa->startaddr = address;
-	return 0;
-}
-		
-/* Buffer of size at least COSA_MAX_ID_STRING is expected */
-static inline int cosa_getidstr(struct cosa_data *cosa, char *string)
-{
-	int l = strlen(cosa->id_string)+1;
-	copy_to_user_ret(string, cosa->id_string, l, -EFAULT);
-	return l;
-}
-
-/* Buffer of size at least COSA_MAX_ID_STRING is expected */
-static inline int cosa_gettype(struct cosa_data *cosa, char *string)
-{
-	int l = strlen(cosa->type)+1;
-	copy_to_user_ret(string, cosa->type, l, -EFAULT);
-	return l;
-}
-
-static int cosa_ioctl_common(struct cosa_data *cosa,
-	struct channel_data *channel, unsigned int cmd, unsigned long arg)
-{
-	switch(cmd) {
-	case COSAIORSET:	/* Reset the device */
-		if (!suser())
-			return -EACCES;
-		return cosa_reset(cosa);
-	case COSAIOSTRT:	/* Start the firmware */
-		if (!suser())
-			return -EACCES;
-		return cosa_start(cosa, arg);
-	case COSAIODOWNLD:	/* Download the firmware */
-		if (!suser())
-			return -EACCES;
-		return cosa_download(cosa, (struct cosa_download *)arg);
-	case COSAIORMEM:
-		if (!suser())
-			return -EACCES;
-		return cosa_readmem(cosa, (struct cosa_download *)arg);
-	case COSAIORTYPE:
-		return cosa_gettype(cosa, (char *)arg);
-	case COSAIORIDSTR:
-		return cosa_getidstr(cosa, (char *)arg);
-/*
- * These two are _very_ugly_hack_(tm). Don't even look at this.
- * Implementing this saved me few reboots after some process segfaulted
- * inside this module.
- */
-#ifdef MODULE
-#if 0
-	case COSAIOMINC:
-		MOD_INC_USE_COUNT;
-		return 0;
-	case COSAIOMDEC:
-		MOD_DEC_USE_COUNT;
-		return 0;
-#endif
-#endif
-	case COSAIONRCARDS:
-		return nr_cards;
-	case COSAIONRCHANS:
-		return cosa->nchannels;
-	case COSAIOBMSET:
-		if (!suser())
-			return -EACCES;
-		if (is_8bit(cosa))
-			return -EINVAL;
-		if (arg != COSA_BM_OFF && arg != COSA_BM_ON)
-			return -EINVAL;
-		cosa->busmaster = arg;
-		return 0;
-	case COSAIOBMGET:
-		return cosa->busmaster;
-	}
-	return -ENOIOCTLCMD;
-}
-
-static int cosa_sppp_ioctl(struct net_device *dev, struct ifreq *ifr,
-	int cmd)
-{
-	int rv;
-	struct channel_data *chan = (struct channel_data *)dev->priv;
-	rv = cosa_ioctl_common(chan->cosa, chan, cmd, (int)ifr->ifr_data);
-	if (rv == -ENOIOCTLCMD) {
-		return sppp_do_ioctl(dev, ifr, cmd);
-	}
-	return rv;
-}
-
-static int cosa_chardev_ioctl(struct inode *inode, struct file *file,
-	unsigned int cmd, unsigned long arg)
-{
-	struct channel_data *channel = (struct channel_data *)file->private_data;
-	struct cosa_data *cosa = channel->cosa;
-	return cosa_ioctl_common(cosa, channel, cmd, arg);
-}
-
-
-/*---------- HW layer interface ---------- */
-
-/*
- * The higher layer can bind itself to the HW layer by setting the callbacks
- * in the channel_data structure and by using these routines.
- */
-static void cosa_enable_rx(struct channel_data *chan)
-{
-	struct cosa_data *cosa = chan->cosa;
-
-	if (!test_and_set_bit(chan->num, &cosa->rxbitmap))
-		put_driver_status(cosa);
-}
-
-static void cosa_disable_rx(struct channel_data *chan)
-{
-	struct cosa_data *cosa = chan->cosa;
-
-	if (test_and_clear_bit(chan->num, &cosa->rxbitmap))
-		put_driver_status(cosa);
-}
-
-/*
- * FIXME: This routine probably should check for cosa_start_tx() called when
- * the previous transmit is still unfinished. In this case the non-zero
- * return value should indicate to the caller that the queuing(sp?) up
- * the transmit has failed.
- */
-static int cosa_start_tx(struct channel_data *chan, char *buf, int len)
-{
-	struct cosa_data *cosa = chan->cosa;
-	int flags;
-#ifdef DEBUG_DATA
-	int i;
-
-	printk(KERN_INFO "cosa%dc%d: starting tx(0x%x)", chan->cosa->num,
-		chan->num, len);
-	for (i=0; i<len; i++)
-		printk(" %02x", buf[i]&0xff);
-	printk("\n");
-#endif
-	spin_lock_irqsave(&cosa->lock, flags);
-	chan->txbuf = buf;
-	chan->txsize = len;
-	if (len > COSA_MTU)
-		chan->txsize = COSA_MTU;
-	spin_unlock_irqrestore(&cosa->lock, flags);
-
-	/* Tell the firmware we are ready */
-	set_bit(chan->num, &cosa->txbitmap);
-	put_driver_status(cosa);
-
-	return 0;
-}
-
-static void put_driver_status(struct cosa_data *cosa)
-{
-	unsigned flags=0;
-	int status;
-
-	spin_lock_irqsave(&cosa->lock, flags);
-
-	status = (cosa->rxbitmap ? DRIVER_RX_READY : 0)
-		| (cosa->txbitmap ? DRIVER_TX_READY : 0)
-		| (cosa->txbitmap? ~(cosa->txbitmap<<DRIVER_TXMAP_SHIFT)
-			&DRIVER_TXMAP_MASK : 0);
-	if (!cosa->rxtx) {
-		if (cosa->rxbitmap|cosa->txbitmap) {
-			if (!cosa->enabled) {
-				cosa_putstatus(cosa, SR_RX_INT_ENA);
-#ifdef DEBUG_IO
-				debug_status_out(cosa, SR_RX_INT_ENA);
-#endif
-				cosa->enabled = 1;
-			}
-		} else if (cosa->enabled) {
-			cosa->enabled = 0;
-			cosa_putstatus(cosa, 0);
-#ifdef DEBUG_IO
-			debug_status_out(cosa, 0);
-#endif
-		}
-		cosa_putdata8(cosa, status);
-#ifdef DEBUG_IO
-		debug_data_cmd(cosa, status);
-#endif
-	}
-	spin_unlock_irqrestore(&cosa->lock, flags);
-}
-
-static void put_driver_status_nolock(struct cosa_data *cosa)
-{
-	int status;
-
-	status = (cosa->rxbitmap ? DRIVER_RX_READY : 0)
-		| (cosa->txbitmap ? DRIVER_TX_READY : 0)
-		| (cosa->txbitmap? ~(cosa->txbitmap<<DRIVER_TXMAP_SHIFT)
-			&DRIVER_TXMAP_MASK : 0);
-
-	if (cosa->rxbitmap|cosa->txbitmap) {
-		cosa_putstatus(cosa, SR_RX_INT_ENA);
-#ifdef DEBUG_IO
-		debug_status_out(cosa, SR_RX_INT_ENA);
-#endif
-		cosa->enabled = 1;
-	} else {
-		cosa_putstatus(cosa, 0);
-#ifdef DEBUG_IO
-		debug_status_out(cosa, 0);
-#endif
-		cosa->enabled = 0;
-	}
-	cosa_putdata8(cosa, status);
-#ifdef DEBUG_IO
-	debug_data_cmd(cosa, status);
-#endif
-}
-
-/*
- * The "kickme" function: When the DMA times out, this is called to
- * clean up the driver status.
- * FIXME: Preliminary support, the interface is probably wrong.
- */
-static void cosa_kick(struct cosa_data *cosa)
-{
-	unsigned flags, flags1;
-	char *s = "Unknown";
-
-	if (test_bit(RXBIT, &cosa->rxtx))
-		s = "RX";
-	if (test_bit(TXBIT, &cosa->rxtx))
-		s = "TX";
-
-	printk(KERN_INFO "%s: %s DMA timeout - restarting.\n", cosa->name, s); 
-	spin_lock_irqsave(&cosa->lock, flags);
-	cosa->rxtx = 0;
-
-	flags1 = claim_dma_lock();
-	disable_dma(cosa->dma);
-	clear_dma_ff(cosa->dma);
-	release_dma_lock(flags1);
-
-	/* FIXME: Anything else? */
-	udelay(100);
-	cosa_putstatus(cosa, 0);
-	udelay(100);
-	(void) cosa_getdata8(cosa);
-	udelay(100);
-	cosa_putdata8(cosa, 0);
-	udelay(100);
-	put_driver_status_nolock(cosa);
-	spin_unlock_irqrestore(&cosa->lock, flags);
-}
-
-/*
- * Check if the whole buffer is DMA-able. It means it is below the 16M of
- * physical memory and doesn't span the 64k boundary. For now it seems
- * SKB's never do this, but we'll check this anyway.
- */
-static int cosa_dma_able(struct channel_data *chan, char *buf, int len)
-{
-	static int count = 0;
-	unsigned long b = (unsigned long)buf;
-	if (b+len >= MAX_DMA_ADDRESS)
-		return 0;
-	if ((b^ (b+len)) & 0x10000) {
-		if (count++ < 5)
-			printk(KERN_INFO "%s: packet spanning a 64k boundary\n",
-				chan->name);
-		return 0;
-	}
-	return 1;
-}
-
-
-/* ---------- The SRP/COSA ROM monitor functions ---------- */
-
-/*
- * Downloading SRP microcode: say "w" to SRP monitor, it answers by "w=",
- * drivers need to say 4-digit hex number meaning start address of the microcode
- * separated by a single space. Monitor replies by saying " =". Now driver
- * has to write 4-digit hex number meaning the last byte address ended
- * by a single space. Monitor has to reply with a space. Now the download
- * begins. After the download monitor replies with "\r\n." (CR LF dot).
- */
-static int download(struct cosa_data *cosa, char *microcode, int length, int address)
-{
-	int i;
-
-	if (put_wait_data(cosa, 'w') == -1) return -1;
-	if ((i=get_wait_data(cosa)) != 'w') { printk("dnld: 0x%04x\n",i); return -2;}
-	if (get_wait_data(cosa) != '=') return -3;
-
-	if (puthexnumber(cosa, address) < 0) return -4;
-	if (put_wait_data(cosa, ' ') == -1) return -10;
-	if (get_wait_data(cosa) != ' ') return -11;
-	if (get_wait_data(cosa) != '=') return -12;
-
-	if (puthexnumber(cosa, address+length-1) < 0) return -13;
-	if (put_wait_data(cosa, ' ') == -1) return -18;
-	if (get_wait_data(cosa) != ' ') return -19;
-
-	while (length--) {
-		char c;
-#ifndef SRP_DOWNLOAD_AT_BOOT
-		get_user_ret(c,microcode, -23);
-#else
-		c = *microcode;
-#endif
-		if (put_wait_data(cosa, c) == -1)
-			return -20;
-		microcode++;
-	}
-
-	if (get_wait_data(cosa) != '\r') return -21;
-	if (get_wait_data(cosa) != '\n') return -22;
-	if (get_wait_data(cosa) != '.') return -23;
-#if 0
-	printk(KERN_DEBUG "cosa%d: download completed.\n", cosa->num);
-#endif
-	return 0;
-}
-
-
-/*
- * Starting microcode is done via the "g" command of the SRP monitor.
- * The chat should be the following: "g" "g=" "<addr><CR>"
- * "<CR><CR><LF><CR><LF>".
- */
-static int startmicrocode(struct cosa_data *cosa, int address)
-{
-	if (put_wait_data(cosa, 'g') == -1) return -1;
-	if (get_wait_data(cosa) != 'g') return -2;
-	if (get_wait_data(cosa) != '=') return -3;
-
-	if (puthexnumber(cosa, address) < 0) return -4;
-	if (put_wait_data(cosa, '\r') == -1) return -5;
-	
-	if (get_wait_data(cosa) != '\r') return -6;
-	if (get_wait_data(cosa) != '\r') return -7;
-	if (get_wait_data(cosa) != '\n') return -8;
-	if (get_wait_data(cosa) != '\r') return -9;
-	if (get_wait_data(cosa) != '\n') return -10;
-#if 0
-	printk(KERN_DEBUG "cosa%d: microcode started\n", cosa->num);
-#endif
-	return 0;
-}
-
-/*
- * Reading memory is done via the "r" command of the SRP monitor.
- * The chat is the following "r" "r=" "<addr> " " =" "<last_byte> " " "
- * Then driver can read the data and the conversation is finished
- * by SRP monitor sending "<CR><LF>." (dot at the end).
- *
- * This routine is not needed during the normal operation and serves
- * for debugging purposes only.
- */
-static int readmem(struct cosa_data *cosa, char *microcode, int length, int address)
-{
-	if (put_wait_data(cosa, 'r') == -1) return -1;
-	if ((get_wait_data(cosa)) != 'r') return -2;
-	if ((get_wait_data(cosa)) != '=') return -3;
-
-	if (puthexnumber(cosa, address) < 0) return -4;
-	if (put_wait_data(cosa, ' ') == -1) return -5;
-	if (get_wait_data(cosa) != ' ') return -6;
-	if (get_wait_data(cosa) != '=') return -7;
-
-	if (puthexnumber(cosa, address+length-1) < 0) return -8;
-	if (put_wait_data(cosa, ' ') == -1) return -9;
-	if (get_wait_data(cosa) != ' ') return -10;
-
-	while (length--) {
-		char c;
-		int i;
-		if ((i=get_wait_data(cosa)) == -1) {
-			printk (KERN_INFO "cosa: 0x%04x bytes remaining\n",
-				length);
-			return -11;
-		}
-		c=i;
-#if 1
-		put_user_ret(c,microcode, -23);
-#else
-		*microcode = c;
-#endif
-		microcode++;
-	}
-
-	if (get_wait_data(cosa) != '\r') return -21;
-	if (get_wait_data(cosa) != '\n') return -22;
-	if (get_wait_data(cosa) != '.') return -23;
-#if 0
-	printk(KERN_DEBUG "cosa%d: readmem completed.\n", cosa->num);
-#endif
-	return 0;
-}
-
-/*
- * This function resets the device and reads the initial prompt
- * of the device's ROM monitor.
- */
-static int cosa_reset_and_read_id(struct cosa_data *cosa, char *idstring)
-{
-	int i=0, id=0, prev=0, curr=0;
-
-	/* Reset the card ... */
-	cosa_putstatus(cosa, 0);
-	cosa_getdata8(cosa);
-	cosa_putstatus(cosa, SR_RST);
-#ifdef MODULE
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(HZ/2);
-	current->state = TASK_RUNNING;
-#else
-	udelay(5*100000);
-#endif
-	/* Disable all IRQs from the card */
-	cosa_putstatus(cosa, 0);
-
-	/*
-	 * Try to read the ID string. The card then prints out the
-	 * identification string ended by the "\n\x2e".
-	 *
-	 * The following loop is indexed through i (instead of id)
-	 * to avoid looping forever when for any reason
-	 * the port returns '\r', '\n' or '\x2e' permanently.
-	 */
-	for (i=0; i<COSA_MAX_ID_STRING-1; i++, prev=curr) {
-		if ((curr = get_wait_data(cosa)) == -1) {
-			return -1;
-		}
-		curr &= 0xff;
-		if (curr != '\r' && curr != '\n' && curr != 0x2e)
-			idstring[id++] = curr;
-		if (curr == 0x2e && prev == '\n')
-			break;
-	}
-	/* Perhaps we should fail when i==COSA_MAX_ID_STRING-1 ? */
-	idstring[id] = '\0';
-	return id;
-}
-
-
-/* ---------- Auxiliary routines for COSA/SRP monitor ---------- */
-
-/*
- * This routine gets the data byte from the card waiting for the SR_RX_RDY
- * bit to be set in a loop. It should be used in the exceptional cases
- * only (for example when resetting the card or downloading the firmware.
- */
-static int get_wait_data(struct cosa_data *cosa)
-{
-	int retries = 1000;
-
-	while (--retries) {
-		/* read data and return them */
-		if (cosa_getstatus(cosa) & SR_RX_RDY) {
-			short r;
-			r = cosa_getdata8(cosa);
-#if 0
-			printk(KERN_INFO "cosa: get_wait_data returning after %d retries\n", 999-retries);
-#endif
-			return r;
-		}
-		/* sleep if not ready to read */
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(1);
-	}
-	printk(KERN_INFO "cosa: timeout in get_wait_data (status 0x%x)\n",
-		cosa_getstatus(cosa));
-	return -1;
-}
-
-/*
- * This routine puts the data byte to the card waiting for the SR_TX_RDY
- * bit to be set in a loop. It should be used in the exceptional cases
- * only (for example when resetting the card or downloading the firmware).
- */
-static int put_wait_data(struct cosa_data *cosa, int data)
-{
-	int retries = 1000;
-	while (--retries) {
-		/* read data and return them */
-		if (cosa_getstatus(cosa) & SR_TX_RDY) {
-			cosa_putdata8(cosa, data);
-#if 0
-			printk(KERN_INFO "Putdata: %d retries\n", 999-retries);
-#endif
-			return 0;
-		}
-#if 0
-		/* sleep if not ready to read */
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(1);
-#endif
-	}
-	printk(KERN_INFO "cosa%d: timeout in put_wait_data (status 0x%x)\n",
-		cosa->num, cosa_getstatus(cosa));
-	return -1;
-}
-	
-/* 
- * The following routine puts the hexadecimal number into the SRP monitor
- * and verifies the proper echo of the sent bytes. Returns 0 on success,
- * negative number on failure (-1,-3,-5,-7) means that put_wait_data() failed,
- * (-2,-4,-6,-8) means that reading echo failed.
- */
-static int puthexnumber(struct cosa_data *cosa, int number)
-{
-	char temp[5];
-	int i;
-
-	/* Well, I should probably replace this by something faster. */
-	sprintf(temp, "%04X", number);
-	for (i=0; i<4; i++) {
-		if (put_wait_data(cosa, temp[i]) == -1) {
-			printk(KERN_NOTICE "cosa%d: puthexnumber failed to write byte %d\n",
-				cosa->num, i);
-			return -1-2*i;
-		}
-		if (get_wait_data(cosa) != temp[i]) {
-			printk(KERN_NOTICE "cosa%d: puthexhumber failed to read echo of byte %d\n",
-				cosa->num, i);
-			return -2-2*i;
-		}
-	}
-	return 0;
-}
-
-
-/* ---------- Interrupt routines ---------- */
-
-/*
- * There are three types of interrupt:
- * At the beginning of transmit - this handled is in tx_interrupt(),
- * at the beginning of receive - it is in rx_interrupt() and
- * at the end of transmit/receive - it is the eot_interrupt() function.
- * These functions are multiplexed by cosa_interrupt() according to the
- * COSA status byte. I have moved the rx/tx/eot interrupt handling into
- * separate functions to make it more readable. These functions are inline,
- * so there should be no overhead of function call.
- * 
- * In the COSA bus-master mode, we need to tell the card the address of a
- * buffer. Unfortunately, COSA may be too slow for us, so we must busy-wait.
- * It's time to use the bottom half :-(
- */
-
-/*
- * Transmit interrupt routine - called when COSA is willing to obtain
- * data from the OS. The most tricky part of the routine is selection
- * of channel we (OS) want to send packet for. For SRP we should probably
- * use the round-robin approach. The newer COSA firmwares have a simple
- * flow-control - in the status word has bits 2 and 3 set to 1 means that the
- * channel 0 or 1 doesn't want to receive data.
- *
- * It seems there is a bug in COSA firmware (need to trace it further):
- * When the driver status says that the kernel has no more data for transmit
- * (e.g. at the end of TX DMA) and then the kernel changes its mind
- * (e.g. new packet is queued to hard_start_xmit()), the card issues
- * the TX interrupt but does not mark the channel as ready-to-transmit.
- * The fix seems to be to push the packet to COSA despite its request.
- * We first try to obey the card's opinion, and then fall back to forced TX.
- */
-static inline void tx_interrupt(struct cosa_data *cosa, int status)
-{
-	unsigned long flags, flags1;
-#ifdef DEBUG_IRQS
-	printk(KERN_INFO "cosa%d: SR_DOWN_REQUEST status=0x%04x\n",
-		cosa->num, status);
-#endif
-	spin_lock_irqsave(&cosa->lock, flags);
-	set_bit(TXBIT, &cosa->rxtx);
-	if (!test_bit(IRQBIT, &cosa->rxtx)) {
-		/* flow control, see the comment above */
-		int i=0;
-		if (!cosa->txbitmap) {
-			printk(KERN_WARNING "%s: No channel wants data "
-				"in TX IRQ. Expect DMA timeout.",
-				cosa->name);
-			put_driver_status_nolock(cosa);
-			clear_bit(TXBIT, &cosa->rxtx);
-			spin_unlock_irqrestore(&cosa->lock, flags);
-			return;
-		}
-		while(1) {
-			cosa->txchan++;
-			i++;
-			if (cosa->txchan >= cosa->nchannels)
-				cosa->txchan = 0;
-			if (!(cosa->txbitmap & (1<<cosa->txchan)))
-				continue;
-			if (~status & (1 << (cosa->txchan+DRIVER_TXMAP_SHIFT)))
-				break;
-			/* in second pass, accept first ready-to-TX channel */
-			if (i > cosa->nchannels) {
-				/* Can be safely ignored */
-				printk(KERN_DEBUG "%s: Forcing TX "
-					"to not-ready channel %d\n",
-					cosa->name, cosa->txchan);
-				break;
-			}
-		}
-
-		cosa->txsize = cosa->chan[cosa->txchan].txsize;
-		if (cosa_dma_able(cosa->chan+cosa->txchan,
-			cosa->chan[cosa->txchan].txbuf, cosa->txsize)) {
-			cosa->txbuf = cosa->chan[cosa->txchan].txbuf;
-		} else {
-			memcpy(cosa->bouncebuf, cosa->chan[cosa->txchan].txbuf,
-				cosa->txsize);
-			cosa->txbuf = cosa->bouncebuf;
-		}
-	}
-
-	if (is_8bit(cosa)) {
-		if (!test_bit(IRQBIT, &cosa->rxtx)) {
-			cosa_putstatus(cosa, SR_TX_INT_ENA);
-			cosa_putdata8(cosa, ((cosa->txchan << 5) & 0xe0)|
-				((cosa->txsize >> 8) & 0x1f));
-#ifdef DEBUG_IO
-			debug_status_out(cosa, SR_TX_INT_ENA);
-			debug_data_out(cosa, ((cosa->txchan << 5) & 0xe0)|
-                                ((cosa->txsize >> 8) & 0x1f));
-			debug_data_in(cosa, cosa_getdata8(cosa));
-#else
-			cosa_getdata8(cosa);
-#endif
-			set_bit(IRQBIT, &cosa->rxtx);
-			spin_unlock_irqrestore(&cosa->lock, flags);
-			return;
-		} else {
-			clear_bit(IRQBIT, &cosa->rxtx);
-			cosa_putstatus(cosa, 0);
-			cosa_putdata8(cosa, cosa->txsize&0xff);
-#ifdef DEBUG_IO
-			debug_status_out(cosa, 0);
-			debug_data_out(cosa, cosa->txsize&0xff);
-#endif
-		}
-	} else {
-		cosa_putstatus(cosa, SR_TX_INT_ENA);
-		cosa_putdata16(cosa, ((cosa->txchan<<13) & 0xe000)
-			| (cosa->txsize & 0x1fff));
-#ifdef DEBUG_IO
-		debug_status_out(cosa, SR_TX_INT_ENA);
-		debug_data_out(cosa, ((cosa->txchan<<13) & 0xe000)
-                        | (cosa->txsize & 0x1fff));
-		debug_data_in(cosa, cosa_getdata8(cosa));
-		debug_status_out(cosa, 0);
-#else
-		cosa_getdata8(cosa);
-#endif
-		cosa_putstatus(cosa, 0);
-	}
-
-	if (cosa->busmaster) {
-		unsigned long addr = virt_to_bus(cosa->txbuf);
-		int count=0;
-		printk(KERN_INFO "busmaster IRQ\n");
-		while (!(cosa_getstatus(cosa)&SR_TX_RDY)) {
-			count++;
-			udelay(10);
-			if (count > 1000) break;
-		}
-		printk(KERN_INFO "status %x\n", cosa_getstatus(cosa));
-		printk(KERN_INFO "ready after %d loops\n", count);
-		cosa_putdata16(cosa, (addr >> 16)&0xffff);
-
-		count = 0;
-		while (!(cosa_getstatus(cosa)&SR_TX_RDY)) {
-			count++;
-			if (count > 1000) break;
-			udelay(10);
-		}
-		printk(KERN_INFO "ready after %d loops\n", count);
-		cosa_putdata16(cosa, addr &0xffff);
-		flags1 = claim_dma_lock();
-		set_dma_mode(cosa->dma, DMA_MODE_CASCADE);
-		enable_dma(cosa->dma);
-		release_dma_lock(flags1);
-	} else {
-		/* start the DMA */
-		flags1 = claim_dma_lock();
-		disable_dma(cosa->dma);
-		clear_dma_ff(cosa->dma);
-		set_dma_mode(cosa->dma, DMA_MODE_WRITE);
-		set_dma_addr(cosa->dma, virt_to_bus(cosa->txbuf));
-		set_dma_count(cosa->dma, cosa->txsize);
-		enable_dma(cosa->dma);
-		release_dma_lock(flags1);
-	}
-	cosa_putstatus(cosa, SR_TX_DMA_ENA|SR_USR_INT_ENA);
-#ifdef DEBUG_IO
-	debug_status_out(cosa, SR_TX_DMA_ENA|SR_USR_INT_ENA);
-#endif
-	spin_unlock_irqrestore(&cosa->lock, flags);
-}
-
-static inline void rx_interrupt(struct cosa_data *cosa, int status)
-{
-	unsigned long flags;
-#ifdef DEBUG_IRQS
-	printk(KERN_INFO "cosa%d: SR_UP_REQUEST\n", cosa->num);
-#endif
-
-	spin_lock_irqsave(&cosa->lock, flags);
-	set_bit(RXBIT, &cosa->rxtx);
-
-	if (is_8bit(cosa)) {
-		if (!test_bit(IRQBIT, &cosa->rxtx)) {
-			set_bit(IRQBIT, &cosa->rxtx);
-			put_driver_status_nolock(cosa);
-			cosa->rxsize = cosa_getdata8(cosa) <<8;
-#ifdef DEBUG_IO
-			debug_data_in(cosa, cosa->rxsize >> 8);
-#endif
-			spin_unlock_irqrestore(&cosa->lock, flags);
-			return;
-		} else {
-			clear_bit(IRQBIT, &cosa->rxtx);
-			cosa->rxsize |= cosa_getdata8(cosa) & 0xff;
-#ifdef DEBUG_IO
-			debug_data_in(cosa, cosa->rxsize & 0xff);
-#endif
-#if 0
-			printk(KERN_INFO "cosa%d: receive rxsize = (0x%04x).\n",
-				cosa->num, cosa->rxsize);
-#endif
-		}
-	} else {
-		cosa->rxsize = cosa_getdata16(cosa);
-#ifdef DEBUG_IO
-		debug_data_in(cosa, cosa->rxsize);
-#endif
-#if 0
-		printk(KERN_INFO "cosa%d: receive rxsize = (0x%04x).\n",
-			cosa->num, cosa->rxsize);
-#endif
-	}
-	if (((cosa->rxsize & 0xe000) >> 13) >= cosa->nchannels) {
-		printk(KERN_WARNING "%s: rx for unknown channel (0x%04x)\n",
-			cosa->name, cosa->rxsize);
-		spin_unlock_irqrestore(&cosa->lock, flags);
-		goto reject;
-	}
-	cosa->rxchan = cosa->chan + ((cosa->rxsize & 0xe000) >> 13);
-	cosa->rxsize &= 0x1fff;
-	spin_unlock_irqrestore(&cosa->lock, flags);
-
-	cosa->rxbuf = NULL;
-	if (cosa->rxchan->setup_rx)
-		cosa->rxbuf = cosa->rxchan->setup_rx(cosa->rxchan, cosa->rxsize);
-
-	if (!cosa->rxbuf) {
-reject:		/* Reject the packet */
-		printk(KERN_INFO "cosa%d: rejecting packet on channel %d\n",
-			cosa->num, cosa->rxchan->num);
-		cosa->rxbuf = cosa->bouncebuf;
-	}
-
-	/* start the DMA */
-	flags = claim_dma_lock();
-	disable_dma(cosa->dma);
-	clear_dma_ff(cosa->dma);
-	set_dma_mode(cosa->dma, DMA_MODE_READ);
-	if (cosa_dma_able(cosa->rxchan, cosa->rxbuf, cosa->rxsize & 0x1fff)) {
-		set_dma_addr(cosa->dma, virt_to_bus(cosa->rxbuf));
-	} else {
-		set_dma_addr(cosa->dma, virt_to_bus(cosa->bouncebuf));
-	}
-	set_dma_count(cosa->dma, (cosa->rxsize&0x1fff));
-	enable_dma(cosa->dma);
-	release_dma_lock(flags);
-	spin_lock_irqsave(&cosa->lock, flags);
-	cosa_putstatus(cosa, SR_RX_DMA_ENA|SR_USR_INT_ENA);
-	if (!is_8bit(cosa) && (status & SR_TX_RDY))
-		cosa_putdata8(cosa, DRIVER_RX_READY);
-#ifdef DEBUG_IO
-	debug_status_out(cosa, SR_RX_DMA_ENA|SR_USR_INT_ENA);
-	if (!is_8bit(cosa) && (status & SR_TX_RDY))
-		debug_data_cmd(cosa, DRIVER_RX_READY);
-#endif
-	spin_unlock_irqrestore(&cosa->lock, flags);
-}
-
-static void inline eot_interrupt(struct cosa_data *cosa, int status)
-{
-	unsigned long flags, flags1;
-	spin_lock_irqsave(&cosa->lock, flags);
-	flags1 = claim_dma_lock();
-	disable_dma(cosa->dma);
-	clear_dma_ff(cosa->dma);
-	release_dma_lock(flags1);
-	if (test_bit(TXBIT, &cosa->rxtx)) {
-		struct channel_data *chan = cosa->chan+cosa->txchan;
-		if (chan->tx_done)
-			if (chan->tx_done(chan, cosa->txsize))
-				clear_bit(chan->num, &cosa->txbitmap);
-	} else if (test_bit(RXBIT, &cosa->rxtx)) {
-#ifdef DEBUG_DATA
-	{
-		int i;
-		printk(KERN_INFO "cosa%dc%d: done rx(0x%x)", cosa->num, 
-			cosa->rxchan->num, cosa->rxsize);
-		for (i=0; i<cosa->rxsize; i++)
-			printk (" %02x", cosa->rxbuf[i]&0xff);
-		printk("\n");
-	}
-#endif
-		/* Packet for unknown channel? */
-		if (cosa->rxbuf == cosa->bouncebuf)
-			goto out;
-		if (!cosa_dma_able(cosa->rxchan, cosa->rxbuf, cosa->rxsize))
-			memcpy(cosa->rxbuf, cosa->bouncebuf, cosa->rxsize);
-		if (cosa->rxchan->rx_done)
-			if (cosa->rxchan->rx_done(cosa->rxchan))
-				clear_bit(cosa->rxchan->num, &cosa->rxbitmap);
-	} else {
-		printk(KERN_NOTICE "cosa%d: unexpected EOT interrupt\n",
-			cosa->num);
-	}
-	/*
-	 * Clear the RXBIT, TXBIT and IRQBIT (the latest should be
-	 * cleared anyway). We should do it as soon as possible
-	 * so that we can tell the COSA we are done and to give it a time
-	 * for recovery.
-	 */
-out:
-	cosa->rxtx = 0;
-	put_driver_status_nolock(cosa);
-	spin_unlock_irqrestore(&cosa->lock, flags);
-}
-
-static void cosa_interrupt(int irq, void *cosa_, struct pt_regs *regs)
-{
-	unsigned status;
-	int count = 0;
-	struct cosa_data *cosa = cosa_;
-again:
-	status = cosa_getstatus(cosa);
-#ifdef DEBUG_IRQS
-	printk(KERN_INFO "cosa%d: got IRQ, status 0x%02x\n", cosa->num,
-		status & 0xff);
-#endif
-#ifdef DEBUG_IO
-	debug_status_in(cosa, status);
-#endif
-	switch (status & SR_CMD_FROM_SRP_MASK) {
-	case SR_DOWN_REQUEST:
-		tx_interrupt(cosa, status);
-		break;
-	case SR_UP_REQUEST:
-		rx_interrupt(cosa, status);
-		break;
-	case SR_END_OF_TRANSFER:
-		eot_interrupt(cosa, status);
-		break;
-	default:
-		/* We may be too fast for SRP. Try to wait a bit more. */
-		if (count++ < 100) {
-			udelay(100);
-			goto again;
-		}
-		printk(KERN_INFO "cosa%d: unknown status 0x%02x in IRQ after %d retries\n",
-			cosa->num, status & 0xff, count);
-	}
-#ifdef DEBUG_IRQS
-	if (count)
-		printk(KERN_INFO "%s: %d-times got unknown status in IRQ\n",
-			cosa->name, count);
-	else
-		printk(KERN_INFO "%s: returning from IRQ\n", cosa->name);
-#endif
-}
-
-
-/* ---------- I/O debugging routines ---------- */
-/*
- * These routines can be used to monitor COSA/SRP I/O and to printk()
- * the data being transfered on the data and status I/O port in a
- * readable way.
- */
-
-#ifdef DEBUG_IO
-static void debug_status_in(struct cosa_data *cosa, int status)
-{
-	char *s;
-	switch(status & SR_CMD_FROM_SRP_MASK) {
-	case SR_UP_REQUEST:
-		s = "RX_REQ";
-		break;
-	case SR_DOWN_REQUEST:
-		s = "TX_REQ";
-		break;
-	case SR_END_OF_TRANSFER:
-		s = "ET_REQ";
-		break;
-	default:
-		s = "NO_REQ";
-		break;
-	}
-	printk(KERN_INFO "%s: IO: status -> 0x%02x (%s%s%s%s)\n",
-		cosa->name,
-		status,
-		status & SR_USR_RQ ? "USR_RQ|":"",
-		status & SR_TX_RDY ? "TX_RDY|":"",
-		status & SR_RX_RDY ? "RX_RDY|":"",
-		s);
-}
-
-static void debug_status_out(struct cosa_data *cosa, int status)
-{
-	printk(KERN_INFO "%s: IO: status <- 0x%02x (%s%s%s%s%s%s)\n",
-		cosa->name,
-		status,
-		status & SR_RX_DMA_ENA  ? "RXDMA|":"!rxdma|",
-		status & SR_TX_DMA_ENA  ? "TXDMA|":"!txdma|",
-		status & SR_RST         ? "RESET|":"",
-		status & SR_USR_INT_ENA ? "USRINT|":"!usrint|",
-		status & SR_TX_INT_ENA  ? "TXINT|":"!txint|",
-		status & SR_RX_INT_ENA  ? "RXINT":"!rxint");
-}
-
-static void debug_data_in(struct cosa_data *cosa, int data)
-{
-	printk(KERN_INFO "%s: IO: data -> 0x%04x\n", cosa->name, data);
-}
-
-static void debug_data_out(struct cosa_data *cosa, int data)
-{
-	printk(KERN_INFO "%s: IO: data <- 0x%04x\n", cosa->name, data);
-}
-
-static void debug_data_cmd(struct cosa_data *cosa, int data)
-{
-	printk(KERN_INFO "%s: IO: data <- 0x%04x (%s|%s)\n",
-		cosa->name, data,
-		data & SR_RDY_RCV ? "RX_RDY" : "!rx_rdy",
-		data & SR_RDY_SND ? "TX_RDY" : "!tx_rdy");
-}
-#endif
-
-/* EOF -- this file has not been truncated */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/cosa.h linux/drivers/net/cosa.h
--- v2.3.20/linux/drivers/net/cosa.h	Sun Mar  7 15:47:46 1999
+++ linux/drivers/net/cosa.h	Wed Dec 31 16:00:00 1969
@@ -1,111 +0,0 @@
-/* $Id: cosa.h,v 1.6 1999/01/06 14:02:44 kas Exp $ */
-
-/*
- *  Copyright (C) 1995-1997  Jan "Yenya" Kasprzak <kas@fi.muni.cz>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef COSA_H__
-#define COSA_H__
-
-#include <linux/ioctl.h>
-
-#ifdef __KERNEL__
-/* status register - output bits */
-#define SR_RX_DMA_ENA   0x04    /* receiver DMA enable bit */
-#define SR_TX_DMA_ENA   0x08    /* transmitter DMA enable bit */
-#define SR_RST          0x10    /* SRP reset */
-#define SR_USR_INT_ENA  0x20    /* user interrupt enable bit */
-#define SR_TX_INT_ENA   0x40    /* transmitter interrupt enable bit */
-#define SR_RX_INT_ENA   0x80    /* receiver interrupt enable bit */
-
-/* status register - input bits */
-#define SR_USR_RQ       0x20    /* user interupt request pending */
-#define SR_TX_RDY       0x40    /* transmitter empty (ready) */
-#define SR_RX_RDY       0x80    /* receiver data ready */
-
-#define SR_UP_REQUEST   0x02    /* request from SRP to transfer data
-                                   up to PC */
-#define SR_DOWN_REQUEST 0x01    /* SRP is able to transfer data down
-                                   from PC to SRP */
-#define SR_END_OF_TRANSFER      0x03    /* SRP signalize end of
-                                           transfer (up or down) */
-
-#define SR_CMD_FROM_SRP_MASK    0x03    /* mask to get SRP command */
-
-/* bits in driver status byte definitions : */
-#define SR_RDY_RCV      0x01    /* ready to receive packet */
-#define SR_RDY_SND      0x02    /* ready to send packet */
-#define SR_CMD_PND      0x04    /* command pending */ /* not currently used */
-
-/* ???? */
-#define SR_PKT_UP       0x01    /* transfer of packet up in progress */
-#define SR_PKT_DOWN     0x02    /* transfer of packet down in progress */
-
-#endif /* __KERNEL__ */
-
-#define SR_LOAD_ADDR    0x4400  /* SRP microcode load address */
-#define SR_START_ADDR   0x4400  /* SRP microcode start address */
-
-#define COSA_LOAD_ADDR    0x400  /* SRP microcode load address */
-#define COSA_MAX_FIRMWARE_SIZE	0x10000
-
-/* ioctls */
-struct cosa_download {
-	int addr, len;
-	char *code;
-};
-
-/* Reset the device */
-#define COSAIORSET	_IO('C',0xf0)
-
-/* Start microcode at given address */
-#define COSAIOSTRT	_IOW('C',0xf1,sizeof(int))
-
-/* Read the block from the device memory */
-#define COSAIORMEM	_IOR('C',0xf2,sizeof(struct cosa_download *))
-
-/* Write the block to the device memory (i.e. download the microcode) */
-#define COSAIODOWNLD	_IOW('C',0xf2,sizeof(struct cosa_download *))
-
-/* Read the device type (one of "srp", "cosa", and "cosa8" for now) */
-#define COSAIORTYPE	_IOR('C',0xf3,sizeof(char *))
-
-/* Read the device identification string */
-#define COSAIORIDSTR	_IOR('C',0xf4,sizeof(char *))
-/* Maximum length of the identification string. */
-#define COSA_MAX_ID_STRING 128
-
-/* Increment/decrement the module usage count :-) */
-/* #define COSAIOMINC	_IO('C',0xf5) */
-/* #define COSAIOMDEC	_IO('C',0xf6) */
-
-/* Get the total number of cards installed */
-#define COSAIONRCARDS	_IO('C',0xf7)
-
-/* Get the number of channels on this card */
-#define COSAIONRCHANS	_IO('C',0xf8)
-
-/* Set the driver for the bus-master operations */
-#define COSAIOBMSET	_IOW('C', 0xf9, sizeof(unsigned short))
-
-#define COSA_BM_OFF	0	/* Bus-mastering off - use ISA DMA (default) */
-#define COSA_BM_ON	1	/* Bus-mastering on - faster but untested */
-
-/* Gets the busmaster status */
-#define COSAIOBMGET	_IO('C', 0xfa)
-
-#endif /* !COSA_H__ */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/cycx_drv.c linux/drivers/net/cycx_drv.c
--- v2.3.20/linux/drivers/net/cycx_drv.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/net/cycx_drv.c	Wed Dec 31 16:00:00 1969
@@ -1,660 +0,0 @@
-/*
-* cycx_drv.c	cycx Support Module.
-*
-*		This module is a library of common hardware-specific
-*		functions used by all Cyclades sync and some async (8x & 16x)
-*		drivers.
-*
-* Copyright:	(c) 1998, 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
-*
-* Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
-*
-* Based on sdladrv.c by Gene Kozin <genek@compuserve.com>
-*
-*		This program is free software; you can redistribute it and/or
-*		modify it under the terms of the GNU General Public License
-*		as published by the Free Software Foundation; either version
-*		2 of the License, or (at your option) any later version.
-* ============================================================================
-* 1999/05/28    acme		cycx_intack & cycx_intde gone for good
-* 1999/05/18	acme		lots of unlogged work, submitting to Linus...
-* 1999/01/03	acme		more judicious use of data types
-* 1999/01/03	acme		judicious use of data types :>
-*				cycx_inten trying to reset pending interrupts
-*				from cyclom 2x - I think this isn't the way to
-*				go, but for now...
-* 1999/01/02	acme		cycx_intack ok, I think there's nothing to do
-*				to ack an int in cycx_drv.c, only handle it in
-*				cyx_isr (or in the other protocols: cyp_isr,
-*				cyf_isr, when they get implemented.
-* Dec 31, 1998	Arnaldo         cycx_data_boot & cycx_code_boot fixed, crossing
-*				fingers to see x25_configure in cycx_x25.c
-*				work... :)
-* Dec 26, 1998	Arnaldo         load implementation fixed, seems to work! :)
-*				cycx_2x_dpmbase_options with all the possible
-*				DPM addresses (20).
-*				cycx_intr implemented (test this!)
-*				general code cleanup
-* Dec  8, 1998	Ivan Passos	Cyclom-2X firmware load implementation.
-* Aug  8, 1998	Arnaldo		Initial version.
-*/
-
-#ifdef MODULE
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
-#include <linux/module.h>
-#else
-#define EXPORT_SYMBOL(function)
-#endif
-#include <linux/kernel.h>	/* printk(), and other useful stuff */
-#include <linux/stddef.h>	/* offsetof(), etc. */
-#include <linux/errno.h>	/* return codes */
-#include <linux/sched.h>	/* for jiffies, HZ, etc. */
-#include <linux/cycx_drv.h>	/* API definitions */
-#include <linux/cycx_cfm.h>	/* CYCX firmware module definitions */
-#include <linux/delay.h>	/* udelay */
-#include <asm/io.h>		/* for inb(), outb(), etc. */
-
-#define	MOD_VERSION	0
-#define	MOD_RELEASE	2
-
-#ifdef MODULE
-MODULE_AUTHOR("Arnaldo Carvalho de Melo");
-MODULE_DESCRIPTION("Cyclades Sync Cards Driver.");
-#endif
-
-/* Function Prototypes */
-/* Module entry points. These are called by the OS and must be public. */
-int init_module (void);
-void cleanup_module (void);
-
-/* Hardware-specific functions */
-static int cycx_detect (cycxhw_t *hw);
-static int cycx_load (cycxhw_t *hw, cfm_t *cfm, u32 len);
-static int cycx_init (cycxhw_t *hw);
-static int cycx_reset (cycxhw_t *hw);
-static void cycx_bootcfg (cycxhw_t *hw);
-
-static int init_cycx_2x (cycxhw_t *hw);
-static int reset_cycx_2x (u32 addr);
-static int detect_cycx_2x (u32 addr);
-
-/* Miscellaneous functions */
-static void delay_cycx (int sec);
-static int get_option_index (u32 *optlist, u32 optval);
-static u16 checksum (u8 *buf, u32 len);
-
-#define wait_cyc(addr) cycx_exec(addr + CMD_OFFSET)
-
-/* Global Data
- * Note: All data must be explicitly initialized!!! */
-
-/* private data */
-static char modname[] = "cycx_drv";
-static char fullname[] = "Cyclom X Support Module";
-static char copyright[]	= "(c) 1998, 1999 Arnaldo Carvalho de Melo";
-
-/* Hardware configuration options.
- * These are arrays of configuration options used by verification routines.
- * The first element of each array is its size (i.e. number of options).
- */
-static u32 cycx_2x_dpmbase_options[] =
-{
-	20,
-	0xA0000, 0xA4000, 0xA8000, 0xAC000, 0xB0000, 0xB4000, 0xB8000,
-	0xBC000, 0xC0000, 0xC4000, 0xC8000, 0xCC000, 0xD0000, 0xD4000,
-	0xD8000, 0xDC000, 0xE0000, 0xE4000, 0xE8000, 0xEC000
-};
-
-static u32 cycx_2x_irq_options[]  = { 7, 3, 5, 9, 10, 11, 12, 15 };
-
-/* Kernel Loadable Module Entry Points */
-/* Module 'insert' entry point.
- * o print announcement
- * o initialize static data
- *
- * Return:	0	Ok
- *		< 0	error.
- * Context:	process */
-#ifdef MODULE
-int init_module (void)
-{
-	printk(KERN_INFO "%s v%u.%u %s\n",
-		fullname, MOD_VERSION, MOD_RELEASE, copyright);
-	return 0;
-}
-/* Module 'remove' entry point.
- * o release all remaining system resources */
-void cleanup_module (void)
-{
-}
-#endif
-/* Kernel APIs */
-/* Set up adapter.
- * o detect adapter type
- * o verify hardware configuration options
- * o check for hardware conflicts
- * o set up adapter shared memory
- * o test adapter memory
- * o load firmware
- * Return:	0	ok.
- *		< 0	error */
-EXPORT_SYMBOL(cycx_setup);
-int cycx_setup (cycxhw_t *hw, void *cfm, u32 len)
-{
-	u32 *irq_opt = NULL;	/* IRQ options */
-	u32 *dpmbase_opt = NULL;/* DPM window base options */
-	int err = 0;
-
-	if (cycx_detect(hw)) {
-		printk(KERN_ERR "%s: adapter Cyclom %uX not found at "
-				"address 0x%lX!\n",
-			modname, hw->type, (unsigned long) hw->dpmbase);
-		return -EINVAL;
-	}
-
-	printk(KERN_INFO "%s: found Cyclom %uX card at address 0x%lx.\n",
-			 modname, hw->type, (unsigned long) hw->dpmbase);
-
-	switch (hw->type) {
-		case CYCX_2X:
-			irq_opt	= cycx_2x_irq_options;
-			dpmbase_opt = cycx_2x_dpmbase_options;
-			break;
-		default:
-			printk(KERN_ERR "%s: unknown card.\n", modname);
-			return -EINVAL;
-	}
-
-	/* Verify IRQ configuration options */
-	if (!get_option_index(irq_opt, hw->irq)) {
-		printk (KERN_ERR "%s: IRQ %d is illegal!\n", modname, hw->irq);
-		return -EINVAL;
-	} 
-
-	/* Setup adapter dual-port memory window and test memory */
-	if (!hw->dpmbase) {
-		printk(KERN_ERR "%s: you must specify the dpm address!\n",
-				modname);
- 		return -EINVAL;
-	}
-	else if (!get_option_index(dpmbase_opt, hw->dpmbase)) {
-		printk(KERN_ERR "%s: memory address 0x%lX is illegal!\n",
-				modname, (unsigned long) hw->dpmbase);
-		return -EINVAL;
-	}
-
-	hw->dpmsize = CYCX_WINDOWSIZE;
-	/* FIXME! Is this the only amount ever available? */
-	hw->memory = 0x40000;
-
-	cycx_init(hw);
-
-	printk(KERN_INFO "%s: dual-port memory window is set at 0x%lX.\n",
-			 modname, (unsigned long) hw->dpmbase);
-	printk(KERN_INFO "%s: found %luK bytes of on-board memory.\n",
-			 modname, (unsigned long) hw->memory / 1024);
-
-	/* Load firmware. If loader fails then shut down adapter */
-	err = cycx_load(hw, cfm, len);
-	if (err) cycx_down(hw);		/* shutdown adapter */
-	return err;
-} 
-
-/* Shut down CYCX: disable shared memory access and interrupts, stop CPU,etc.*/ 
-EXPORT_SYMBOL(cycx_down);
-int cycx_down (cycxhw_t *hw)
-{
-	return 0; /* FIXME: anything needed here? */
-}
-
-/* Enable interrupt generation.  */
-EXPORT_SYMBOL(cycx_inten);
-int cycx_inten (cycxhw_t *hw)
-{
-	switch (hw->type) {
-		case CYCX_2X: writeb (0, hw->dpmbase); break;
-		default: return -EINVAL;
-	}
-
-	return 0;
-}
-
-/* Generate an interrupt to adapter's CPU. */
-EXPORT_SYMBOL(cycx_intr);
-int cycx_intr (cycxhw_t *hw)
-{
-	switch (hw->type) {
-		case CYCX_2X:
-			writew(0, hw->dpmbase + GEN_CYCX_INTR);
-			return 0;
-		default: return -EINVAL;
-	}
-
-	return 0;
-}
-
-/* Execute Adapter Command.
- * o Set exec flag.
- * o Busy-wait until flag is reset. */
-EXPORT_SYMBOL(cycx_exec);
-int cycx_exec (u32 addr)
-{
-	u16 i = 0;
-	/* wait till addr content is zeroed */
-
-	while (readw(addr) != 0) {
-		udelay(1000);
-		if (++i > 50) return -1;
-	}
-
-	return 0;
-}
-
-/* Read absolute adapter memory.
- * Transfer data from adapter's memory to data buffer. */
-EXPORT_SYMBOL(cycx_peek);
-int cycx_peek (cycxhw_t *hw, u32 addr, void *buf, u32 len)
-{
-	if (len == 1)	*(u8*)buf = readb (hw->dpmbase + addr);
-	else 		memcpy_fromio(buf, hw->dpmbase + addr, len);
-
-	return 0;
-}
-
-/* Write Absolute Adapter Memory.
- * Transfer data from data buffer to adapter's memory. */
-EXPORT_SYMBOL(cycx_poke);
-int cycx_poke (cycxhw_t *hw, u32 addr, void *buf, u32 len)
-{
-	if (len == 1) writeb (*(u8*)buf, hw->dpmbase + addr);
-	else	      memcpy_toio(hw->dpmbase + addr, buf, len);
-
-	return 0;
-}
-
-/* Hardware-Specific Functions */
-/* Detect adapter type.
- * o if adapter type is specified then call detection routine for that adapter
- *   type.  Otherwise call detection routines for every adapter types until
- *   adapter is detected.
- *
- * Notes:
- * 1) Detection tests are destructive! Adapter will be left in shutdown state
- *    after the test. */
-static int cycx_detect (cycxhw_t *hw)
-{
-	int err = 0;
-
-	if (!hw->dpmbase) return -EFAULT;
-
-	switch (hw->type) {
-		case CYCX_2X:
-			if (!detect_cycx_2x(hw->dpmbase)) err = -ENODEV;
-			break;
-		default:
-			if (detect_cycx_2x(hw->dpmbase)) hw->type = CYCX_2X;
-			else err = -ENODEV;
-	}
-
-	return err;
-}
-
-/* Load Aux Routines */
-/* Reset board hardware.
-   return 1 if memory exists at addr and 0 if not. */
-static int memory_exists(u32 addr)
-{
-	int timeout = 0;
-
-	for (; timeout < 3 ; timeout++) {
-		writew (TEST_PATTERN, addr + 0x10);
-
-		if (readw (addr + 0x10) == TEST_PATTERN)
-			if (readw (addr + 0x10) == TEST_PATTERN) return 1;
-
-		delay_cycx(1);
-	}
-
-	return 0;
-}
-
-/* Reset board hardware. */
-static int cycx_reset(cycxhw_t *hw)
-{
-	/* Reset board */
-	switch (hw->type) {
-		case CYCX_2X: return reset_cycx_2x(hw->dpmbase);
-	}
-
-	return -EINVAL;
-}
-
-/* Load reset code. */
-static void reset_load(u32 addr, u8 *buffer, u32 cnt)
-{
-	u32 pt_code = addr + RESET_OFFSET;
-	u16 i, j;
-
-	for ( i = 0 ; i < cnt ; i++) {
-		for (j = 0 ; j < 50 ; j++); /* Delay - FIXME busy waiting... */
-		writeb(*buffer++, pt_code++);
-	}
-}
-
-/* Load buffer using boot interface.
- * o copy data from buffer to Cyclom-X memory
- * o wait for reset code to copy it to right portion of memory */
-static int buffer_load(u32 addr, u8 *buffer, u32 cnt)
-{
-	memcpy_toio(addr + DATA_OFFSET, buffer, cnt);
-	writew(GEN_BOOT_DAT, addr + CMD_OFFSET);
-	return wait_cyc(addr);
-}
-
-/* Set up entry point and kick start Cyclom-X CPU. */
-static void cycx_start (u32 addr)
-{
-	/* put in 0x30 offset the jump instruction to the code entry point */
-	writeb(0xea, addr + 0x30);
-	writeb(0x00, addr + 0x31);
-	writeb(0xc4, addr + 0x32);
-	writeb(0x00, addr + 0x33);
-	writeb(0x00, addr + 0x34);
-
-	/* cmd to start executing code */
-	writew(GEN_START, addr + CMD_OFFSET);
-}         
-
-/* Load and boot reset code. */
-static void cycx_reset_boot(u32 addr, u8 *code, u32 len)
-{
-	u32 pt_start = addr + START_OFFSET;
-
-        writeb(0xea, pt_start++); /* jmp to f000:3f00 */
-        writeb(0x00, pt_start++);
-        writeb(0xfc, pt_start++);
-        writeb(0x00, pt_start++);
-        writeb(0xf0, pt_start);
-	reset_load(addr, code, len);
-
-	/* 80186 was in hold, go */
-	writeb(0, addr + START_CPU);
-	delay_cycx(1);
-}
-
-/* Load data.bin file through boot (reset) interface. */
-static int cycx_data_boot(u32 addr, u8 *code, u32 len)
-{
-	u32 pt_boot_cmd = addr + CMD_OFFSET;
-	u32 i;
-
-	/* boot buffer lenght */
-	writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16));
-	writew(GEN_DEFPAR, pt_boot_cmd);
-
-	if (wait_cyc(addr) < 0) return 2;
-
-	writew(0, pt_boot_cmd + sizeof(u16));
-	writew(0x4000, pt_boot_cmd + 2 * sizeof(u16));
-	writew(GEN_SET_SEG, pt_boot_cmd);
-
-	if (wait_cyc(addr) < 0) return 2;
-
-	for (i = 0 ; i < len ; i += CFM_LOAD_BUFSZ)
-		if (buffer_load(addr, code + i,
-				MIN(CFM_LOAD_BUFSZ, (len - i))) < 0) {
-			printk(KERN_ERR "%s: Error !!\n", modname);
-			return 4;
-		}
-
-	return 0;
-}
-
-
-/* Load code.bin file through boot (reset) interface. */
-static int cycx_code_boot(u32 addr, u8 *code, u32 len)
-{
-	u32 pt_boot_cmd = addr + CMD_OFFSET;
-	u32 i;
-
-	/* boot buffer lenght */
-	writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16));
-	writew(GEN_DEFPAR, pt_boot_cmd);
-
-	if (wait_cyc(addr) == -1) return 2;
-
-	writew(0x0000, pt_boot_cmd + sizeof(u16));
-	writew(0xc400, pt_boot_cmd + 2 * sizeof(u16));
-	writew(GEN_SET_SEG, pt_boot_cmd);
-
-	if (wait_cyc(addr) == -1) return 1;
-
-	for (i = 0 ; i < len ; i += CFM_LOAD_BUFSZ)
-		if (buffer_load(addr, code + i,MIN(CFM_LOAD_BUFSZ,(len - i)))) {
-			printk(KERN_ERR "%s: Error !!\n", modname);
-			return 4;
-		}
-
-	return 0;
-}
-
-/* Initialize CYCX hardware: setup memory window, IRQ, etc. */
-static int cycx_init (cycxhw_t *hw)
-{
-	switch (hw->type) {
-		case CYCX_2X: return init_cycx_2x(hw);
-	}
-
-	return -EINVAL;
-}
-
-/* Load adapter from the memory image of the CYCX firmware module. 
- * o verify firmware integrity and compatibility
- * o start adapter up */
-static int cycx_load (cycxhw_t *hw, cfm_t *cfm, u32 len)
-{
-	int i, j, status;
-	cycx_header_t *img_hdr;
-	u8 *reset_image,
-	   *data_image,
-	   *code_image;
-	u32 pt_cycld = hw->dpmbase + 0x400;
-	u16 cksum;
-
-	/* Announce */
-	printk(KERN_INFO "%s: firmware signature=\"%s\"\n",
-			 modname, cfm->signature); 
-
-	/* Verify firmware signature */
-	if (strcmp(cfm->signature, CFM_SIGNATURE)) {
-		printk(KERN_ERR "%s:cycx_load: not Cyclom-2X firmware!\n",
-				modname);
-		return -EINVAL;
-	}
-
-	printk(KERN_INFO "%s: firmware version=%u\n", modname, cfm->version);
-
-	/* Verify firmware module format version */
-	if (cfm->version != CFM_VERSION) {
-		printk(KERN_ERR "%s:cycx_load: firmware format %u rejected! "
-				"Expecting %u.\n",
-				modname, cfm->version, CFM_VERSION);
-		return -EINVAL;
-	}
-
-	/* Verify firmware module length and checksum */
-	cksum = checksum((u8*)&cfm->info, sizeof(cfm_info_t) +
-					      cfm->info.codesize);
-/*
-        FIXME cfm->info.codesize is off by 2
-	if (((len - sizeof(cfm_t) - 1) != cfm->info.codesize) ||
-*/
-	if (cksum != cfm->checksum) {
-		printk(KERN_ERR "%s:cycx_load: firmware corrupted!\n", modname);
-		printk(KERN_ERR " cdsize = 0x%x (expected 0x%lx)\n",
-                       len - sizeof(cfm_t) - 1, cfm->info.codesize);
-                printk(KERN_ERR " chksum = 0x%x (expected 0x%x)\n",
-                       cksum, cfm->checksum);
-		return -EINVAL;
-	}
-
-	/* If everything is ok, set reset, data and code pointers */
-
-	img_hdr = (cycx_header_t*)(((u8*) cfm) + sizeof(cfm_t) - 1);
-#ifdef FIRMWARE_DEBUG
-	printk(KERN_INFO "%s:cycx_load: image sizes\n", modname);
-	printk(KERN_INFO " reset=%lu\n", img_hdr->reset_size);
-	printk(KERN_INFO "  data=%lu\n", img_hdr->data_size);
-	printk(KERN_INFO "  code=%lu\n", img_hdr->code_size);
-#endif
-	reset_image = ((u8 *) img_hdr) + sizeof(cycx_header_t);
-	data_image = reset_image + img_hdr->reset_size;
-	code_image = data_image + img_hdr->data_size;
-
-	/*---- Start load ----*/
-        /* Announce */
-	printk(KERN_INFO "%s: loading firmware %s (ID=%u)...\n", modname,
-		(cfm->descr[0] != '\0') ? cfm->descr : "unknown firmware",
-		cfm->info.codeid);
-
-	for (i = 0 ; i < 5 ; i++) {
-		/* Reset Cyclom hardware */
-		if ((status = cycx_reset(hw)) != 0) {
-			printk(KERN_ERR "%s: dpm problem or board not "
-					"found (%d).\n", modname, status);
-			return -EINVAL;
-		}
-
-		/* Load reset.bin */
-                cycx_reset_boot(hw->dpmbase, reset_image, img_hdr->reset_size);
-		/* reset is waiting for boot */
-		writew(GEN_POWER_ON, pt_cycld);
-		delay_cycx(1);
-
-		for (j = 0 ; j < 3 ; j++)
-			if (!readw(pt_cycld)) goto reset_loaded;
-			else delay_cycx(1);
-	}
-
-	printk(KERN_ERR "%s: reset not started.\n", modname);
-	return -EINVAL;
-reset_loaded:
-	/* Load data.bin */
-	if((status = cycx_data_boot(hw->dpmbase, data_image, 
-		                    img_hdr->data_size)) != 0) {
-		printk(KERN_ERR "%s: cannot load data file (%d).\n",
-				modname, status);
-		return -EINVAL;
-	}
-
-	/* Load code.bin */
-	if((status = cycx_code_boot(hw->dpmbase, code_image, 
-		                    img_hdr->code_size)) != 0) {
-		printk(KERN_ERR "%s: cannot load code file (%d).\n",
-				modname, status);
-		return -EINVAL;
-	}
-
-	/* Prepare boot-time configuration data */
-	cycx_bootcfg(hw);
-
-	/* kick-off CPU */
-	cycx_start(hw->dpmbase);
-
-	/* Arthur Ganzert's tip: wait a while after the firmware loading...
-	   seg abr 26 17:17:12 EST 1999 - acme */
-	delay_cycx(7);
-	printk(KERN_INFO "%s: firmware loaded!\n", modname);
-
-	/* enable interrupts */
-        if (cycx_inten(hw)) {
-		printk(KERN_ERR "%s: adapter hardware failure!\n", modname);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-/* Prepare boot-time firmware configuration data.
- * o initialize configuration data area
-   From async.doc - V_3.4.0 - 07/18/1994
-   - As of now, only static buffers are available to the user.
-     So, the bit VD_RXDIRC must be set in 'valid'. That means that user
-     wants to use the static transmission and reception buffers. */
-static void cycx_bootcfg (cycxhw_t *hw)
-{
-	/* use fixed buffers */
-	writeb(FIXED_BUFFERS, hw->dpmbase + CONF_OFFSET); 
-}
-
-/* Initialize CYCX_2X adapter. */
-static int init_cycx_2x (cycxhw_t *hw)
-{
-	if (!detect_cycx_2x(hw->dpmbase)) return -ENODEV;
-	return 0;
-}
-
-/* Detect Cyclom 2x adapter.
- *	Following tests are used to detect Cyclom 2x adapter:
- *       to be completed based on the tests done below
- *	Return 1 if detected o.k. or 0 if failed.
- *	Note:	This test is destructive! Adapter will be left in shutdown
- *		state after the test. */
-static int detect_cycx_2x (u32 addr)
-{
-	printk(KERN_INFO "%s: looking for a cyclom 2x at 0x%lX...\n",
-			 modname, (unsigned long) addr);
-
-	reset_cycx_2x(addr);
-	return memory_exists(addr);
-}
-
-/* Miscellaneous */
-/* Get option's index into the options list.
- *	Return option's index (1 .. N) or zero if option is invalid. */
-static int get_option_index (u32 *optlist, u32 optval)
-{
-	int i = 1;
-	for (; i <= optlist[0]; ++i) if (optlist[i] == optval) return i;
-	return 0;
-}
-
-/* Reset adapter's CPU. */
-static int reset_cycx_2x (u32 addr)
-{
-	writeb (0, addr + RST_ENABLE);  delay_cycx (2);
-	writeb (0, addr + RST_DISABLE); delay_cycx (2);
-	return memory_exists(addr) ? 0 : 1;
-}
-
-/* Delay */
-static void delay_cycx (int sec)
-{
-/* acme
-   Thu dez 31 21:45:16 EDT 1998
-   FIXME I'll keep this comment here just in case, as of now I don't
-   know it all the contexts where this routine is used are interruptible... */
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(sec*HZ);
-}
-
-/* Calculate 16-bit CRC using CCITT polynomial. */
-static u16 checksum (u8 *buf, u32 len)
-{
-	u16 crc = 0;
-	u16 mask, flag;
-
-	for (; len; --len, ++buf)
-		for (mask = 0x80; mask; mask >>= 1) {
-			flag = (crc & 0x8000);
-			crc <<= 1;
-			crc |= ((*buf & mask) ? 1 : 0);
-			if (flag) crc ^= 0x1021;
-		}
-
-	return crc;
-}
-/* End */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/cycx_main.c linux/drivers/net/cycx_main.c
--- v2.3.20/linux/drivers/net/cycx_main.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/net/cycx_main.c	Wed Dec 31 16:00:00 1969
@@ -1,379 +0,0 @@
-/*
-* cycx_main.c	Cyclades Cyclom X Multiprotocol WAN Link Driver. Main module.
-*
-* Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
-*
-* Copyright:	(c) 1998, 1999 Arnaldo Carvalho de Melo
-*
-* Based on sdlamain.c by Gene Kozin <genek@compuserve.com> &
-*			 Jaspreet Singh	<jaspreet@sangoma.com>
-*
-*		This program is free software; you can redistribute it and/or
-*		modify it under the terms of the GNU General Public License
-*		as published by the Free Software Foundation; either version
-*		2 of the License, or (at your option) any later version.
-* ============================================================================
-* 1999/08/09	acme		removed references to enable_tx_int
-*				use spinlocks instead of cli/sti in
-*				cyclomx_set_state
-* 1999/05/19	acme		works directly linked into the kernel
-*				init_waitqueue_head for 2.3.* kernel
-* 1999/05/18	acme		major cleanup (polling not needed), etc
-* 1998/08/28	acme		minor cleanup (ioctls for firmware deleted)
-*				queue_task activated
-* 1998/08/08	acme		Initial version.
-*/
-
-#include <linux/config.h>	/* OS configuration options */
-#include <linux/stddef.h>	/* offsetof(), etc. */
-#include <linux/errno.h>	/* return codes */
-#include <linux/string.h>	/* inline memset(), etc. */
-#include <linux/malloc.h>	/* kmalloc(), kfree() */
-#include <linux/kernel.h>	/* printk(), and other useful stuff */
-#include <linux/module.h>	/* support for loadable modules */
-#include <linux/ioport.h>	/* request_region(), release_region() */
-#include <linux/tqueue.h>	/* for kernel task queues */
-#include <linux/wanrouter.h>	/* WAN router definitions */
-#include <linux/cyclomx.h>	/* cyclomx common user API definitions */
-#include <asm/uaccess.h>	/* kernel <-> user copy */
-#include <linux/init.h>         /* __init (when not using as a module) */
-
-#ifdef MODULE
-MODULE_AUTHOR("Arnaldo Carvalho de Melo");
-MODULE_DESCRIPTION("Cyclades Sync Cards Driver.");
-#endif
-
-/* Defines & Macros */
-
-#define	DRV_VERSION	0		/* version number */
-#define	DRV_RELEASE	4		/* release (minor version) number */
-#define	MAX_CARDS	1		/* max number of adapters */
-
-#ifndef	CONFIG_CYCLOMX_CARDS		/* configurable option */
-#define	CONFIG_CYCLOMX_CARDS 1
-#endif
-
-/* Function Prototypes */
-
-/* Module entry points */
-int init_module (void);
-void cleanup_module (void);
-
-/* WAN link driver entry points */
-static int setup (wan_device_t *wandev, wandev_conf_t *conf);
-static int shutdown (wan_device_t *wandev);
-static int ioctl (wan_device_t *wandev, unsigned cmd, unsigned long arg);
-
-/* Miscellaneous functions */
-static void cycx_isr (int irq, void *dev_id, struct pt_regs *regs);
-
-/* Global Data
- * Note: All data must be explicitly initialized!!!
- */
-
-/* private data */
-static char drvname[]	= "cyclomx";
-static char fullname[]	= "CYCLOM X(tm) Multiprotocol Driver";
-static char copyright[]	= "(c) 1998, 1999 Arnaldo Carvalho de Melo";
-static int ncards = CONFIG_CYCLOMX_CARDS;
-static cycx_t *card_array = NULL;	/* adapter data space */
-
-/* Kernel Loadable Module Entry Points */
-
-/*
- * Module 'insert' entry point.
- * o print announcement
- * o allocate adapter data space
- * o initialize static data
- * o register all cards with WAN router
- * o calibrate CYCX shared memory access delay.
- *
- * Return:	0	Ok
- *		< 0	error.
- * Context:	process
- */
-#ifdef MODULE
-int init_module (void)
-#else
-int __init cyclomx_init (void)
-#endif
-{
-	int cnt, err = 0;
-
-	printk(KERN_INFO "%s v%u.%u %s\n",
-		fullname, DRV_VERSION, DRV_RELEASE, copyright);
-
-	/* Verify number of cards and allocate adapter data space */
-	ncards = min(ncards, MAX_CARDS);
-	ncards = max(ncards, 1);
-	card_array = kmalloc(sizeof(cycx_t) * ncards, GFP_KERNEL);
-
-	if (card_array == NULL) return -ENOMEM;
-
-	memset(card_array, 0, sizeof(cycx_t) * ncards);
-
-	/* Register adapters with WAN router */
-	for (cnt = 0; cnt < ncards; ++cnt) {
-		cycx_t *card = &card_array[cnt];
-		wan_device_t *wandev = &card->wandev;
-
-		sprintf(card->devname, "%s%d", drvname, cnt + 1);
-		wandev->magic    = ROUTER_MAGIC;
-		wandev->name     = card->devname;
-		wandev->private  = card;
-		wandev->setup    = &setup;
-		wandev->shutdown = &shutdown;
-		wandev->ioctl    = &ioctl;
-		err = register_wan_device(wandev);
-
-		if (err) {
-			printk(KERN_ERR
-				"%s: %s registration failed with error %d!\n",
-				drvname, card->devname, err);
-			break;
-		}
-	}
-
-	if (cnt) ncards = cnt;	/* adjust actual number of cards */
-	else {
-		kfree(card_array);
-		err = -ENODEV;
-	}
-
-	return err;
-}
-
-/*
- * Module 'remove' entry point.
- * o unregister all adapters from the WAN router
- * o release all remaining system resources
- */
-#ifdef MODULE
-void cleanup_module (void)
-{
-	int i = 0;
-
-	for (; i < ncards; ++i) {
-		cycx_t *card = &card_array[i];
-		unregister_wan_device(card->devname);
-	}
-
-	kfree(card_array);
-}
-#endif
-/* WAN Device Driver Entry Points */
-/*
- * Setup/confugure WAN link driver.
- * o check adapter state
- * o make sure firmware is present in configuration
- * o allocate interrupt vector
- * o setup CYCLOM X hardware
- * o call appropriate routine to perform protocol-specific initialization
- * o mark I/O region as used
- *
- * This function is called when router handles ROUTER_SETUP IOCTL. The
- * configuration structure is in kernel memory (including extended data, if
- * any).
- */
-static int setup (wan_device_t *wandev, wandev_conf_t *conf)
-{
-	cycx_t *card;
-	int err = 0;
-	int irq;
-
-	/* Sanity checks */
-	if (!wandev || !wandev->private || !conf) return -EFAULT;
-
-	card = wandev->private;
-
-	if (wandev->state != WAN_UNCONFIGURED) return -EBUSY;
-
-	if (!conf->data_size || (conf->data == NULL)) {
-		printk(KERN_ERR "%s: firmware not found in configuration "
-				"data!\n", wandev->name);
-		return -EINVAL;
-	}
-
-	if (conf->irq <= 0) {
-		printk(KERN_ERR "%s: can't configure without IRQ!\n",
-				wandev->name);
-		return -EINVAL;
-	}
-
-	/* Allocate IRQ */
-	irq = conf->irq == 2 ? 9 : conf->irq;	/* IRQ2 -> IRQ9 */
-
-	if (request_irq(irq, cycx_isr, 0, wandev->name, card)) {
-		printk(KERN_ERR "%s: can't reserve IRQ %d!\n",
-				wandev->name, irq);
-		return -EINVAL;
-	}
-
-	/* Configure hardware, load firmware, etc. */
-	memset(&card->hw, 0, sizeof(cycxhw_t));
-	card->hw.irq = (conf->irq == 9) ? 2 : conf->irq;
-	card->hw.dpmbase = conf->maddr;
-	card->hw.dpmsize = CYCX_WINDOWSIZE;
-	card->hw.type = conf->hw_opt[0];
-	card->hw.fwid = CFID_X25_2X;
-	card->lock = SPIN_LOCK_UNLOCKED;
-#if LINUX_VERSION_CODE >= 0x020300
-	init_waitqueue_head(&card->wait_stats);
-#else
-	card->wait_stats = NULL;
-#endif
-	err = cycx_setup(&card->hw, conf->data, conf->data_size);
-
-	if (err) {
-		free_irq(irq, card);
-		return err;
-	}
-
-	/* Intialize WAN device data space */
-	wandev->irq       = irq;
-	wandev->dma       = wandev->ioport = 0;
-	wandev->maddr     = (unsigned long*)card->hw.dpmbase;
-	wandev->msize     = card->hw.dpmsize;
-	wandev->hw_opt[0] = card->hw.type;
-	wandev->hw_opt[1] = card->hw.pclk;
-	wandev->hw_opt[2] = card->hw.memory;
-	wandev->hw_opt[3] = card->hw.fwid;
-
-	/* Protocol-specific initialization */
-	switch (card->hw.fwid) {
-#ifdef CONFIG_CYCLOMX_X25
-		case CFID_X25_2X: err = cyx_init(card, conf); break;
-#endif
-		default:
-			printk(KERN_ERR "%s: this firmware is not supported!\n",
-					wandev->name);
-			err = -EINVAL;
-	}
-
-	if (err) {
-		cycx_down(&card->hw);
-		free_irq(irq, card);
-		return err;
-	}
-
-	return 0;
-}
-
-/*
- * Shut down WAN link driver. 
- * o shut down adapter hardware
- * o release system resources.
- *
- * This function is called by the router when device is being unregistered or
- * when it handles ROUTER_DOWN IOCTL.
- */
-static int shutdown (wan_device_t *wandev)
-{
-	cycx_t *card;
-
-	/* sanity checks */
-	if (!wandev || !wandev->private) return -EFAULT;
-
-	if (wandev->state == WAN_UNCONFIGURED) return 0;
-
-	card = wandev->private;
-	wandev->state = WAN_UNCONFIGURED;
-	cycx_down(&card->hw);
-	printk(KERN_INFO "%s: irq %d being freed!\n", wandev->name,wandev->irq);
-	free_irq(wandev->irq, card);
-	return 0;
-}
-
-/*
- * Driver I/O control. 
- * o verify arguments
- * o perform requested action
- *
- * This function is called when router handles one of the reserved user
- * IOCTLs.  Note that 'arg' stil points to user address space.
- */
-static int ioctl (wan_device_t *wandev, unsigned cmd, unsigned long arg)
-{
-	return -EINVAL;
-}
-
-/* Miscellaneous */
-/*
- * CYCX Interrupt Service Routine.
- * o acknowledge CYCX hardware interrupt.
- * o call protocol-specific interrupt service routine, if any.
- */
-static void cycx_isr (int irq, void *dev_id, struct pt_regs *regs)
-{
-#define	card	((cycx_t*)dev_id)
-	if (!card || card->wandev.state == WAN_UNCONFIGURED)
-		return;
-
-	if (card->in_isr) {
-		printk(KERN_WARNING "%s: interrupt re-entrancy on IRQ %d!\n",
-				    card->devname, card->wandev.irq);
-		return;
-	}
-
-	if (card->isr)
-		card->isr(card);
-#undef	card
-}
-
-/*
- * This routine is called by the protocol-specific modules when network
- * interface is being open.  The only reason we need this, is because we
- * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's
- * defined more than once into the same kernel module.
- */
-void cyclomx_open (cycx_t *card)
-{
-	++card->open_cnt;
-	MOD_INC_USE_COUNT;
-}
-
-/*
- * This routine is called by the protocol-specific modules when network
- * interface is being closed.  The only reason we need this, is because we
- * have to call MOD_DEC_USE_COUNT, but cannot include 'module.h' where it's
- * defined more than once into the same kernel module.
- */
-void cyclomx_close (cycx_t *card)
-{
-	--card->open_cnt;
-	MOD_DEC_USE_COUNT;
-}
-
-/* Set WAN device state.  */
-void cyclomx_set_state (cycx_t *card, int state)
-{
-	unsigned long host_cpu_flags;
-
-	spin_lock_irqsave(&card->lock, host_cpu_flags);
-
-	if (card->wandev.state != state) {
-		switch (state) {
-			case WAN_CONNECTED:
-				printk (KERN_INFO "%s: link connected!\n",
-						  card->devname);
-				break;
-
-			case WAN_CONNECTING:
-				printk (KERN_INFO "%s: link connecting...\n",
-						  card->devname);
-				break;
-
-			case WAN_DISCONNECTED:
-				printk (KERN_INFO "%s: link disconnected!\n",
-						  card->devname);
-				break;
-		}
-
-		card->wandev.state = state;
-	}
-
-	card->state_tick = jiffies;
-	spin_unlock_irqrestore(&card->lock, host_cpu_flags);
-}
-
-/* End */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/cycx_x25.c linux/drivers/net/cycx_x25.c
--- v2.3.20/linux/drivers/net/cycx_x25.c	Wed Aug 18 11:36:41 1999
+++ linux/drivers/net/cycx_x25.c	Wed Dec 31 16:00:00 1969
@@ -1,1488 +0,0 @@
-/*
-* cycx_x25.c	CYCLOM X Multiprotocol WAN Link Driver.  X.25 module.
-*
-* Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
-* Copyright:	(c) 1998, 1999 Arnaldo Carvalho de Melo
-*
-* Based on sdla_x25.c by Gene Kozin <genek@compuserve.com>
-*
-*		This program is free software; you can redistribute it and/or
-*		modify it under the terms of the GNU General Public License
-*		as published by the Free Software Foundation; either version
-*		2 of the License, or (at your option) any later version.
-* ============================================================================
-* 1999/08/10	acme		serialized access to the card thru a spinlock
-*				in x25_exec
-* 1999/08/09	acme		removed per channel spinlocks
-*				removed references to enable_tx_int
-* 1999/05/28	acme		fixed nibble_to_byte, ackvc now properly treated
-*				if_send simplified
-* 1999/05/25	acme		fixed t1, t2, t21 & t23 configuration
-*				use spinlocks instead of cli/sti in some points
-* 1999/05/24	acme		finished the x25_get_stat function
-* 1999/05/23	acme		dev->type = ARPHRD_X25 (tcpdump only works,
-*				AFAIT, with ARPHRD_ETHER). This seems to be
-*				needed to use socket(AF_X25)...
-*				Now the config file must specify a peer media
-*				address for svc channes over a crossover cable.
-*				Removed hold_timeout from x25_channel_t,
-*				not used.
-*				A little enhancement in the DEBUG processing
-* 1999/05/22	acme		go to DISCONNECTED in disconnect_confirm_intr,
-*				instead of chan_disc.
-* 1999/05/16	marcelo		fixed timer initialization in SVCs
-* 1999/01/05	acme		x25_configure now get (most of) all
-*				parameters...
-* 1999/01/05	acme		pktlen now (correctly) uses log2 (value
-*				configured)
-* 1999/01/03	acme		judicious use of data types (u8, u16, u32, etc)
-* 1999/01/03	acme		cyx_isr: reset dpmbase to acknowledge
-*				indication (interrupt from cyclom 2x)
-* 1999/01/02	acme		cyx_isr: first hackings...
-* 1999/01/0203  acme 		when initializing an array don't give less
-*				elements than declared...
-* 				example: char send_cmd[6] = "?\xFF\x10";
-*          			you'll gonna lose a couple hours, 'cause your
-*				brain won't admit that there's an error in the
-*				above declaration...  the side effect is that
-*				memset is put into the unresolved symbols
-*				instead of using the inline memset functions...
-* 1999/01/02    acme 		began chan_connect, chan_send, x25_send
-* Dec 31, 1998	Arnaldo		x25_configure
-*				this code can be compiled as non module
-* Dec 27, 1998	Arnaldo		code cleanup
-*				IPX code wiped out! let's decrease code
-*				complexity for now, remember: I'm learning! :)
-*                               bps_to_speed_code OK
-* Dec 26, 1998	Arnaldo		Minimal debug code cleanup
-* Aug 08, 1998	Arnaldo		Initial version.
-*/
-#define CYCLOMX_X25_DEBUG 1
-
-#include <linux/version.h>
-#include <linux/kernel.h>	/* printk(), and other useful stuff */
-#include <linux/stddef.h>	/* offsetof(), etc. */
-#include <linux/errno.h>	/* return codes */
-#include <linux/string.h>	/* inline memset(), etc. */
-#include <linux/malloc.h>	/* kmalloc(), kfree() */
-#include <linux/wanrouter.h>	/* WAN router definitions */
-#include <asm/byteorder.h>	/* htons(), etc. */
-#include <linux/if_arp.h>       /* ARPHRD_X25 */
-#include <linux/cyclomx.h>	/* CYCLOM X common user API definitions */
-#include <linux/cycx_x25.h>	/* X.25 firmware API definitions */
-
-/* Defines & Macros */
-#define MAX_CMD_RETRY	5
-#define X25_CHAN_MTU	2048	/* unfragmented logical channel MTU */
-
-/* Data Structures */
-/* This is an extention of the 'struct net_device' we create for each network
-   interface to keep the rest of X.25 channel-specific data. */
-typedef struct x25_channel {
-	char name[WAN_IFNAME_SZ+1];	/* interface name, ASCIIZ */
-	char addr[WAN_ADDRESS_SZ+1];	/* media address, ASCIIZ */
-	char *local_addr;		/* local media address, ASCIIZ -
-					   svc thru crossover cable */
-	s16 lcn;			/* logical channel number/conn.req.key*/
-	u8 link;
-	struct timer_list timer;	/* timer used for svc channel disc. */
-	u16 protocol;			/* ethertype, 0 - multiplexed */
-	u8 svc;				/* 0 - permanent, 1 - switched */
-	u8 state;			/* channel state */
-	u8 drop_sequence;		/* mark sequence for dropping */
-	u32 idle_tmout;			/* sec, before disconnecting */
-	struct sk_buff *rx_skb;		/* receive socket buffer */
-	cycx_t *card;			/* -> owner */
-	struct enet_statistics ifstats;	/* interface statistics */
-} x25_channel_t;
-
-/* Function Prototypes */
-/* WAN link driver entry points. These are called by the WAN router module. */
-static int update (wan_device_t *wandev),
-	   new_if (wan_device_t *wandev, struct net_device *dev,wanif_conf_t *conf),
-	   del_if (wan_device_t *wandev, struct net_device *dev);
-
-/* Network device interface */
-static int if_init (struct net_device *dev),
-	   if_open (struct net_device *dev),
-	   if_close (struct net_device *dev),
-	   if_header (struct sk_buff *skb, struct net_device *dev,
-		      u16 type, void *daddr, void *saddr, unsigned len),
-	   if_rebuild_hdr (struct sk_buff *skb),
-	   if_send (struct sk_buff *skb, struct net_device *dev);
-
-static struct net_device_stats * if_stats (struct net_device *dev);
-
-/* Interrupt handlers */
-static void cyx_isr (cycx_t *card),
-	    tx_intr (cycx_t *card, TX25Cmd *cmd),
-	    rx_intr (cycx_t *card, TX25Cmd *cmd),
-	    log_intr (cycx_t *card, TX25Cmd *cmd),
-	    stat_intr (cycx_t *card, TX25Cmd *cmd),
-	    connect_confirm_intr (cycx_t *card, TX25Cmd *cmd),
-	    disconnect_confirm_intr (cycx_t *card, TX25Cmd *cmd),
-	    connect_intr (cycx_t *card, TX25Cmd *cmd),
-	    disconnect_intr (cycx_t *card, TX25Cmd *cmd),
-	    spur_intr (cycx_t *card, TX25Cmd *cmd);
-
-/* X.25 firmware interface functions */
-static int x25_configure (cycx_t *card, TX25Config *conf),
-	   x25_get_stats (cycx_t *card),
-	   x25_send (cycx_t *card, u8 link, u8 lcn, u8 bitm, int len,void *buf),
-	   x25_connect_response (cycx_t *card, x25_channel_t *chan),
-	   x25_disconnect_response (cycx_t *card, u8 link, u8 lcn);
-
-/* Miscellaneous functions */
-static int chan_connect (struct net_device *dev),
-	   chan_send (struct net_device *dev, struct sk_buff *skb);
-
-static void set_chan_state (struct net_device *dev, u8 state),
-	    nibble_to_byte (u8 *s, u8 *d, u8 len, u8 nibble),
-	    reset_timer (struct net_device *dev),
-	    chan_disc (struct net_device *dev),
-	    chan_timer (unsigned long d);
-
-static u8 bps_to_speed_code (u32 bps);
-static u8 log2 (u32 n);
-
-static unsigned dec_to_uint (u8 *str, int len);
-
-static struct net_device *get_dev_by_lcn (wan_device_t *wandev, s16 lcn);
-static struct net_device *get_dev_by_dte_addr (wan_device_t *wandev, char *dte);
-
-#ifdef CYCLOMX_X25_DEBUG
-static void hex_dump(char *msg, unsigned char *p, int len);
-static void x25_dump_config(TX25Config *conf);
-static void x25_dump_stats(TX25Stats *stats);
-static void x25_dump_devs(wan_device_t *wandev);
-#define dprintk(format, a...) printk(format, ##a)
-#else
-#define hex_dump(msg, p, len)
-#define x25_dump_config(conf)
-#define x25_dump_stats(stats)
-#define x25_dump_devs(wandev)
-#define dprintk(format, a...)
-#endif
-/* Public Functions */
-
-/* X.25 Protocol Initialization routine.
- *
- * This routine is called by the main CYCLOM X module during setup.  At this
- * point adapter is completely initialized and X.25 firmware is running.
- *  o read firmware version (to make sure it's alive)
- *  o configure adapter
- *  o initialize protocol-specific fields of the adapter data space.
- *
- * Return:	0	o.k.
- *		< 0	failure.  */
-int cyx_init (cycx_t *card, wandev_conf_t *conf)
-{
-	TX25Config cfg;
-
-	/* Verify configuration ID */
-	if (conf->config_id != WANCONFIG_X25) {
-		printk(KERN_INFO "%s: invalid configuration ID %u!\n",
-				 card->devname, conf->config_id);
-		return -EINVAL;
-	}
-
-	/* Initialize protocol-specific fields */
-	card->mbox  = card->hw.dpmbase + X25_MBOX_OFFS;
-	card->u.x.connection_keys = 0;
-	card->u.x.lock = SPIN_LOCK_UNLOCKED;
-
-	/* Configure adapter. Here we set resonable defaults, then parse
-	 * device configuration structure and set configuration options.
-	 * Most configuration options are verified and corrected (if
-	 * necessary) since we can't rely on the adapter to do so and don't
-	 * want it to fail either. */
-	memset(&cfg, 0, sizeof(cfg));
-	cfg.link = 0;
-	cfg.clock = conf->clocking == WANOPT_EXTERNAL ? 8 : 55;
-	cfg.speed = bps_to_speed_code(conf->bps);
-	cfg.n3win = 7;
-	cfg.n2win = 2;
-	cfg.n2 = 5;
-	cfg.nvc = 1;
-	cfg.npvc = 1;
-	cfg.flags = 0x02; /* default = V35 */
-	cfg.t1 = 10;   /* line carrier timeout */
-	cfg.t2 = 29;   /* tx timeout */
-	cfg.t21 = 180; /* CALL timeout */
-	cfg.t23 = 180; /* CLEAR timeout */
-
-	/* adjust MTU */
-	if (!conf->mtu || conf->mtu >= 512)
-		card->wandev.mtu = 512;
-	else if (conf->mtu >= 256)
-		card->wandev.mtu = 256;
-	else if (conf->mtu >= 128)
-		card->wandev.mtu = 128;
-	else
-		card->wandev.mtu = 64;
-
-	cfg.pktlen = log2(card->wandev.mtu);
-
-	if (conf->station == WANOPT_DTE) {
-		cfg.locaddr = 3; /* DTE */
-		cfg.remaddr = 1; /* DCE */
-	} else {
-		cfg.locaddr = 1; /* DCE */
-		cfg.remaddr = 3; /* DTE */
-	}
-
-        if (conf->interface == WANOPT_RS232)
-	        cfg.flags = 0;      /* FIXME just reset the 2nd bit */
-
-	if (conf->u.x25.hi_pvc) {
-		card->u.x.hi_pvc = min(conf->u.x25.hi_pvc, 4095);
-		card->u.x.lo_pvc = min(conf->u.x25.lo_pvc, card->u.x.hi_pvc);
-	}
-
-	if (conf->u.x25.hi_svc) {
-		card->u.x.hi_svc = min(conf->u.x25.hi_svc, 4095);
-		card->u.x.lo_svc = min(conf->u.x25.lo_svc, card->u.x.hi_svc);
-	}
-
-	if (card->u.x.lo_pvc == 255)
-		cfg.npvc = 0;
-	else
-		cfg.npvc = card->u.x.hi_pvc - card->u.x.lo_pvc + 1;
-
-	cfg.nvc = card->u.x.hi_svc - card->u.x.lo_svc + 1 + cfg.npvc;
-
-	if (conf->u.x25.hdlc_window)
-		cfg.n2win = min(conf->u.x25.hdlc_window, 7);
-
-	if (conf->u.x25.pkt_window)
-		cfg.n3win = min(conf->u.x25.pkt_window, 7);
-
-	if (conf->u.x25.t1)
-		cfg.t1 = min(conf->u.x25.t1, 30);
-
-	if (conf->u.x25.t2)
-		cfg.t2 = min(conf->u.x25.t2, 30);
-
-	if (conf->u.x25.t11_t21)
-		cfg.t21 = min(conf->u.x25.t11_t21, 30);
-
-	if (conf->u.x25.t13_t23)
-		cfg.t23 = min(conf->u.x25.t13_t23, 30);
-
-	if (conf->u.x25.n2)
-		cfg.n2 = min(conf->u.x25.n2, 30);
-
-	/* initialize adapter */
-	if (x25_configure(card, &cfg))
-		return -EIO;
-
-	/* Initialize protocol-specific fields of adapter data space */
-	card->wandev.bps	= conf->bps;
-	card->wandev.interface	= conf->interface;
-	card->wandev.clocking	= conf->clocking;
-	card->wandev.station	= conf->station;
-	card->isr		= &cyx_isr;
-	card->exec		= NULL;
-	card->wandev.update	= &update;
-	card->wandev.new_if	= &new_if;
-	card->wandev.del_if	= &del_if;
-	card->wandev.state	= WAN_DISCONNECTED;
-	return 0;
-}
-
-/* WAN Device Driver Entry Points */
-/* Update device status & statistics. */
-static int update (wan_device_t *wandev)
-{
-	/* sanity checks */
-	if (!wandev || !wandev->private)
-		return -EFAULT;
-
-	if (wandev->state == WAN_UNCONFIGURED)
-		return -ENODEV;
-
-	x25_get_stats(wandev->private);
-	return 0;
-}
-
-/* Create new logical channel.
- * This routine is called by the router when ROUTER_IFNEW IOCTL is being
- * handled.
- * o parse media- and hardware-specific configuration
- * o make sure that a new channel can be created
- * o allocate resources, if necessary
- * o prepare network device structure for registaration.
- *
- * Return:	0	o.k.
- *		< 0	failure (channel will not be created) */
-static int new_if (wan_device_t *wandev, struct net_device *dev, wanif_conf_t *conf)
-{
-	cycx_t *card = wandev->private;
-	x25_channel_t *chan;
-	int err = 0;
-
-	if (conf->name[0] == '\0' || strlen(conf->name) > WAN_IFNAME_SZ) {
-		printk(KERN_INFO "%s: invalid interface name!\n",card->devname);
-		return -EINVAL;
-	}
-
-	/* allocate and initialize private data */
-	if ((chan = kmalloc(sizeof(x25_channel_t), GFP_KERNEL)) == NULL)
-		return -ENOMEM;
-
-	memset(chan, 0, sizeof(x25_channel_t));
-	strcpy(chan->name, conf->name);
-	chan->card = card;
-	chan->link = conf->port;
-	chan->protocol = ETH_P_IP;
-	chan->rx_skb = NULL;
-	/* only used in svc connected thru crossover cable */
-	chan->local_addr = NULL;
-
-	if (conf->addr[0] == '@') {	/* SVC */
-		int len = strlen(conf->local_addr);
-
-		if (len) {
-			if (len > WAN_ADDRESS_SZ) {
-				printk(KERN_ERR "%s: %s local addr too long!\n",
-						wandev->name, chan->name);
-				kfree(chan);
-				return -EINVAL;
-			} else {
-				chan->local_addr = kmalloc(len + 1, GFP_KERNEL);
-
-				if (!chan->local_addr) {
-					kfree(chan);
-					return ENOMEM;
-				}
-			}
-
-                	strncpy(chan->local_addr, conf->local_addr,
-				WAN_ADDRESS_SZ);
-		}
-
-                chan->svc = 1;
-                strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ);
-		init_timer(&chan->timer);
-		chan->timer.function = chan_timer;
-		chan->timer.data = (unsigned long) dev;
-
-                /* Set channel timeouts (default if not specified) */
-                chan->idle_tmout = conf->idle_timeout ? conf->idle_timeout : 90;
-        } else if (is_digit(conf->addr[0])) {	/* PVC */
-		s16 lcn = dec_to_uint(conf->addr, 0);
-
-		if (lcn >= card->u.x.lo_pvc && lcn <= card->u.x.hi_pvc)
-			chan->lcn = lcn;
-		else {
-			printk(KERN_ERR
-				"%s: PVC %u is out of range on interface %s!\n",
-				wandev->name, lcn, chan->name);
-			err = -EINVAL;
-		}
-	} else {
-		printk(KERN_ERR "%s: invalid media address on interface %s!\n",
-				wandev->name, chan->name);
-		err = -EINVAL;
-	}
-
-	if (err) {
-		if (chan->local_addr)
-			kfree(chan->local_addr);
-
-		kfree(chan);
-		return err;
-	}
-
-	/* prepare network device data space for registration */
-	dev->name = chan->name;
-	dev->init = &if_init;
-	dev->priv = chan;
-	return 0;
-}
-
-/* Delete logical channel. */
-static int del_if (wan_device_t *wandev, struct net_device *dev)
-{
-	if (!dev) {
-		printk(KERN_ERR "cycx_x25:del_if:dev == NULL!\n");
-		return 0;
-	}
-
-	if (dev->priv) {
-		x25_channel_t *chan = dev->priv;
-
-		if (chan->svc) {
-			if (chan->local_addr)
-				kfree(chan->local_addr);
-
-			if (chan->state == WAN_CONNECTED)
-				del_timer(&chan->timer);
-		}
-
-		kfree(chan);
-		dev->priv = NULL;
-	}
-
-	return 0;
-}
-
-/* Network Device Interface */
-/* Initialize Linux network interface.
- *
- * This routine is called only once for each interface, during Linux network
- * interface registration.  Returning anything but zero will fail interface
- * registration. */
-static int if_init (struct net_device *dev)
-{
-	x25_channel_t *chan = dev->priv;
-	cycx_t *card = chan->card;
-	wan_device_t *wandev = &card->wandev;
-
-	/* Initialize device driver entry points */
-	dev->open = &if_open;
-	dev->stop = &if_close;
-	dev->hard_header = &if_header;
-	dev->rebuild_header = &if_rebuild_hdr;
-	dev->hard_start_xmit = &if_send;
-	dev->get_stats = &if_stats;
-
-	/* Initialize media-specific parameters */
-	dev->mtu = X25_CHAN_MTU;
-	dev->type = ARPHRD_X25;		/* ARP h/w type */
-	dev->hard_header_len = 0;	/* media header length */
-	dev->addr_len = 0;		/* hardware address length */
-
-	if (!chan->svc)
-		*(u16*)dev->dev_addr = htons(chan->lcn);
-
-	/* Initialize hardware parameters (just for reference) */
-	dev->irq = wandev->irq;
-	dev->dma = wandev->dma;
-	dev->base_addr = wandev->ioport;
-	dev->mem_start = (unsigned long)wandev->maddr;
-	dev->mem_end = (unsigned long)(wandev->maddr + wandev->msize - 1);
-	dev->flags |= IFF_NOARP;
-
-        /* Set transmit buffer queue length */
-        dev->tx_queue_len = 10;
-
-	/* Initialize socket buffers */
-	dev_init_buffers(dev);
-	set_chan_state(dev, WAN_DISCONNECTED);
-	return 0;
-}
-
-/* Open network interface.
- * o prevent module from unloading by incrementing use count
- * o if link is disconnected then initiate connection
- *
- * Return 0 if O.k. or errno.  */
-static int if_open (struct net_device *dev)
-{
-	x25_channel_t *chan = dev->priv;
-	cycx_t *card = chan->card;
-
-	if (dev->start)
-		return -EBUSY; /* only one open is allowed */ 
-
-	dev->interrupt = 0;
-	dev->tbusy = 0;
-	dev->start = 1;
-	cyclomx_open(card);
-
-	return 0;
-}
-
-/* Close network interface.
- * o reset flags.
- * o if there's no more open channels then disconnect physical link. */
-static int if_close (struct net_device *dev)
-{
-	x25_channel_t *chan = dev->priv;
-	cycx_t *card = chan->card;
-
-	dev->start = 0;
-
-	if (chan->state == WAN_CONNECTED || chan->state == WAN_CONNECTING)
-		chan_disc(dev);
-		
-	cyclomx_close(card);
-	return 0;
-}
-
-/* Build media header.
- * o encapsulate packet according to encapsulation type.
- *
- * The trick here is to put packet type (Ethertype) into 'protocol' field of
- * the socket buffer, so that we don't forget it.  If encapsulation fails,
- * set skb->protocol to 0 and discard packet later.
- *
- * Return:	media header length. */
-static int if_header (struct sk_buff *skb, struct net_device *dev,
-		      u16 type, void *daddr, void *saddr, unsigned len)
-{
-	skb->protocol = type;
-	return dev->hard_header_len;
-}
-
-/* * Re-build media header.
- * Return:	1	physical address resolved.
- *		0	physical address not resolved */
-static int if_rebuild_hdr (struct sk_buff *skb)
-{
-	return 1;
-}
-
-/* Send a packet on a network interface.
- * o set tbusy flag (marks start of the transmission).
- * o check link state. If link is not up, then drop the packet.
- * o check channel status. If it's down then initiate a call.
- * o pass a packet to corresponding WAN device.
- * o free socket buffer
- *
- * Return:	0	complete (socket buffer must be freed)
- *		non-0	packet may be re-transmitted (tbusy must be set)
- *
- * Notes:
- * 1. This routine is called either by the protocol stack or by the "net
- *    bottom half" (with interrupts enabled).
- * 2. Setting tbusy flag will inhibit further transmit requests from the
- *    protocol stack and can be used for flow control with protocol layer. */
-static int if_send (struct sk_buff *skb, struct net_device *dev)
-{
-	x25_channel_t *chan = dev->priv;
-	cycx_t *card = chan->card;
-
-	if (dev->tbusy) {
-		++chan->ifstats.rx_dropped;	
-		return -EBUSY;	
-	}
-
-	if (!chan->svc)
-		chan->protocol = skb->protocol;
-
-	if (card->wandev.state != WAN_CONNECTED)
-		++chan->ifstats.tx_dropped;
-        else if (chan->svc && chan->protocol &&
-		 chan->protocol != skb->protocol) {
-                printk(KERN_INFO
-                        "%s: unsupported Ethertype 0x%04X on interface %s!\n",
-                        card->devname, skb->protocol, dev->name);
-                ++chan->ifstats.tx_errors;
-        } else switch (chan->state) {
-		case WAN_DISCONNECTED:
-			if (chan_connect(dev)) {
-				dev->tbusy = 1;
-				return -EBUSY;
-			}
-			/* fall thru */
-		case WAN_CONNECTED:
-			reset_timer(dev);
-			dev->trans_start = jiffies;
-			dev->tbusy = 1;
-
-			if (chan_send(dev, skb)) {
-				return -EBUSY;
-			}
-			break;
-		default:
-			++chan->ifstats.tx_dropped;	
-			++card->wandev.stats.tx_dropped;
-	}
-
-	dev_kfree_skb(skb);
-	return 0;
-}
-
-/* Get Ethernet-style interface statistics.
- * Return a pointer to struct net_device_stats */
-static struct net_device_stats *if_stats (struct net_device *dev)
-{
-        x25_channel_t *chan = dev->priv;
-
-	return chan ? &chan->ifstats : NULL;
-}
-
-/* Interrupt Handlers */
-/* X.25 Interrupt Service Routine. */
-static void cyx_isr (cycx_t *card)
-{
-	TX25Cmd cmd;
-	u16 z = 0;
-
-	card->in_isr = 1;
-	card->buff_int_mode_unbusy = 0;
-	cycx_peek(&card->hw, X25_RXMBOX_OFFS, &cmd, sizeof(cmd));
-
-	switch (cmd.command) {
-		case X25_DATA_INDICATION:
-			rx_intr(card, &cmd);
-			break;
-		case X25_ACK_FROM_VC:
-			tx_intr(card, &cmd);
-			break;
-		case X25_LOG: 
-			log_intr(card, &cmd);
-			break;
-		case X25_STATISTIC: 
-			stat_intr(card, &cmd);
-			break;
-		case X25_CONNECT_CONFIRM:
-			connect_confirm_intr(card, &cmd);
-			break;
-		case X25_CONNECT_INDICATION:
-			connect_intr(card, &cmd);
-			break;
-		case X25_DISCONNECT_INDICATION:
-			disconnect_intr(card, &cmd);
-			break;
-		case X25_DISCONNECT_CONFIRM:
-			disconnect_confirm_intr(card, &cmd);
-			break;
-		case X25_LINE_ON:
-			cyclomx_set_state(card, WAN_CONNECTED);
-			break;
-		case X25_LINE_OFF:
-			cyclomx_set_state(card, WAN_DISCONNECTED);
-			break;
-		default: 
-			spur_intr(card, &cmd); /* unwanted interrupt */
-	}
-
-	cycx_poke(&card->hw, 0, &z, sizeof(z));
-	cycx_poke(&card->hw, X25_RXMBOX_OFFS, &z, sizeof(z));
-	card->in_isr = 0;
-
-	if (card->buff_int_mode_unbusy)
-		mark_bh(NET_BH);
-}
-
-/* Transmit interrupt handler.
- *	o Release socket buffer
- *	o Clear 'tbusy' flag */
-static void tx_intr (cycx_t *card, TX25Cmd *cmd)
-{
-	struct net_device *dev;
-	wan_device_t *wandev = &card->wandev;
-	u8 lcn;
-
-	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
-
-	/* unbusy device and then dev_tint(); */
-	if ((dev = get_dev_by_lcn (wandev, lcn)) != NULL) {
-		card->buff_int_mode_unbusy = 1;
-		dev->tbusy = 0;
-	} else
-		printk(KERN_ERR "%s:ackvc for inexistent lcn %d\n",
-				 card->devname, lcn);
-}
-
-/* Receive interrupt handler.
- * This routine handles fragmented IP packets using M-bit according to the
- * RFC1356.
- * o map ligical channel number to network interface.
- * o allocate socket buffer or append received packet to the existing one.
- * o if M-bit is reset (i.e. it's the last packet in a sequence) then 
- *   decapsulate packet and pass socket buffer to the protocol stack.
- *
- * Notes:
- * 1. When allocating a socket buffer, if M-bit is set then more data is
- *    comming and we have to allocate buffer for the maximum IP packet size
- *    expected on this channel.
- * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no
- *    socket buffers available) the whole packet sequence must be discarded. */
-static void rx_intr (cycx_t *card, TX25Cmd *cmd)
-{
-	wan_device_t *wandev = &card->wandev;
-	struct net_device *dev;
-	x25_channel_t *chan;
-	struct sk_buff *skb;
-	u8 bitm, lcn;
-	int pktlen = cmd->len - 5;
-
-	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
-	cycx_peek(&card->hw, cmd->buf + 4, &bitm, sizeof(bitm));
-	bitm &= 0x10;
-
-	if ((dev = get_dev_by_lcn(wandev, lcn)) == NULL) {
-		/* Invalid channel, discard packet */
-		printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n",
-				 card->devname, lcn);
-		return;
-	}
-
-	chan = dev->priv;
-	reset_timer(dev);
-
-	if (chan->drop_sequence) {
-		if (!bitm)
-			chan->drop_sequence = 0;
-		else
-			return;
-	}
-
-	if ((skb = chan->rx_skb) == NULL) {
-		/* Allocate new socket buffer */
-		int bufsize = bitm ? dev->mtu : pktlen;
-
-		if ((skb = dev_alloc_skb(bufsize +
-					 dev->hard_header_len)) == NULL) {
-			printk(KERN_INFO "%s: no socket buffers available!\n",
-					 card->devname);
-			chan->drop_sequence = 1;
-			++chan->ifstats.rx_dropped;
-			return;
-		}
-
-		skb->dev = dev;
-		skb->protocol = htons(chan->protocol);
-		chan->rx_skb = skb;
-	}
-
-	if (skb_tailroom(skb) < pktlen) {
-		/* No room for the packet. Call off the whole thing! */
-		dev_kfree_skb(skb);
-		chan->rx_skb = NULL;
-
-		if (bitm)
-			chan->drop_sequence = 1;
-
-		printk(KERN_INFO "%s: unexpectedly long packet sequence "
-			"on interface %s!\n", card->devname, dev->name);
-		++chan->ifstats.rx_length_errors;
-		return;
-	}
-
-	/* Append packet to the socket buffer  */
-	cycx_peek(&card->hw, cmd->buf + 5, skb_put(skb, pktlen), pktlen);
-
-	if (bitm)
-		return; /* more data is coming */
-
-	dev->last_rx = jiffies;		/* timestamp */
-	chan->rx_skb = NULL;		/* dequeue packet */
-
-	skb->protocol = htons(ETH_P_IP);
-	skb->dev = dev;
-	skb->mac.raw = skb->data;
-	netif_rx(skb);
-	++chan->ifstats.rx_packets;
-	chan->ifstats.rx_bytes += skb->len;
-}
-
-/* Connect interrupt handler. */
-static void connect_intr (cycx_t *card, TX25Cmd *cmd)
-{
-	wan_device_t *wandev = &card->wandev;
-	struct net_device *dev = NULL;
-	x25_channel_t *chan;
-	u8 d[32],
-	   loc[24],
-	   rem[24];
-	u8 lcn, sizeloc, sizerem;
-
-	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
-	cycx_peek(&card->hw, cmd->buf + 5, &sizeloc, sizeof(sizeloc));
-	cycx_peek(&card->hw, cmd->buf + 6, d, cmd->len - 6);
-
-	sizerem = sizeloc >> 4;
-	sizeloc &= 0x0F;
-
-	loc[0] = rem[0] = '\0';
-
-	if (sizeloc)
-		nibble_to_byte(d, loc, sizeloc, 0);
-
-	if (sizerem)
-		nibble_to_byte(d + (sizeloc >> 1), rem, sizerem, sizeloc & 1);
-
-	dprintk(KERN_INFO "connect_intr:lcn=%d, local=%s, remote=%s\n",
-			  lcn, loc, rem);
-	if ((dev = get_dev_by_dte_addr(wandev, rem)) == NULL) {
-		/* Invalid channel, discard packet */
-		printk(KERN_INFO "%s: connect not expected: remote %s!\n",
-				 card->devname, rem);
-		return;
-	}
-
-	chan = dev->priv;
-	chan->lcn = lcn;
-	x25_connect_response(card, chan);
-	set_chan_state(dev, WAN_CONNECTED);
-}
-
-/* Connect confirm interrupt handler. */
-static void connect_confirm_intr (cycx_t *card, TX25Cmd *cmd)
-{
-	wan_device_t *wandev = &card->wandev;
-	struct net_device *dev;
-	x25_channel_t *chan;
-	u8 lcn, key;
-
-	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
-	cycx_peek(&card->hw, cmd->buf + 1, &key, sizeof(key));
-	dprintk(KERN_INFO "%s: connect_confirm_intr:lcn=%d, key=%d\n",
-			  card->devname, lcn, key);
-	if ((dev = get_dev_by_lcn(wandev, -key)) == NULL) {
-		/* Invalid channel, discard packet */
-		clear_bit(--key, (void*)&card->u.x.connection_keys);
-		printk(KERN_INFO "%s: connect confirm not expected: lcn %d, "
-				 "key=%d!\n", card->devname, lcn, key);
-		return;
-	}
-
-	clear_bit(--key, (void*)&card->u.x.connection_keys);
-	chan = dev->priv;
-	chan->lcn = lcn;
-	set_chan_state(dev, WAN_CONNECTED);
-}
-
-/* Disonnect confirm interrupt handler. */
-static void disconnect_confirm_intr (cycx_t *card, TX25Cmd *cmd)
-{
-	wan_device_t *wandev = &card->wandev;
-	struct net_device *dev;
-	u8 lcn;
-
-	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
-	dprintk(KERN_INFO "%s: disconnect_confirm_intr:lcn=%d\n",
-			  card->devname, lcn);
-	if ((dev = get_dev_by_lcn(wandev, lcn)) == NULL) {
-		/* Invalid channel, discard packet */
-		printk(KERN_INFO "%s:disconnect confirm not expected!:lcn %d\n",
-				 card->devname, lcn);
-		return;
-	}
-
-	set_chan_state(dev, WAN_DISCONNECTED);
-}
-
-/* disconnect interrupt handler. */
-static void disconnect_intr (cycx_t *card, TX25Cmd *cmd)
-{
-	wan_device_t *wandev = &card->wandev;
-	struct net_device *dev;
-	u8 lcn;
-
-	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
-	dprintk(KERN_INFO "disconnect_intr:lcn=%d\n", lcn);
-
-	if ((dev = get_dev_by_lcn(wandev, lcn)) != NULL) {
-		x25_channel_t *chan = dev->priv;
-
-		x25_disconnect_response(card, chan->link, lcn);
-		set_chan_state(dev, WAN_DISCONNECTED);
-	} else
-		x25_disconnect_response(card, 0, lcn);
-}
-
-/* LOG interrupt handler. */
-static void log_intr (cycx_t *card, TX25Cmd *cmd)
-{
-#if CYCLOMX_X25_DEBUG
-	char bf[20];
-	u16 size, toread, link, msg_code;
-	u8 code, routine;
-
-	cycx_peek(&card->hw, cmd->buf, &msg_code, sizeof(msg_code));
-	cycx_peek(&card->hw, cmd->buf + 2, &link, sizeof(link));
-	cycx_peek(&card->hw, cmd->buf + 4, &size, sizeof(size));
-	/* at most 20 bytes are available... thanx to Daniela :) */
-	toread = size < 20 ? size : 20;
-	cycx_peek(&card->hw, cmd->buf + 10, &bf, toread);
-	cycx_peek(&card->hw, cmd->buf + 10 + toread, &code, 1);
-	cycx_peek(&card->hw, cmd->buf + 10 + toread + 1, &routine, 1);
-
-	printk(KERN_INFO "cyx_isr: X25_LOG (0x4500) indic.:\n");
-	printk(KERN_INFO "cmd->buf=0x%X\n", cmd->buf);
-	printk(KERN_INFO "Log message code=0x%X\n", msg_code);
-	printk(KERN_INFO "Link=%d\n", link);
-	printk(KERN_INFO "log code=0x%X\n", code);
-	printk(KERN_INFO "log routine=0x%X\n", routine);
-	printk(KERN_INFO "Message size=%d\n", size);
-	hex_dump("Message", bf, toread);
-#endif
-}
-
-/* STATISTIC interrupt handler. */
-static void stat_intr (cycx_t *card, TX25Cmd *cmd)
-{
-	cycx_peek(&card->hw, cmd->buf, &card->u.x.stats,
-		  sizeof(card->u.x.stats));
-	hex_dump("stat_intr", (unsigned char*)&card->u.x.stats,
-		 sizeof(card->u.x.stats));
-	x25_dump_stats(&card->u.x.stats);
-	wake_up_interruptible(&card->wait_stats);
-}
-
-/* Spurious interrupt handler.
- * o print a warning
- * If number of spurious interrupts exceeded some limit, then ??? */
-static void spur_intr (cycx_t *card, TX25Cmd *cmd)
-{
-	printk(KERN_INFO "%s: spurious interrupt (0x%X)!\n",
-			 card->devname, cmd->command);
-}
-#ifdef CYCLOMX_X25_DEBUG
-static void hex_dump(char *msg, unsigned char *p, int len)
-{
-	unsigned char hex[1024],
-	    	* phex = hex;
-
-	if (len >= (sizeof(hex) / 2))
-		len = (sizeof(hex) / 2) - 1;
-
-	while (len--) {
-		sprintf(phex, "%02x", *p++);
-		phex += 2;
-	}
-
-	printk(KERN_INFO "%s: %s\n", msg, hex);
-}
-#endif
-/* CYCLOM X Firmware-Specific Functions */
-/* Exec x25 command. */
-static int x25_exec (cycx_t *card, int command, int link,
-		     void *d1, int len1, void *d2, int len2)
-{
-	TX25Cmd c;
-	unsigned long flags;
-	u32 addr = 0x1200 + 0x2E0 * link + 0x1E2;
-	u8 retry = MAX_CMD_RETRY;
-	int err = 0;
-
-	c.command = command;
-	c.link = link;
-	c.len = len1 + len2;
-
-	spin_lock_irqsave(&card->u.x.lock, flags);
-
-	/* write command */
-	cycx_poke(&card->hw, X25_MBOX_OFFS, &c, sizeof(c) - sizeof(c.buf));
-
-	/* write x25 data */
-	if (d1) {
-		cycx_poke(&card->hw, addr, d1, len1);
-
-		if (d2) {
-			if (len2 > 254) {
-				u32 addr1 = 0xA00 + 0x400 * link;
-
-				cycx_poke(&card->hw, addr + len1, d2, 249);
-				cycx_poke(&card->hw, addr1, ((u8*) d2) + 249,
-					  len2 - 249);
-			} else
-				cycx_poke(&card->hw, addr + len1, d2, len2);
-		}
-	}
-
-	/* generate interruption, executing command */
-	cycx_intr(&card->hw);
-
-	/* wait till card->mbox == 0 */
-	do {
-		err = cycx_exec(card->mbox);
-	} while (retry-- && err);
-
-	spin_unlock_irqrestore(&card->u.x.lock, flags);
-
-	return err;
-}
-
-/* Configure adapter. */
-static int x25_configure (cycx_t *card, TX25Config *conf)
-{
-	struct {
-		u16 nlinks;
-		TX25Config conf[2];
-	} x25_cmd_conf;
-
-	memset (&x25_cmd_conf, 0, sizeof(x25_cmd_conf));
-	x25_cmd_conf.nlinks = 2;
-	x25_cmd_conf.conf[0] = *conf;
-	/* FIXME: we need to find a way in the wanrouter framework
-		  to configure the second link, for now lets use it
-		  with the same config from the first link, fixing
-		  the interface type to RS232, the speed in 38400 and
-		  the clock to external */
-	x25_cmd_conf.conf[1] = *conf;
-	x25_cmd_conf.conf[1].link = 1;
-	x25_cmd_conf.conf[1].speed = 5; /* 38400 */
-	x25_cmd_conf.conf[1].clock = 8;
-	x25_cmd_conf.conf[1].flags = 0; /* default = RS232 */
-
-	x25_dump_config(&x25_cmd_conf.conf[0]);
-	x25_dump_config(&x25_cmd_conf.conf[1]);
-
-	return x25_exec(card, X25_CONFIG, 0,
-			&x25_cmd_conf, sizeof(x25_cmd_conf), NULL, 0);
-}
-
-/* Get protocol statistics. */
-static int x25_get_stats (cycx_t *card)
-{
-	/* the firmware expects 20 in the size field!!!
-	   thanx to Daniela */
-	int err = x25_exec(card, X25_STATISTIC, 0, NULL, 20, NULL, 0);
-
-	if (err)
-		return err;
-
-	interruptible_sleep_on(&card->wait_stats);
-
-	if (signal_pending(current))
-		return -EINTR;
-
-	card->wandev.stats.rx_packets = card->u.x.stats.n2_rx_frames;
-	card->wandev.stats.rx_over_errors = card->u.x.stats.rx_over_errors;
-	card->wandev.stats.rx_crc_errors = card->u.x.stats.rx_crc_errors;
-	card->wandev.stats.rx_length_errors = 0; /* not available from fw */
-	card->wandev.stats.rx_frame_errors = 0; /* not available from fw */
-	card->wandev.stats.rx_missed_errors = card->u.x.stats.rx_aborts;
-	card->wandev.stats.rx_dropped = 0; /* not available from fw */
-	card->wandev.stats.rx_errors = 0; /* not available from fw */
-	card->wandev.stats.tx_packets = card->u.x.stats.n2_tx_frames;
-	card->wandev.stats.tx_aborted_errors = card->u.x.stats.tx_aborts;
-	card->wandev.stats.tx_dropped = 0; /* not available from fw */
-	card->wandev.stats.collisions = 0; /* not available from fw */
-	card->wandev.stats.tx_errors = 0; /* not available from fw */
-
-	x25_dump_devs(&card->wandev);
-	return 0;
-}
-
-/* return the number of nibbles */
-static int byte_to_nibble(u8 *s, u8 *d, char *nibble)
-{
-        int i = 0;
-
-        if (*nibble && *s) {
-                d[i] |= *s++ - '0';
-                *nibble = 0;
-                ++i;
-        }
-
-        while (*s) {
-                d[i] = (*s - '0') << 4;
-                if (*(s + 1))
-			d[i] |= *(s + 1) - '0';
-                else {
-                        *nibble = 1;
-                        break;
-                }
-                ++i;
-                s += 2;
-        }
-
-        return i;
-}
-
-static void nibble_to_byte(u8 *s, u8 *d, u8 len, u8 nibble)
-{
-	if (nibble) {
-		*d++ = '0' + (*s++ & 0x0F);
-		--len;
-	}
-
-	while (len) {
-		*d++ = '0' + (*s >> 4);
-
-		if (--len) {
-			*d++ = '0' + (*s & 0x0F);
-			--len;
-		} else break;
-		
-		++s;
-	}
-
-	*d = '\0';
-}
-
-/* Place X.25 call. */
-static int x25_place_call (cycx_t *card, x25_channel_t *chan)
-{
-	int err = 0,
-	    len;
-	char d[64],
-	     nibble = 0,
-	     mylen = chan->local_addr ? strlen(chan->local_addr) : 0,
-	     remotelen = strlen(chan->addr);
-	u8 key;
-
-	if (card->u.x.connection_keys == ~0UL) {
-		printk(KERN_INFO "%s: too many simultaneous connection "
-				 "requests!\n", card->devname);
-		return -EAGAIN;
-	}
-
-	key = ffz(card->u.x.connection_keys);
-	set_bit(key, (void*)&card->u.x.connection_keys);
-	++key;
-	dprintk(KERN_INFO "%s:x25_place_call:key=%d\n", card->devname, key);
-	memset(d, 0, sizeof(d));
-	d[1] = key; /* user key */
-	d[2] = 0x10;
-	d[4] = 0x0B;
-
-	len = byte_to_nibble(chan->addr, d + 6, &nibble);
-
-	if (chan->local_addr)
-		len += byte_to_nibble(chan->local_addr, d + 6 + len, &nibble);
-
-	if (nibble)
-		++len;
-
-	d[5] = mylen << 4 | remotelen;
-	d[6 + len + 1] = 0xCC; /* TCP/IP over X.25, thanx to Daniela :) */
-	
-	if ((err = x25_exec(card, X25_CONNECT_REQUEST, chan->link,
-			    &d, 7 + len + 1, NULL, 0)) != 0)
-		clear_bit(--key, (void*)&card->u.x.connection_keys);
-	else {
-                chan->lcn = -key;
-                chan->protocol = ETH_P_IP;
-        }
-
-        return err;
-}
-
-/* Place X.25 CONNECT RESPONSE. */
-static int x25_connect_response (cycx_t *card, x25_channel_t *chan)
-{
-	u8 d[8];
-
-	memset(d, 0, sizeof(d));
-	d[0] = d[3] = chan->lcn;
-	d[2] = 0x10;
-	d[4] = 0x0F;
-	d[7] = 0xCC; /* TCP/IP over X.25, thanx Daniela */
-
-	return x25_exec(card, X25_CONNECT_RESPONSE, chan->link, &d, 8, NULL, 0);
-}
-
-/* Place X.25 DISCONNECT RESPONSE.  */
-static int x25_disconnect_response (cycx_t *card, u8 link, u8 lcn)
-{
-	char d[5];
-
-	memset(d, 0, sizeof(d));
-	d[0] = d[3] = lcn;
-	d[2] = 0x10;
-	d[4] = 0x17;
-	return x25_exec(card, X25_DISCONNECT_RESPONSE, link, &d, 5, NULL, 0);
-}
-
-/* Clear X.25 call.  */
-static int x25_clear_call (cycx_t *card, u8 link, u8 lcn, u8 cause, u8 diagn)
-{
-	u8 d[7];
-
-	memset(d, 0, sizeof(d));
-	d[0] = d[3] = lcn;
-	d[2] = 0x10;
-	d[4] = 0x13;
-	d[5] = cause;
-	d[6] = diagn;
-
-	return x25_exec(card, X25_DISCONNECT_REQUEST, link, d, 7, NULL, 0);
-}
-
-/* Send X.25 data packet. */
-static int x25_send (cycx_t *card, u8 link, u8 lcn, u8 bitm, int len, void *buf)
-{
-	u8 d[] = "?\xFF\x10??"; 
-
-	d[0] = d[3] = lcn;
-	d[4] = bitm;
-
-	return x25_exec(card, X25_DATA_REQUEST, link, &d, 5, buf, len);
-}
-
-/* Miscellaneous */
-/* Find network device by its channel number.  */
-static struct net_device *get_dev_by_lcn (wan_device_t *wandev, s16 lcn)
-{
-	struct net_device *dev = wandev->dev;
-
-	for (; dev; dev = dev->slave)
-		if (((x25_channel_t*)dev->priv)->lcn == lcn)
-			break;
-	return dev;
-}
-
-/* Find network device by its remote dte address. */
-static struct net_device *get_dev_by_dte_addr (wan_device_t *wandev, char *dte)
-{
-	struct net_device *dev = wandev->dev;
-
-	for (; dev; dev = dev->slave)
-		if (!strcmp (((x25_channel_t*)dev->priv)->addr, dte))
-			break;
-	return dev;
-}
-
-/* Initiate connection on the logical channel.
- * o for PVC we just get channel configuration
- * o for SVCs place an X.25 call
- *
- * Return:	0	connected
- *		>0	connection in progress
- *		<0	failure */
-static int chan_connect (struct net_device *dev)
-{
-	x25_channel_t *chan = dev->priv;
-	cycx_t *card = chan->card;
-
-	if (chan->svc) {
-                if (!chan->addr[0])
-			return -EINVAL; /* no destination address */
-                dprintk(KERN_INFO "%s: placing X.25 call to %s...\n",
-				  card->devname, chan->addr);
-                if (x25_place_call(card, chan))
-			return -EIO;
-                set_chan_state(dev, WAN_CONNECTING);
-                return 1;
-        } else 
-		set_chan_state(dev, WAN_CONNECTED);
-
-	return 0;
-}
-
-/* Disconnect logical channel.
- * o if SVC then clear X.25 call */
-static void chan_disc (struct net_device *dev)
-{
-	x25_channel_t *chan = dev->priv;
-
-	if (chan->svc) {
-		x25_clear_call(chan->card, chan->link, chan->lcn, 0, 0);
-		set_chan_state(dev, WAN_DISCONNECTING);
-	} else
-		set_chan_state(dev, WAN_DISCONNECTED);
-}
-
-/* Called by kernel timer */
-static void chan_timer (unsigned long d)
-{
-	struct net_device *dev = (struct net_device*) d;
-	x25_channel_t *chan = dev->priv;
-	
-	switch (chan->state) {
-		case WAN_CONNECTED:
-			chan_disc(dev);
-			break;
-		default:
-			printk (KERN_ERR "%s: chan_timer for svc (%s) not "
-					 "connected!\n",
-					 chan->card->devname, dev->name);
-	}
-}
-
-/* Set logical channel state. */
-static void set_chan_state (struct net_device *dev, u8 state)
-{
-	x25_channel_t *chan = dev->priv;
-	cycx_t *card = chan->card;
-	u32 flags = 0;
-
-	spin_lock_irqsave(&card->lock, flags);
-
-	if (chan->state != state) {
-		if (chan->svc && chan->state == WAN_CONNECTED)
-			del_timer(&chan->timer);
-	
-		switch (state) {
-			case WAN_CONNECTED:
-				printk (KERN_INFO "%s: interface %s "
-						  "connected!\n",
-						  card->devname, dev->name);
-				*(u16*)dev->dev_addr = htons(chan->lcn);
-				dev->tbusy = 0;
-				reset_timer(dev);
-				break;
-
-			case WAN_CONNECTING:
-				printk (KERN_INFO "%s: interface %s "
-						  "connecting...\n",
-						  card->devname, dev->name);
-				break;
-
-			case WAN_DISCONNECTING:
-				printk (KERN_INFO "%s: interface %s "
-						  "disconnecting...\n",
-						  card->devname, dev->name);
-				break;
-
-			case WAN_DISCONNECTED:
-				printk (KERN_INFO "%s: interface %s "
-						  "disconnected!\n",
-						  card->devname, dev->name);
-				if (chan->svc) {
-					*(unsigned short*)dev->dev_addr = 0;
-					chan->lcn = 0;
-                                }
-				dev->tbusy = 0;
-				break;
-		}
-
-		chan->state = state;
-	}
-
-	spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/* Send packet on a logical channel.
- *	When this function is called, tx_skb field of the channel data space
- *	points to the transmit socket buffer.  When transmission is complete,
- *	release socket buffer and reset 'tbusy' flag.
- *
- * Return:	0	- transmission complete
- *		1	- busy
- *
- * Notes:
- * 1. If packet length is greater than MTU for this channel, we'll fragment
- *    the packet into 'complete sequence' using M-bit.
- * 2. When transmission is complete, an event notification should be issued
- *    to the router.  */
-static int chan_send (struct net_device *dev, struct sk_buff *skb)
-{
-	x25_channel_t *chan = dev->priv;
-	cycx_t *card = chan->card;
-	int bitm = 0;		/* final packet */
-	unsigned len = skb->len;
-
-	if (skb->len > card->wandev.mtu) {
-		len = card->wandev.mtu;
-		bitm = 0x10;		/* set M-bit (more data) */
-	}
-
-	if (x25_send(card, chan->link, chan->lcn, bitm, len, skb->data))
-		return 1;
-		
-	if (bitm) {
-		skb_pull(skb, len);
-		return 1;
-	}
-
-	++chan->ifstats.tx_packets;
-	chan->ifstats.tx_bytes += len;
-	return 0;
-}
-
-/* Convert line speed in bps to a number used by cyclom 2x code. */
-static u8 bps_to_speed_code (u32 bps)
-{
-	u8 number = 0; /* defaults to the lowest (1200) speed ;> */
-
-	     if (bps >= 512000) number = 8;
-	else if (bps >= 256000) number = 7;
-	else if (bps >= 64000)  number = 6;
-	else if (bps >= 38400)  number = 5;
-	else if (bps >= 19200)  number = 4;
-	else if (bps >= 9600)   number = 3;
-	else if (bps >= 4800)   number = 2;
-	else if (bps >= 2400)   number = 1;
-
-	return number;
-}
-
-/* log base 2 */
-static u8 log2 (u32 n)
-{
-        u8 log = 0;
-
-        if (!n)
-		return 0;
-
-        while (n > 1) {
-                n >>= 1;
-                ++log;
-        }
-
-        return log;
-}
-
-/* Convert decimal string to unsigned integer.
- * If len != 0 then only 'len' characters of the string are converted. */
-static unsigned dec_to_uint (u8 *str, int len)
-{
-	unsigned val = 0;
-
-	if (!len)
-		len = strlen(str);
-
-	for (; len && is_digit(*str); ++str, --len)
-		val = (val * 10) + (*str - (unsigned)'0');
-
-	return val;
-}
-
-static void reset_timer(struct net_device *dev)
-{
-	x25_channel_t *chan = dev->priv;
-
-	if (!chan->svc)
-		return;
-
-	del_timer(&chan->timer);
-	chan->timer.expires = jiffies + chan->idle_tmout * HZ;
-	add_timer(&chan->timer);
-}
-#ifdef CYCLOMX_X25_DEBUG
-static void x25_dump_config(TX25Config *conf)
-{
-	printk (KERN_INFO "x25 configuration\n");
-	printk (KERN_INFO "-----------------\n");
-        printk (KERN_INFO "link number=%d\n", conf->link);
-        printk (KERN_INFO "line speed=%d\n", conf->speed);
-        printk (KERN_INFO "clock=%sternal\n", conf->clock == 8 ? "Ex" : "In");
-        printk (KERN_INFO "# level 2 retransm.=%d\n", conf->n2);
-        printk (KERN_INFO "level 2 window=%d\n", conf->n2win);
-        printk (KERN_INFO "level 3 window=%d\n", conf->n3win);
-        printk (KERN_INFO "# logical channels=%d\n", conf->nvc);
-        printk (KERN_INFO "level 3 pkt len=%d\n", conf->pktlen);
-	printk (KERN_INFO "my address=%d\n", conf->locaddr);
-        printk (KERN_INFO "remote address=%d\n", conf->remaddr);
-        printk (KERN_INFO "t1=%d seconds\n", conf->t1);
-        printk (KERN_INFO "t2=%d seconds\n", conf->t2);
-        printk (KERN_INFO "t21=%d seconds\n", conf->t21);
-        printk (KERN_INFO "# PVCs=%d\n", conf->npvc);
-	printk (KERN_INFO "t23=%d seconds\n", conf->t23);
-        printk (KERN_INFO "flags=0x%x\n", conf->flags);
-}
-
-static void x25_dump_stats(TX25Stats *stats)
-{
-	printk (KERN_INFO "x25 statistics\n");
-	printk (KERN_INFO "--------------\n");
-        printk (KERN_INFO "rx_crc_errors=%d\n", stats->rx_crc_errors);
-        printk (KERN_INFO "rx_over_errors=%d\n", stats->rx_over_errors);
-        printk (KERN_INFO "n2_tx_frames=%d\n", stats->n2_tx_frames);
-        printk (KERN_INFO "n2_rx_frames=%d\n", stats->n2_rx_frames);
-        printk (KERN_INFO "tx_timeouts=%d\n", stats->tx_timeouts);
-        printk (KERN_INFO "rx_timeouts=%d\n", stats->rx_timeouts);
-        printk (KERN_INFO "n3_tx_packets=%d\n", stats->n3_tx_packets);
-        printk (KERN_INFO "n3_rx_packets=%d\n", stats->n3_rx_packets);
-        printk (KERN_INFO "tx_aborts=%d\n", stats->tx_aborts);
-        printk (KERN_INFO "rx_aborts=%d\n", stats->rx_aborts);
-}
-
-static void x25_dump_devs(wan_device_t *wandev)
-{
-	struct net_device *dev = wandev->dev;
-
-	printk (KERN_INFO "x25 dev states\n");
-	printk (KERN_INFO "name: addr:           tbusy:\n");
-	printk (KERN_INFO "----------------------------\n");
-
-	for (; dev; dev = dev->slave) {
-		x25_channel_t *chan = dev->priv;
-
-		printk (KERN_INFO "%-5.5s %-15.15s   %ld\n",
-				  chan->name, chan->addr, dev->tbusy);
-	}
-}
-
-#endif /* CYCLOMX_X25_DEBUG */
-/* End */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/dlci.c linux/drivers/net/dlci.c
--- v2.3.20/linux/drivers/net/dlci.c	Thu Aug 26 13:05:38 1999
+++ linux/drivers/net/dlci.c	Wed Dec 31 16:00:00 1969
@@ -1,634 +0,0 @@
-/*
- * DLCI		Implementation of Frame Relay protocol for Linux, according to
- *		RFC 1490.  This generic device provides en/decapsulation for an
- *		underlying hardware driver.  Routes & IPs are assigned to these
- *		interfaces.  Requires 'dlcicfg' program to create usable 
- *		interfaces, the initial one, 'dlci' is for IOCTL use only.
- *
- * Version:	@(#)dlci.c	0.35	4 Jan 1997
- *
- * Author:	Mike McLagan <mike.mclagan@linux.org>
- *
- * Changes:
- *
- *		0.15	Mike Mclagan	Packet freeing, bug in kmalloc call
- *					DLCI_RET handling
- *		0.20	Mike McLagan	More conservative on which packets
- *					are returned for retry and whic are
- *					are dropped.  If DLCI_RET_DROP is
- *					returned from the FRAD, the packet is
- *				 	sent back to Linux for re-transmission
- *		0.25	Mike McLagan	Converted to use SIOC IOCTL calls
- *		0.30	Jim Freeman	Fixed to allow IPX traffic
- *		0.35	Michael Elizabeth	Fixed incorrect memcpy_fromfs
- *
- *		This program is free software; you can redistribute it and/or
- *		modify it under the terms of the GNU General Public License
- *		as published by the Free Software Foundation; either version
- *		2 of the License, or (at your option) any later version.
- */
-
-#include <linux/config.h> /* for CONFIG_DLCI_COUNT */
-#include <linux/module.h>
-
-#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/init.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/uaccess.h>
-
-#include <linux/errno.h>
-
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/if_frad.h>
-
-#include <net/sock.h>
-
-static const char *devname = "dlci";
-static const char *version = "DLCI driver v0.35, 4 Jan 1997, mike.mclagan@linux.org";
-
-static struct net_device *open_dev[CONFIG_DLCI_COUNT];
-
-static char *basename[16];
-
-int dlci_init(struct net_device *dev);
-
-/* allow FRAD's to register their name as a valid FRAD */
-int register_frad(const char *name)
-{
-	int i;
-
-	if (!name)
-		return(-EINVAL);
-
-	for (i=0;i<sizeof(basename) / sizeof(char *);i++)
-	{
-		if (!basename[i])
-			break;
-
-		/* take care of multiple registrations */
-		if (strcmp(basename[i], name) == 0)
-			return(0);
-	}
-
-	if (i == sizeof(basename) / sizeof(char *))
-		return(-EMLINK);
-
-	basename[i] = kmalloc(strlen(name) + 1, GFP_KERNEL);
-	if (!basename[i])
-		return(-ENOMEM);
-
-	strcpy(basename[i], name);
-
-	return(0);
-}
-
-int unregister_frad(const char *name)
-{
-	int i;
-
-	if (!name)
-		return(-EINVAL);
-
-	for (i=0;i<sizeof(basename) / sizeof(char *);i++)
-		if (basename[i] && (strcmp(basename[i], name) == 0))
-			break;
-
-	if (i == sizeof(basename) / sizeof(char *))
-		return(-EINVAL);
-
-	kfree(basename[i]);
-	basename[i] = NULL;
-
-	return(0);
-}
-
-/* 
- * these encapsulate the RFC 1490 requirements as well as 
- * deal with packet transmission and reception, working with
- * the upper network layers 
- */
-
-static int dlci_header(struct sk_buff *skb, struct net_device *dev, 
-                           unsigned short type, void *daddr, void *saddr, 
-                           unsigned len)
-{
-	struct frhdr		hdr;
-	struct dlci_local	*dlp;
-	unsigned int		hlen;
-	char			*dest;
-
-	dlp = dev->priv;
-
-	hdr.control = FRAD_I_UI;
-	switch(type)
-	{
-		case ETH_P_IP:
-			hdr.IP_NLPID = FRAD_P_IP;
-			hlen = sizeof(hdr.control) + sizeof(hdr.IP_NLPID);
-			break;
-
-		/* feel free to add other types, if necessary */
-
-		default:
-			hdr.pad = FRAD_P_PADDING;
-			hdr.NLPID = FRAD_P_SNAP;
-			memset(hdr.OUI, 0, sizeof(hdr.OUI));
-			hdr.PID = htons(type);
-			hlen = sizeof(hdr);
-			break;
-	}
-
-	dest = skb_push(skb, hlen);
-	if (!dest)
-		return(0);
-
-	memcpy(dest, &hdr, hlen);
-
-	return(hlen);
-}
-
-static void dlci_receive(struct sk_buff *skb, struct net_device *dev)
-{
-	struct dlci_local *dlp;
-	struct frhdr		*hdr;
-	int					process, header;
-
-	dlp = dev->priv;
-	hdr = (struct frhdr *) skb->data;
-	process = 0;
-	header = 0;
-	skb->dev = dev;
-
-	if (hdr->control != FRAD_I_UI)
-	{
-		printk(KERN_NOTICE "%s: Invalid header flag 0x%02X.\n", dev->name, hdr->control);
-		dlp->stats.rx_errors++;
-	}
-	else
-		switch(hdr->IP_NLPID)
-		{
-			case FRAD_P_PADDING:
-				if (hdr->NLPID != FRAD_P_SNAP)
-				{
-					printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->NLPID);
-					dlp->stats.rx_errors++;
-					break;
-				}
-	 
-				if (hdr->OUI[0] + hdr->OUI[1] + hdr->OUI[2] != 0)
-				{
-					printk(KERN_NOTICE "%s: Unsupported organizationally unique identifier 0x%02X-%02X-%02X.\n", dev->name, hdr->OUI[0], hdr->OUI[1], hdr->OUI[2]);
-					dlp->stats.rx_errors++;
-					break;
-				}
-
-				/* at this point, it's an EtherType frame */
-				header = sizeof(struct frhdr);
-				/* Already in network order ! */
-				skb->protocol = hdr->PID;
-				process = 1;
-				break;
-
-			case FRAD_P_IP:
-				header = sizeof(hdr->control) + sizeof(hdr->IP_NLPID);
-				skb->protocol = htons(ETH_P_IP);
-				process = 1;
-				break;
-
-			case FRAD_P_SNAP:
-			case FRAD_P_Q933:
-			case FRAD_P_CLNP:
-				printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->pad);
-				dlp->stats.rx_errors++;
-				break;
-
-			default:
-				printk(KERN_NOTICE "%s: Invalid pad byte 0x%02X.\n", dev->name, hdr->pad);
-				dlp->stats.rx_errors++;
-				break;				
-		}
-
-	if (process)
-	{
-		/* we've set up the protocol, so discard the header */
-		skb->mac.raw = skb->data; 
-		skb_pull(skb, header);
-		netif_rx(skb);
-		dlp->stats.rx_packets++;
-	}
-	else
-		dev_kfree_skb(skb);
-}
-
-static int dlci_transmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct dlci_local *dlp;
-	int					ret;
-
-	ret = 0;
-
-	if (!skb || !dev)
-		return(0);
-
-	if (dev->tbusy)
-		return(1);
-
-	dlp = dev->priv;
-
-	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
-		printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
-	else
-	{
-		ret = dlp->slave->hard_start_xmit(skb, dlp->slave);
-		switch (ret)
-		{
-			case DLCI_RET_OK:
-				dlp->stats.tx_packets++;
-				ret = 0;
-				break;
-
-			case DLCI_RET_ERR:
-				dlp->stats.tx_errors++;
-				ret = 0;
-				break;
-
-			case DLCI_RET_DROP:
-				dlp->stats.tx_dropped++;
-				ret = 1;
-				break;
-		}
-
-		/* Alan Cox recommends always returning 0, and always freeing the packet */
-		/* experience suggest a slightly more conservative approach */
-
-		if (!ret)
-			dev_kfree_skb(skb);
-
-		dev->tbusy = 0;
-	}
-
-	return(ret);
-}
-
-int dlci_config(struct net_device *dev, struct dlci_conf *conf, int get)
-{
-	struct dlci_conf	config;
-	struct dlci_local	*dlp;
-	struct frad_local	*flp;
-	int			err;
-
-	dlp = dev->priv;
-
-	flp = dlp->slave->priv;
-
-	if (!get)
-	{
-		if(copy_from_user(&config, conf, sizeof(struct dlci_conf)))
-			return -EFAULT;
-		if (config.flags & ~DLCI_VALID_FLAGS)
-			return(-EINVAL);
-		memcpy(&dlp->config, &config, sizeof(struct dlci_conf));
-		dlp->configured = 1;
-	}
-
-	err = (*flp->dlci_conf)(dlp->slave, dev, get);
-	if (err)
-		return(err);
-
-	if (get)
-	{
-		if(copy_to_user(conf, &dlp->config, sizeof(struct dlci_conf)))
-			return -EFAULT;
-	}
-
-	return(0);
-}
-
-int dlci_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-	struct dlci_local *dlp;
-
-	if (!capable(CAP_NET_ADMIN))
-		return(-EPERM);
-
-	dlp = dev->priv;
-
-	switch(cmd)
-	{
-		case DLCI_GET_SLAVE:
-			if (!*(short *)(dev->dev_addr))
-				return(-EINVAL);
-
-			strncpy(ifr->ifr_slave, dlp->slave->name, sizeof(ifr->ifr_slave));
-			break;
-
-		case DLCI_GET_CONF:
-		case DLCI_SET_CONF:
-			if (!*(short *)(dev->dev_addr))
-				return(-EINVAL);
-
-			return(dlci_config(dev, (struct dlci_conf *) ifr->ifr_data, cmd == DLCI_GET_CONF));
-			break;
-
-		default: 
-			return(-EOPNOTSUPP);
-	}
-	return(0);
-}
-
-static int dlci_change_mtu(struct net_device *dev, int new_mtu)
-{
-	struct dlci_local *dlp;
-
-	dlp = dev->priv;
-
-	return((*dlp->slave->change_mtu)(dlp->slave, new_mtu));
-}
-
-static int dlci_open(struct net_device *dev)
-{
-	struct dlci_local	*dlp;
-	struct frad_local	*flp;
-	int			err;
-
-	dlp = dev->priv;
-
-	if (!*(short *)(dev->dev_addr))
-		return(-EINVAL);
-
-	if (!dlp->slave->start)
-		return(-ENOTCONN);
-
-	dev->flags = 0;
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 1;
-
-	flp = dlp->slave->priv;
-	err = (*flp->activate)(dlp->slave, dev);
-	if (err)
-		return(err);
-
-	return 0;
-}
-
-static int dlci_close(struct net_device *dev)
-{
-	struct dlci_local	*dlp;
-	struct frad_local	*flp;
-	int			err;
-
-	dlp = dev->priv;
-
-	flp = dlp->slave->priv;
-	err = (*flp->deactivate)(dlp->slave, dev);
-
-	dev->start = 0;
-	dev->tbusy = 1;
-
-	return 0;
-}
-
-static struct net_device_stats *dlci_get_stats(struct net_device *dev)
-{
-	struct dlci_local *dlp;
-
-	dlp = dev->priv;
-
-	return(&dlp->stats);
-}
-
-int dlci_add(struct dlci_add *dlci)
-{
-	struct net_device		*master, *slave;
-	struct dlci_local	*dlp;
-	struct frad_local	*flp;
-	int			err, i;
-	char			buf[10];
-
-	/* validate slave device */
-	slave = __dev_get_by_name(dlci->devname);
-	if (!slave)
-		return(-ENODEV);
-
-	if (slave->type != ARPHRD_FRAD)
-		return(-EINVAL);
-
-	/* check for registration */
-	for (i=0;i<sizeof(basename) / sizeof(char *); i++)
-		if ((basename[i]) && 
-			 (strncmp(dlci->devname, basename[i], strlen(basename[i])) == 0) && 
-			 (strlen(dlci->devname) > strlen(basename[i])))
-			break;
-
-	if (i == sizeof(basename) / sizeof(char *))
-		return(-EINVAL);
-
-	/* check for too many open devices : should this be dynamic ? */
-	for(i=0;i<CONFIG_DLCI_COUNT;i++)
-		if (!open_dev[i])
-			break;
-
-	if (i == CONFIG_DLCI_COUNT)
-		return(-ENOSPC);  /*  #### Alan: Comments on this?? */
-
-	/* create device name */
-	sprintf(buf, "%s%02i", devname, i);
-
-	master = kmalloc(sizeof(*master), GFP_KERNEL);
-	if (!master)
-		return(-ENOMEM);
-
-	memset(master, 0, sizeof(*master));
-	master->name = kmalloc(strlen(buf) + 1, GFP_KERNEL);
-
-	if (!master->name)
-	{
-		kfree(master);
-		return(-ENOMEM);
-	}
-
-	strcpy(master->name, buf);
-	master->init = dlci_init;
-	master->flags = 0;
-
-	err = register_netdev(master);
-	if (err < 0)
-	{
-		kfree(master->name);
-		kfree(master);
-		return(err);
-	}
-
-	*(short *)(master->dev_addr) = dlci->dlci;
-
-	dlp = (struct dlci_local *) master->priv;
-	dlp->slave = slave;
-
-	flp = slave->priv;
-	err = flp ? (*flp->assoc)(slave, master) : -EINVAL;
-	if (err < 0)
-	{
-		unregister_netdev(master);
-		kfree(master->priv);
-		kfree(master->name);
-		kfree(master);
-		return(err);
-	}
-
-	strcpy(dlci->devname, buf);
-	open_dev[i] = master;
-	MOD_INC_USE_COUNT;
-	return(0);
-}
-
-int dlci_del(struct dlci_add *dlci)
-{
-	struct dlci_local	*dlp;
-	struct frad_local	*flp;
-	struct net_device		*master, *slave;
-	int			i, err;
-
-	/* validate slave device */
-	master = __dev_get_by_name(dlci->devname);
-	if (!master)
-		return(-ENODEV);
-
-	if (master->start)
-		return(-EBUSY);
-
-	dlp = master->priv;
-	slave = dlp->slave;
-	flp = slave->priv;
-
-	err = (*flp->deassoc)(slave, master);
-	if (err)
-		return(err);
-
-	unregister_netdev(master);
-
-	for(i=0;i<CONFIG_DLCI_COUNT;i++)
-		if (master == open_dev[i])
-			break;
-
-	if (i<CONFIG_DLCI_COUNT)
-		open_dev[i] = NULL;
-
-	kfree(master->priv);
-	kfree(master->name);
-	kfree(master);
-
-	MOD_DEC_USE_COUNT;
-
-	return(0);
-}
-
-int dlci_ioctl(unsigned int cmd, void *arg)
-{
-	struct dlci_add add;
-	int err;
-	
-	if (!capable(CAP_NET_ADMIN))
-		return(-EPERM);
-
-	if(copy_from_user(&add, arg, sizeof(struct dlci_add)))
-		return -EFAULT;
-
-	switch (cmd)
-	{
-		case SIOCADDDLCI:
-			err = dlci_add(&add);
-
-			if (!err)
-				if(copy_to_user(arg, &add, sizeof(struct dlci_add)))
-					return -EFAULT;
-			break;
-
-		case SIOCDELDLCI:
-			err = dlci_del(&add);
-			break;
-
-		default:
-			err = -EINVAL;
-	}
-
-	return(err);
-}
-
-int dlci_init(struct net_device *dev)
-{
-	struct dlci_local *dlp;
-
-	dev->priv = kmalloc(sizeof(struct dlci_local), GFP_KERNEL);
-	if (!dev->priv)
-		return(-ENOMEM);
-
-	memset(dev->priv, 0, sizeof(struct dlci_local));
-	dlp = dev->priv;
-
-	dev->flags		= 0;
-	dev->open		= dlci_open;
-	dev->stop		= dlci_close;
-	dev->do_ioctl		= dlci_dev_ioctl;
-	dev->hard_start_xmit	= dlci_transmit;
-	dev->hard_header	= dlci_header;
-	dev->get_stats		= dlci_get_stats;
-	dev->change_mtu		= dlci_change_mtu;
-
-	dlp->receive		= dlci_receive;
-
-	dev->type		= ARPHRD_DLCI;
-	dev->hard_header_len	= sizeof(struct frhdr);
-	dev->addr_len		= sizeof(short);
-	memset(dev->dev_addr, 0, sizeof(dev->dev_addr));
-
-	dev_init_buffers(dev);
-	
-	return(0);
-}
-
-int __init dlci_setup(void)
-{
-	int i;
-
-	printk("%s.\n", version);
-	
-	for(i=0;i<CONFIG_DLCI_COUNT;i++)
-		open_dev[i] = NULL;
-
-	for(i=0;i<sizeof(basename) / sizeof(char *);i++)
-		basename[i] = NULL;
-
-	return(0);
-}
-
-#ifdef MODULE
-
-extern int (*dlci_ioctl_hook)(unsigned int, void *);
-
-int init_module(void)
-{
-	dlci_ioctl_hook = dlci_ioctl;
-
-	return(dlci_setup());
-}
-
-void cleanup_module(void)
-{
-	dlci_ioctl_hook = NULL;
-}
-#endif /* MODULE */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/hostess_sv11.c linux/drivers/net/hostess_sv11.c
--- v2.3.20/linux/drivers/net/hostess_sv11.c	Wed Aug 18 11:36:42 1999
+++ linux/drivers/net/hostess_sv11.c	Wed Dec 31 16:00:00 1969
@@ -1,434 +0,0 @@
-#define LINUX_21
-
-/*
- *	Comtrol SV11 card driver
- *
- *	This is a slightly odd Z85230 synchronous driver. All you need to
- *	know basically is
- *
- *	Its a genuine Z85230
- *
- *	It supports DMA using two DMA channels in SYNC mode. The driver doesn't
- *	use these facilities
- *	
- *	The control port is at io+1, the data at io+3 and turning off the DMA
- *	is done by writing 0 to io+4
- *
- *	The hardware does the bus handling to avoid the need for delays between
- *	touching control registers.
- *
- *	Port B isnt wired (why - beats me)
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/net.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <net/arp.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/byteorder.h>
-#include "syncppp.h"
-#include "z85230.h"
-
-static int dma;
-
-struct sv11_device
-{
-	struct z8530_dev sync;
-	struct ppp_device netdev;
-	char name[16];
-};
-
-/*
- *	Network driver support routines
- */
-
-/*
- *	Frame receive. Simple for our card as we do sync ppp and there
- *	is no funny garbage involved
- */
- 
-static void hostess_input(struct z8530_channel *c, struct sk_buff *skb)
-{
-	/* Drop the CRC - its not a good idea to try and negotiate it ;) */
-	skb_trim(skb, skb->len-2);
-	skb->protocol=htons(ETH_P_WAN_PPP);
-	skb->mac.raw=skb->data;
-	skb->dev=c->netdevice;
-	/*
-	 *	Send it to the PPP layer. We dont have time to process
-	 *	it right now.
-	 */
-	netif_rx(skb);
-}
- 
-/*
- *	We've been placed in the UP state
- */ 
- 
-static int hostess_open(struct net_device *d)
-{
-	struct sv11_device *sv11=d->priv;
-	int err = -1;
-	
-	/*
-	 *	Link layer up
-	 */
-	switch(dma)
-	{
-		case 0:
-			err=z8530_sync_open(d, &sv11->sync.chanA);
-			break;
-		case 1:
-			err=z8530_sync_dma_open(d, &sv11->sync.chanA);
-			break;
-		case 2:
-			err=z8530_sync_txdma_open(d, &sv11->sync.chanA);
-			break;
-	}
-	
-	if(err)
-		return err;
-	/*
-	 *	Begin PPP
-	 */
-	err=sppp_open(d);
-	if(err)
-	{
-		switch(dma)
-		{
-			case 0:
-				z8530_sync_close(d, &sv11->sync.chanA);
-				break;
-			case 1:
-				z8530_sync_dma_close(d, &sv11->sync.chanA);
-				break;
-			case 2:
-				z8530_sync_txdma_close(d, &sv11->sync.chanA);
-				break;
-		}				
-		return err;
-	}
-	sv11->sync.chanA.rx_function=hostess_input;
-	
-	/*
-	 *	Go go go
-	 */
-	d->tbusy=0;
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-
-static int hostess_close(struct net_device *d)
-{
-	struct sv11_device *sv11=d->priv;
-	/*
-	 *	Discard new frames
-	 */
-	sv11->sync.chanA.rx_function=z8530_null_rx;
-	/*
-	 *	PPP off
-	 */
-	sppp_close(d);
-	/*
-	 *	Link layer down
-	 */
-	d->tbusy=1;
-	
-	switch(dma)
-	{
-		case 0:
-			z8530_sync_close(d, &sv11->sync.chanA);
-			break;
-		case 1:
-			z8530_sync_dma_close(d, &sv11->sync.chanA);
-			break;
-		case 2:
-			z8530_sync_txdma_close(d, &sv11->sync.chanA);
-			break;
-	}
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-static int hostess_ioctl(struct net_device *d, struct ifreq *ifr, int cmd)
-{
-	/* struct sv11_device *sv11=d->priv;
-	   z8530_ioctl(d,&sv11->sync.chanA,ifr,cmd) */
-	return sppp_do_ioctl(d, ifr,cmd);
-}
-
-static struct enet_statistics *hostess_get_stats(struct net_device *d)
-{
-	struct sv11_device *sv11=d->priv;
-	if(sv11)
-		return z8530_get_stats(&sv11->sync.chanA);
-	else
-		return NULL;
-}
-
-/*
- *	Passed PPP frames, fire them downwind.
- */
- 
-static int hostess_queue_xmit(struct sk_buff *skb, struct net_device *d)
-{
-	struct sv11_device *sv11=d->priv;
-	return z8530_queue_xmit(&sv11->sync.chanA, skb);
-}
-
-#ifdef LINUX_21
-static int hostess_neigh_setup(struct neighbour *n)
-{
-	if (n->nud_state == NUD_NONE) {
-		n->ops = &arp_broken_ops;
-		n->output = n->ops->output;
-	}
-	return 0;
-}
-
-static int hostess_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p)
-{
-	if (p->tbl->family == AF_INET) {
-		p->neigh_setup = hostess_neigh_setup;
-		p->ucast_probes = 0;
-		p->mcast_probes = 0;
-	}
-	return 0;
-}
-
-#else
-
-static int return_0(struct net_device *d)
-{
-	return 0;
-}
-
-#endif
-
-/*
- *	Description block for a Comtrol Hostess SV11 card
- */
- 
-static struct sv11_device *sv11_init(int iobase, int irq)
-{
-	struct z8530_dev *dev;
-	struct sv11_device *sv;
-	int i;
-	unsigned long flags;
-	
-	/*
-	 *	Get the needed I/O space
-	 */
-	 
-	if(check_region(iobase, 8))
-	{	
-		printk(KERN_WARNING "hostess: I/O 0x%X already in use.\n", iobase);
-		return NULL;
-	}
-	request_region(iobase, 8, "Comtrol SV11");
-	
-	sv=(struct sv11_device *)kmalloc(sizeof(struct sv11_device), GFP_KERNEL);
-	if(!sv)
-		goto fail3;
-			
-	memset(sv, 0, sizeof(*sv));
-	
-	dev=&sv->sync;
-	
-	/*
-	 *	Stuff in the I/O addressing
-	 */
-	 
-	dev->active = 0;
-	
-	dev->chanA.ctrlio=iobase+1;
-	dev->chanA.dataio=iobase+3;
-	dev->chanB.ctrlio=-1;
-	dev->chanB.dataio=-1;
-	dev->chanA.irqs=&z8530_nop;
-	dev->chanB.irqs=&z8530_nop;
-	
-	outb(0, iobase+4);		/* DMA off */
-	
-	/* We want a fast IRQ for this device. Actually we'd like an even faster
-	   IRQ ;) - This is one driver RtLinux is made for */
-	   
-	if(request_irq(irq, &z8530_interrupt, SA_INTERRUPT, "Hostess SV/11", dev)<0)
-	{
-		printk(KERN_WARNING "hostess: IRQ %d already in use.\n", irq);
-		goto fail2;
-	}
-	
-	dev->irq=irq;
-	dev->chanA.private=sv;
-	dev->chanA.netdevice=&sv->netdev.dev;
-	dev->chanA.dev=dev;
-	dev->chanB.dev=dev;
-	dev->name=sv->name;
-	
-	if(dma)
-	{
-		/*
-		 *	You can have DMA off or 1 and 3 thats the lot
-		 *	on the Comtrol.
-		 */
-		dev->chanA.txdma=3;
-		dev->chanA.rxdma=1;
-		outb(0x03|0x08, iobase+4);		/* DMA on */
-		if(request_dma(dev->chanA.txdma, "Hostess SV/11 (TX)")!=0)
-			goto fail;
-			
-		if(dma==1)
-		{
-			if(request_dma(dev->chanA.rxdma, "Hostess SV/11 (RX)")!=0)
-				goto dmafail;
-		}
-	}
-	save_flags(flags);
-	cli();
-	
-	/*
-	 *	Begin normal initialise
-	 */
-	 
-	if(z8530_init(dev)!=0)
-	{
-		printk(KERN_ERR "Z8530 series device not found.\n");
-		goto dmafail2;
-	}
-	z8530_channel_load(&dev->chanB, z8530_dead_port);
-	if(dev->type==Z85C30)
-		z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream);
-	else
-		z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream_85230);
-	
-	restore_flags(flags);
-
-
-	/*
-	 *	Now we can take the IRQ
-	 */
-	
-	for(i=0;i<999;i++)
-	{
-		sprintf(sv->name,"hdlc%d", i);
-		if(dev_get(sv->name)==NULL)
-		{
-			struct net_device *d=dev->chanA.netdevice;
-	
-			/* 
-			 *	Initialise the PPP components
-			 */
-			sppp_attach(&sv->netdev);
-			
-			/*
-			 *	Local fields
-			 */	
-			sprintf(sv->name,"hdlc%d", i);
-			
-			d->name = sv->name;
-			d->base_addr = iobase;
-			d->irq = irq;
-			d->priv = sv;
-			d->init = NULL;
-			
-			d->open = hostess_open;
-			d->stop = hostess_close;
-			d->hard_start_xmit = hostess_queue_xmit;
-			d->get_stats = hostess_get_stats;
-			d->set_multicast_list = NULL;
-			d->do_ioctl = hostess_ioctl;
-#ifdef LINUX_21			
-			d->neigh_setup = hostess_neigh_setup_dev;
-			dev_init_buffers(d);
-#else
-			d->init = return_0;
-#endif
-			d->set_mac_address = NULL;
-			
-			if(register_netdev(d)==-1)
-			{
-				printk(KERN_ERR "%s: unable to register device.\n",
-					sv->name);
-				goto fail;
-			}				
-
-			z8530_describe(dev, "I/O", iobase);
-			dev->active=1;
-		 	return sv;	
-		}
-	}
-dmafail2:
-	if(dma==1)
-		free_dma(dev->chanA.rxdma);
-dmafail:
-	if(dma)
-		free_dma(dev->chanA.txdma);
-fail:
-	free_irq(irq, dev);
-fail2:
-	kfree(sv);
-fail3:
-	release_region(iobase,8);
-	return NULL;
-}
-
-static void sv11_shutdown(struct sv11_device *dev)
-{
-	sppp_detach(&dev->netdev.dev);
-	z8530_shutdown(&dev->sync);
-	unregister_netdev(&dev->netdev.dev);
-	free_irq(dev->sync.irq, dev);
-	if(dma)
-	{
-		if(dma==1)
-			free_dma(dev->sync.chanA.rxdma);
-		free_dma(dev->sync.chanA.txdma);
-	}
-	release_region(dev->sync.chanA.ctrlio-1, 8);
-}
-
-#ifdef MODULE
-
-static int io=0x200;
-static int irq=9;
-
-#ifdef LINUX_21
-MODULE_PARM(io,"i");
-MODULE_PARM_DESC(io, "The I/O base of the Comtrol Hostess SV11 card");
-MODULE_PARM(dma,"i");
-MODULE_PARM_DESC(dma, "Set this to 1 to use DMA1/DMA3 for TX/RX");
-MODULE_PARM(irq,"i");
-MODULE_PARM_DESC(irq, "The interrupt line setting for the Comtrol Hostess SV11 card");
-
-MODULE_AUTHOR("Bulding Number Three Ltd");
-MODULE_DESCRIPTION("Modular driver for the Comtrol Hostess SV11");
-#endif
-
-static struct sv11_device *sv11_unit;
-
-int init_module(void)
-{
-	printk(KERN_INFO "SV-11 Z85230 Synchronous Driver v 0.02.\n");
-	printk(KERN_INFO "(c) Copyright 1998, Building Number Three Ltd.\n");	
-	if((sv11_unit=sv11_init(io,irq))==NULL)
-		return -ENODEV;
-	return 0;
-}
-
-void cleanup_module(void)
-{
-	if(sv11_unit)
-		sv11_shutdown(sv11_unit);
-}
-
-#endif
-
diff -u --recursive --new-file v2.3.20/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c
--- v2.3.20/linux/drivers/net/ibmtr.c	Fri Sep 10 23:57:30 1999
+++ linux/drivers/net/ibmtr.c	Wed Dec 31 16:00:00 1969
@@ -1,1769 +0,0 @@
-/* ibmtr.c:  A shared-memory IBM Token Ring 16/4 driver for linux
- *
- *	Written 1993 by Mark Swanson and Peter De Schrijver.
- *	This software may be used and distributed according to the terms
- *	of the GNU Public License, incorporated herein by reference.
- *
- *	This device driver should work with Any IBM Token Ring Card that does
- *	not use DMA.
- *
- *	I used Donald Becker's (becker@cesdis.gsfc.nasa.gov) device driver work
- *	as a base for most of my initial work.
- *
- *	Changes by Peter De Schrijver (Peter.Deschrijver@linux.cc.kuleuven.ac.be) :
- *
- *	+ changed name to ibmtr.c in anticipation of other tr boards.
- *	+ changed reset code and adapter open code.
- *	+ added SAP open code.
- *	+ a first attempt to write interrupt, transmit and receive routines.
- *
- *	Changes by David W. Morris (dwm@shell.portal.com) :
- *	941003 dwm: - Restructure tok_probe for multiple adapters, devices.
- *	+ Add comments, misc reorg for clarity.
- *	+ Flatten interrupt handler levels.
- *
- *	Changes by Farzad Farid (farzy@zen.via.ecp.fr)
- *	and Pascal Andre (andre@chimay.via.ecp.fr) (March 9 1995) :
- *	+ multi ring support clean up.
- *	+ RFC1042 compliance enhanced.
- *
- *	Changes by Pascal Andre (andre@chimay.via.ecp.fr) (September 7 1995) :
- *	+ bug correction in tr_tx
- *	+ removed redundant information display
- *	+ some code reworking
- *
- *	Changes by Michel Lespinasse (walken@via.ecp.fr),
- *	Yann Doussot (doussot@via.ecp.fr) and Pascal Andre (andre@via.ecp.fr)
- *	(February 18, 1996) :
- *	+ modified shared memory and mmio access port the driver to
- *	  alpha platform (structure access -> readb/writeb)
- *
- *	Changes by Steve Kipisz (bungy@ibm.net or kipisz@vnet.ibm.com)
- *	(January 18 1996):
- *	+ swapped WWOR and WWCR in ibmtr.h
- *	+ moved some init code from tok_probe into trdev_init.  The
- *	  PCMCIA code can call trdev_init to complete initializing
- *	  the driver.
- *	+ added -DPCMCIA to support PCMCIA
- *	+ detecting PCMCIA Card Removal in interrupt handler.  If
- *	  ISRP is FF, then a PCMCIA card has been removed
- *
- *	Changes by Paul Norton (pnorton@cts.com) :
- *	+ restructured the READ.LOG logic to prevent the transmit SRB
- *	  from being rudely overwritten before the transmit cycle is
- *	  complete. (August 15 1996)
- *	+ completed multiple adapter support. (November 20 1996)
- *	+ implemented csum_partial_copy in tr_rx and increased receive 
- *        buffer size and count. Minor fixes. (March 15, 1997)
- *
- *	Changes by Christopher Turcksin <wabbit@rtfc.demon.co.uk>
- *	+ Now compiles ok as a module again.
- *
- *	Changes by Paul Norton (pnorton@ieee.org) :
- *      + moved the header manipulation code in tr_tx and tr_rx to
- *        net/802/tr.c. (July 12 1997)
- *      + add retry and timeout on open if cable disconnected. (May 5 1998)
- *      + lifted 2000 byte mtu limit. now depends on shared-RAM size.
- *        May 25 1998)
- *      + can't allocate 2k recv buff at 8k shared-RAM. (20 October 1998)
- *
- *      Changes by Joel Sloan (jjs@c-me.com) :
- *      + disable verbose debug messages by default - to enable verbose
- *	  debugging, edit the IBMTR_DEBUG_MESSAGES define below 
- *	
- *	Changes by Mike Phillips <phillim@amtrak.com> :
- *	+ Added extra #ifdef's to work with new PCMCIA Token Ring Code.
- *	  The PCMCIA code now just sets up the card so it can be recognized
- *        by ibmtr_probe. Also checks allocated memory vs. on-board memory
- *	  for correct figure to use.
- *
- *	Changes by Tim Hockin (thockin@isunix.it.ilstu.edu) :
- *	+ added spinlocks for SMP sanity (10 March 1999)
- */
-
-/* change the define of IBMTR_DEBUG_MESSAGES to a nonzero value 
-in the event that chatty debug messages are desired - jjs 12/30/98 */
-
-#define IBMTR_DEBUG_MESSAGES 0
-
-#ifdef PCMCIA
-#define MODULE
-#endif
-
-#include <linux/module.h>
-
-#ifdef PCMCIA
-#undef MODULE
-#endif
-
-#define NO_AUTODETECT 1
-#undef NO_AUTODETECT
-#undef ENABLE_PAGING
-
-
-#define FALSE 0
-#define TRUE (!FALSE)
-
-/* changes the output format of driver initialisation */
-#define TR_NEWFORMAT	1
-#define TR_VERBOSE	0
-
-/* some 95 OS send many non UI frame; this allow removing the warning */
-#define TR_FILTERNONUI	1
-
-/* version and credits */
-static char *version =
-"ibmtr.c: v1.3.57   8/ 7/94 Peter De Schrijver and Mark Swanson\n"
-"         v2.1.125 10/20/98 Paul Norton <pnorton@ieee.org>\n"
-"         v2.2.0   12/30/98 Joel Sloan <jjs@c-me.com>\n";
-
-static char pcchannelid[] = {
-	0x05, 0x00, 0x04, 0x09,
-	0x04, 0x03, 0x04, 0x0f,
-	0x03, 0x06, 0x03, 0x01,
-	0x03, 0x01, 0x03, 0x00,
-	0x03, 0x09, 0x03, 0x09,
-	0x03, 0x00, 0x02, 0x00
-};
-
-static char mcchannelid[] = {
-	0x04, 0x0d, 0x04, 0x01,
-	0x05, 0x02, 0x05, 0x03,
-	0x03, 0x06, 0x03, 0x03,
-	0x05, 0x08, 0x03, 0x04,
-	0x03, 0x05, 0x03, 0x01,
-	0x03, 0x08, 0x02, 0x00
-};
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <linux/in.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/skbuff.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/trdevice.h>
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <net/checksum.h>
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-
-#include "ibmtr.h"
-
-
-#define DPRINTK(format, args...) printk("%s: " format, dev->name , ## args)
-#define DPRINTD(format, args...) DummyCall("%s: " format, dev->name , ## args)
-#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
-#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
-
-#if TR_NEWFORMAT
-/* this allows displaying full adapter information */
-
-const char *channel_def[] __initdata = { 
-	"ISA", "MCA", "ISA P&P" 
-};
-
-char __init *adapter_def(char type)
-{
-	switch (type) 
-	{
-	      case 0xF : return "PC Adapter | PC Adapter II | Adapter/A";
-	      case 0xE : return "16/4 Adapter | 16/4 Adapter/A (long)";
-	      case 0xD : return "16/4 Adapter/A (short) | 16/4 ISA-16 Adapter";
-	      case 0xC : return "Auto 16/4 Adapter";
-	      default  : return "adapter (unknown type)";
-	};
-};
-#endif
-
-#if !TR_NEWFORMAT
-unsigned char ibmtr_debug_trace=1;  /*  Patch or otherwise alter to
-                                         control tokenring tracing.  */
-#else
-unsigned char ibmtr_debug_trace=0;
-#endif
-#define TRC_INIT 0x01              /*  Trace initialization & PROBEs */
-#define TRC_INITV 0x02             /*  verbose init trace points     */
-
-int		ibmtr_probe(struct net_device *dev);
-static int	ibmtr_probe1(struct net_device *dev, int ioaddr);
-static unsigned char	get_sram_size(struct tok_info *adapt_info);
-#ifdef PCMCIA
-extern unsigned char 	pcmcia_reality_check(unsigned char gss);
-#endif
-static int	tok_init_card(struct net_device *dev);
-void		tok_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int	trdev_init(struct net_device *dev);
-static void 	initial_tok_int(struct net_device *dev);
-static void 	open_sap(unsigned char type,struct net_device *dev);
-void		tok_open_adapter(unsigned long dev_addr);
-static		void tr_rx(struct net_device *dev);
-static		void tr_tx(struct net_device *dev);
-static int	tok_open(struct net_device *dev);
-static int	tok_close(struct net_device *dev);
-static int	tok_send_packet(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats * tok_get_stats(struct net_device *dev);
-void		ibmtr_readlog(struct net_device *dev);
-void		ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev);
-int             ibmtr_change_mtu(struct net_device *dev, int mtu);
-
-static unsigned int ibmtr_portlist[] __initdata = {
-	0xa20, 0xa24, 0
-};
-
-static __u32 ibmtr_mem_base = 0xd0000;
-
-static void __init PrtChanID(char *pcid, short stride) 
-{
-	short i, j;
-	for (i=0, j=0; i<24; i++, j+=stride)
-		printk("%1x", ((int) pcid[j]) & 0x0f);
-	printk("\n");
-}
-
-static void __init HWPrtChanID (__u32 pcid, short stride)
-{
-	short i, j;
-	for (i=0, j=0; i<24; i++, j+=stride)
-		printk("%1x", ((int)readb(pcid + j)) & 0x0f);
-	printk("\n");
-}
-
-/*
- *	ibmtr_probe():  Routine specified in the network device structure
- *	to probe for an IBM Token Ring Adapter.  Routine outline:
- *	I.    Interrogate hardware to determine if an adapter exists
- *	      and what the speeds and feeds are
- *	II.   Setup data structures to control execution based upon
- *	      adapter characteristics.
- *	III.  Initialize adapter operation
- *
- *	We expect ibmtr_probe to be called once for each device entry
- *	which references it.
- */
- 
-int __init ibmtr_probe(struct net_device *dev)
-{
-        int i;
-        int base_addr = dev ? dev->base_addr : 0;
-
-        if (base_addr > 0x1ff) 
-        { 
-        	/*
-        	 *	Check a single specified location. 
- 		 */
- 		 
-	        if (ibmtr_probe1(dev, base_addr)) 
-	        {
-#ifndef MODULE
-#ifndef PCMCIA
-		       tr_freedev(dev);
-#endif
-#endif
-		       return -ENODEV;
-		} else
-		       return 0;
-	}
-        else if (base_addr != 0)   /* Don't probe at all. */
-	        return -ENXIO;
-
-	for (i = 0; ibmtr_portlist[i]; i++) 
-	{
-	        int ioaddr = ibmtr_portlist[i];
-		if (check_region(ioaddr, IBMTR_IO_EXTENT))
-		        continue;
-                if (ibmtr_probe1(dev, ioaddr)) {
-#ifndef MODULE
-#ifndef PCMCIA
-		        tr_freedev(dev);
-#endif
-#endif
-		} else
-			return 0;
-        }
-
-        return -ENODEV;
-}
-
-static int __init ibmtr_probe1(struct net_device *dev, int PIOaddr)
-{
-	unsigned char segment=0, intr=0, irq=0, i=0, j=0, cardpresent=NOTOK,temp=0;
-	__u32 t_mmio=0;
-	struct tok_info *ti=0;
-	__u32 cd_chanid;
-	unsigned char *tchanid, ctemp;
-	unsigned long timeout;
-
-#ifndef MODULE
-#ifndef PCMCIA
-	dev = init_trdev(dev,0);
-#endif
-#endif
-
-	/*	Query the adapter PIO base port which will return
-	 *	indication of where MMIO was placed. We also have a
-	 *	coded interrupt number.
-	 */
-
-       	segment = inb(PIOaddr);
-
-	/*
-	 *	Out of range values so we'll assume non-existent IO device 
-	 */
-	 
-	if (segment < 0x40 || segment > 0xe0)
-                return -ENODEV;
-
-	/*
-	 *	Compute the linear base address of the MMIO area
-	 *	as LINUX doesn't care about segments
-	 */
-
-	t_mmio=(((__u32)(segment & 0xfc) << 11) + 0x80000);
-	intr = segment & 0x03;   /* low bits is coded interrupt # */
-	if (ibmtr_debug_trace & TRC_INIT)
-		DPRINTK("PIOaddr: %4hx seg/intr: %2x mmio base: %08X intr: %d\n",
-                         PIOaddr, (int)segment, t_mmio, (int)intr);
-
-	/*
-	 *	Now we will compare expected 'channelid' strings with
-	 *	what we is there to learn of ISA/MCA or not TR card
-	 */
-	 
-	cd_chanid = (CHANNEL_ID + t_mmio);  /* for efficiency */
-	tchanid=pcchannelid;
-	cardpresent=TR_ISA;  /* try ISA */
-
-	/*
-	 *	Suboptimize knowing first byte different
-	 */
-
-	ctemp = readb(cd_chanid) & 0x0f;
-	if (ctemp != *tchanid) { /* NOT ISA card, try MCA */
-		tchanid=mcchannelid;
-		cardpresent=TR_MCA;
-		if (ctemp != *tchanid)  /* Neither ISA nor MCA */
-			cardpresent=NOTOK;
-	}
-
-	if (cardpresent != NOTOK) 
-	{
-		/* 
-		 *	Know presumed type, try rest of ID 
-		 */
-		for (i=2,j=1; i<=46; i=i+2,j++) 
-		{
-			if ((readb(cd_chanid+i) & 0x0f) != tchanid[j]) {
-				cardpresent=NOTOK;   /* match failed, not TR card */
-				break;
-			}
-		}
-	}
-
-	/* 
-	 *	If we have an ISA board check for the ISA P&P version,
-	 *	as it has different IRQ settings 
-	 */
-
-	if (cardpresent == TR_ISA && (readb(AIPFID + t_mmio)==0x0e))
-	        cardpresent=TR_ISAPNP;
-
-	if (cardpresent == NOTOK) { /* "channel_id" did not match, report */
-		if (ibmtr_debug_trace & TRC_INIT) {
-			DPRINTK("Channel ID string not found for PIOaddr: %4hx\n", PIOaddr);
-			DPRINTK("Expected for ISA: ");  PrtChanID(pcchannelid,1);
-			DPRINTK("           found: ");  HWPrtChanID(cd_chanid,2);
-			DPRINTK("Expected for MCA: ");  PrtChanID(mcchannelid,1);
-		}
-                return -ENODEV;
-	}
-
-	/* Now, allocate some of the pl0 buffers for this driver.. */
-
-	/* If called from PCMCIA, ti is already set up, so no need to 
-	   waste the memory, just use the existing structure */
-
-#ifndef PCMCIA
-	ti = (struct tok_info *)kmalloc(sizeof(struct tok_info), GFP_KERNEL);
-	if (ti == NULL) 
-		return -ENOMEM;
-
-	memset(ti, 0, sizeof(struct tok_info));
-#else
-	ti = dev->priv ; 
-#endif
-	ti->mmio= t_mmio;
-	ti->readlog_pending = 0;
-	init_waitqueue_head(&ti->wait_for_tok_int);
-	init_waitqueue_head(&ti->wait_for_reset);
-
-	dev->priv = ti;     /* this seems like the logical use of the
-                         field ... let's try some empirical tests
-                         using the token-info structure -- that
-                         should fit with out future hope of multiple
-                         adapter support as well /dwm   */
-
-	/* if PCMCIA, then the card is recognized as TR_ISAPNP 
-	 * and there is no need to set up the interrupt, it is already done. */
-        
-#ifndef PCMCIA
-	switch (cardpresent) 
-	{
-		case TR_ISA:
-			if (intr==0)
-				irq=9; /* irq2 really is irq9 */
-			if (intr==1)
-				irq=3;
-			if (intr==2)
-				irq=6;
-			if (intr==3)
-				irq=7;
-			ti->global_int_enable=GLOBAL_INT_ENABLE+((irq==9) ? 2 : irq);
-			ti->adapter_int_enable=PIOaddr+ADAPTINTREL;
-			ti->sram=0;
-#if !TR_NEWFORMAT
-			DPRINTK("ti->global_int_enable: %04X\n",ti->global_int_enable);
-#endif
-			break;
-		case TR_MCA:
-			if (intr==0)
-				irq=9;
-			if (intr==1)
-				irq=3;
-			if (intr==2)
-				irq=10;
-			if (intr==3)
-				irq=11;
-			ti->global_int_enable=0;
-			ti->adapter_int_enable=0;
-			ti->sram=((__u32)(inb(PIOaddr+ADAPTRESETREL) & 0xfe) << 12);
-			break;
-		case TR_ISAPNP:
-			if (intr==0)
-				irq=9;
-			if (intr==1)
-				irq=3;
-			if (intr==2)
-				irq=10;
-			if (intr==3)
-				irq=11;
-			timeout = jiffies + TR_SPIN_INTERVAL;
-			while(!readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN))
-				if (time_after(jiffies, timeout)) {
-					DPRINTK("Hardware timeout during initialization.\n");
-					kfree_s(ti, sizeof(struct tok_info));
-					return -ENODEV;
-			        }
-
-			ti->sram=((__u32)readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)<<12);
-			ti->global_int_enable=PIOaddr+ADAPTINTREL;
-			ti->adapter_int_enable=PIOaddr+ADAPTINTREL;
-			break;
-	}
-#endif
-
-	if (ibmtr_debug_trace & TRC_INIT) { /* just report int */
-		DPRINTK("irq=%d",irq);
-		if (ibmtr_debug_trace & TRC_INITV) { /* full chat in verbose only */
-			DPRINTK(", ti->mmio=%08X",ti->mmio);
-			printk(", segment=%02X",segment);
-		}
-		printk(".\n");
-	}
-
-	/* Get hw address of token ring card */
-#if !TR_NEWFORMAT
-	DPRINTK("hw address: ");
-#endif
-	j=0;
-	for (i=0; i<0x18; i=i+2) 
-	{
-		/* technical reference states to do this */
-		temp = readb(ti->mmio + AIP + i) & 0x0f;
-#if !TR_NEWFORMAT
-		printk("%1X",ti->hw_address[j]=temp);
-#else
-		ti->hw_address[j]=temp;
-#endif
-		if(j&1)
-			dev->dev_addr[(j/2)]=ti->hw_address[j]+(ti->hw_address[j-1]<<4);
-		++j;
-	}
-#ifndef TR_NEWFORMAT
-	printk("\n");
-#endif
-
-	/* get Adapter type:  'F' = Adapter/A, 'E' = 16/4 Adapter II,...*/
-	ti->adapter_type = readb(ti->mmio + AIPADAPTYPE);
-
-	/* get Data Rate:  F=4Mb, E=16Mb, D=4Mb & 16Mb ?? */
-	ti->data_rate = readb(ti->mmio + AIPDATARATE);
-
-	/* Get Early Token Release support?: F=no, E=4Mb, D=16Mb, C=4&16Mb */
-	ti->token_release = readb(ti->mmio + AIPEARLYTOKEN);
-
-	/* How much shared RAM is on adapter ? */
-#ifdef PCMCIA
-	ti->avail_shared_ram = pcmcia_reality_check(get_sram_size(ti));
-	ibmtr_mem_base = ti->sram_base << 12 ; 
-#else
-	ti->avail_shared_ram = get_sram_size(ti);
-#endif
-	/* We need to set or do a bunch of work here based on previous results.. */
-	/* Support paging?  What sizes?:  F=no, E=16k, D=32k, C=16 & 32k */
-	ti->shared_ram_paging = readb(ti->mmio + AIPSHRAMPAGE);
-
-        /* Available DHB  4Mb size:   F=2048, E=4096, D=4464 */
-	switch (readb(ti->mmio + AIP4MBDHB)) {
-	case 0xe : 
-		ti->dhb_size4mb = 4096;
-		break; 
-	case 0xd : 
-		ti->dhb_size4mb = 4464;
-		break; 
-	default  : 
-		ti->dhb_size4mb = 2048;
-		break; 
-	}
-
-	/* Available DHB 16Mb size:  F=2048, E=4096, D=8192, C=16384, B=17960 */
-	switch (readb(ti->mmio + AIP16MBDHB)) {
-	case 0xe : 
-		ti->dhb_size16mb = 4096;
-		break; 
-	case 0xd : 
-		ti->dhb_size16mb = 8192;
-		break; 
-	case 0xc : 
-		ti->dhb_size16mb = 16384;
-		break; 
-	case 0xb : 
-		ti->dhb_size16mb = 17960;
-		break; 
-	default  : 
-		ti->dhb_size16mb = 2048;
-		break; 
-	}
-
-#if !TR_NEWFORMAT
-	DPRINTK("atype=%x, drate=%x, trel=%x, asram=%dK, srp=%x, "
-		"dhb(4mb=%x, 16mb=%x)\n",ti->adapter_type,
-		ti->data_rate, ti->token_release, ti->avail_shared_ram/2,
-		ti->shared_ram_paging, ti->dhb_size4mb, ti->dhb_size16mb);
-#endif
-
-	/*	We must figure out how much shared memory space this adapter
-	 *	will occupy so that if there are two adapters we can fit both
-	 *	in.  Given a choice, we will limit this adapter to 32K.  The
-	 *	maximum space will will use for two adapters is 64K so if the
-	 *	adapter we are working on demands 64K (it also doesn't support
-	 *	paging), then only one adapter can be supported.  
-	 */
-
-	/*
-	 *	determine how much of total RAM is mapped into PC space 
-	 */
-	ti->mapped_ram_size=1<<((((readb(ti->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD)) >>2) & 0x03) + 4);
-	ti->page_mask=0;
-	if (ti->shared_ram_paging == 0xf) { /* No paging in adapter */
-		ti->mapped_ram_size = ti->avail_shared_ram;
-	} else {
-#ifdef ENABLE_PAGING
-		unsigned char pg_size;
-#endif
-
-#if !TR_NEWFORMAT
-		DPRINTK("shared ram page size: %dK\n",ti->mapped_ram_size/2);
-#endif
-#ifdef ENABLE_PAGING
-	switch(ti->shared_ram_paging) 
-	{
-		case 0xf:
-			break;
-		case 0xe:
-			ti->page_mask=(ti->mapped_ram_size==32) ? 0xc0 : 0;
-			pg_size=32;   /* 16KB page size */
-			break;
-		case 0xd:
-			ti->page_mask=(ti->mapped_ram_size==64) ? 0x80 : 0;
-			pg_size=64;   /* 32KB page size */
-			break;
-		case 0xc:
-			ti->page_mask=(ti->mapped_ram_size==32) ? 0xc0 : 0;
-			ti->page_mask=(ti->mapped_ram_size==64) ? 0x80 : 0;
-			DPRINTK("Dual size shared RAM page (code=0xC), don't support it!\n");
-			/* nb/dwm: I did this because RRR (3,2) bits are documented as
-			   R/O and I can't find how to select which page size
-			   Also, the above conditional statement sequence is invalid
-			   as page_mask will always be set by the second stmt */
-			kfree_s(ti, sizeof(struct tok_info));
-			return -ENODEV;
-			break;
-		default:
-			DPRINTK("Unknown shared ram paging info %01X\n",ti->shared_ram_paging);
-			kfree_s(ti, sizeof(struct tok_info));
-			return -ENODEV;
-			break;
-	}
-	if (ti->page_mask) {
-		if (pg_size > ti->mapped_ram_size) {
-			DPRINTK("Page size (%d) > mapped ram window (%d), can't page.\n",
-				pg_size, ti->mapped_ram_size);
-				ti->page_mask = 0;    /* reset paging */
-		} else {
-			ti->mapped_ram_size=ti->avail_shared_ram;
-			DPRINTK("Shared RAM paging enabled. Page size : %uK\n",
-				((ti->page_mask^ 0xff)+1)>>2);
-		}
-#endif
-	}
-	/* finish figuring the shared RAM address */
-	if (cardpresent==TR_ISA) {
-		static __u32 ram_bndry_mask[]={0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000};
-		__u32 new_base, rrr_32, chk_base, rbm;
-
-		rrr_32 = ((readb(ti->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD))>>2) & 0x00000003;
-		rbm = ram_bndry_mask[rrr_32];
-		new_base = (ibmtr_mem_base + (~rbm)) & rbm; /* up to boundary */
-		chk_base = new_base + (ti->mapped_ram_size<<9);
-		if (chk_base > (ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE)) {
-			DPRINTK("Shared RAM for this adapter (%05x) exceeds driver"
-				" limit (%05x), adapter not started.\n",
-				chk_base, ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE);
-			kfree_s(ti, sizeof(struct tok_info));
-                        return -ENODEV;
-		} else {  /* seems cool, record what we have figured out */
-			ti->sram_base = new_base >> 12;
-			ibmtr_mem_base = chk_base;
-		}
-	}
-
-#if !TR_NEWFORMAT
-	DPRINTK("Using %dK shared RAM\n",ti->mapped_ram_size/2);
-#endif
-
-	/* The PCMCIA has already got the interrupt line and the io port, 
-	   so no chance of anybody else getting it - MLP */
-
-#ifndef PCMCIA
-	if (request_irq (dev->irq = irq, &tok_interrupt,0,"ibmtr", dev) != 0) {
-		DPRINTK("Could not grab irq %d.  Halting Token Ring driver.\n",irq);
-		kfree_s(ti, sizeof(struct tok_info));
-		return -ENODEV;
-	}
- 
-	/*?? Now, allocate some of the PIO PORTs for this driver.. */
-	request_region(PIOaddr,IBMTR_IO_EXTENT,"ibmtr");  /* record PIOaddr range as busy */
-#endif
-
-#if !TR_NEWFORMAT
-	DPRINTK("%s",version); /* As we have passed card identification,
-                                  let the world know we're here! */
-#else
-
-	if (version) {
-	        printk("%s",version);
-                version = NULL;
-        }
-	DPRINTK("%s %s found\n",
-		channel_def[cardpresent-1], adapter_def(ti->adapter_type));
-	DPRINTK("using irq %d, PIOaddr %hx, %dK shared RAM.\n",
-	        irq, PIOaddr, ti->mapped_ram_size/2);
-	DPRINTK("Hardware address : %02X:%02X:%02X:%02X:%02X:%02X\n",
-		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
-#endif
-	/* Calculate the maximum DHB we can use */
-	switch (ti->mapped_ram_size) {
-	case  16 : /* 8KB shared RAM */
-		ti->dhb_size4mb  = MIN(ti->dhb_size4mb, 2048);
-		ti->rbuf_len4 = 1032;
-		ti->rbuf_cnt4 = 2;
-		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 2048);
-		ti->rbuf_len16 = 1032;
-		ti->rbuf_cnt16 = 2;
-		break;
-	case  32 : /* 16KB shared RAM */
-		ti->dhb_size4mb  = MIN(ti->dhb_size4mb, 4464);
-		ti->rbuf_len4 = 520;
-		ti->rbuf_cnt4 = 9;
-		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 4096);
-		ti->rbuf_len16 = 1032; /* 1024 usable */
-		ti->rbuf_cnt16 = 4;
-		break;
-	case  64 : /* 32KB shared RAM */
-		ti->dhb_size4mb  = MIN(ti->dhb_size4mb, 4464);
-		ti->rbuf_len4 = 1032;
-		ti->rbuf_cnt4 = 6;
-		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 10240);
-		ti->rbuf_len16 = 1032;
-		ti->rbuf_cnt16 = 10;
-		break;
-	case 127 : /* 63KB shared RAM */
-		ti->dhb_size4mb  = MIN(ti->dhb_size4mb, 4464);
-		ti->rbuf_len4 = 1032;
-		ti->rbuf_cnt4 = 6;
-		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 16384);
-		ti->rbuf_len16 = 1032;
-		ti->rbuf_cnt16 = 16;
-		break;
-	case 128 : /* 64KB shared RAM */
-		ti->dhb_size4mb  = MIN(ti->dhb_size4mb, 4464);
-		ti->rbuf_len4 = 1032;
-		ti->rbuf_cnt4 = 6;
-		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 17960);
-		ti->rbuf_len16 = 1032;
-		ti->rbuf_cnt16 = 18;
-		break;
-	default  :
-		ti->dhb_size4mb  = 2048;
-		ti->rbuf_len4 = 1032;
-		ti->rbuf_cnt4 = 2;
-		ti->dhb_size16mb = 2048;
-		ti->rbuf_len16 = 1032;
-		ti->rbuf_cnt16 = 2;
-		break;
-	}
-
-	ti->maxmtu16 = (ti->rbuf_len16*ti->rbuf_cnt16)-((ti->rbuf_cnt16)<<3)-TR_HLEN;
-	ti->maxmtu4  = (ti->rbuf_len4*ti->rbuf_cnt4)-((ti->rbuf_cnt4)<<3)-TR_HLEN;
-	DPRINTK("Maximum MTU 16Mbps: %d, 4Mbps: %d\n",
-		ti->maxmtu16, ti->maxmtu4);
-
-	dev->base_addr=PIOaddr; /* set the value for device */
-
-	trdev_init(dev);
-	tok_init_card(dev);
-
-	return 0;  /* Return 0 to indicate we have found a Token Ring card. */
-}
-
-/* query the adapter for the size of shared RAM  */
-
-static unsigned char __init get_sram_size(struct tok_info *adapt_info)
-{
-
-	unsigned char avail_sram_code;
-	static unsigned char size_code[]={ 0,16,32,64,127,128 };
-	/* Adapter gives
-	   'F' -- use RRR bits 3,2
-	   'E' -- 8kb   'D' -- 16kb
-	   'C' -- 32kb  'A' -- 64KB
-	   'B' - 64KB less 512 bytes at top
-	   (WARNING ... must zero top bytes in INIT */
-
-	avail_sram_code=0xf-readb(adapt_info->mmio + AIPAVAILSHRAM);
-	if (avail_sram_code)
-		return size_code[avail_sram_code];
-	else  /* for code 'F', must compute size from RRR(3,2) bits */
-		return 1<<((readb(adapt_info->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD)>>2)+4);
-}
-
-static int __init trdev_init(struct net_device *dev)
-{
-	struct tok_info *ti=(struct tok_info *)dev->priv;
-
-	ti->open_status		= CLOSED;
-
-	dev->init		= tok_init_card;
-	dev->open		= tok_open;
-	dev->stop		= tok_close;
-	dev->hard_start_xmit	= tok_send_packet;
-	dev->get_stats 		= tok_get_stats;
-	dev->set_multicast_list = NULL;
-	dev->change_mtu         = ibmtr_change_mtu;
-
-#ifndef MODULE
-#ifndef PCMCIA
-	tr_setup(dev);
-#endif
-#endif
-	return 0;
-}
-
-
-
-static int tok_open(struct net_device *dev)
-{
-	struct tok_info *ti=(struct tok_info *)dev->priv;
-
-	/* init the spinlock */
-	ti->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
-
-	if (ti->open_status==CLOSED) tok_init_card(dev);
-
-	if (ti->open_status==IN_PROGRESS) sleep_on(&ti->wait_for_reset);
-
-	if (ti->open_status==SUCCESS) {
-		dev->tbusy=0;
-		dev->interrupt=0;
-		dev->start=1;
-		/* NEED to see smem size *AND* reset high 512 bytes if needed */
-
-		MOD_INC_USE_COUNT;
-
-		return 0;
-	} else return -EAGAIN;
-
-}
-
-static int tok_close(struct net_device *dev)
-{
-
-	struct tok_info *ti=(struct tok_info *) dev->priv;
-
-	writeb(DIR_CLOSE_ADAPTER,
-	       ti->srb + offsetof(struct srb_close_adapter, command));
-	writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
-
-	ti->open_status=CLOSED;
-
-	sleep_on(&ti->wait_for_tok_int);
-
-	if (readb(ti->srb + offsetof(struct srb_close_adapter, ret_code)))
-		DPRINTK("close adapter failed: %02X\n",
-			(int)readb(ti->srb + offsetof(struct srb_close_adapter, ret_code)));
-
-        dev->start = 0;
-#ifdef PCMCIA
-	ti->sram = 0 ;
-#endif
-	DPRINTK("Adapter closed.\n");
-	MOD_DEC_USE_COUNT;
-
-	return 0;
-}
-
-void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
-{
-	unsigned char status;
-	struct tok_info *ti;
-	struct net_device *dev;
-
-	dev = dev_id;
-#if TR_VERBOSE
-	DPRINTK("Int from tok_driver, dev : %p\n",dev);
-#endif
-	ti  = (struct tok_info *) dev->priv;
-	spin_lock(&(ti->lock));
-
-      	/* Disable interrupts till processing is finished */
-	dev->interrupt=1;
-	writeb((~INT_ENABLE), ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
-
-	/* Reset interrupt for ISA boards */
-        if (ti->adapter_int_enable)
-                outb(0,ti->adapter_int_enable);
-	else
-		outb(0,ti->global_int_enable);
-
-
-	switch (ti->do_tok_int) {
-
-	      case NOT_FIRST:
-
-		/*  Begin the regular interrupt handler HERE inline to avoid
-		    the extra levels of logic and call depth for the
-		    original solution.   */
-
-		status=readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_ODD);
-#ifdef PCMCIA
-      		/* Check if the PCMCIA card was pulled. */
-    		if (status == 0xFF)
-       		{
-		          DPRINTK("PCMCIA card removed.\n");
-			  spin_unlock(&(ti->lock));
-        		  dev->interrupt = 0;
-         		  return;
-       		}
-
-    	        /* Check ISRP EVEN too. */
-      	        if ( readb (ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) == 0xFF)
-    	        {
-         		 DPRINTK("PCMCIA card removed.\n");
-			 spin_unlock(&(ti->lock));
-         		 dev->interrupt = 0;
-         		 return;
-      		 }
-#endif
-
-
-		if (status & ADAP_CHK_INT) {
-
-			int i;
-			__u32 check_reason;
-
-			check_reason=ti->mmio + ntohs(readw(ti->sram + ACA_OFFSET + ACA_RW +WWCR_EVEN));
-
-			DPRINTK("Adapter check interrupt\n");
-			DPRINTK("8 reason bytes follow: ");
-			for(i=0; i<8; i++, check_reason++)
-				printk("%02X ", (int)readb(check_reason));
-			printk("\n");
-
-			writeb((~ADAP_CHK_INT), ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
-			writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET  + ISRP_EVEN);
-			dev->interrupt=0;
-
-		} else if (readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN)
-				 & (TCR_INT | ERR_INT | ACCESS_INT)) {
-
-			DPRINTK("adapter error: ISRP_EVEN : %02x\n",
-				(int)readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN));
-			writeb(~(TCR_INT | ERR_INT | ACCESS_INT),
-			       ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
-			writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET  + ISRP_EVEN);
-			dev->interrupt=0;
-
-		} else if (status
-			   & (SRB_RESP_INT | ASB_FREE_INT | ARB_CMD_INT | SSB_RESP_INT)) {
-			/* SRB, ASB, ARB or SSB response */
-
-			if (status & SRB_RESP_INT) { /* SRB response */
-
-				switch(readb(ti->srb)) { /* SRB command check */
-
-				      case XMIT_DIR_FRAME: {
-					      unsigned char xmit_ret_code;
-
-					      xmit_ret_code=readb(ti->srb + offsetof(struct srb_xmit, ret_code));
-					      if (xmit_ret_code != 0xff) {
-						      DPRINTK("error on xmit_dir_frame request: %02X\n",
-							      xmit_ret_code);
-						      if (ti->current_skb) {
-							      dev_kfree_skb(ti->current_skb);
-							      ti->current_skb=NULL;
-						      }
-						      dev->tbusy=0;
-						      if (ti->readlog_pending) ibmtr_readlog(dev);
-					      }
-				      }
-				      break;
-
-				      case XMIT_UI_FRAME: {
-					      unsigned char xmit_ret_code;
-
-					      xmit_ret_code=readb(ti->srb + offsetof(struct srb_xmit, ret_code));
-					      if (xmit_ret_code != 0xff) {
-						      DPRINTK("error on xmit_ui_frame request: %02X\n",
-							      xmit_ret_code);
-						      if (ti->current_skb) {
-							      dev_kfree_skb(ti->current_skb);
-							      ti->current_skb=NULL;
-						      }
-						      dev->tbusy=0;
-						      if (ti->readlog_pending) ibmtr_readlog(dev);
-					      }
-				      }
-				      break;
-
-				      case DIR_OPEN_ADAPTER: {
-					      unsigned char open_ret_code;
-					      __u16 open_error_code;
-
-					      ti->srb=ti->sram+ntohs(readw(ti->init_srb +offsetof(struct srb_open_response, srb_addr)));
-					      ti->ssb=ti->sram+ntohs(readw(ti->init_srb +offsetof(struct srb_open_response, ssb_addr)));
-					      ti->arb=ti->sram+ntohs(readw(ti->init_srb +offsetof(struct srb_open_response, arb_addr)));
-					      ti->asb=ti->sram+ntohs(readw(ti->init_srb +offsetof(struct srb_open_response, asb_addr)));
-					      ti->current_skb=NULL;
-
-					      open_ret_code = readb(ti->init_srb +offsetof(struct srb_open_response, ret_code));
-					      open_error_code = ntohs(readw(ti->init_srb +offsetof(struct srb_open_response, error_code)));
-
-					      if (open_ret_code==7) {
-
-						      if (!ti->auto_ringspeedsave && (open_error_code==0x24)) {
-							      DPRINTK("Open failed: Adapter speed must match ring "
-								      "speed if Automatic Ring Speed Save is disabled.\n");
-							      ti->open_status=FAILURE;
-							      wake_up(&ti->wait_for_reset);
-						      } else if (open_error_code==0x24)
-							      DPRINTK("Retrying open to adjust to ring speed.\n");
-						      else if ((open_error_code==0x2d) && ti->auto_ringspeedsave)
-							      DPRINTK("No signal detected for Auto Speed Detection.\n");
-						      else if (open_error_code==0x11)
-						      {
-							      if (ti->retry_count--) 
-								      DPRINTK("Ring broken/disconnected, retrying...\n");
-							      else {
-								      DPRINTK("Ring broken/disconnected, open failed.\n");
-								      ti->open_status = FAILURE;
-							      }
-						      }
-						      else DPRINTK("Unrecoverable error: error code = %04x.\n",
-								   open_error_code);
-
-					      } else if (!open_ret_code) {
-#if !TR_NEWFORMAT
-						      DPRINTK("board opened...\n");
-#else
-						      DPRINTK("Adapter initialized and opened.\n");
-#endif
-						      writeb(~(SRB_RESP_INT),
-							     ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
-						      writeb(~(CMD_IN_SRB),
-							     ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD);
-						      open_sap(EXTENDED_SAP,dev);
-
-						      /* YdW probably hates me */
-						      goto skip_reset;
-					      } else
-						      DPRINTK("open failed: ret_code = %02X, retrying\n",
-							      open_ret_code);
-
-					      if (ti->open_status != FAILURE) {
-						      ibmtr_reset_timer(&(ti->tr_timer), dev);
-					      }
-
-				      }
-				      break;
-
-				      case DIR_CLOSE_ADAPTER:
-					wake_up(&ti->wait_for_tok_int);
-					break;
-
-				      case DLC_OPEN_SAP:
-					if (readb(ti->srb+offsetof(struct dlc_open_sap, ret_code))) {
-						DPRINTK("open_sap failed: ret_code = %02X,retrying\n",
-							(int)readb(ti->srb+offsetof(struct dlc_open_sap, ret_code)));
-						ibmtr_reset_timer(&(ti->tr_timer), dev);
-					} else {
-						ti->exsap_station_id=
-							readw(ti->srb+offsetof(struct dlc_open_sap, station_id));
-						ti->open_status=SUCCESS; /* TR adapter is now available */
-						wake_up(&ti->wait_for_reset);
-					}
-					break;
-
-				      case DIR_INTERRUPT:
-				      case DIR_MOD_OPEN_PARAMS:
-				      case DIR_SET_GRP_ADDR:
-				      case DIR_SET_FUNC_ADDR:
-				      case DLC_CLOSE_SAP:
-					if (readb(ti->srb+offsetof(struct srb_interrupt, ret_code)))
-						DPRINTK("error on %02X: %02X\n",
-							(int)readb(ti->srb+offsetof(struct srb_interrupt, command)),
-							(int)readb(ti->srb+offsetof(struct srb_interrupt, ret_code)));
-					break;
-
-				      case DIR_READ_LOG:
-					if (readb(ti->srb+offsetof(struct srb_read_log, ret_code)))
-						DPRINTK("error on dir_read_log: %02X\n",
-							(int)readb(ti->srb+offsetof(struct srb_read_log, ret_code)));
-					else
-					    if (IBMTR_DEBUG_MESSAGES) {
-						DPRINTK(
-							"Line errors %02X, Internal errors %02X, Burst errors %02X\n"
-							"A/C errors %02X, Abort delimiters %02X, Lost frames %02X\n"
-							"Receive congestion count %02X, Frame copied errors %02X\n"
-							"Frequency errors %02X, Token errors %02X\n",
-							(int)readb(ti->srb+offsetof(struct srb_read_log,
-										    line_errors)),
-							(int)readb(ti->srb+offsetof(struct srb_read_log,
-										    internal_errors)),
-							(int)readb(ti->srb+offsetof(struct srb_read_log,
-										    burst_errors)),
-							(int)readb(ti->srb+offsetof(struct srb_read_log, A_C_errors)),
-							(int)readb(ti->srb+offsetof(struct srb_read_log,
-										    abort_delimiters)),
-							(int)readb(ti->srb+offsetof(struct srb_read_log,
-										    lost_frames)),
-							(int)readb(ti->srb+offsetof(struct srb_read_log,
-												    recv_congest_count)),
-							(int)readb(ti->srb+offsetof(struct srb_read_log,
-										    frame_copied_errors)),
-							(int)readb(ti->srb+offsetof(struct srb_read_log,
-										    frequency_errors)),
-							(int)readb(ti->srb+offsetof(struct srb_read_log,
-												    token_errors)));
-					    }
-					dev->tbusy=0;
-					break;
-
-				      default:
-					DPRINTK("Unknown command %02X encountered\n",
-						(int)readb(ti->srb));
-
-				} /* SRB command check */
-
-				writeb(~CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD);
-				writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
-
-			  skip_reset:
-			} /* SRB response */
-
-			if (status & ASB_FREE_INT) { /* ASB response */
-
-				switch(readb(ti->asb)) { /* ASB command check */
-
-				      case REC_DATA:
-				      case XMIT_UI_FRAME:
-				      case XMIT_DIR_FRAME:
-					break;
-
-				      default:
-					DPRINTK("unknown command in asb %02X\n",
-						(int)readb(ti->asb));
-
-				} /* ASB command check */
-
-				if (readb(ti->asb+2)!=0xff) /* checks ret_code */
-				    DPRINTK("ASB error %02X in cmd %02X\n",
-					    (int)readb(ti->asb+2),(int)readb(ti->asb));
-				writeb(~ASB_FREE_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
-
-			} /* ASB response */
-
-			if (status & ARB_CMD_INT) { /* ARB response */
-
-				switch (readb(ti->arb)) { /* ARB command check */
-
-				      case DLC_STATUS:
-					DPRINTK("DLC_STATUS new status: %02X on station %02X\n",
-						ntohs(readw(ti->arb + offsetof(struct arb_dlc_status, status))),
-						ntohs(readw(ti->arb
-									    +offsetof(struct arb_dlc_status, station_id))));
-					break;
-
-				      case REC_DATA:
-					tr_rx(dev);
-					break;
-
-				      case RING_STAT_CHANGE: {
-					      unsigned short ring_status;
-
-					      ring_status=ntohs(readw(ti->arb
-								      +offsetof(struct arb_ring_stat_change, ring_status)));
-
-					      if (ring_status & (SIGNAL_LOSS | LOBE_FAULT)) {
-
-						      DPRINTK("Signal loss/Lobe fault\n");
-						      DPRINTK("We try to reopen the adapter.\n");
-						      ibmtr_reset_timer(&(ti->tr_timer), dev);
-					      } else if (ring_status & (HARD_ERROR | XMIT_BEACON
-											| AUTO_REMOVAL | REMOVE_RECV | RING_RECOVER))
-						      DPRINTK("New ring status: %02X\n", ring_status);
-
-					      if (ring_status & LOG_OVERFLOW) {
-						      if (dev->tbusy)
-                                                              ti->readlog_pending = 1;
-						      else
-                                                              ibmtr_readlog(dev);
-					      }
-				      }
-				      break;
-
-				      case XMIT_DATA_REQ:
-					tr_tx(dev);
-					break;
-
-				      default:
-					DPRINTK("Unknown command %02X in arb\n",
-						(int)readb(ti->arb));
-					break;
-
-				} /* ARB command check */
-
-				writeb(~ARB_CMD_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
-				writeb(ARB_FREE, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
-
-			} /* ARB response */
-
-			if (status & SSB_RESP_INT) { /* SSB response */
-				unsigned char retcode;
-				switch (readb(ti->ssb)) { /* SSB command check */
-				      
-				      case XMIT_DIR_FRAME:
-				      case XMIT_UI_FRAME:
-					retcode = readb(ti->ssb+2);
-					if (retcode && (retcode != 0x22)) /* checks ret_code */
-						DPRINTK("xmit ret_code: %02X xmit error code: %02X\n",
-							(int)retcode, (int)readb(ti->ssb+6));
-					else ti->tr_stats.tx_packets++;
-					break;
-
-				      case XMIT_XID_CMD:
-					DPRINTK("xmit xid ret_code: %02X\n", (int)readb(ti->ssb+2));
-
-				      default:
-					DPRINTK("Unknown command %02X in ssb\n", (int)readb(ti->ssb));
-
-				} /* SSB command check */
-
-				writeb(~SSB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
-				writeb(SSB_FREE, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
-
-			} /* SSB response */
-
-		}	 /* SRB, ARB, ASB or SSB response */
-
-		dev->interrupt=0;
-		writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
-		break;
-
-	      case FIRST_INT:
-		initial_tok_int(dev);
-		break;
-
-	      default:
-		DPRINTK("Unexpected interrupt from tr adapter\n");
-
-	}
-	spin_unlock(&(ti->lock));
-}
-
-static void initial_tok_int(struct net_device *dev)
-{
-
-	__u32 encoded_addr;
-	__u32 hw_encoded_addr;
-	struct tok_info *ti;
-	ti=(struct tok_info *) dev->priv;
-
-	ti->do_tok_int=NOT_FIRST;
-
-#ifndef TR_NEWFORMAT
-	DPRINTK("Initial tok int received\n");
-#endif
-
-	/* we assign the shared-ram address for ISA devices */
-	if(!ti->sram) {
-		writeb(ti->sram_base, ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN);
-		ti->sram=((__u32)ti->sram_base << 12);
-	}
-	ti->init_srb=ti->sram
-		+ntohs((unsigned short)readw(ti->mmio+ ACA_OFFSET + WRBR_EVEN));
-	SET_PAGE(ntohs((unsigned short)readw(ti->mmio+ACA_OFFSET + WRBR_EVEN)));
-
-	dev->mem_start = ti->sram;
-	dev->mem_end = ti->sram + (ti->mapped_ram_size<<9) - 1;
-
-#if TR_VERBOSE
-	{
-		int i;
-		DPRINTK("init_srb(%p):", ti->init_srb);
-		for (i=0;i<17;i++) printk("%02X ", (int)readb(ti->init_srb+i));
-		printk("\n");
-	}
-#endif
-
-	hw_encoded_addr = readw(ti->init_srb
-				+ offsetof(struct srb_init_response, encoded_address));
-
-#if !TR_NEWFORMAT
-	DPRINTK("srb_init_response->encoded_address: %04X\n", hw_encoded_addr);
-	DPRINTK("ntohs(srb_init_response->encoded_address): %04X\n",
-		ntohs(hw_encoded_addr));
-#endif
-
-	encoded_addr=(ti->sram + ntohs(hw_encoded_addr));
-	ti->ring_speed = readb(ti->init_srb+offsetof(struct srb_init_response, init_status)) & 0x01 ? 16 : 4;
-#if !TR_NEWFORMAT
-	DPRINTK("encoded addr (%04X,%04X,%08X): ", hw_encoded_addr,
-		ntohs(hw_encoded_addr), encoded_addr);
-#else
-	DPRINTK("Initial interrupt : %d Mbps, shared RAM base %08x.\n",
-		ti->ring_speed, ti->sram);
-#endif
-
-	ti->auto_ringspeedsave=readb(ti->init_srb
-				     +offsetof(struct srb_init_response, init_status_2)) & 0x4 ? TRUE : FALSE;
-
-#if !TR_NEWFORMAT
-	for(i=0;i<TR_ALEN;i++) {
-		dev->dev_addr[i]=readb(encoded_addr + i);
-		printk("%02X%s", dev->dev_addr[i], (i==TR_ALEN-1) ? "" : ":" );
-	}
-	printk("\n");
-#endif
-
-	tok_open_adapter((unsigned long)dev);
-}
-
-static int tok_init_card(struct net_device *dev)
-{
-	struct tok_info *ti;
-	short PIOaddr;
-	unsigned long i;
-	PIOaddr = dev->base_addr;
-	ti=(struct tok_info *) dev->priv;
-
-	/* Special processing for first interrupt after reset */
-	ti->do_tok_int=FIRST_INT;
-
-	/* Reset adapter */
-	dev->tbusy=1; /* nothing can be done before reset and open completed */
-
-#ifdef ENABLE_PAGING
-	if(ti->page_mask)
-		writeb(SRPR_ENABLE_PAGING, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN);
-#endif
-
-	writeb(~INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
-
-#if !TR_NEWFORMAT
-	DPRINTK("resetting card\n");
-#endif
-
-	outb(0, PIOaddr+ADAPTRESET);
-	for (i=jiffies+TR_RESET_INTERVAL; time_before_eq(jiffies, i);); /* wait 50ms */
-	outb(0,PIOaddr+ADAPTRESETREL);
-
-#if !TR_NEWFORMAT
-	DPRINTK("card reset\n");
-#endif
-
-	ti->open_status=IN_PROGRESS;
-	writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
-	return 0;
-}
-
-static void open_sap(unsigned char type,struct net_device *dev)
-{
-	int i;
-	struct tok_info *ti=(struct tok_info *) dev->priv;
-
-	SET_PAGE(ti->srb);
-	for (i=0; i<sizeof(struct dlc_open_sap); i++)
-		writeb(0, ti->srb+i);
-
-	writeb(DLC_OPEN_SAP, ti->srb + offsetof(struct dlc_open_sap, command));
-	writew(htons(MAX_I_FIELD),
-	       ti->srb + offsetof(struct dlc_open_sap, max_i_field));
-	writeb(SAP_OPEN_IND_SAP | SAP_OPEN_PRIORITY,
-	       ti->srb + offsetof(struct dlc_open_sap, sap_options));
-	writeb(SAP_OPEN_STATION_CNT,
-	       ti->srb + offsetof(struct dlc_open_sap, station_count));
-	writeb(type, ti->srb + offsetof(struct dlc_open_sap, sap_value));
-
-	writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
-
-}
-
-void tok_open_adapter(unsigned long dev_addr)
-{
-
-	struct net_device *dev=(struct net_device *)dev_addr;
-	struct tok_info *ti;
-	int i;
-
-	ti=(struct tok_info *) dev->priv;
-
-#if !TR_NEWFORMAT
-	DPRINTK("now opening the board...\n");
-#endif
-
-	writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
-	writeb(~CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD);
-
-	for (i=0; i<sizeof(struct dir_open_adapter); i++)
-		writeb(0, ti->init_srb+i);
-
-	writeb(DIR_OPEN_ADAPTER,
-	       ti->init_srb + offsetof(struct dir_open_adapter, command));
-	writew(htons(OPEN_PASS_BCON_MAC),
-	       ti->init_srb + offsetof(struct dir_open_adapter, open_options));
-	if (ti->ring_speed == 16) {
-		writew(htons(ti->dhb_size16mb),
-		       ti->init_srb + offsetof(struct dir_open_adapter, dhb_length));
-		writew(htons(ti->rbuf_cnt16),
-		       ti->init_srb + offsetof(struct dir_open_adapter, num_rcv_buf));
-		writew(htons(ti->rbuf_len16),
-		       ti->init_srb + offsetof(struct dir_open_adapter, rcv_buf_len));
-	} else {
-		writew(htons(ti->dhb_size4mb),
-		       ti->init_srb + offsetof(struct dir_open_adapter, dhb_length));
-		writew(htons(ti->rbuf_cnt4),
-		       ti->init_srb + offsetof(struct dir_open_adapter, num_rcv_buf));
-		writew(htons(ti->rbuf_len4),
-		       ti->init_srb + offsetof(struct dir_open_adapter, rcv_buf_len));
-	}
-	writeb(NUM_DHB, /* always 2 */ 
-	       ti->init_srb + offsetof(struct dir_open_adapter, num_dhb));
-	writeb(DLC_MAX_SAP,
-	       ti->init_srb + offsetof(struct dir_open_adapter, dlc_max_sap));
-	writeb(DLC_MAX_STA,
-	       ti->init_srb + offsetof(struct dir_open_adapter, dlc_max_sta));
-
-	ti->srb=ti->init_srb; /* We use this one in the interrupt handler */
-
-	writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
-	writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
-
-}
-
-static void tr_tx(struct net_device *dev)
-{
-	struct tok_info *ti=(struct tok_info *) dev->priv;
-	struct trh_hdr *trhdr=(struct trh_hdr *)ti->current_skb->data;
-	unsigned int hdr_len;
-	__u32 dhb;
-	unsigned char xmit_command;
-	int i;
-	struct trllc	*llc;
-
-	if (readb(ti->asb + offsetof(struct asb_xmit_resp, ret_code))!=0xFF)
-		DPRINTK("ASB not free !!!\n");
-
-	/* in providing the transmit interrupts,
-	   is telling us it is ready for data and
-	   providing a shared memory address for us
-	   to stuff with data.  Here we compute the
-	   effective address where we will place data.*/
-	dhb=ti->sram
-		+ntohs(readw(ti->arb + offsetof(struct arb_xmit_req, dhb_address)));
-	
-	/* Figure out the size of the 802.5 header */
-	if (!(trhdr->saddr[0] & 0x80)) /* RIF present? */
-		hdr_len=sizeof(struct trh_hdr)-TR_MAXRIFLEN;
-	else 
-		hdr_len=((ntohs(trhdr->rcf) & TR_RCF_LEN_MASK)>>8)
-			+sizeof(struct trh_hdr)-TR_MAXRIFLEN;
-
-	llc = (struct trllc *)(ti->current_skb->data + hdr_len);
-
-	xmit_command = readb(ti->srb + offsetof(struct srb_xmit, command));
-
-	writeb(xmit_command, ti->asb + offsetof(struct asb_xmit_resp, command));
-	writew(readb(ti->srb + offsetof(struct srb_xmit, station_id)),
-	       ti->asb + offsetof(struct asb_xmit_resp, station_id));
-	writeb(llc->ssap, ti->asb + offsetof(struct asb_xmit_resp, rsap_value));
-	writeb(readb(ti->srb + offsetof(struct srb_xmit, cmd_corr)),
-	       ti->asb + offsetof(struct asb_xmit_resp, cmd_corr));
-	writeb(0, ti->asb + offsetof(struct asb_xmit_resp, ret_code));
-
-	if ((xmit_command==XMIT_XID_CMD) || (xmit_command==XMIT_TEST_CMD)) {
-
-		writew(htons(0x11),
-		       ti->asb + offsetof(struct asb_xmit_resp, frame_length));
-		writeb(0x0e, ti->asb + offsetof(struct asb_xmit_resp, hdr_length));
-		writeb(AC, dhb);
-		writeb(LLC_FRAME, dhb+1);
-
-		for (i=0; i<TR_ALEN; i++) writeb((int)0x0FF, dhb+i+2);
-		for (i=0; i<TR_ALEN; i++) writeb(0, dhb+i+TR_ALEN+2);
-
-		writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
-		return;
-
-	}
-
-	/*
-	 *      the token ring packet is copied from sk_buff to the adapter
-	 *      buffer identified in the command data received with the interrupt.
-	 */
-	writeb(hdr_len, ti->asb + offsetof(struct asb_xmit_resp, hdr_length));
-	writew(htons(ti->current_skb->len),
-	       ti->asb + offsetof(struct asb_xmit_resp, frame_length));
-
-	memcpy_toio(dhb, ti->current_skb->data, ti->current_skb->len);
-
-	writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
-	ti->tr_stats.tx_bytes+=ti->current_skb->len;
-	dev->tbusy=0;
-	dev_kfree_skb(ti->current_skb);
-	ti->current_skb=NULL;
-	mark_bh(NET_BH);
-	if (ti->readlog_pending) ibmtr_readlog(dev);
-}
-
-static void tr_rx(struct net_device *dev)
-{
-	struct tok_info *ti=(struct tok_info *) dev->priv;
-	__u32 rbuffer, rbufdata;
-	__u32 llc;
-	unsigned char *data;
-	unsigned int rbuffer_len, lan_hdr_len, hdr_len, ip_len, length;
-	struct sk_buff *skb;
-	unsigned int skb_size = 0;
-	int	IPv4_p = 0;
-	unsigned int chksum = 0;
-	struct iphdr *iph;
-
-	rbuffer=(ti->sram
-		 +ntohs(readw(ti->arb + offsetof(struct arb_rec_req, rec_buf_addr))))+2;
- 
-	if(readb(ti->asb + offsetof(struct asb_rec, ret_code))!=0xFF)
-		DPRINTK("ASB not free !!!\n");
-
-	writeb(REC_DATA,
-	       ti->asb + offsetof(struct asb_rec, command));
-	writew(readw(ti->arb + offsetof(struct arb_rec_req, station_id)),
-	       ti->asb + offsetof(struct asb_rec, station_id));
-	writew(readw(ti->arb + offsetof(struct arb_rec_req, rec_buf_addr)),
-	       ti->asb + offsetof(struct asb_rec, rec_buf_addr));
-
-	lan_hdr_len=readb(ti->arb + offsetof(struct arb_rec_req, lan_hdr_len));
-	hdr_len = lan_hdr_len + sizeof(struct trllc) + sizeof(struct iphdr);
-	
-	llc=(rbuffer + offsetof(struct rec_buf, data) + lan_hdr_len);
-
-#if TR_VERBOSE
-	DPRINTK("offsetof data: %02X lan_hdr_len: %02X\n",
-		(unsigned int)offsetof(struct rec_buf,data), (unsigned int)lan_hdr_len);
-	DPRINTK("llc: %08X rec_buf_addr: %04X ti->sram: %p\n", llc,
-		ntohs(readw(ti->arb + offsetof(struct arb_rec_req, rec_buf_addr))),
-		ti->sram);
-	DPRINTK("dsap: %02X, ssap: %02X, llc: %02X, protid: %02X%02X%02X, "
-		"ethertype: %04X\n",
-		(int)readb(llc + offsetof(struct trllc, dsap)),
-		(int)readb(llc + offsetof(struct trllc, ssap)),
-		(int)readb(llc + offsetof(struct trllc, llc)),
-		(int)readb(llc + offsetof(struct trllc, protid)),
-		(int)readb(llc + offsetof(struct trllc, protid)+1),
-		(int)readb(llc + offsetof(struct trllc, protid)+2),
-		(int)readw(llc + offsetof(struct trllc, ethertype)));
-#endif
-	if (readb(llc + offsetof(struct trllc, llc))!=UI_CMD) {
-		writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code));
-		ti->tr_stats.rx_dropped++;
-		writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
-		return;
-	}
-
-	length = ntohs(readw(ti->arb+offsetof(struct arb_rec_req, frame_len)));
-       	if ((readb(llc + offsetof(struct trllc, dsap))==EXTENDED_SAP) &&
-       	    (readb(llc + offsetof(struct trllc, ssap))==EXTENDED_SAP) &&
-		(length>=hdr_len)) {
-       		IPv4_p = 1;
-       	}
-
-#if TR_VERBOSE
-       	if (!IPv4_p){
-
-       		__u32 trhhdr;
-
-       		trhhdr=(rbuffer+offsetof(struct rec_buf,data));
-
-       		DPRINTK("Probably non-IP frame received.\n");
-       		DPRINTK("ssap: %02X dsap: %02X saddr: %02X:%02X:%02X:%02X:%02X:%02X "
-       			"daddr: %02X:%02X:%02X:%02X:%02X:%02X\n",
-       			(int)readb(llc + offsetof(struct trllc, ssap)),
-       			(int)readb(llc + offsetof(struct trllc, dsap)),
-       			(int)readb(trhhdr + offsetof(struct trh_hdr, saddr)),
-       			(int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+1),
-       			(int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+2),
-       			(int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+3),
-       			(int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+4),
-       			(int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+5),
-       			(int)readb(trhhdr + offsetof(struct trh_hdr, daddr)),
-       			(int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+1),
-       			(int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+2),
-       			(int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+3),
-       			(int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+4),
-       			(int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+5));
-       	}
-#endif
-
-       	skb_size = length-lan_hdr_len+sizeof(struct trh_hdr)+sizeof(struct trllc);
- 
-       	if (!(skb=dev_alloc_skb(skb_size))) {
-       		DPRINTK("out of memory. frame dropped.\n");
-       		ti->tr_stats.rx_dropped++;
-       		writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code));
-       		writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
-       		return;
-       	}
-
-      	skb_put(skb, length);
-	skb_reserve(skb, sizeof(struct trh_hdr)-lan_hdr_len+sizeof(struct trllc));
-       	skb->dev=dev;
-       	data=skb->data;
-	rbuffer_len=ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len)));
-	rbufdata = rbuffer + offsetof(struct rec_buf,data);
-
-	if (IPv4_p) {
-                /* Copy the headers without checksumming */
-		memcpy_fromio(data, rbufdata, hdr_len);
-
-		/* Watch for padded packets and bogons */
-		iph=(struct iphdr*)(data + lan_hdr_len + sizeof(struct trllc));
-		ip_len = ntohs(iph->tot_len) - sizeof(struct iphdr);
-		length -= hdr_len;
-		if ((ip_len <= length) && (ip_len > 7))
-			length = ip_len;
-		data += hdr_len;
-		rbuffer_len -= hdr_len;
-		rbufdata += hdr_len;
-        }
-
-	/* Copy the payload... */
-	for (;;) {
-		if (IPv4_p)
-			chksum = csum_partial_copy(bus_to_virt(rbufdata), data,
-						   length < rbuffer_len ? length : rbuffer_len,
-						   chksum);
-		else
-			memcpy_fromio(data, rbufdata, rbuffer_len);
-		rbuffer = ntohs(readw(rbuffer));
-		if (!rbuffer)
-			break;
-		length -= rbuffer_len;
-		data += rbuffer_len;
-		rbuffer += ti->sram;
-		rbuffer_len = ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len)));
-		rbufdata = rbuffer + offsetof(struct rec_buf, data);
-	}
-
-       	writeb(0, ti->asb + offsetof(struct asb_rec, ret_code));
-
-       	writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
-
-	ti->tr_stats.rx_bytes += skb->len;
-       	ti->tr_stats.rx_packets++;
-
-	skb->protocol = tr_type_trans(skb,dev);
-
- 	if (IPv4_p){
-		skb->csum      = chksum;
-		skb->ip_summed = 1;
-	}
-
-	netif_rx(skb);
-}
-
-static int tok_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-	struct tok_info *ti;
-	ti=(struct tok_info *) dev->priv;
-
-	if (dev->tbusy) {
-		int ticks_waited;
-
-		ticks_waited=jiffies - dev->trans_start;
-		if (ticks_waited<TR_BUSY_INTERVAL) return 1;
-
-		DPRINTK("Arrg. Transmitter busy.\n");
-		dev->trans_start+=5; /* we fake the transmission start time... */
-		return 1;
-	}
-
-	if (test_and_set_bit(0,(void *)&dev->tbusy)!=0)
-		DPRINTK("Transmitter access conflict\n");
-	else {
-		int flags;
-
-		/* lock against other CPUs */
-		spin_lock_irqsave(&(ti->lock), flags);
-
-		/* Save skb; we'll need it when the adapter asks for the data */
-		ti->current_skb=skb;
-		writeb(XMIT_UI_FRAME, ti->srb + offsetof(struct srb_xmit, command));
-		writew(ti->exsap_station_id, ti->srb
-		       +offsetof(struct srb_xmit, station_id));
-		writeb(CMD_IN_SRB, (ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD));
-		spin_unlock_irqrestore(&(ti->lock), flags);
-
-		dev->trans_start=jiffies;
-	}
-
-	return 0;
-}
-
-void ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev) {
-	tmr->expires  = jiffies + TR_RETRY_INTERVAL;
-	tmr->data     = (unsigned long) dev;
-	tmr->function = tok_open_adapter;
-	init_timer(tmr);
-	add_timer(tmr);
-}
-
-void ibmtr_readlog(struct net_device *dev) {
-	 struct tok_info *ti;
-	 ti=(struct tok_info *) dev->priv;
-
-	 ti->readlog_pending = 0;
-	 writeb(DIR_READ_LOG, ti->srb);
-	 writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
-	 writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
-	 dev->tbusy=1; /* really srb busy... */
-}
-
-/* tok_get_stats():  Basically a scaffold routine which will return
-   the address of the tr_statistics structure associated with
-   this device -- the tr.... structure is an ethnet look-alike
-   so at least for this iteration may suffice.   */
-
-static struct net_device_stats * tok_get_stats(struct net_device *dev) {
-
-	struct tok_info *toki;
-	toki=(struct tok_info *) dev->priv;
-	return (struct net_device_stats *) &toki->tr_stats;
-}
-
-int ibmtr_change_mtu(struct net_device *dev, int mtu) {
-	struct tok_info *ti = (struct tok_info *) dev->priv;
-	
-	if (ti->ring_speed == 16 && mtu > ti->maxmtu16)
-		return -EINVAL;
-	if (ti->ring_speed == 4 && mtu > ti->maxmtu4)
-		return -EINVAL;
-	dev->mtu = mtu;
-	return 0;
-}
-
-#ifdef MODULE
-
-/* 3COM 3C619C supports 8 interrupts, 32 I/O ports */
-static struct net_device* dev_ibmtr[IBMTR_MAX_ADAPTERS];
-static int io[IBMTR_MAX_ADAPTERS] = {0xa20,0xa24};
-static int irq[IBMTR_MAX_ADAPTERS] = {0,0};
-static int mem[IBMTR_MAX_ADAPTERS] = {0,0};
-
-MODULE_PARM(io, "1-" __MODULE_STRING(IBMTR_MAX_ADAPTERS) "i");
-MODULE_PARM(irq, "1-" __MODULE_STRING(IBMTR_MAX_ADAPTERS) "i");
-MODULE_PARM(mem, "1-" __MODULE_STRING(IBMTR_MAX_ADAPTERS) "i");
-
-int init_module(void)
-{
-        int i;
-        for (i = 0; io[i] && (i<IBMTR_MAX_ADAPTERS); i++) {
-	        irq[i] = 0;
-		mem[i] = 0;
-		dev_ibmtr[i] = NULL;
-                dev_ibmtr[i] = init_trdev(dev_ibmtr[i], 0);
-                if (dev_ibmtr[i] == NULL)
-                        return -ENOMEM;
-
-	        dev_ibmtr[i]->base_addr = io[i];
-	        dev_ibmtr[i]->irq       = irq[i];
-		dev_ibmtr[i]->mem_start = mem[i];
-		dev_ibmtr[i]->init      = &ibmtr_probe;
-
-	        if (register_trdev(dev_ibmtr[i]) != 0) {
-			kfree_s(dev_ibmtr[i], sizeof(struct net_device));
-			dev_ibmtr[i] = NULL;
-		        if (i == 0) {
-			        printk("ibmtr: register_trdev() returned non-zero.\n");
-		                return -EIO;
-			} else {
-			        return 0;
-			}
-	        }
-	}
-	return 0;
-}
-
-void cleanup_module(void)
-{
-        int i;
-
-        for (i = 0; i < IBMTR_MAX_ADAPTERS; i++)
-	        if (dev_ibmtr[i]) {
-			 unregister_trdev(dev_ibmtr[i]);
-			 free_irq(dev_ibmtr[i]->irq, dev_ibmtr[i]);
-			 release_region(dev_ibmtr[i]->base_addr, IBMTR_IO_EXTENT);
-			 kfree_s(dev_ibmtr[i]->priv, sizeof(struct tok_info));
-			 kfree_s(dev_ibmtr[i], sizeof(struct net_device));
-			 dev_ibmtr[i] = NULL;
-                }
-}
-#endif /* MODULE */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/ibmtr.h linux/drivers/net/ibmtr.h
--- v2.3.20/linux/drivers/net/ibmtr.h	Wed May 12 13:27:37 1999
+++ linux/drivers/net/ibmtr.h	Wed Dec 31 16:00:00 1969
@@ -1,449 +0,0 @@
-/* Definitions for an IBM Token Ring card. */
-/* This file is distributed under the GNU GPL   */
-
-/* ported to the Alpha architecture 02/20/96 (just used the HZ macro) */
-
-#define TR_RETRY_INTERVAL (5*HZ) /* 500 on PC = 5 s */
-#define TR_RESET_INTERVAL (HZ/20) /* 5 on PC = 50 ms */
-#define TR_BUSY_INTERVAL (HZ/5) /* 5 on PC = 200 ms */
-#define TR_SPIN_INTERVAL (3*HZ) /* 3 seconds before init timeout */
-#define TR_RETRIES 6            /* number of open retries */ 
-
-#define TR_ISA 1
-#define TR_MCA 2
-#define TR_ISAPNP 3
-#define NOTOK 0
-#define TOKDEBUG 1
-
-#define IBMTR_SHARED_RAM_SIZE 0x10000
-#define IBMTR_IO_EXTENT 4
-#define IBMTR_MAX_ADAPTERS 2
-
-#define CHANNEL_ID      0X1F30
-#define AIP             0X1F00
-#define AIPCHKSUM1      0X1F60
-#define AIPCHKSUM2      0X1FF0
-#define AIPADAPTYPE     0X1FA0
-#define AIPDATARATE     0X1FA2
-#define AIPEARLYTOKEN   0X1FA4
-#define AIPAVAILSHRAM   0X1FA6
-#define AIPSHRAMPAGE    0X1FA8
-#define AIP4MBDHB       0X1FAA
-#define AIP16MBDHB      0X1FAC
-#define AIPFID		0X1FBA
-
-/* Note, 0xA20 == 0x220 since motherboard decodes 10 bits.  I left everything
-   the way my documentation had it, ie: 0x0A20.     */
-#define ADAPTINTCNTRL   0x02f0  /* Adapter interrupt control */
-#define ADAPTRESET      0x1     /* Control Adapter reset (add to base) */
-#define ADAPTRESETREL   0x2     /* Release Adapter from reset ( """)  */
-#define ADAPTINTREL	0x3 	/* Adapter interrupt release */
-
-#define MMIOStartLocP   0x0a20  /* Primary adapter's starting MMIO area */
-#define MMIOStartLocA   0x0a24  /* Alternate adapter's starting MMIO area */
-
-#define GLOBAL_INT_ENABLE 0x02f0
-
-/* MMIO bits 0-4 select register */
-#define RRR_EVEN        0x00    /* Shared RAM relocation registers - even and odd */
-/* Used to set the starting address of shared RAM  */
-/* Bits 1 through 7 of this register map to bits 13 through 19 of the shared RAM address.*/
-/* ie: 0x02 sets RAM address to ...ato!  issy su wazzoo !! GODZILLA!!! */
-#define RRR_ODD         0x01
-/* Bits 2 and 3 of this register can be read to determine shared RAM size */
-/* 00 for 8k, 01 for 16k, 10 for 32k, 11 for 64k  */
-#define WRBR_EVEN       0x02    /* Write region base registers - even and odd */
-#define WRBR_ODD        0x03
-#define WWOR_EVEN       0x04    /* Write window open registers - even and odd */
-#define WWOR_ODD        0x05
-#define WWCR_EVEN       0x06    /* Write window close registers - even and odd */
-#define WWCR_ODD        0x07
-
-/* Interrupt status registers - PC system  - even and odd */
-#define ISRP_EVEN       0x08
-
-#define TCR_INT 0x10    /* Bit 4 - Timer interrupt.  The TVR_EVEN timer has
-                                                                   expired. */
-#define ERR_INT 0x08    /* Bit 3 - Error interrupt.  The adapter has had an
-                                                                   internal error. */
-#define ACCESS_INT 0x04    /* Bit 2 - Access interrupt.  You have attempted to
-                                                           write to an invalid area of shared RAM or an invalid
-                                                                   register within the MMIO. */
-/*      In addition, the following bits within ISRP_EVEN can be turned on or off by you */
-/*      to control the interrupt processing:   */
-#define INT_IRQ 0x80    /* Bit 7 - If 0 the adapter will issue a CHCK, if 1 and
-                                                              IRQ.  This should normally be set (by you) to 1.  */
-#define INT_ENABLE 0x40 /* Bit 6 - Interrupt enable.  If 0, no interrupts will
-                                                                   occur.  If 1, interrupts will occur normally.
-                                                                   Normally set to 1.  */
-/* Bit 0 - Primary or alternate adapter.  Set to zero if this adapter is the primary adapter,*/
-/*         1 if this adapter is the alternate adapter. */
-
-
-#define ISRP_ODD        0x09
-
-#define ADAP_CHK_INT 0x40 /* Bit 6 - Adapter check.  the adapter has
-                             encountered a serious problem and has closed
-                             itself.  Whoa.  */
-#define SRB_RESP_INT 0x20 /* Bit 5 - SRB response.  The adapter has accepted
-                             an SRB request and set the return code within
-                             the SRB. */
-#define ASB_FREE_INT 0x10 /* Bit 4 - ASB free.  The adapter has read the ASB
-                                                                          and this area can be safely reused. This interrupt
-                                                                          is only used if your application has set the ASB
-                                                                          free request bit in ISRA_ODD or if an error was
-                                                                detected in your response. */
-#define ARB_CMD_INT  0x08 /* Bit 3 - ARB command.  The adapter has given you a
-                                                                          command for action.  The command is located in the
-                                                                          ARB area of shared memory. */
-#define SSB_RESP_INT 0x04 /* Bit 2 - SSB response.  The adapter has posted a
-                                                                          response to your SRB (the response is located in
-                                                                          the SSB area of shared memory). */
-/* Bit 1 - Bridge frame forward complete. */
-
-
-
-#define ISRA_EVEN       0x0A    /* Interrupt status registers - adapter  - even and odd */
-/* Bit 7 - Internal parity error (on adapter's internal bus) */
-/* Bit 6 - Timer interrupt pending */
-/* Bit 5 - Access interrupt (attempt by adapter to access illegal address) */
-/* Bit 4 - Adapter microcode problem (microcode dead-man timer expired) */
-/* Bit 3 - Adapter processor check status */
-/* Bit 2 - Reserved */
-/* Bit 1 - Adapter hardware interrupt mask (prevents internal interrupts) */
-/* Bit 0 - Adapter software interrupt mask (prevents internal software interrupts) */
-
-#define ISRA_ODD        0x0B
-#define CMD_IN_SRB 0x20 /* Bit 5  - Indicates that you have placed a new
-                           command in the SRB and are ready for the adapter to
-                           process the command. */
-#define RESP_IN_ASB 0x10 /* Bit 4 - Indicates that you have placed a response
-                                                                    (an ASB) in the shared RAM which is available for
-                                                                         the adapter's use. */
-/* Bit 3 - Indicates that you are ready to put an SRB in the shared RAM, but that a previous */
-/*         command is still pending.  The adapter will then interrupt you when the previous */
-/*         command is completed */
-/* Bit 2 - Indicates that you are ready to put an ASB in the shared RAM, but that a previous */
-/*         ASB is still pending.  The adapter will then interrupt you when the previous ASB */
-/*         is copied.  */
-#define ARB_FREE 0x2
-#define SSB_FREE 0x1
-
-#define TCR_EVEN        0x0C    /* Timer control registers - even and odd */
-#define TCR_ODD         0x0D
-#define TVR_EVEN        0x0E    /* Timer value registers - even and odd */
-#define TVR_ODD         0x0F
-#define SRPR_EVEN       0x10    /* Shared RAM paging registers - even and odd */
-#define SRPR_ENABLE_PAGING 0xc0
-#define SRPR_ODD        0x11 /* Not used. */
-#define TOKREAD         0x60
-#define TOKOR           0x40
-#define TOKAND          0x20
-#define TOKWRITE        0x00
-
-/* MMIO bits 5-6 select operation */
-/* 00 is used to write to a register */
-/* 01 is used to bitwise AND a byte with a register */
-/* 10 is used to bitwise OR a byte with a register  */
-/* 11 is used to read from a register */
-
-/* MMIO bits 7-8 select area of interest.. see below */
-/* 00 selects attachment control area. */
-/* 01 is reserved. */
-/* 10 selects adapter identification area A containing the adapter encoded address. */
-/* 11 selects the adapter identification area B containing test patterns. */
-
-#define PCCHANNELID 5049434F3631313039393020
-#define MCCHANNELID 4D4152533633583435313820
-
-#define ACA_OFFSET 0x1e00
-#define ACA_SET 0x40
-#define ACA_RESET 0x20
-#define ACA_RW 0x00
-
-#ifdef ENABLE_PAGING
-#define SET_PAGE(x) (writeb(((x>>8)&ti.page_mask), \
-  ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN))
-#else
-#define SET_PAGE(x)
-#endif
-
-typedef enum { IN_PROGRESS, SUCCESS, FAILURE, CLOSED } open_state;
-
-/* do_tok_int possible values */
-#define FIRST_INT 1
-#define NOT_FIRST 2
-
-struct tok_info {
-	unsigned char irq;
-	__u32 mmio;
-	unsigned char hw_address[32];
-	unsigned char adapter_type;
-	unsigned char data_rate;
-	unsigned char token_release;
-	unsigned char avail_shared_ram;
-	unsigned char shared_ram_paging;
-	unsigned short dhb_size4mb;
-	unsigned short rbuf_len4;
-	unsigned short rbuf_cnt4;
-	unsigned short maxmtu4;
-	unsigned short dhb_size16mb;
-	unsigned short rbuf_len16;
-	unsigned short rbuf_cnt16;
-	unsigned short maxmtu16;
-	/* Additions by David Morris       */
-	unsigned char do_tok_int;
-	wait_queue_head_t wait_for_tok_int;
-	wait_queue_head_t wait_for_reset;
-	unsigned char sram_base;
-	/* Additions by Peter De Schrijver */
-	unsigned char page_mask;          /* mask to select RAM page to Map*/
-	unsigned char mapped_ram_size;    /* size of RAM page */
-	__u32 sram;                       /* Shared memory base address */
-	__u32 init_srb;                   /* Initial System Request Block address */
-	__u32 srb;                        /* System Request Block address */
-	__u32 ssb;                        /* System Status Block address */
-	__u32 arb;                        /* Adapter Request Block address */
-	__u32 asb;                        /* Adapter Status Block address */
-	unsigned short exsap_station_id;
-	unsigned short global_int_enable;
-	struct sk_buff *current_skb;
-	struct net_device_stats tr_stats;
-	unsigned char auto_ringspeedsave;
-	open_state open_status;
-	unsigned char readlog_pending;
-	unsigned short adapter_int_enable; /* Adapter-specific int enable */
-        struct timer_list tr_timer;
-	unsigned char ring_speed;
-	__u32 func_addr;
-	unsigned int retry_count;
-	spinlock_t lock;		/* SMP protection */
-};
-
-/* token ring adapter commands */
-#define DIR_INTERRUPT 		0x00 /* struct srb_interrupt */
-#define DIR_MOD_OPEN_PARAMS 	0x01
-#define DIR_OPEN_ADAPTER 	0x03 /* struct dir_open_adapter */
-#define DIR_CLOSE_ADAPTER   	0x04
-#define DIR_SET_GRP_ADDR    	0x06
-#define DIR_SET_FUNC_ADDR   	0x07 /* struct srb_set_funct_addr */
-#define DIR_READ_LOG 		0x08 /* struct srb_read_log */
-#define DLC_OPEN_SAP 		0x15 /* struct dlc_open_sap */
-#define DLC_CLOSE_SAP       	0x16
-#define DATA_LOST 		0x20 /* struct asb_rec */
-#define REC_DATA 		0x81 /* struct arb_rec_req */
-#define XMIT_DATA_REQ 		0x82 /* struct arb_xmit_req */
-#define DLC_STATUS 		0x83 /* struct arb_dlc_status */
-#define RING_STAT_CHANGE    	0x84 /* struct dlc_open_sap ??? */
-
-/* DIR_OPEN_ADAPTER options */
-#define OPEN_PASS_BCON_MAC 0x0100
-#define NUM_RCV_BUF 2
-#define RCV_BUF_LEN 1024
-#define DHB_LENGTH 2048
-#define NUM_DHB 2
-#define DLC_MAX_SAP 2
-#define DLC_MAX_STA 1
-
-/* DLC_OPEN_SAP options */
-#define MAX_I_FIELD 0x0088
-#define SAP_OPEN_IND_SAP 0x04
-#define SAP_OPEN_PRIORITY 0x20
-#define SAP_OPEN_STATION_CNT 0x1
-#define XMIT_DIR_FRAME 0x0A
-#define XMIT_UI_FRAME  0x0d
-#define XMIT_XID_CMD   0x0e
-#define XMIT_TEST_CMD  0x11
-
-/* srb close return code */
-#define SIGNAL_LOSS  0x8000
-#define HARD_ERROR   0x4000
-#define XMIT_BEACON  0x1000
-#define LOBE_FAULT   0x0800
-#define AUTO_REMOVAL 0x0400
-#define REMOVE_RECV  0x0100
-#define LOG_OVERFLOW 0x0080
-#define RING_RECOVER 0x0020
-
-struct srb_init_response {
-	unsigned char command;
-	unsigned char init_status;
-	unsigned char init_status_2;
-	unsigned char reserved[3];
-	__u16 bring_up_code;
-	__u16 encoded_address;
-	__u16 level_address;
-	__u16 adapter_address;
-	__u16 parms_address;
-	__u16 mac_address;
-};
-
-struct dir_open_adapter {
-	unsigned char command;
-	char reserved[7];
-	__u16 open_options;
-	unsigned char node_address[6];
-	unsigned char group_address[4];
-	unsigned char funct_address[4];
-	__u16 num_rcv_buf;
-	__u16 rcv_buf_len;
-	__u16 dhb_length;
-	unsigned char num_dhb;
-	char reserved2;
-	unsigned char dlc_max_sap;
-	unsigned char dlc_max_sta;
-	unsigned char dlc_max_gsap;
-	unsigned char dlc_max_gmem;
-	unsigned char dlc_t1_tick_1;
-	unsigned char dlc_t2_tick_1;
-	unsigned char dlc_ti_tick_1;
-	unsigned char dlc_t1_tick_2;
-	unsigned char dlc_t2_tick_2;
-	unsigned char dlc_ti_tick_2;
-	unsigned char product_id[18];
-};
-
-struct srb_open_response {
-	unsigned char command;
-	unsigned char reserved1;
-	unsigned char ret_code;
-	unsigned char reserved2[3];
-	__u16 error_code;
-	__u16 asb_addr;
-	__u16 srb_addr;
-	__u16 arb_addr;
-	__u16 ssb_addr;
-};
-
-struct dlc_open_sap {
-	unsigned char command;
-	unsigned char reserved1;
-	unsigned char ret_code;
-	unsigned char reserved2;
-	__u16 station_id;
-	unsigned char timer_t1;
-	unsigned char timer_t2;
-	unsigned char timer_ti;
-	unsigned char maxout;
-	unsigned char maxin;
-	unsigned char maxout_incr;
-	unsigned char max_retry_count;
-	unsigned char gsap_max_mem;
-	__u16 max_i_field;
-	unsigned char sap_value;
-	unsigned char sap_options;
-	unsigned char station_count;
-	unsigned char sap_gsap_mem;
-	unsigned char gsap[0];
-};
-
-struct srb_xmit {
-	unsigned char command;
-	unsigned char cmd_corr;
-	unsigned char ret_code;
-	unsigned char reserved1;
-	__u16 station_id;
-};
-
-struct srb_interrupt {
-	unsigned char command;
-	unsigned char cmd_corr;
-	unsigned char ret_code;
-};
-
-struct srb_read_log {
-	unsigned char command;
-	unsigned char reserved1;
-	unsigned char ret_code;
-	unsigned char reserved2;
-	unsigned char line_errors;
-	unsigned char internal_errors;
-	unsigned char burst_errors;
-	unsigned char A_C_errors;
-	unsigned char abort_delimiters;
-	unsigned char reserved3;
-	unsigned char lost_frames;
-	unsigned char recv_congest_count;
-	unsigned char frame_copied_errors;
-	unsigned char frequency_errors;
-	unsigned char token_errors;
-};
-
-struct asb_xmit_resp {
-	unsigned char command;
-	unsigned char cmd_corr;
-	unsigned char ret_code;
-	unsigned char reserved;
-	__u16 station_id;
-	__u16 frame_length;
-	unsigned char hdr_length;
-	unsigned char rsap_value;
-};
-
-struct arb_xmit_req {
-	unsigned char command;
-	unsigned char cmd_corr;
-	unsigned char reserved1[2];
-	__u16 station_id;
-	__u16 dhb_address;
-};
-
-struct arb_rec_req {
-	unsigned char command;
-	unsigned char reserved1[3];
-	__u16 station_id;
-	__u16 rec_buf_addr;
-	unsigned char lan_hdr_len;
-	unsigned char dlc_hdr_len;
-	__u16 frame_len;
-	unsigned char msg_type;
-};
-
-struct asb_rec {
-	unsigned char command;
-	unsigned char reserved1;
-	unsigned char ret_code;
-	unsigned char reserved2;
-	__u16 station_id;
-	__u16 rec_buf_addr;
-};
-
-struct rec_buf {
-  /*	unsigned char reserved1[2]; */
-	__u16 buf_ptr;
-	unsigned char reserved2;
-	__u16 buf_len;
-	unsigned char data[0];
-};
-
-struct arb_dlc_status {
-	unsigned char command;
-	unsigned char reserved1[3];
-	__u16 station_id;
-	__u16 status;
-	unsigned char frmr_data[5];
-	unsigned char access_prio;
-	unsigned char rem_addr[TR_ALEN];
-	unsigned char rsap_value;
-};
-
-struct arb_ring_stat_change {
-	unsigned char command;
-	unsigned char reserved1[5];
-	__u16 ring_status;
-};
-
-struct srb_close_adapter {
-	unsigned char command;
-	unsigned char reserved1;
-	unsigned char ret_code;
-};
-
-struct srb_set_funct_addr {
-	unsigned char command;
-	unsigned char reserved1;
-	unsigned char ret_code;
-	unsigned char reserved2[3];
-	__u32 funct_address;
-};
-
diff -u --recursive --new-file v2.3.20/linux/drivers/net/lapbether.c linux/drivers/net/lapbether.c
--- v2.3.20/linux/drivers/net/lapbether.c	Thu Aug 26 13:05:38 1999
+++ linux/drivers/net/lapbether.c	Wed Dec 31 16:00:00 1969
@@ -1,571 +0,0 @@
-/*
- *	"LAPB via ethernet" driver release 001
- *
- *	This code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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 is a "pseudo" network driver to allow LAPB over Ethernet.
- *
- *	This driver can use any ethernet destination address, and can be 
- *	limited to accept frames from one dedicated ethernet card only.
- *
- *	History
- *	LAPBETH 001	Jonathan Naylor		Cloned from bpqether.c
- */
-
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/net.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/notifier.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/netfilter.h>
-#include <linux/module.h>
-#include <linux/lapb.h>
-#include <linux/init.h>
-
-static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
-
-static int lapbeth_rcv(struct sk_buff *, struct net_device *, struct packet_type *);
-static int lapbeth_device_event(struct notifier_block *, unsigned long, void *);
-
-static struct packet_type lapbeth_packet_type = {
-	0,		/* ntohs(ETH_P_DEC),*/
-	0,		/* copy */
-	lapbeth_rcv,
-	NULL,
-	NULL,
-};
-
-static struct notifier_block lapbeth_dev_notifier = {
-	lapbeth_device_event,
-	0
-};
-
-
-#define MAXLAPBDEV 100
-
-static struct lapbethdev {
-	struct lapbethdev *next;
-	char   ethname[14];		/* ether device name */
-	struct net_device *ethdev;		/* link to ethernet device */
-	struct net_device axdev;		/* lapbeth device (lapb#) */
-	struct net_device_stats stats;	/* some statistics */
-} *lapbeth_devices = NULL;
-
-
-/* ------------------------------------------------------------------------ */
-
-
-/*
- *	Get the ethernet device for a LAPB device
- */
-static __inline__ struct net_device *lapbeth_get_ether_dev(struct net_device *dev)
-{
-	struct lapbethdev *lapbeth;
-	
-	lapbeth = (struct lapbethdev *)dev->priv;
-
-	return (lapbeth != NULL) ? lapbeth->ethdev : NULL;
-}
-
-/*
- *	Get the LAPB device for the ethernet device
- */
-static __inline__ struct net_device *lapbeth_get_x25_dev(struct net_device *dev)
-{
-	struct lapbethdev *lapbeth;
-
-	for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth->next)
-		if (lapbeth->ethdev == dev)
-			return &lapbeth->axdev;
-
-	return NULL;
-}
-
-static __inline__ int dev_is_ethdev(struct net_device *dev)
-{
-	return (
-			dev->type == ARPHRD_ETHER
-			&& strncmp(dev->name, "dummy", 5)
-	);
-}
-
-/*
- *	Sanity check: remove all devices that ceased to exists and
- *	return '1' if the given LAPB device was affected.
- */
-static int lapbeth_check_devices(struct net_device *dev)
-{
-	struct lapbethdev *lapbeth, *lapbeth_prev;
-	int result = 0;
-	unsigned long flags;
-	
-	save_flags(flags);
-	cli();
-
-	lapbeth_prev = NULL;
-
-	for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth->next) {
-		if (!dev_get(lapbeth->ethname)) {
-			if (lapbeth_prev)
-				lapbeth_prev->next = lapbeth->next;
-			else
-				lapbeth_devices = lapbeth->next;
-				
-			if (&lapbeth->axdev == dev)
-				result = 1;
-
-			unregister_netdev(&lapbeth->axdev);
-			kfree(lapbeth);
-		}
-
-		lapbeth_prev = lapbeth;
-	}
-	
-	restore_flags(flags);
-	
-	return result;
-}
-
-
-/* ------------------------------------------------------------------------ */
-
-
-/*
- *	Receive a LAPB frame via an ethernet interface.
- */
-static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype)
-{
-	int len, err;
-	struct lapbethdev *lapbeth;
-
-	skb->sk = NULL;		/* Initially we don't know who it's for */
-	
-	dev = lapbeth_get_x25_dev(dev);
-
-	if (dev == NULL || dev->start == 0) {
-		kfree_skb(skb);
-		return 0;
-	}
-
-	lapbeth = (struct lapbethdev *)dev->priv;
-
-	lapbeth->stats.rx_packets++;
-
-	len = skb->data[0] + skb->data[1] * 256;
-
-	skb_pull(skb, 2);	/* Remove the length bytes */
-	skb_trim(skb, len);	/* Set the length of the data */
-
-	if ((err = lapb_data_received(lapbeth, skb)) != LAPB_OK) {
-		kfree_skb(skb);
-		printk(KERN_DEBUG "lapbether: lapb_data_received err - %d\n", err);
-	}
-
-	return 0;
-}
-
-static void lapbeth_data_indication(void *token, struct sk_buff *skb)
-{
-	struct lapbethdev *lapbeth = (struct lapbethdev *)token;
-	unsigned char *ptr;
-
-	ptr  = skb_push(skb, 1);
-	*ptr = 0x00;
-
-	skb->dev      = &lapbeth->axdev;
-	skb->protocol = htons(ETH_P_X25);
-	skb->mac.raw  = skb->data;
-	skb->pkt_type = PACKET_HOST;
-
-	netif_rx(skb);
-}
-
-/*
- * 	Send a LAPB frame via an ethernet interface
- */
-static int lapbeth_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct lapbethdev *lapbeth;
-	int err;
-	
-	lapbeth = (struct lapbethdev *)dev->priv;
-
-	/*
-	 * Just to be *really* sure not to send anything if the interface
-	 * is down, the ethernet device may have gone.
-	 */
-	if (!dev->start) {
-		lapbeth_check_devices(dev);
-		kfree_skb(skb);
-		return -ENODEV;
-	}
-
-	switch (skb->data[0]) {
-		case 0x00:
-			break;
-		case 0x01:
-			if ((err = lapb_connect_request(lapbeth)) != LAPB_OK)
-				printk(KERN_ERR "lapbeth: lapb_connect_request error - %d\n", err);
-			kfree_skb(skb);
-			return 0;
-		case 0x02:
-			if ((err = lapb_disconnect_request(lapbeth)) != LAPB_OK)
-				printk(KERN_ERR "lapbeth: lapb_disconnect_request err - %d\n", err);
-			kfree_skb(skb);
-			return 0;
-		default:
-			kfree_skb(skb);
-			return 0;
-	}
-
-	skb_pull(skb, 1);
-
-	if ((err = lapb_data_request(lapbeth, skb)) != LAPB_OK) {
-		printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err);
-		kfree_skb(skb);
-		return -ENOMEM;
-	}
-
-	return 0;
-}
-	
-static void lapbeth_data_transmit(void *token, struct sk_buff *skb)
-{
-	struct lapbethdev *lapbeth = (struct lapbethdev *)token;
-	unsigned char *ptr;
-	struct net_device *dev;
-	int size;
-
-	skb->protocol = htons(ETH_P_X25);
-
-	size = skb->len;
-
-	ptr = skb_push(skb, 2);
-
-	*ptr++ = size % 256;
-	*ptr++ = size / 256;
-
-	lapbeth->stats.tx_packets++;
-
-	skb->dev = dev = lapbeth->ethdev;
-
-	dev->hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0);
-
-	dev_queue_xmit(skb);
-}
-
-static void lapbeth_connected(void *token, int reason)
-{
-	struct lapbethdev *lapbeth = (struct lapbethdev *)token;
-	struct sk_buff *skb;
-	unsigned char *ptr;
-
-	if ((skb = dev_alloc_skb(1)) == NULL) {
-		printk(KERN_ERR "lapbeth: out of memory\n");
-		return;
-	}
-
-	ptr  = skb_put(skb, 1);
-	*ptr = 0x01;
-
-	skb->dev      = &lapbeth->axdev;
-	skb->protocol = htons(ETH_P_X25);
-	skb->mac.raw  = skb->data;
-	skb->pkt_type = PACKET_HOST;
-
-	netif_rx(skb);
-}
-
-static void lapbeth_disconnected(void *token, int reason)
-{
-	struct lapbethdev *lapbeth = (struct lapbethdev *)token;
-	struct sk_buff *skb;
-	unsigned char *ptr;
-
-	if ((skb = dev_alloc_skb(1)) == NULL) {
-		printk(KERN_ERR "lapbeth: out of memory\n");
-		return;
-	}
-
-	ptr  = skb_put(skb, 1);
-	*ptr = 0x02;
-
-	skb->dev      = &lapbeth->axdev;
-	skb->protocol = htons(ETH_P_X25);
-	skb->mac.raw  = skb->data;
-	skb->pkt_type = PACKET_HOST;
-
-	netif_rx(skb);
-}
-
-/*
- *	Statistics
- */
-static struct net_device_stats *lapbeth_get_stats(struct net_device *dev)
-{
-	struct lapbethdev *lapbeth;
-
-	lapbeth = (struct lapbethdev *)dev->priv;
-
-	return &lapbeth->stats;
-}
-
-/*
- *	Set AX.25 callsign
- */
-static int lapbeth_set_mac_address(struct net_device *dev, void *addr)
-{
-    struct sockaddr *sa = (struct sockaddr *)addr;
-
-    memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
-
-    return 0;
-}
-
-static int lapbeth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-	return -EINVAL;
-}
-
-/*
- * open/close a device
- */
-static int lapbeth_open(struct net_device *dev)
-{
-	struct lapb_register_struct lapbeth_callbacks;
-	struct lapbethdev *lapbeth;
-	int err;
-
-	if (lapbeth_check_devices(dev))
-		return -ENODEV;		/* oops, it's gone */
-	
-	dev->tbusy = 0;
-	dev->start = 1;
-
-	lapbeth = (struct lapbethdev *)dev->priv;
-
-	lapbeth_callbacks.connect_confirmation    = lapbeth_connected;
-	lapbeth_callbacks.connect_indication      = lapbeth_connected;
-	lapbeth_callbacks.disconnect_confirmation = lapbeth_disconnected;
-	lapbeth_callbacks.disconnect_indication   = lapbeth_disconnected;
-	lapbeth_callbacks.data_indication         = lapbeth_data_indication;
-	lapbeth_callbacks.data_transmit           = lapbeth_data_transmit;
-
-	if ((err = lapb_register(lapbeth, &lapbeth_callbacks)) != LAPB_OK) {
-		printk(KERN_ERR "lapbeth: lapb_register error - %d\n", err);
-		dev->tbusy = 1;
-		dev->start = 0;
-		return -ENODEV;
-	}
-
-	MOD_INC_USE_COUNT;
-
-	return 0;
-}
-
-static int lapbeth_close(struct net_device *dev)
-{
-	struct lapbethdev *lapbeth;
-	int err;
-
-	dev->tbusy = 1;
-	dev->start = 0;
-
-	lapbeth = (struct lapbethdev *)dev->priv;
-
-	if ((err = lapb_unregister(lapbeth)) != LAPB_OK)
-		printk(KERN_ERR "lapbeth: lapb_unregister error - %d\n", err);
-
-	MOD_DEC_USE_COUNT;
-
-	return 0;
-}
-
-static int lapbeth_dev_init(struct net_device *dev)
-{
-	return 0;
-}
-
-/* ------------------------------------------------------------------------ */
-
-/*
- *	Setup a new device.
- */
-static int lapbeth_new_device(struct net_device *dev)
-{
-	int k;
-	unsigned char *buf;
-	struct lapbethdev *lapbeth, *lapbeth2;
-	
-	if ((lapbeth = kmalloc(sizeof(struct lapbethdev), GFP_KERNEL)) == NULL)
-		return -ENOMEM;
-		
-	memset(lapbeth, 0, sizeof(struct lapbethdev));
-	
-	lapbeth->ethdev = dev;
-
-	lapbeth->ethname[sizeof(lapbeth->ethname)-1] = '\0';
-	strncpy(lapbeth->ethname, dev->name, sizeof(lapbeth->ethname)-1);
-
-	dev = &lapbeth->axdev;
-	buf = kmalloc(14, GFP_KERNEL);
-
-	for (k = 0; k < MAXLAPBDEV; k++) {
-		struct net_device *odev;
-
-		sprintf(buf, "lapb%d", k);
-
-		if ((odev = __dev_get_by_name(buf)) == NULL || lapbeth_check_devices(odev))
-			break;
-	}
-
-	if (k == MAXLAPBDEV) {
-		kfree(lapbeth);
-		return -ENODEV;
-	}
-	
-	dev->priv = (void *)lapbeth;	/* pointer back */
-	dev->name = buf;
-	dev->init = lapbeth_dev_init;
-
-	if (register_netdev(dev) != 0) {
-		kfree(lapbeth);
-                return -EIO;
-        }
-
-	dev_init_buffers(dev);
-
-	dev->hard_start_xmit = lapbeth_xmit;
-	dev->open	     = lapbeth_open;
-	dev->stop	     = lapbeth_close;
-	dev->set_mac_address = lapbeth_set_mac_address;
-	dev->get_stats	     = lapbeth_get_stats;
-	dev->do_ioctl	     = lapbeth_ioctl;
-
-	dev->flags      = 0;
-
-	dev->type            = ARPHRD_X25;
-	dev->hard_header_len = 3;
-	dev->mtu             = 1000;
-	dev->addr_len        = 0;
-
-	cli();
-
-	if (lapbeth_devices == NULL) {
-		lapbeth_devices = lapbeth;
-	} else {
-		for (lapbeth2 = lapbeth_devices; lapbeth2->next != NULL; lapbeth2 = lapbeth2->next);
-		lapbeth2->next = lapbeth;
-	}
-	
-	sti();
-
-	return 0;
-}
-
-
-/*
- *	Handle device status changes.
- */
-static int lapbeth_device_event(struct notifier_block *this,unsigned long event, void *ptr)
-{
-	struct net_device *dev = (struct net_device *)ptr;
-	
-	if (!dev_is_ethdev(dev))
-		return NOTIFY_DONE;
-
-	lapbeth_check_devices(NULL);
-
-	switch (event) {
-		case NETDEV_UP:		/* new ethernet device -> new LAPB interface */
-			if (lapbeth_get_x25_dev(dev) == NULL)
-				lapbeth_new_device(dev);
-			break;
-
-		case NETDEV_DOWN:	/* ethernet device closed -> close LAPB interface */
-			if ((dev = lapbeth_get_x25_dev(dev)) != NULL)
-				dev_close(dev);
-			break;
-
-		default:
-			break;
-	}
-
-	return NOTIFY_DONE;
-}
-
-
-/* ------------------------------------------------------------------------ */
-
-/*
- * Initialize driver. To be called from af_ax25 if not compiled as a
- * module
- */
-int lapbeth_init(void)
-{
-	struct net_device *dev;
-
-	lapbeth_packet_type.type  = htons(ETH_P_DEC);
-	dev_add_pack(&lapbeth_packet_type);
-
-	register_netdevice_notifier(&lapbeth_dev_notifier);
-
-	printk(KERN_INFO "LAPB Ethernet driver version 0.01\n");
-
-	read_lock_bh(&dev_base_lock);
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
-		if (dev_is_ethdev(dev)) {
-			read_unlock_bh(&dev_base_lock);
-			lapbeth_new_device(dev);
-			read_lock_bh(&dev_base_lock);
-		}
-	}
-	read_unlock_bh(&dev_base_lock);
-
-	return 0;
-}
-
-#ifdef MODULE
-EXPORT_NO_SYMBOLS;
-
-MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");
-MODULE_DESCRIPTION("The unofficial LAPB over Ethernet driver");
-
-int init_module(void)
-{
-	return lapbeth_init();
-}
-
-void cleanup_module(void)
-{
-	struct lapbethdev *lapbeth;
-
-	dev_remove_pack(&lapbeth_packet_type);
-
-	unregister_netdevice_notifier(&lapbeth_dev_notifier);
-
-	for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth->next)
-		unregister_netdev(&lapbeth->axdev);
-}
-#endif
diff -u --recursive --new-file v2.3.20/linux/drivers/net/ncr885_debug.h linux/drivers/net/ncr885_debug.h
--- v2.3.20/linux/drivers/net/ncr885_debug.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/ncr885_debug.h	Mon Oct 11 10:13:24 1999
@@ -0,0 +1,54 @@
+#ifndef _H_NCR885_DEBUG
+#define _H_NCR885_DEBUG
+
+struct ncr885e_regs {
+  unsigned long tx_status;
+  unsigned long rx_status;
+  unsigned long mac_config;
+  unsigned long tx_control;
+  unsigned long rx_control;
+  unsigned long tx_cmd_ptr;
+  unsigned long rx_cmd_ptr;
+  unsigned long int_status;
+};
+
+#ifndef __KERNEL__
+
+struct ncr885e_private {
+
+  struct dbdma_cmd *head;
+  struct dbdma_cmd *tx_cmds;
+  struct dbdma_cmd *rx_cmds;
+  struct dbdma_cmd *stop_cmd;
+
+  struct sk_buff *tx_skbufs[NR_TX_RING];
+  struct sk_buff *rx_skbufs[NR_RX_RING];
+
+  int rx_current;
+  int rx_dirty;
+
+  int tx_dirty;
+  int tx_current;
+
+  unsigned short tx_status[NR_TX_RING];
+
+  unsigned char tx_fullup;
+  unsigned char tx_active;
+  
+  struct net_device_stats  stats;
+
+  struct device *dev;
+
+  struct timer_list tx_timeout;
+  int timeout_active;
+
+  spinlock_t lock;
+};
+
+#endif /* __KERNEL__ */
+
+
+#define NCR885E_GET_PRIV   _IOR('N',1,sizeof( struct ncr885e_private ))
+#define NCR885E_GET_REGS   _IOR('N',2,sizeof( struct ncr885e_regs ))
+
+#endif
diff -u --recursive --new-file v2.3.20/linux/drivers/net/ncr885e.c linux/drivers/net/ncr885e.c
--- v2.3.20/linux/drivers/net/ncr885e.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/ncr885e.c	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,1458 @@
+/*
+ *  An Ethernet driver for the dual-function NCR 53C885 SCSI/Ethernet
+ *  controller.
+ *
+ *
+ *  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.
+ *
+ */
+
+static const char *version =
+"ncr885e.c:v0.8 11/30/98 dan@synergymicro.com\n";
+
+#include <linux/config.h>
+
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT 
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/dbdma.h>
+#include <asm/uaccess.h>
+
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "ncr885e.h"
+#include "ncr885_debug.h"
+
+static const char *chipname = "ncr885e";
+
+/* debugging flags */
+#if 0
+#define DEBUG_FUNC    0x0001
+#define DEBUG_PACKET  0x0002
+#define DEBUG_CMD     0x0004
+#define DEBUG_CHANNEL 0x0008
+#define DEBUG_INT     0x0010
+#define DEBUG_RX      0x0020
+#define DEBUG_TX      0x0040
+#define DEBUG_DMA     0x0080
+#define DEBUG_MAC     0x0100
+#define DEBUG_DRIVER  0x0200
+#define DEBUG_ALL     0x1fff
+#endif
+
+#ifdef DEBUG_NCR885E
+#define NCR885E_DEBUG   0
+#else
+#define NCR885E_DEBUG   0
+#endif
+
+/* The 885's Ethernet PCI device id. */
+#ifndef PCI_DEVICE_ID_NCR_53C885_ETHERNET
+#define PCI_DEVICE_ID_NCR_53C885_ETHERNET  0x0701
+#endif
+
+#define NR_RX_RING    8
+#define NR_TX_RING    8
+#define MAX_TX_ACTIVE (NR_TX_RING-1)
+#define NCMDS_TX      NR_TX_RING
+
+#define RX_BUFLEN     (ETH_FRAME_LEN + 8)
+#define TX_TIMEOUT    5*HZ
+
+#define NCR885E_TOTAL_SIZE 0xe0
+
+#define TXSR          (1<<6)   /* tx: xfer status written */
+#define TXABORT       (1<<7)   /* tx: abort */
+#define EOP           (1<<7)   /* rx: end of packet written to buffer */
+
+int ncr885e_debug = NCR885E_DEBUG;
+static int print_version = 0;
+
+struct ncr885e_private {
+
+	/* preserve a 1-1 marking with buffs */
+	struct dbdma_cmd *head;
+	struct dbdma_cmd *tx_cmds;
+	struct dbdma_cmd *rx_cmds;
+	struct dbdma_cmd *stop_cmd;
+
+	struct sk_buff *tx_skbufs[NR_TX_RING];
+	struct sk_buff *rx_skbufs[NR_RX_RING];
+
+	int rx_current;
+	int rx_dirty;
+
+	int tx_dirty;
+	int tx_current;
+
+	unsigned short tx_status[NR_TX_RING];
+
+	unsigned char tx_fullup;
+	unsigned char tx_active;
+  
+	struct net_device_stats  stats;
+
+	struct net_device *dev;
+
+	struct timer_list tx_timeout;
+	int timeout_active;
+
+	spinlock_t lock;
+};
+
+#ifdef MODULE
+static struct net_device *root_dev = NULL;
+#endif
+
+
+static int ncr885e_open( struct net_device *dev );
+static int ncr885e_close( struct net_device *dev );
+static void ncr885e_rx( struct net_device *dev );
+static void ncr885e_tx( struct net_device *dev );
+static int ncr885e_probe1( struct net_device *dev, unsigned long ioaddr,
+			   unsigned char irq );
+static int ncr885e_xmit_start( struct sk_buff *skb, struct net_device *dev );
+static struct net_device_stats *ncr885e_stats( struct net_device *dev );
+static void ncr885e_set_multicast( struct net_device *dev );
+static void ncr885e_config( struct net_device *dev );
+static int ncr885e_set_address( struct net_device *dev, void *addr );
+static void ncr885e_interrupt( int irq, void *dev_id, struct pt_regs *regs );
+static void show_dbdma_cmd( volatile struct dbdma_cmd *cmd );
+#if 0
+static int read_eeprom( unsigned int ioadddr, int location );
+#endif
+
+#ifdef NCR885E_DEBUG_MII
+static void show_mii( unsigned long ioaddr );
+static int read_mii( unsigned long ioaddr, int reg );
+static void write_mii( unsigned long ioaddr, int reg, int data );
+#endif /* NCR885E_DEBUG_MII */
+
+#define TX_RESET_FLAGS    (TX_CHANNEL_RUN|TX_CHANNEL_PAUSE|TX_CHANNEL_WAKE)
+#define RX_RESET_FLAGS    (RX_CHANNEL_RUN|RX_CHANNEL_PAUSE|RX_CHANNEL_WAKE)
+
+
+#if 0
+static int
+debug_ioctl( struct net_device *dev, struct ifreq *req, int cmd )
+{
+	unsigned long ioaddr = dev->base_addr;
+	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+	struct ncr885e_private *data;
+	struct ncr885e_regs *regs;
+	unsigned long flags;
+
+	union {
+		struct ncr885e_regs dump;
+		struct ncr885e_private priv;    
+	} temp;
+
+	switch( cmd ) {
+
+		/* dump the rx ring status */
+	case NCR885E_GET_PRIV:
+
+		data = (struct ncr885e_private *) &req->ifr_data;    
+
+		if ( verify_area(VERIFY_WRITE, &req->ifr_data,
+				 sizeof( struct ncr885e_private )))
+			return -EFAULT;
+
+		memcpy((char *) &temp.priv, sp, sizeof( struct ncr885e_private ));
+		copy_to_user( data, (char *) &temp.priv, sizeof( struct ncr885e_private));
+		break;
+
+	case NCR885E_GET_REGS:
+
+		regs = (struct ncr885e_regs *) &req->ifr_data;
+  
+		if ( verify_area( VERIFY_WRITE, &req->ifr_data,
+				  sizeof( struct ncr885e_regs )))
+			return -EFAULT;
+
+		spin_lock_irqsave( &sp->lock, flags ); 
+
+		temp.dump.tx_status = inl( ioaddr + TX_CHANNEL_STATUS );
+		temp.dump.rx_status = inl( ioaddr + RX_CHANNEL_STATUS );
+		temp.dump.mac_config = inl( ioaddr + MAC_CONFIG );
+		temp.dump.tx_control = inl( ioaddr + TX_CHANNEL_CONTROL );
+		temp.dump.rx_control = inl( ioaddr + RX_CHANNEL_CONTROL );
+		temp.dump.tx_cmd_ptr = inl( ioaddr + TX_CMD_PTR_LO );
+		temp.dump.rx_cmd_ptr = inl( ioaddr + RX_CMD_PTR_LO );
+		temp.dump.int_status = inl( ioaddr + INTERRUPT_STATUS_REG );
+
+		spin_unlock_irqrestore( &sp->lock, flags );
+		copy_to_user( regs, (char *) &temp.dump, sizeof( struct ncr885e_regs ));
+
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+#endif
+
+/*  Enable interrupts on the 53C885 */
+static inline void
+ncr885e_enable( struct net_device *dev )
+
+{
+	unsigned long ioaddr = dev->base_addr;
+	unsigned short reg;
+
+	reg = inw(ioaddr + INTERRUPT_ENABLE);
+	outw(reg | INTERRUPT_INTE, ioaddr + INTERRUPT_ENABLE);
+}
+
+/*  Disable interrupts on the 53c885 */
+static inline void
+ncr885e_disable( struct net_device *dev )
+
+{
+	unsigned long ioaddr = dev->base_addr;
+	unsigned short reg;
+
+	reg = inw( ioaddr + INTERRUPT_ENABLE );
+	outw( reg & ~INTERRUPT_INTE, ioaddr + INTERRUPT_ENABLE );
+}
+
+
+static inline void
+ncr885e_reset( struct net_device *dev )
+
+{
+	unsigned short reg;  
+	unsigned long cntl;
+	int i;
+	unsigned long ioaddr = dev->base_addr;
+
+	if (ncr885e_debug > 1)
+		printk( KERN_INFO "%s: Resetting 53C885...\n", dev->name );
+
+	/* disable interrupts on the 53C885 */
+	ncr885e_disable( dev );
+  
+	/* disable rx in the MAC */
+	reg = inw( ioaddr + MAC_CONFIG );
+	outw( reg & ~MAC_CONFIG_RXEN, ioaddr + MAC_CONFIG );
+  
+	for( i=0; i < 100; i++ ) {
+
+		if ( !(inw( ioaddr + MAC_CONFIG ) & MAC_CONFIG_RXEN ))
+			break;
+		udelay( 10 );
+	}
+  
+	reg = inw( ioaddr + MAC_CONFIG );
+	outw( reg | MAC_CONFIG_SRST, ioaddr + MAC_CONFIG );
+	outw( reg, ioaddr + MAC_CONFIG );
+
+	/* disable both rx and tx DBDMA channels */
+	outl( TX_DBDMA_ENABLE << 16, ioaddr + TX_CHANNEL_CONTROL );
+	outl( RX_DBDMA_ENABLE << 16, ioaddr + RX_CHANNEL_CONTROL );
+
+	for( i=0; i < 100; i++ ) {
+    
+		if ( !(inw( ioaddr + TX_CHANNEL_STATUS ) & TX_DBDMA_ENABLE ) &&
+		     !(inw( ioaddr + RX_CHANNEL_STATUS ) & RX_DBDMA_ENABLE ))
+			break;
+		udelay( 10 );
+	}
+
+	/* perform a "software reset" */
+	cntl = inl( ioaddr + DBDMA_CONTROL );
+	outl( cntl | DBDMA_SRST, ioaddr + DBDMA_CONTROL );
+
+	for( i=0; i < 100; i++ ) {
+  
+		if ( !(inl( ioaddr + DBDMA_CONTROL ) & DBDMA_SRST ))
+			break;
+		udelay( 10 );
+	}
+
+	/* books says that a software reset should be done to the MAC, as
+	   well.  This true??? */
+
+	if (ncr885e_debug > 3) 
+		printk( KERN_INFO "%s: reset complete\n", dev->name );
+
+}
+
+
+/*  configure the 53C885 chip.
+
+    The DBDMA command descriptors on the 53C885 can be programmed to
+    branch, interrupt or pause conditionally or always by using the
+    interrupt, branch and wait select registers.  */
+
+static void
+ncr885e_config( struct net_device *dev )
+
+{
+	unsigned long ioaddr = dev->base_addr;
+
+	if (ncr885e_debug > 3)
+		printk( KERN_INFO "%s: Configuring 53C885.\n", dev->name );
+
+	ncr885e_reset( dev );
+ 
+	/* The 53C885 can be programmed to perform conditional DBDMA
+	   branches, interrupts or waits.
+  
+	   Neither channel makes use of "wait", as it requires that the
+	   DBDMA engine to be restarted.  Don't go there.  The rx channel
+	   will branch upon the successful reception of a packet ('EOP' in
+	   the xfer_status field).  The branch address is to the STOP
+	   DBDMA command descriptor, which shuts down the rx channel until
+	   the interrupt is serviced.   */
+     
+	/* cause tx channel to stop after "status received" */
+	outl( 0, ioaddr + TX_INT_SELECT );
+	outl( (TX_WAIT_STAT_RECV << 16) | TX_WAIT_STAT_RECV, 
+	      ioaddr + TX_WAIT_SELECT );
+	outl( 0, ioaddr + TX_BRANCH_SELECT );
+
+	/* cause rx channel to branch to the STOP descriptor on "End-of-Packet" */
+#if 0
+	outl( (RX_INT_SELECT_EOP << 16) | RX_INT_SELECT_EOP,
+	      ioaddr + RX_INT_SELECT );
+#else
+	outl( 0, ioaddr + RX_INT_SELECT );
+#endif
+#if 0
+	outl( 0, ioaddr + RX_WAIT_SELECT );
+#else
+	outl( (RX_WAIT_SELECT_EOP << 16) | RX_WAIT_SELECT_EOP, 
+	      ioaddr + RX_WAIT_SELECT );
+#endif
+#if 1
+	outl( 0, ioaddr + RX_BRANCH_SELECT );
+#else
+	outl( (RX_BRANCH_SELECT_EOP << 16) | RX_BRANCH_SELECT_EOP,
+	      ioaddr + RX_BRANCH_SELECT );
+#endif
+
+	/* configure DBDMA */
+	outl( (DBDMA_BE | DBDMA_DPMRLE | DBDMA_TDPCE |
+	       DBDMA_DDPE | DBDMA_TDPE |
+	       (DBDMA_BURST_4 << DBDMA_TX_BST_SHIFT) |
+	       (DBDMA_BURST_4 << DBDMA_RX_BST_SHIFT) |
+	       (DBDMA_TX_ARBITRATION_DEFAULT) |
+	       (DBDMA_RX_ARBITRATION_DEFAULT)), ioaddr + DBDMA_CONTROL );
+
+	outl( 0, ioaddr + TX_THRESHOLD );
+
+	/* disable MAC loopback */
+	outl( (MAC_CONFIG_ITXA | MAC_CONFIG_RXEN | MAC_CONFIG_RETRYL |
+	       MAC_CONFIG_PADEN | (0x18 << 16)),
+	      ioaddr + MAC_CONFIG );
+
+	/* configure MAC */
+	outl( (MAC_CONFIG_ITXA | MAC_CONFIG_RXEN | MAC_CONFIG_RETRYL |
+	       MAC_CONFIG_PADEN | ( 0x18 << 16)), ioaddr + MAC_CONFIG );
+
+	outw( (0x1018), ioaddr + NBTOB_INTP_GAP );
+
+	/* clear and enable interrupts */
+	inw( ioaddr + INTERRUPT_CLEAR );
+	ncr885e_enable( dev );
+
+	/* and enable them in the chip */
+	outl( (INTERRUPT_INTE|INTERRUPT_TX_MASK|INTERRUPT_RX_MASK)<<16,
+	      ioaddr + INTERRUPT_ENABLE - 2);
+
+	if (ncr885e_debug > 3)
+		printk( KERN_INFO "%s: 53C885 config complete.\n", dev->name );
+
+	return;
+}
+
+
+
+/*
+   transmit interrupt  */
+
+static void
+ncr885e_tx( struct net_device *dev )
+
+{
+	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+	volatile struct dbdma_cmd *cp, *dp;
+	unsigned short txbits, xfer;
+	int i;
+
+	del_timer( &sp->tx_timeout );
+
+	if (ncr885e_debug > 3)
+		printk( KERN_INFO "%s: ncr885e_tx: active=%d, dirty=%d, current=%d\n", 
+			dev->name, sp->tx_active, sp->tx_dirty, sp->tx_current );
+
+	sp->timeout_active = 0;
+
+	i = sp->tx_dirty;
+	cp = sp->tx_cmds + (i*3);
+	dp = cp+1;
+	sp->tx_active--;
+
+	xfer = inw( &dp->xfer_status );
+	txbits = inw( &sp->tx_status[i] );
+
+	if (ncr885e_debug > 4) {
+		show_dbdma_cmd( cp );
+		show_dbdma_cmd( dp );
+	}
+
+	/* get xmit result */
+	txbits = inw( &sp->tx_status[i] );
+
+	if (ncr885e_debug > 3)
+		printk( KERN_INFO "%s: tx xfer=%04x, txbits=%04x\n", dev->name,
+			xfer, txbits );
+
+	/* look for any channel status (?) */
+	if ( xfer ) {
+
+		dev_kfree_skb( sp->tx_skbufs[i] );
+		mark_bh( NET_BH );
+
+		if ( txbits & TX_STATUS_TXOK ) {
+			sp->stats.tx_packets++;
+			sp->stats.tx_bytes += inw( &cp->req_count );
+		}
+
+		/* dropped packets */
+		if ( txbits & (TX_STATUS_TDLC|TX_STATUS_TDEC) ) {
+			sp->stats.tx_dropped++;
+		}
+
+		/* add the collisions */
+		sp->stats.collisions += ( txbits & 0x04 );
+
+	}
+
+	dev->tbusy = 0;
+  
+	return;
+}
+
+/*  rx interrupt handling */
+static void
+ncr885e_rx( struct net_device *dev )
+
+{
+	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+	volatile struct dbdma_cmd *cp;
+	struct sk_buff *skb;
+	int i, nb;
+	unsigned short status;
+	unsigned char *data, *stats;
+	unsigned long rxbits, ioaddr = dev->base_addr;
+
+	i = sp->rx_current;
+	cp = sp->rx_cmds + (i*2);
+
+	if (ncr885e_debug > 3)
+		printk( KERN_INFO "%s: ncr885e_rx dirty=%d, current=%d (cp@%p)\n",
+			dev->name, sp->rx_dirty, sp->rx_current, cp );
+
+	nb = inw( &cp->req_count ) - inw( &cp->res_count );
+	status = inw( &cp->xfer_status );
+
+	if (ncr885e_debug > 3)
+		printk( KERN_INFO "%s: (rx %d) bytes=%d, xfer_status=%04x\n", 
+			dev->name, i, nb, status );
+
+	if ( status ) {
+
+		skb = sp->rx_skbufs[i];
+		data = skb->data;
+		stats = data + nb - 3;
+		rxbits = (stats[0]|stats[1]<<8|stats[2]<<16);
+  
+		if (ncr885e_debug > 3)
+			printk( KERN_INFO "  rx_bits=%06lx\n", rxbits );
+
+		skb->dev = dev;
+		skb_put( skb, nb-3 );
+		skb->protocol = eth_type_trans( skb, dev );
+		netif_rx( skb );
+		sp->rx_skbufs[i] = 0;
+
+		if ( rxbits & RX_STATUS_RXOK ) {
+			sp->stats.rx_packets++;
+			sp->stats.rx_bytes += nb;
+		}
+
+		if ( rxbits & RX_STATUS_MCAST )
+			sp->stats.multicast++;
+
+	}
+
+	sp->rx_dirty = sp->rx_current;
+
+	if ( ++sp->rx_current >= NR_RX_RING )
+		sp->rx_current = 0;
+
+	/* fix up the one we just trashed */
+	cp = sp->rx_cmds + (sp->rx_dirty * 2);
+
+	skb = dev_alloc_skb( RX_BUFLEN + 2 );
+	if ( skb != 0 ) {
+		skb_reserve( skb, 2 );
+		sp->rx_skbufs[sp->rx_dirty] = skb;
+	}
+
+	if (ncr885e_debug > 2)
+		printk( KERN_INFO "%s: ncr885e_rx: using ring index %d, filling cp @ %p\n", 
+			dev->name, sp->rx_current, cp );
+  
+	outw( RX_BUFLEN, &cp->req_count );
+	outw( 0, &cp->res_count );
+	data = skb->data;
+	outl( virt_to_bus( data ), &cp->phy_addr );
+	outw( 0, &cp->xfer_status );
+
+	cp = sp->rx_cmds + (sp->rx_current * 2);
+
+	/* restart rx DMA */
+	outl( virt_to_bus( cp ), ioaddr + RX_CMD_PTR_LO );
+	outl( (RX_DBDMA_ENABLE << 16)|RX_CHANNEL_RUN,
+	      ioaddr + RX_CHANNEL_CONTROL );
+
+	return;
+}
+
+static void
+ncr885e_misc_ints( struct net_device *dev, unsigned short status )
+
+{
+	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+	struct dbdma_cmd *cp;
+	unsigned long ioaddr = dev->base_addr;
+
+	if (ncr885e_debug > 1)
+		printk( KERN_INFO "miscellaneous interrupt handled; status=%02x\n", 
+			status );
+
+	/* various transmit errors */
+	if ( status & 
+	     (INTERRUPT_PPET | INTERRUPT_PBFT | INTERRUPT_IIDT) ) {
+
+		/* illegal instruction in tx dma */
+		if ( status & INTERRUPT_IIDT ) {
+
+			cp = (struct dbdma_cmd *) bus_to_virt( inl( ioaddr + TX_CMD_PTR_LO ));
+			printk( KERN_INFO "%s: tx illegal insn:\n", dev->name );
+			printk( KERN_INFO " tx DBDMA - cmd = %p, status = %04x\n", 
+				cp, inw( ioaddr + TX_CHANNEL_STATUS ));
+			printk( KERN_INFO " command = %04x, phy_addr=%08x, req_count=%04x\n",
+				inw( &cp->command ), inw( &cp->phy_addr ), inw( &cp->req_count ));
+		}
+
+		if ( status & INTERRUPT_PPET )
+			printk( KERN_INFO "%s: tx PCI parity error\n", dev->name );
+ 
+		if ( status & INTERRUPT_PBFT )
+			printk( KERN_INFO "%s: tx PCI bus fault\n", dev->name );
+	}
+
+	/* look for rx errors */
+	if ( status &
+	     (INTERRUPT_PPER | INTERRUPT_PBFR | INTERRUPT_IIDR)) {
+
+		/* illegal instruction in rx dma */
+		if ( status & INTERRUPT_IIDR ) {
+#if 0
+			cmd = inl( ioaddr + RX_CMD_PTR_LO );      
+#endif
+			printk( KERN_ERR "%s: rx illegal DMA instruction:\n", dev->name );
+			printk( KERN_ERR "    channel status=%04x,\n",
+				inl( ioaddr + RX_CHANNEL_STATUS ));
+#if 0
+			show_dbdma_cmd( bus_to_virt( inl( ioaddr + RX_CMD_PTR_LO )));
+			printk( KERN_ERR "    instr (%08x) %08x %08x %08x\n",
+				(int) cmd, cmd[0], cmd[1], cmd[2] );
+#endif
+		}
+
+		/* PCI parity error */
+		if ( status & INTERRUPT_PPER )
+			printk( KERN_INFO "%s: rx PCI parity error\n", dev->name );
+
+		if ( status & INTERRUPT_PBFR )
+			printk( KERN_INFO "%s: rx PCI bus fault\n", dev->name );
+
+		sp->stats.rx_errors++;
+	}
+
+	if ( status & INTERRUPT_WI ) {
+		printk( KERN_INFO "%s: link pulse\n", dev->name );
+	}
+
+	/* bump any counters */
+  
+
+	return;
+}
+
+static void
+ncr885e_interrupt( int irq, void *dev_id, struct pt_regs *regs )
+
+{
+	struct net_device  *dev = (struct net_device *) dev_id;
+	struct ncr885e_private *sp;
+	unsigned short status;
+	int ioaddr;
+
+	if ( dev == NULL ) {
+		printk( KERN_ERR "symba: Interrupt IRQ %d for unknown device\n", irq );
+		return;
+	}
+
+	ioaddr = dev->base_addr;
+	sp = (struct ncr885e_private *) dev->priv;
+	spin_lock( &sp->lock );
+  
+	if ( dev->interrupt ) {
+		printk( KERN_ERR "%s: Re-entering interrupt handler...\n", 
+			dev->name );
+	}
+
+	dev->interrupt = 1;
+	status = inw( ioaddr + INTERRUPT_CLEAR );
+
+	if (ncr885e_debug > 2)
+		printk( KERN_INFO "%s: 53C885 interrupt 0x%02x\n", dev->name, status );
+
+	/* handle non-tx and rx interrupts first */
+	if ( status & ~(INTERRUPT_DIT|INTERRUPT_DIR))
+		ncr885e_misc_ints( dev, status );
+
+	/* look for tx interrupt: more to transmit, DBDMA stopped, or tx done */
+	if ( ( status & INTERRUPT_DIT ) ) {
+
+		if (ncr885e_debug > 2)
+			printk( KERN_INFO "%s: tx int; int=%02x, chan stat=%02x\n", 
+				dev->name, status, inw( ioaddr + TX_CHANNEL_STATUS ));
+
+		/* turn off timer */
+		del_timer( &sp->tx_timeout );
+		sp->timeout_active = 0;
+
+		/* stop DMA */
+		outl( TX_DBDMA_ENABLE << 16, ioaddr + TX_CHANNEL_CONTROL );
+
+		ncr885e_tx( dev );
+	}
+
+	if ( status & INTERRUPT_DIR ) {
+
+		if ( ncr885e_debug > 2 )
+			printk( KERN_INFO "%s: rx interrupt; int=%02x, rx channel stat=%02x\n", 
+				dev->name, status, inw( ioaddr + RX_CHANNEL_STATUS ));
+
+		/* stop DMA */
+		outl( RX_DBDMA_ENABLE << 16, ioaddr + RX_CHANNEL_CONTROL );
+    
+		/* and handle the interrupt */
+		ncr885e_rx( dev );
+	}
+  
+	dev->interrupt = 0;
+	spin_unlock( &sp->lock );
+
+	return;
+}
+
+
+/*  doesn't set the address permanently, however... */
+static int 
+ncr885e_set_address( struct net_device *dev, void *addr )
+
+{
+	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+	struct sockaddr *saddr = addr;
+	unsigned long  flags;
+	unsigned short reg[3];
+	unsigned char *ioaddr, *p;
+	int i;
+
+	memcpy( dev->dev_addr, saddr->sa_data, dev->addr_len );
+
+	p = (unsigned char *) dev->dev_addr;
+	printk( KERN_INFO "%s: setting new MAC address - ", dev->name );
+#if 0
+	for( p = (unsigned char *) dev->dev_addr, i=0; i < 6; i++, p++ ) 
+		printk("%c%2.2x", i ? ':' : ' ', *p );
+#endif
+
+
+	p = (unsigned char *) &reg;
+	for( i=0; i < 6; i++ )
+		p[i] = dev->dev_addr[i];
+
+#if 0
+	printk("%s: Setting new mac address - ", dev->name );
+	for( i=0; i < 6; i++ ) {
+		printk("%02x", i ? ':' : ' ', p[i] );
+	}
+
+	printk("\n");
+#endif
+
+	/* stop rx for the change */
+	outl( RX_DBDMA_ENABLE << 16, ioaddr + RX_CHANNEL_CONTROL );
+  
+	spin_lock_irqsave( &sp->lock, flags );
+
+	ioaddr = (unsigned char *) dev->base_addr;
+
+	for( i = 0; i < 3; i++ ) {
+		reg[i] = ((reg[i] & 0xff) << 8) | ((reg[i] >> 8) & 0xff);
+		printk("%04x ", reg[i] );
+		outw( reg[i], ioaddr + STATION_ADDRESS_0 + (i*2));
+	}
+	printk("\n");
+
+	spin_unlock_irqrestore( &sp->lock, flags );
+
+	/* restart rx */
+	outl((RX_DBDMA_ENABLE << 16)|RX_CHANNEL_RUN, 
+	     ioaddr + RX_CHANNEL_CONTROL );
+
+	return 0;
+}
+
+static void 
+ncr885e_tx_timeout( unsigned long data )
+
+{
+	struct net_device *dev = (struct net_device *) data;
+	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+	unsigned long flags, ioaddr;
+	int i;
+  
+	save_flags( flags );
+	cli();
+
+	ioaddr = dev->base_addr;
+	sp->timeout_active = 0;
+	i = sp->tx_dirty;
+
+	/* if we weren't active, bail... */
+	if ( sp->tx_active == 0 ) {
+		printk( KERN_INFO "%s: ncr885e_timeout...tx not active!\n", dev->name );
+		goto out;
+	}
+
+	printk( KERN_ERR "%s: 53C885 timed out.  Resetting...\n", dev->name );
+
+	/* disable rx and tx DMA */
+	outl( (TX_DBDMA_ENABLE << 16), ioaddr + TX_CHANNEL_CONTROL );
+	outl( (RX_DBDMA_ENABLE << 16), ioaddr + RX_CHANNEL_CONTROL );
+
+	/* reset the chip */
+	ncr885e_config( dev );
+	ncr885e_enable( dev );
+
+	/* clear the wedged skb in the tx ring */
+	sp->tx_active = 0;
+	++sp->stats.tx_errors;
+  
+	if ( sp->tx_skbufs[i] ) {
+		dev_kfree_skb( sp->tx_skbufs[i] );
+		sp->tx_skbufs[i] = 0;
+	}
+
+	/* start anew from the beginning of the ring buffer (why not?) */
+	sp->tx_current = 0;
+	dev->tbusy = 0;
+	mark_bh( NET_BH );
+
+	/* restart rx dma */
+	outl( (RX_DBDMA_ENABLE << 16) | RX_CHANNEL_RUN,
+	      ioaddr + RX_CHANNEL_CONTROL );  
+ out:
+
+	restore_flags( flags );
+}
+
+static inline void
+ncr885e_set_timeout( struct net_device *dev )
+
+{
+	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+
+	if ( sp->timeout_active )
+		del_timer( &sp->tx_timeout );
+
+	sp->tx_timeout.expires = jiffies + TX_TIMEOUT;
+	sp->tx_timeout.function = ncr885e_tx_timeout;
+	sp->tx_timeout.data = (unsigned long) dev;
+	add_timer( &sp->tx_timeout );
+	sp->timeout_active = 1;
+	restore_flags( flags );
+}
+
+
+/*
+ *  The goal is to set up DBDMA such that the rx ring contains only
+ *  one DMA descriptor per ring element and the tx ring has two (using
+ *  the cool features of branch- and wait-select.  However, I'm not sure
+ *  if it's possible.  For now, we plod through it with 3 descriptors
+ *  for tx, and two for rx.
+ */
+
+static int
+ncr885e_open( struct net_device *dev )
+
+{
+	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	struct sk_buff *skb;
+	int i, size;
+	char *data;
+	struct dbdma_cmd *cp;
+	unsigned long flags;
+
+	/* allocate enough space for the tx and rx rings and a STOP descriptor */  
+	size = (sizeof( struct dbdma_cmd ) *
+		((NR_TX_RING * 3) + (NR_RX_RING * 2) + 1));
+
+	cp = kmalloc( size, GFP_KERNEL );
+
+	if ( cp == 0 ) {
+		printk( KERN_ERR "Insufficient memory (%d bytes) for DBDMA\n", size );
+		return -ENOMEM;
+	}
+
+	spin_lock_init( &sp->lock );
+	spin_lock_irqsave( &sp->lock, flags );
+
+	memset((char *) cp, 0, size );
+	sp->head = cp;
+
+	sp->stop_cmd = cp;
+	outl( DBDMA_STOP, &cp->command );
+  
+	sp->rx_cmds = ++cp;
+
+	for( i = 0; i < NR_RX_RING; i++ ) {
+
+		cp = sp->rx_cmds + (i*2);
+		skb = dev_alloc_skb( RX_BUFLEN + 2 );
+
+		/* if there is insufficient memory, make this last ring use a 
+		   static buffer and leave the loop with that skb as final one */
+		if ( skb == 0 ) {
+			printk( KERN_ERR "%s: insufficient memory for rx ring buffer\n",
+				dev->name );
+			break;
+		}
+
+		skb_reserve( skb, 2 );
+		sp->rx_skbufs[i] = skb;
+		data = skb->data;
+
+		/* The DMA commands here are done such that an EOP is the only
+		   way that we should get an interrupt.  This means that we could
+		   fill more than one skbuff before getting the interrupt at EOP. */
+
+		/* Handle rx DMA such that it always interrupts.... */
+		outw( (INPUT_MORE|INTR_ALWAYS), &cp->command );
+		outw( RX_BUFLEN, &cp->req_count );
+		outw( 0, &cp->res_count );
+		outl( virt_to_bus( data ), &cp->phy_addr );
+		outl( virt_to_bus( sp->stop_cmd ), &cp->cmd_dep );
+		outw( 0, &cp->xfer_status );
+#if 0
+		printk( KERN_INFO "rx at %p\n", cp );
+		show_dbdma_cmd( cp );
+#endif
+		++cp;
+
+		outw( DBDMA_STOP, &cp->command );
+
+	}
+
+	/* initialize to all rx buffers are available, fill limit is the end */
+	sp->rx_dirty = 0;
+	sp->rx_current = 0;
+
+	/* fill the tx ring */
+	sp->tx_cmds = cp+1;
+
+	for( i = 0; i < NR_TX_RING; i++ ) {
+
+		/* minimal setup for tx command */
+		cp = sp->tx_cmds + (i*3);
+		outw( OUTPUT_LAST, &cp->command );
+		if (ncr885e_debug > 3) {
+			printk( KERN_INFO "tx OUTPUT_LAST at %p\n", cp );
+			show_dbdma_cmd( cp );
+		}
+
+		/* full setup for the status cmd */
+		cp++;
+		outw( INPUT_LAST|INTR_ALWAYS|WAIT_IFCLR, &cp->command );
+		outl( virt_to_bus( &sp->tx_status[i] ), &cp->phy_addr );
+		outw( 2, &cp->req_count );
+		if ( ncr885e_debug > 3) {
+			printk( KERN_INFO "tx INPUT_LAST cmd at %p\n", cp );
+			show_dbdma_cmd( cp );
+		}
+
+		++cp;
+		outw( DBDMA_STOP, &cp->command );
+ 
+	}
+#if 0
+	/* chain the last tx DMA command to the STOP cmd */
+	outw((INPUT_LAST|INTR_ALWAYS|BR_ALWAYS), &cp->command );
+	outl( virt_to_bus( sp->stop_cmd ), &cp->cmd_dep );
+#endif
+	sp->tx_active = 0;
+	sp->tx_current = 0;
+	sp->tx_dirty = 0;
+
+	spin_unlock_irqrestore( &sp->lock, flags );
+
+	/* the order seems important here for some reason.  If the MPIC isn't
+	   enabled before the ethernet chip is enabled, shrapnel from the
+	   bootloader causes us to receive interrupts even though we've not 
+	   yet enabled the tx channel.  Go figure.  It'd be better to configure
+	   the chip in the probe1() routine, but then we don't see interrupts
+	   at all.  Everything looks all right on the logic analyzer, but... */
+
+	ncr885e_config( dev );
+
+	/* enable ethernet interrupts */
+	if ( request_irq( dev->irq, &ncr885e_interrupt, SA_SHIRQ, chipname, dev )) {
+		printk( KERN_ERR "%s: can't get irq %d\n", dev->name, dev->irq );
+		return -EAGAIN;
+	}
+
+	(void) inw( ioaddr + INTERRUPT_CLEAR );
+
+	ncr885e_enable( dev );
+
+	/* start rx DBDMA */
+	outl( virt_to_bus( sp->rx_cmds ), ioaddr + RX_CMD_PTR_LO );
+	outl( (RX_DBDMA_ENABLE << 16)|RX_CHANNEL_RUN,
+	      ioaddr + RX_CHANNEL_CONTROL );
+
+	dev->start = 1;
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+static int
+ncr885e_xmit_start( struct sk_buff *skb, struct net_device *dev )
+
+{
+	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+	volatile struct dbdma_cmd *cp, *dp;
+	unsigned long flags, ioaddr = dev->base_addr;
+	int len, next, fill, entry;
+
+	if ( ncr885e_debug > 3)
+		printk( KERN_INFO "%s: xmit_start len=%d, dirty=%d, current=%d, active=%d\n",
+			dev->name, skb->len, sp->tx_dirty, sp->tx_current, sp->tx_active );
+
+	spin_lock_irqsave( &sp->lock, flags );
+
+	/* find the free slot in the ring buffer */
+	fill = sp->tx_current;
+	next = fill + 1;
+
+	if ( next >= NR_TX_RING )
+		next = 0;
+
+	/* mark ourselves as busy, even if we have too many packets waiting */
+	dev->tbusy = 1;
+
+	/* see if it's necessary to defer this packet */
+	if ( sp->tx_active >= MAX_TX_ACTIVE ) {
+		spin_unlock_irqrestore( &sp->lock, flags );
+		return -1;
+	}
+
+	sp->tx_active++;  /* bump "active tx" count */
+	sp->tx_current = next;  /* and show that we've used this buffer */
+	sp->tx_dirty = fill;     /* and mark this one to get picked up */
+
+	len = skb->len;
+
+	if ( len > ETH_FRAME_LEN ) {
+		printk( KERN_DEBUG "%s: xmit frame too long (%d)\n", dev->name, len );
+		len = ETH_FRAME_LEN;
+	}  
+
+	/* get index into the tx DBDMA chain */
+	entry = fill * 3;
+	sp->tx_skbufs[fill] = skb;
+	cp = sp->tx_cmds + entry;
+	dp = cp + 1;
+
+	/* update the rest of the OUTPUT_MORE descriptor */
+	outw( len, &cp->req_count );
+	outl( virt_to_bus( skb->data ), &cp->phy_addr );
+	outw( 0, &cp->xfer_status );
+	outw( 0, &cp->res_count );
+
+	/* and finish off the INPUT_MORE */
+	outw( 0, &dp->xfer_status );
+	outw( 0, &dp->res_count );
+	sp->tx_status[fill] = 0;
+	outl( virt_to_bus( &sp->tx_status[fill] ), &dp->phy_addr );
+
+	if ( ncr885e_debug > 2 )
+		printk(KERN_INFO "%s: xmit_start: active %d, tx_current %d, tx_dirty %d\n",
+		       dev->name, sp->tx_active, sp->tx_current, sp->tx_dirty );
+
+	if ( ncr885e_debug > 4 ) {
+		show_dbdma_cmd( cp );
+		show_dbdma_cmd( dp );
+	}
+
+
+	/* restart the tx DMA engine */
+	outl( virt_to_bus( cp ), ioaddr + TX_CMD_PTR_LO );
+	outl( (TX_DBDMA_ENABLE << 16)|TX_CHANNEL_RUN, 
+	      ioaddr + TX_CHANNEL_CONTROL );
+
+	ncr885e_set_timeout( dev );
+
+	spin_unlock_irqrestore( &sp->lock, flags );
+	dev->trans_start = jiffies;
+
+	return 0;      
+}
+
+static int
+ncr885e_close(struct net_device *dev)
+
+{
+	int i;
+	struct ncr885e_private *np = (struct ncr885e_private *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	spin_lock( &np->lock );
+
+	printk(KERN_INFO "%s: NCR885E Ethernet closing...\n", dev->name );
+
+	if (ncr885e_debug > 1)
+		printk(KERN_DEBUG "%s: Shutting down Ethernet chip\n", dev->name);
+
+	ncr885e_disable(dev);
+
+	del_timer(&np->tx_timeout);
+
+	/* flip off rx and tx */
+	outl( (RX_DBDMA_ENABLE << 16), ioaddr + RX_CHANNEL_CONTROL );
+	outl( (TX_DBDMA_ENABLE << 16), ioaddr + TX_CHANNEL_CONTROL );  
+
+	/* free up the IRQ */
+	free_irq( dev->irq, dev );
+
+	for( i = 0; i < NR_RX_RING; i++ ) {
+		if (np->rx_skbufs[i])
+			dev_kfree_skb( np->rx_skbufs[i] );
+		np->rx_skbufs[i] = 0;
+	}
+#if 0
+	for (i = 0; i < NR_TX_RING; i++) {
+		if (np->tx_skbufs[i])
+			dev_kfree_skb(np->tx_skbufs[i]);
+		np->tx_skbufs[i] = 0;
+	}
+#endif
+	spin_unlock( &np->lock );
+
+	kfree( np->head );
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+
+/*
+ *  multicast promiscuous mode isn't used here.  Allow code in the
+ *  IP stack to determine which multicast packets are good or bad....
+ *  (this avoids having to use the hash table registers)
+ */
+static void
+ncr885e_set_multicast( struct net_device *dev )
+
+{
+	int ioaddr = dev->base_addr;
+
+	if ( ncr885e_debug > 3 )
+		printk("%s: set_multicast: dev->flags = %x, AF=%04x\n", 
+		       dev->name, dev->flags, inw( ioaddr + ADDRESS_FILTER ));
+
+	if ( dev->flags & IFF_PROMISC ) {
+		printk( KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name );
+		outw( ADDRESS_RPPRO, ioaddr + ADDRESS_FILTER );
+	}
+
+	/* accept all multicast packets without checking the mc_list.  */
+	else if ( dev->flags & IFF_ALLMULTI ) {
+		printk( KERN_INFO "%s: Enabling all multicast packets.\n", 
+			dev->name );
+		outw( ADDRESS_RPPRM, ioaddr + ADDRESS_FILTER );
+	}
+
+	/* enable broadcast rx */
+	else {
+		outw( ADDRESS_RPABC, ioaddr + ADDRESS_FILTER );
+	}  
+}
+
+static struct net_device_stats *
+ncr885e_stats( struct net_device *dev )
+
+{
+	struct ncr885e_private *np = (struct ncr885e_private *) dev->priv;
+
+	return &np->stats;
+}
+
+/*  By this function, we're certain that we have a 885 Ethernet controller
+ *  so we finish setting it up and wrap up all the required Linux ethernet
+ *  configuration.
+ */
+
+static int
+ncr885e_probe1( struct net_device *dev, unsigned long ioaddr, unsigned char irq )
+
+{
+	struct ncr885e_private *sp;
+	unsigned short station_addr[3], val;
+	unsigned char *p;
+	int  i;
+
+	dev = init_etherdev( dev, 0 );
+
+	/* construct private data for the 885 ethernet */
+	dev->priv = kmalloc( sizeof( struct ncr885e_private ), GFP_KERNEL );
+
+	if ( dev->priv == NULL )
+		return -ENOMEM;
+
+	sp = (struct ncr885e_private *) dev->priv;
+	memset( sp, 0, sizeof( struct ncr885e_private ));
+
+	/* snag the station address and display it */
+	for( i = 0; i < 3; i++ ) {
+		val = inw( ioaddr + STATION_ADDRESS_0 + (i*2));
+		station_addr[i] = ((val >> 8) & 0xff) | ((val << 8) & 0xff00);
+	}
+
+	printk( KERN_INFO "%s: %s at %08lx,", dev->name, chipname, ioaddr );
+
+	p = (unsigned char *) &station_addr;
+
+	for( i=0; i < 6; i++ ) {
+		dev->dev_addr[i] = *p;
+		printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i] );
+		p++;
+	}
+
+	printk(", IRQ %d.\n", irq );
+
+	request_region( ioaddr, NCR885E_TOTAL_SIZE, dev->name );
+
+	/* set up a timer */
+	init_timer( &sp->tx_timeout );
+	sp->timeout_active = 0;
+
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+
+	ether_setup( dev );
+
+	/* everything else */
+	dev->open = ncr885e_open;
+	dev->stop = ncr885e_close;
+	dev->get_stats = ncr885e_stats;
+	dev->hard_start_xmit = ncr885e_xmit_start;
+	dev->set_multicast_list = ncr885e_set_multicast;
+	dev->set_mac_address = ncr885e_set_address;
+
+	return 0;
+}
+
+/*  Since the NCR 53C885 is a multi-function chip, I'm not worrying about
+ *  trying to get the the device(s) in slot order.  For our (Synergy's)
+ *  purpose, there's just a single 53C885 on the board and we don't 
+ *  worry about the rest.
+ */
+
+int __init ncr885e_probe( struct net_device *dev )
+{
+	struct pci_dev *pdev = NULL;
+	unsigned int ioaddr, chips = 0;
+	unsigned short cmd;
+	unsigned char irq, latency;
+
+	while(( pdev = pci_find_device( PCI_VENDOR_ID_NCR, 
+					PCI_DEVICE_ID_NCR_53C885_ETHERNET,
+					pdev )) != NULL ) {
+
+		if ( !print_version ) {
+			print_version++;
+			printk( KERN_INFO "%s", version );
+		}
+
+		/* Use I/O space */
+		pci_read_config_dword( pdev, PCI_BASE_ADDRESS_0, &ioaddr );
+		pci_read_config_byte( pdev, PCI_INTERRUPT_LINE, &irq );
+
+		ioaddr &= ~3;
+		/* Adjust around the Grackle... */
+#ifdef CONFIG_GEMINI
+		ioaddr |= 0xfe000000;
+#endif
+
+		if ( check_region( ioaddr, NCR885E_TOTAL_SIZE ))
+			continue;
+
+		/* finish off the probe */
+		if ( !(ncr885e_probe1( dev, ioaddr, irq ))) {
+
+			chips++;
+
+			/* Access is via I/O space, bus master enabled... */
+			pci_read_config_word( pdev, PCI_COMMAND, &cmd );
+
+			if ( !(cmd & PCI_COMMAND_MASTER) ) {
+				printk( KERN_INFO "  PCI master bit not set! Now setting.\n");
+				cmd |= PCI_COMMAND_MASTER;
+				pci_write_config_word( pdev, PCI_COMMAND, cmd );
+			}
+
+			if ( !(cmd & PCI_COMMAND_IO) ) {
+				printk( KERN_INFO "  Enabling I/O space.\n" );
+				cmd |= PCI_COMMAND_IO;
+				pci_write_config_word( pdev, PCI_COMMAND, cmd );
+			}
+
+			pci_read_config_byte( pdev, PCI_LATENCY_TIMER, &latency );
+
+			if ( latency < 10 ) {
+				printk( KERN_INFO "  PCI latency timer (CFLT) is unreasonably"
+					" low at %d.  Setting to 255.\n", latency );
+				pci_write_config_byte( pdev, PCI_LATENCY_TIMER, 255 );
+			}
+		}
+	}
+
+	if ( !chips )
+		return -ENODEV;
+	else
+		return 0;
+}
+
+/* debugging to peek at dma descriptors */
+static void
+show_dbdma_cmd( volatile struct dbdma_cmd *cmd )
+
+{
+	printk( KERN_INFO " cmd %04x, physaddr %08x, req_count %04x\n",
+		inw( &cmd->command ), inl( &cmd->phy_addr ), inw( &cmd->req_count ));
+	printk( KERN_INFO " res_count %04x, xfer_status %04x, branch %08x\n", 
+		inw( &cmd->res_count ), inw( &cmd->xfer_status ),inl( &cmd->cmd_dep ));
+}
+
+#if 0
+static int
+read_eeprom( unsigned int ioaddr, int location )
+
+{
+	int loop;
+	unsigned char val;
+
+	outb( (location & 0xff), ioaddr + EE_WORD_ADDR );
+
+	/* take spillover from location in control reg */
+	outb(EE_CONTROL_RND_READB | (location & (0x7<<8)), ioaddr + EE_CONTROL);
+
+	loop = 1000;
+	while( (inb( ioaddr + EE_STATUS) & EE_SEB) &&
+	       (loop > 0) ) {
+		udelay( 10 );
+		loop--;
+	}
+
+	if ( inb( ioaddr + EE_STATUS ) & EE_SEE ) {
+		printk("%s: Serial EEPROM read error\n", chipname);
+		val = 0xff;
+	}
+
+	else 
+		val = inb( ioaddr + EE_READ_DATA );
+
+	return (int) val;
+}
+#endif
+
+#ifdef NCR885E_DEBUG_MII
+static void
+show_mii( unsigned long ioaddr )
+
+{
+	int   phyctrl, phystat, phyadvert, phypartner, phyexpan;
+
+	phyctrl = read_mii( ioaddr, MII_AUTO_NEGOTIATION_CONTROL );
+	phystat = read_mii( ioaddr, MII_AUTO_NEGOTIATION_STATUS );
+	phyadvert = read_mii( ioaddr, MII_AUTO_NEGOTIATION_ADVERTISEMENT );
+	phypartner = read_mii( ioaddr, MII_AUTO_NEGOTIATION_LINK_PARTNER );
+	phyexpan = read_mii( ioaddr, MII_AUTO_NEGOTIATION_EXPANSION );
+
+	printk( KERN_INFO "PHY: advert=%d %s, partner=%s %s, link=%d, %s%s\n",
+		(phyadvert & MANATECH_100BASETX_FULL_DUPLEX ? 100 : 10),
+		(phyctrl & MANC_AUTO_NEGOTIATION_ENABLE ? "auto" : "fixed"),
+		(phypartner & MANLP_ACKNOWLEDGE ?
+		 (phypartner & MANATECH_100BASETX_FULL_DUPLEX ? "100" : "10") :
+		 "?"),
+		(phyexpan & MANE_LINK_PARTNER_AUTO_ABLE ? "auto" : "fixed"),
+		(phyctrl & MANC_PHY_SPEED_100 ? 100 : 10),
+		(phystat & MANS_LINK_STATUS ? "up" : "down"),
+		(phyexpan & MANE_PARALLEL_DETECTION_FAULT ? " PD-fault" : "" ));
+	return;
+}
+
+
+static int
+read_mii( unsigned long ioaddr, int reg )
+
+{
+	int    timeout;
+
+
+	timeout = 100000;
+
+	while( inw( ioaddr + MII_INDICATOR ) & MII_BUSY ) {
+
+		if ( timeout-- < 0 ) {
+			printk( KERN_INFO "Timed out waiting for MII\n" );
+			return -1;
+		}
+	}
+
+	outw( (1<<8) + reg, ioaddr + MII_ADDRESS );
+	outw( MIIM_RSTAT, ioaddr + MIIM_COMMAND );
+
+	timeout = 100000;
+	while( inw( ioaddr + MII_INDICATOR ) & MII_BUSY ) {
+		if ( timeout-- < 0 ) {
+			printk( KERN_INFO "Timed out waiting for MII\n" );
+			return -1;
+		}
+	}
+
+	return( inw( ioaddr + MII_READ_DATA ));
+}
+
+static void
+write_mii( unsigned long ioaddr, int reg, int data )
+
+{
+	int timeout=100000;
+
+	printk( KERN_INFO "MII indicator: %02x\n", inw( ioaddr + MII_INDICATOR ));
+
+	while( inw( ioaddr + MII_INDICATOR ) & MII_BUSY ) {
+		if ( timeout-- <= 0 ) {
+			printk( KERN_INFO "Timeout waiting to write to MII\n" );
+			return;
+		}
+		udelay( 10 );
+	}
+
+	outw( (1<<8) + reg, ioaddr + MII_ADDRESS );
+	outw( data, ioaddr + MII_WRITE_DATA );
+
+	return;
+}
+
+#endif /* NCR885E_DEBUG_MII */
+
+#ifdef MODULE
+#if defined(LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20118
+MODULE_AUTHOR("dan@synergymicro.com");
+MODULE_DESCRIPTION("Symbios 53C885 Ethernet driver");
+MODULE_PARM(debug, "i");
+#endif 
+
+static int debug = 1;
+
+int
+init_module(void)
+{
+	if ( debug >= 0)
+		ncr885e_debug = debug;
+
+	return ncr885e_probe( NULL );
+}
+
+void
+cleanup_module(void)
+{
+	struct ncr885e_private *np;
+
+	if ( root_dev ) {
+
+		unregister_netdev( root_dev );
+		np = (struct ncr885e_private *) root_dev->priv;
+		release_region( root_dev->base_addr, NCR885E_TOTAL_SIZE );
+		kfree( root_dev->priv );
+		root_dev = NULL;
+	}  
+}
+#endif /* MODULE */
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O6 -c symba.c"
+ * End:
+ */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/ncr885e.h linux/drivers/net/ncr885e.h
--- v2.3.20/linux/drivers/net/ncr885e.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/ncr885e.h	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,367 @@
+#ifndef _NET_H_SYMBA
+#define _NET_H_SYMBA
+
+/* transmit status bit definitions */
+#define TX_STATUS_TXOK         (1<<13)     /* success */
+#define TX_STATUS_TDLC         (1<<12)     /* dropped for late colls */
+#define TX_STATUS_TCXSDFR      (1<<11)     /* excessive deferral */
+#define TX_STATUS_TDEC         (1<<10)     /* excessive collisions */
+#define TX_STATUS_TAUR         (1<<9)      /* abort on underrun/"jumbo" */
+#define TX_STATUS_PDFRD        (1<<8)      /* packet deferred */
+#define TX_STATUS_BCAST        (1<<7)      /* broadcast ok */
+#define TX_STATUS_MCAST        (1<<6)      /* multicast ok */
+#define TX_STATUS_CRCERR       (1<<5)      /* CRC error */
+#define TX_STATUS_LC           (1<<4)      /* late collision */
+#define TX_STATUS_CCNT_MASK    0xf         /* collision count */
+
+#define T_TXOK      (1<<13)
+#define T_TDLC      (1<<12)
+#define T_TCXSDFR   (1<<11)
+#define T_TDEC      (1<<10)
+#define T_TAUR      (1<<9)
+#define T_PDFRD     (1<<8)
+#define T_BCAST     (1<<7)
+#define T_MCAST     (1<<6)
+#define T_LC        (1<<4)
+#define T_CCNT_MASK 0xf
+
+/* receive status bit definitions */
+#define RX_STATUS_RXOVRN       (1<<23)     /* overrun */
+#define RX_STATUS_CEPS         (1<<22)     /* carrier event already seen */
+#define RX_STATUS_RXOK         (1<<21)     /* success */
+#define RX_STATUS_BCAST        (1<<20)     /* broadcast ok */
+#define RX_STATUS_MCAST        (1<<19)     /* multicast ok */
+#define RX_STATUS_CRCERR       (1<<18)     /* CRC error */
+#define RX_STATUS_DR           (1<<17)     /* dribble nibble */
+#define RX_STATUS_RCV          (1<<16)     /* rx code violation */
+#define RX_STATUS_PTL          (1<<15)     /* pkt > 1518 bytes */
+#define RX_STATUS_PTS          (1<<14)     /* pkt < 64 bytes */
+#define RX_STATUS_LEN_MASK     0x1fff      /* length mask */
+
+#define EEPROM_LENGTH          100
+
+
+/*  Serial EEPROM interface  */
+#define EE_STATUS              0xf0
+#define EE_CONTROL             0xf1
+#define EE_WORD_ADDR           0xf2
+#define EE_READ_DATA           0xf3
+#define EE_WRITE_DATA          0xf4
+#define EE_FEATURE_ENB         0xf5
+
+/*  Use on EE_STATUS  */
+#define EE_SEB                 (1<<8)
+#define EE_SEE                     1
+
+/*  Serial EEPROM commands */
+#define EE_CONTROL_SEQ_READB   (1<<4)
+#define EE_CONTROL_RND_WRITEB  (1<<5)
+#define EE_CONTROL_RND_READB   ((1<<4)|(1<<5))
+
+/*  Enable writing to serial EEPROM */
+#define EE_WRITE_ENB                1
+
+/*  The 885 configuration register */
+#define MAC_CONFIG             0xa0
+#define  MAC_CONFIG_SRST       1<<15
+#define  MAC_CONFIG_ITXA       1<<13
+#define  MAC_CONFIG_RXEN       1<<12
+#define  MAC_CONFIG_INTLB      1<<10
+#define  MAC_CONFIG_MODE_MASK  (1<<8|1<<9)
+#define  MAC_CONFIG_MODE_TP    1<<8
+#define  MAC_CONFIG_HUGEN      1<<5
+#define  MAC_CONFIG_RETRYL     1<<4
+#define  MAC_CONFIG_CRCEN      1<<3
+#define  MAC_CONFIG_PADEN      1<<2
+#define  MAC_CONFIG_FULLD      1<<1
+#define  MAC_CONFIG_NOCFR      1<<0
+
+
+
+
+
+#define TX_WAIT_SELECT         0x18
+#define RX_CHANNEL_CONTROL     0x40
+
+/* Tx channel status */
+#define TX_DBDMA_REG           0x00
+#define TX_CHANNEL_CONTROL     0x00
+#define TX_CHANNEL_STATUS      0x04
+#define  TX_STATUS_RUN         1<<15
+#define  TX_STATUS_PAUSE       1<<14
+#define  TX_STATUS_WAKE        1<<12
+#define  TX_STATUS_DEAD        1<<11
+#define  TX_STATUS_ACTIVE      1<<10
+#define  TX_STATUS_BT          1<<8
+#define  TX_STATUS_TXABORT     1<<7
+#define  TX_STATUS_TXSR        1<<6
+
+#define  TX_CHANNEL_RUN        TX_STATUS_RUN
+#define  TX_CHANNEL_PAUSE      TX_STATUS_PAUSE
+#define  TX_CHANNEL_WAKE       TX_STATUS_WAKE
+#define  TX_CHANNEL_DEAD       TX_STATUS_DEAD
+#define  TX_CHANNEL_ACTIVE     TX_STATUS_ACTIVE
+#define  TX_CHANNEL_BT         TX_STATUS_BT
+#define  TX_CHANNEL_TXABORT    TX_STATUS_TXABORT
+#define  TX_CHANNEL_TXSR       TX_STATUS_TXSR
+
+#define  TX_DBDMA_ENABLE       (TX_CHANNEL_WAKE | TX_CHANNEL_PAUSE | \
+                                TX_CHANNEL_RUN )
+
+/* Transmit command ptr lo register */
+#define TX_CMD_PTR_LO          0x0c
+
+/* Transmit interrupt select register */
+#define TX_INT_SELECT          0x10
+
+/* Transmit branch select register */
+#define TX_BRANCH_SELECT       0x14
+
+/* Transmit wait select register */
+#define TX_WAIT_SELECT         0x18
+#define  TX_WAIT_STAT_RECV     0x40
+
+/* Rx channel status */
+#define RX_DBDMA_REG           0x40
+#define RX_CHANNEL_CONTROL     0x40
+#define RX_CHANNEL_STATUS      0x44
+#define  RX_STATUS_RUN         1<<15
+#define  RX_STATUS_PAUSE       1<<14
+#define  RX_STATUS_WAKE        1<<12
+#define  RX_STATUS_DEAD        1<<11
+#define  RX_STATUS_ACTIVE      1<<10
+#define  RX_STATUS_BT          1<<8
+#define  RX_STATUS_EOP         1<<6
+
+#define  RX_CHANNEL_RUN        RX_STATUS_RUN
+#define  RX_CHANNEL_PAUSE      RX_STATUS_PAUSE
+#define  RX_CHANNEL_WAKE       RX_STATUS_WAKE
+#define  RX_CHANNEL_DEAD       RX_STATUS_DEAD
+#define  RX_CHANNEL_ACTIVE     RX_STATUS_ACTIVE
+#define  RX_CHANNEL_BT         RX_STATUS_BT
+#define  RX_CHANNEL_EOP        RX_STATUS_EOP
+
+#define  RX_DBDMA_ENABLE       (RX_CHANNEL_WAKE | RX_CHANNEL_PAUSE | \
+                                RX_CHANNEL_RUN)
+
+/*  Receive command ptr lo  */
+#define RX_CMD_PTR_LO          0x4c
+
+/*  Receive interrupt select register */
+#define RX_INT_SELECT          0x50
+#define  RX_INT_SELECT_EOP     0x40
+
+/*  Receive branch select  */
+#define RX_BRANCH_SELECT       0x54
+#define  RX_BRANCH_SELECT_EOP  0x40
+
+/*  Receive wait select  */
+#define RX_WAIT_SELECT         0x58
+#define  RX_WAIT_SELECT_EOP    0x40
+
+/*  Event status register  */
+#define EVENT_STATUS           0x80
+#define  EVENT_TXSR            1<<2
+#define  EVENT_EOP             1<<1
+#define  EVENT_TXABORT         1<<0
+
+/*  Interrupt enable register  */
+#define INTERRUPT_ENABLE       0x82
+
+/*  Interrupt clear register  */
+#define INTERRUPT_CLEAR        0x84
+
+/*  Interrupt status register  */
+#define INTERRUPT_STATUS_REG   0x86
+
+/*  bits for the above three interrupt registers */
+#define  INTERRUPT_INTE        1<<15   /* interrupt enable */
+#define  INTERRUPT_WI          1<<9    /* wakeup interrupt */
+#define  INTERRUPT_ERI         1<<8    /* early recieve interrupt */
+#define  INTERRUPT_PPET        1<<7    /* PCI Tx parity error */
+#define  INTERRUPT_PBFT        1<<6    /* PCI Tx bus fault */
+#define  INTERRUPT_IIDT        1<<5    /* illegal instruction Tx */
+#define  INTERRUPT_DIT         1<<4    /* DBDMA Tx interrupt */
+#define  INTERRUPT_PPER        1<<3    /* PCI Rx parity error */
+#define  INTERRUPT_PBFR        1<<2    /* PCI Rx bus fault */
+#define  INTERRUPT_IIDR        1<<1    /* illegal instruction Rx */
+#define  INTERRUPT_DIR         1<<0    /* DBDMA Rx interrupt */
+
+#define  INTERRUPT_TX_MASK     (INTERRUPT_PBFT|INTERRUPT_IIDT| \
+                                INTERRUPT_PPET|INTERRUPT_DIT)
+#define  INTERRUPT_RX_MASK     (INTERRUPT_PBFR|INTERRUPT_IIDR| \
+                                INTERRUPT_PPER|INTERRUPT_DIR)
+
+/*  chip revision register */
+#define CHIP_REVISION_REG      0x8c
+#define  CHIP_PCIREV_MASK      (0xf<<16)
+#define  CHIP_PCIDEV_MASK      0xff
+
+/*  Tx threshold register */
+#define TX_THRESHOLD           0x94
+
+/*  General purpose register */
+#define GEN_PURPOSE_REG        0x9e
+
+/*  General purpose pin control reg */
+#define GEN_PIN_CONTROL_REG    0x9f
+
+/*  DBDMA control register  */
+#define DBDMA_CONTROL          0x90
+#define  DBDMA_SRST            1<<31
+#define  DBDMA_TDPCE           1<<23
+#define  DBDMA_BE              1<<22
+#define  DBDMA_TAP_MASK        (1<<19|1<<20|1<<21)
+#define  DBDMA_RAP_MASK        (1<<16|1<<17|1<<18)
+#define  DBDMA_DPMRLE          1<<15
+#define  DBDMA_WIE             1<<14
+#define  DBDMA_MP              1<<13
+#define  DBDMA_SME             1<<12
+#define  DBDMA_CME             1<<11
+#define  DBDMA_DDPE            1<<10
+#define  DBDMA_TDPE            1<<9
+#define  DBDMA_EXTE            1<<8
+#define  DBDMA_BST_MASK        (1<<4|1<<5|1<<6)
+#define  DBDMA_BSR_MASK        (1<<0|1<<1|1<<2)
+
+#define  DBDMA_BURST_1         (0x00)
+#define  DBDMA_BURST_2         (0x01)
+#define  DBDMA_BURST_4         (0x02)
+#define  DBDMA_BURST_8         (0x03)
+#define  DBDMA_BURST_16        (0x04)
+#define  DBDMA_BURST_32        (0x05)
+#define  DBDMA_BURST_64        (0x06)
+#define  DBDMA_BURST_128       (0x07)
+
+#define  DBDMA_TX_BST_SHIFT    (4)
+#define  DBDMA_RX_BST_SHIFT    (0)
+
+#define  DBDMA_TX_ARBITRATION_DEFAULT ( 1 << 19 )
+#define  DBDMA_RX_ARBITRATION_DEFAULT ( 2 << 16 )
+
+
+/*  Back-to-back interpacket gap register */
+#define BTOB_INTP_GAP          0xa2
+#define  BTOB_INTP_DEFAULT     0x18
+
+/*  Non-back-to-back interpacket gap register */
+#define NBTOB_INTP_GAP         0xa4
+
+/*  MIIM command register */
+#define MIIM_COMMAND           0xa6
+#define  MIIM_SCAN             1<<1
+#define  MIIM_RSTAT            1<<0
+
+/*  MII address register */
+#define MII_ADDRESS            0xa8
+#define  MII_FIAD_MASK         (1<<8|1<<9|1<<10|1<<11|1<<12)
+#define  MII_RGAD_MASK         (1<<0|1<<1|1<<2|1<<3|1<<4)
+
+#define TPPMD_CONTROL_REG      0xa8
+#define  TPPMD_FO              1<<1
+#define  TPPMD_LB              1<<0
+
+/*  MII read and write registers */
+#define MII_WRITE_DATA         0xaa
+#define MII_READ_DATA          0xac
+
+/*  MII indicators */
+#define MII_INDICATOR          0xae
+#define  MII_NVALID            1<<2
+#define  MII_SCAN              1<<1
+#define  MII_BUSY              1<<0
+
+/*  Address filter  */
+#define ADDRESS_FILTER         0xd0
+#define  ADDRESS_RPPRM         1<<3       /* multicast promis. mode */
+#define  ADDRESS_RPPRO         1<<2       /* promiscuous mode */
+#define  ADDRESS_RPAMC         1<<1       /* accept multicasts */
+#define  ADDRESS_RPABC         1<<0       /* accept broadcasts */
+
+/*  Station addresses
+
+    Note that if the serial EEPROM is disabled, these values are all
+    zero.  If, like us, you get the chips when they're fresh, they're
+    also zero and you have to initialize the address */
+#define STATION_ADDRESS_0      0xd2
+#define STATION_ADDRESS_1      0xd4
+#define STATION_ADDRESS_2      0xd6
+
+/*  Hash tables  */
+#define HASH_TABLE_0           0xd8
+#define HASH_TABLE_1           0xda
+#define HASH_TABLE_2           0xdc
+#define HASH_TABLE_3           0xde
+
+/* PHY indentifiers */
+#define PHY_IDENTIFIER_0       0xe4
+#define PHY_IDENTIFIER_1       0xe6
+
+/*  MII Auto-negotiation register definitions  */
+
+#define MII_AUTO_NEGOTIATION_CONTROL        (0x0000)
+#define   MANC_PHY_RESET                      (0x8000)
+#define   MANC_PHY_LOOPBACK_ENABLE            (0x4000)
+#define   MANC_PHY_LOOPBACK_DISABLE           (0x0000)
+#define   MANC_PHY_SPEED_100                  (0x2000)
+#define   MANC_PHY_SPEED_10                   (0x0000)
+#define   MANC_AUTO_NEGOTIATION_ENABLE        (0x1000)
+#define   MANC_AUTO_NEGOTIATION_DISABLE       (0x0000)
+#define   MANC_PHY_POWER_DOWN                 (0x0800)
+#define   MANC_PHY_POWER_UP                   (0x0000)
+#define   MANC_ISOLATE_ENABLE                 (0x0400)
+#define   MANC_ISOLATE_DISABLE                (0x0000)
+#define   MANC_RESTART_AUTO_NEGOTIATION       (0x0200)
+#define   MANC_FULL_DUPLEX                    (0x0100)
+#define   MANC_HALF_DUPLEX                    (0x0000)
+
+#define MII_AUTO_NEGOTIATION_STATUS         (0x0001)
+#define   MANS_100BASE_T4_HALF_DUPLEX         (0x8000)
+#define   MANS_100BASE_X_FULL_DUPLEX          (0x4000)
+#define   MANS_100BASE_X_HALF_DUPLEX          (0x2000)
+#define   MANS_10MBS_FULL_DUPLEX              (0x1000)
+#define   MANS_10MBS_HALF_DUPLEX              (0x0800)
+#define   MANS_AUTO_NEGOTIATION_COMPLETE      (0x0020)
+#define   MANS_REMOTE_FAULT                   (0x0010)
+#define   MANS_AUTO_NEGOTIATION_ABILITY       (0x0008)
+#define   MANS_LINK_STATUS                    (0x0004)
+#define   MANS_JABBER_DETECT                  (0x0002)
+#define   MANS_EXTENDED_CAPABILITY            (0x0001)
+
+#define MII_PHY_IDENTIFIER_1                (0x0002)
+#define MII_PHY_IDENTIFIER_2                (0x0003)
+
+#define MII_AUTO_NEGOTIATION_ADVERTISEMENT  (0x0004)
+#define   MANA_NEXT_PAGE                      (0x8000)
+#define   MANA_REMOTE_FAULT                   (0x2000)
+#define   MANA_TECHNOLOGY_ABILITY_MASK        (0x1FE0)
+#define     MANATECH_10BASET_HALF_DUPLEX        (0x0020)
+#define     MANATECH_10BASET_FULL_DUPLEX        (0x0040)
+#define     MANATECH_100BASETX_HALF_DUPLEX      (0x0080)
+#define     MANATECH_100BASETX_FULL_DUPLEX      (0x0100)
+#define     MANATECH_100BASET4                  (0x0200)
+#define   MANA_SELECTOR_MASK                  (0x001F)
+#define     MANASELECTOR_802_3                  (0x0001)
+
+#define MII_AUTO_NEGOTIATION_LINK_PARTNER   (0x0005)
+#define   MANLP_NEXT_PAGE                     (0x8000)
+#define   MANLP_ACKNOWLEDGE                   (0x4000)
+#define   MANLP_REMOTE_FAULT                  (0x2000)
+#define   MANLP_TECHNOLOGY_ABILITY_MASK       (0x1FE0)
+#define   MANLP_SELECTOR_MASK                 (0x001F)
+
+#define MII_AUTO_NEGOTIATION_EXPANSION      (0x0006)
+#define   MANE_PARALLEL_DETECTION_FAULT       (0x0010)
+#define   MANE_LINK_PARTNER_NEXT_PAGE_ABLE    (0x0008)
+#define   MANE_NEXT_PAGE_ABLE                 (0x0004)
+#define   MANE_PAGE_RECEIVED                  (0x0002)
+#define   MANE_LINK_PARTNER_AUTO_ABLE         (0x0001)
+
+#define MII_AUTO_NEGOTIATION_NEXT_PAGE_TRANSMIT (0x0007)
+#define   MANNPT_NEXT_PAGE                    (0x8000)
+#define   MANNPT_MESSAGE_PAGE                 (0x2000)
+#define   MANNPT_ACKNOWLEDGE_2                (0x1000)
+#define   MANNPT_TOGGLE                       (0x0800)
+#define   MANNPT_MESSAGE_FIELD_MASK           (0x07FF)
+
+#endif
diff -u --recursive --new-file v2.3.20/linux/drivers/net/olympic.c linux/drivers/net/olympic.c
--- v2.3.20/linux/drivers/net/olympic.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/net/olympic.c	Wed Dec 31 16:00:00 1969
@@ -1,1667 +0,0 @@
-/*
- *   olympic.c (c) 1999 Peter De Schrijver All Rights Reserved
- *		   1999 Mike Phillips (phillim@amtrak.com)
- *
- *  Linux driver for IBM PCI tokenring cards based on the Pit/Pit-Phy/Olympic
- *  chipset. 
- *
- *  Base Driver Skeleton:
- *      Written 1993-94 by Donald Becker.
- *
- *      Copyright 1993 United States Government as represented by the
- *      Director, National Security Agency.
- *
- *  Thanks to Erik De Cock, Adrian Bridgett and Frank Fiene for their 
- *  assistance and perserverance with the testing of this driver.
- *
- *  This software may be used and distributed according to the terms
- *  of the GNU Public License, incorporated herein by reference.
- * 
- *  4/27/99 - Alpha Release 0.1.0
- *            First release to the public
- *
- *  6/8/99  - Official Release 0.2.0   
- *            Merged into the kernel code 
- *  8/18/99 - Updated driver for 2.3.13 kernel to use new pci
- *	      resource. Driver also reports the card name returned by
- *            the pci resource.
- *  
- *  To Do:
- *
- *  Sanitize for smp
- *
- *  If Problems do Occur
- *  Most problems can be rectified by either closing and opening the interface
- *  (ifconfig down and up) or rmmod and insmod'ing the driver (a bit difficult
- *  if compiled into the kernel).
- */
-
-/* Change OLYMPIC_DEBUG to 1 to get verbose, and I mean really verbose, messages */
-
-#define OLYMPIC_DEBUG 0
-
-/* Change OLYMPIC_NETWORK_MONITOR to receive mac frames through the arb channel.
- * Will also create a /proc/net/olympic_tr entry if proc_fs is compiled into the
- * kernel.
- * Intended to be used to create a ring-error reporting network module 
- * i.e. it will give you the source address of beaconers on the ring 
- */
-
-#define OLYMPIC_NETWORK_MONITOR 0
-
-#include <linux/config.h>
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <linux/in.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/proc_fs.h>
-#include <linux/ptrace.h>
-#include <linux/skbuff.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/trdevice.h>
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <net/checksum.h>
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-
-#include "olympic.h"
-
-/* I've got to put some intelligence into the version number so that Peter and I know
- * which version of the code somebody has got. 
- * Version Number = a.b.c.d  where a.b.c is the level of code and d is the latest author.
- * So 0.0.1.pds = Peter, 0.0.1.mlp = Mike
- * 
- * Official releases will only have an a.b.c version number format.
- */
-
-static char *version = 
-"Olympic.c v0.3.0 8/18/99 - Peter De Schrijver & Mike Phillips" ; 
-
-static char *open_maj_error[]  = {"No error", "Lobe Media Test", "Physical Insertion",
-				   "Address Verification", "Neighbor Notification (Ring Poll)",
-				   "Request Parameters","FDX Registration Request",
-				   "FDX Duplicate Address Check", "Station registration Query Wait",
-				   "Unknown stage"};
-
-static char *open_min_error[] = {"No error", "Function Failure", "Signal Lost", "Wire Fault",
-				   "Ring Speed Mismatch", "Timeout","Ring Failure","Ring Beaconing",
-				   "Duplicate Node Address","Request Parameters","Remove Received",
-				   "Reserved", "Reserved", "No Monitor Detected for RPL", 
-				   "Monitor Contention failer for RPL", "FDX Protocol Error"};
-
-/* Module paramters */
-
-/* Ring Speed 0,4,16,100 
- * 0 = Autosense         
- * 4,16 = Selected speed only, no autosense
- * This allows the card to be the first on the ring
- * and become the active monitor.
- * 100 = Nothing at present, 100mbps is autodetected
- * if FDX is turned on. May be implemented in the future to 
- * fail if 100mpbs is not detected.
- *
- * WARNING: Some hubs will allow you to insert
- * at the wrong speed
- */
-
-static int ringspeed[OLYMPIC_MAX_ADAPTERS] = {0,} ;
-
-MODULE_PARM(ringspeed, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i");
-
-/* Packet buffer size */
-
-static int pkt_buf_sz[OLYMPIC_MAX_ADAPTERS] = {0,} ;
- 
-MODULE_PARM(pkt_buf_sz, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i") ; 
-
-/* Message Level */
-
-static int message_level[OLYMPIC_MAX_ADAPTERS] = {0,} ; 
-
-MODULE_PARM(message_level, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i") ; 
-
-static int olympic_scan(struct net_device *dev);
-static int olympic_init(struct net_device *dev);
-static int olympic_open(struct net_device *dev);
-static int olympic_xmit(struct sk_buff *skb, struct net_device *dev);
-static int olympic_close(struct net_device *dev);
-static void olympic_set_rx_mode(struct net_device *dev);
-static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static struct net_device_stats * olympic_get_stats(struct net_device *dev);
-static int olympic_set_mac_address(struct net_device *dev, void *addr) ; 
-static void olympic_arb_cmd(struct net_device *dev);
-static int olympic_change_mtu(struct net_device *dev, int mtu);
-static void olympic_srb_bh(struct net_device *dev) ; 
-static void olympic_asb_bh(struct net_device *dev) ; 
-#if OLYMPIC_NETWORK_MONITOR
-#ifdef CONFIG_PROC_FS
-static int sprintf_info(char *buffer, struct net_device *dev) ; 
-#endif
-#endif
-
-int __init olympic_probe(struct net_device *dev)
-{
-	int cards_found;
-
-	cards_found=olympic_scan(dev);
-	return cards_found ? 0 : -ENODEV;
-}
-
-static int __init olympic_scan(struct net_device *dev)
-{
-	struct pci_dev *pci_device = NULL ;
-	struct olympic_private *olympic_priv;
-	int card_no = 0 ;
-	if (pci_present()) {
-
-		while((pci_device=pci_find_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR_WAKE, pci_device))) {
-
-			pci_set_master(pci_device);
-
-			/* Check to see if io has been allocated, if so, we've already done this card,
-			   so continue on the card discovery loop  */
-
-			if (check_region(pci_device->resource[0].start, OLYMPIC_IO_SPACE)) {
-				card_no++ ; 
-				continue ; 
-			}
-
-			olympic_priv=kmalloc(sizeof (struct olympic_private), GFP_KERNEL);
-			memset(olympic_priv, 0, sizeof(struct olympic_private));
-			init_waitqueue_head(&olympic_priv->srb_wait);
-			init_waitqueue_head(&olympic_priv->trb_wait);
-#ifndef MODULE
-			dev=init_trdev(dev, 0);
-#endif
-			dev->priv=(void *)olympic_priv;
-#if OLYMPIC_DEBUG  
-			printk("pci_device: %p, dev:%p, dev->priv: %p\n", pci_device, dev, dev->priv);
-#endif
-			dev->irq=pci_device->irq;
-			dev->base_addr=pci_device->resource[0].start;
-			dev->init=&olympic_init;
-			olympic_priv->olympic_card_name = (char *)pci_device->resource[0].name ; 
-			olympic_priv->olympic_mmio=ioremap(pci_device->resource[1].start,256);
-			olympic_priv->olympic_lap=ioremap(pci_device->resource[2].start,2048);
-			
-			if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000) )
-				olympic_priv->pkt_buf_sz = PKT_BUF_SZ ; 
-			else
-				olympic_priv->pkt_buf_sz = pkt_buf_sz[card_no] ; 
-
-			olympic_priv->olympic_ring_speed = ringspeed[card_no] ; 
-			olympic_priv->olympic_message_level = message_level[card_no] ; 
-			olympic_priv->olympic_multicast_set  = 0 ; 
-	
-			if(olympic_init(dev)==-1) {
-				unregister_netdevice(dev);
-				kfree(dev->priv);
-				return 0;
-			}				
-
-			dev->open=&olympic_open;
-			dev->hard_start_xmit=&olympic_xmit;
-			dev->change_mtu=&olympic_change_mtu;
-
-			dev->stop=&olympic_close;
-			dev->do_ioctl=NULL;
-			dev->set_multicast_list=&olympic_set_rx_mode;
-			dev->get_stats=&olympic_get_stats ;
-			dev->set_mac_address=&olympic_set_mac_address ;  
-			return 1; 
-		}
-	}
-	return  0 ;
-}
-
-
-static int __init olympic_init(struct net_device *dev)
-{
-    	struct olympic_private *olympic_priv;
-	__u8 *olympic_mmio, *init_srb,*adapter_addr;
-	unsigned long t; 
-	unsigned int uaa_addr;
-
-    	olympic_priv=(struct olympic_private *)dev->priv;
-	olympic_mmio=olympic_priv->olympic_mmio;
-
-	printk("%s \n", version);
-	printk("%s: %s. I/O at %hx, MMIO at %p, LAP at %p, using irq %d\n",dev->name, olympic_priv->olympic_card_name, (unsigned int) dev->base_addr,olympic_priv->olympic_mmio, olympic_priv->olympic_lap, dev->irq);
-
-	request_region(dev->base_addr, OLYMPIC_IO_SPACE, "olympic");
-	writel(readl(olympic_mmio+BCTL) | BCTL_SOFTRESET,olympic_mmio+BCTL);
-	t=jiffies;
-	while((readl(olympic_priv->olympic_mmio+BCTL)) & BCTL_SOFTRESET) {
-		schedule();		
-		if(jiffies-t > 40*HZ) {
-			printk(KERN_ERR "IBM PCI tokenring card not responding.\n");
-			release_region(dev->base_addr, OLYMPIC_IO_SPACE) ; 
-			return -1;
-		}
-	}
-
-#if OLYMPIC_DEBUG
-	printk("BCTL: %x\n",readl(olympic_mmio+BCTL));
-	printk("GPR: %x\n",readw(olympic_mmio+GPR));
-	printk("SISRMASK: %x\n",readl(olympic_mmio+SISR_MASK));
-#endif
-	/* Aaaahhh, You have got to be real careful setting GPR, the card
-	   holds the previous values from flash memory, including autosense 
-           and ring speed */
-
-	writel(readl(olympic_mmio+BCTL)|BCTL_MIMREB,olympic_mmio+BCTL);
-	
-	if (olympic_priv->olympic_ring_speed  == 0) { /* Autosense */
-		writel(readl(olympic_mmio+GPR)|GPR_AUTOSENSE,olympic_mmio+GPR);
-		if (olympic_priv->olympic_message_level) 
-			printk(KERN_INFO "%s: Ringspeed autosense mode on\n",dev->name);
-	} else if (olympic_priv->olympic_ring_speed == 16) {
-		if (olympic_priv->olympic_message_level) 
-			printk(KERN_INFO "%s: Trying to open at 16 Mbps as requested\n", dev->name);
-		writel(GPR_16MBPS, olympic_mmio+GPR);
-	} else if (olympic_priv->olympic_ring_speed == 4) {
-		if (olympic_priv->olympic_message_level) 
-			printk(KERN_INFO "%s: Trying to open at 4 Mbps as requested\n", dev->name) ; 
-		writel(0, olympic_mmio+GPR);
-	} 
-	
-	writel(readl(olympic_mmio+GPR)|GPR_NEPTUNE_BF,olympic_mmio+GPR);
-
-#if OLYMPIC_DEBUG
-	printk("GPR = %x\n",readw(olympic_mmio + GPR) ) ; 
-#endif
-	/* start solo init */
-	writel((1<<15),olympic_mmio+SISR_MASK_SUM);
-
-	t=jiffies;
-	while(!((readl(olympic_mmio+SISR_RR)) & SISR_SRB_REPLY)) {
-		schedule();		
-		if(jiffies-t > 40*HZ) {
-			printk(KERN_ERR "IBM PCI tokenring card not responding.\n");
-			release_region(dev->base_addr, OLYMPIC_IO_SPACE); 
-			return -1;
-		}
-	}
-	
-	writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
-
-#if OLYMPIC_DEBUG
-	printk("LAPWWO: %x, LAPA: %x\n",readl(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA));
-#endif
-
-	init_srb=olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWO)) & (~0xf800));
-
-#if OLYMPIC_DEBUG		
-{
-	int i;
-	printk("init_srb(%p): ",init_srb);
-	for(i=0;i<20;i++)
-		printk("%x ",readb(init_srb+i));
-	printk("\n");
-}
-#endif	
-	if(readw(init_srb+6)) {
-		printk(KERN_INFO "tokenring card intialization failed. errorcode : %x\n",readw(init_srb+6));
-		release_region(dev->base_addr, OLYMPIC_IO_SPACE);
-		return -1;
-	}
-
-	uaa_addr=ntohs(readw(init_srb+8));
-
-#if OLYMPIC_DEBUG
-	printk("UAA resides at %x\n",uaa_addr);
-#endif
-
-	writel(uaa_addr,olympic_mmio+LAPA);
-	adapter_addr=olympic_priv->olympic_lap + (uaa_addr & (~0xf800));
-
-#if OLYMPIC_DEBUG
-	printk("adapter address: %02x:%02x:%02x:%02x:%02x:%02x\n",
-			readb(adapter_addr), readb(adapter_addr+1),readb(adapter_addr+2),
-			readb(adapter_addr+3),readb(adapter_addr+4),readb(adapter_addr+5));
-#endif
-
-	memcpy_fromio(&dev->dev_addr[0], adapter_addr,6);
-
-	olympic_priv->olympic_addr_table_addr = ntohs(readw(init_srb + 12)) ; 
-	olympic_priv->olympic_parms_addr      = ntohs(readw(init_srb + 14)) ; 
-
-	return 0;
-
-}
-
-static int olympic_open(struct net_device *dev) 
-{
-	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
-	__u8 *olympic_mmio=olympic_priv->olympic_mmio,*init_srb;
-	unsigned long flags;
-	char open_error[255] ; 
-	int i, open_finished = 1 ;
-
-#if OLYMPIC_NETWORK_MONITOR
-	__u8 *oat ; 
-	__u8 *opt ; 
-#endif
-
-	if(request_irq(dev->irq, &olympic_interrupt, SA_SHIRQ , "olympic", dev)) {
-		return -EAGAIN;
-	}
-
-#if OLYMPIC_DEBUG
-	printk("BMCTL: %x\n",readl(olympic_mmio+BMCTL_SUM));
-	printk("pending ints: %x\n",readl(olympic_mmio+SISR_RR));
-#endif
-
-	writel(SISR_MI,olympic_mmio+SISR_MASK_SUM);
-
-	writel(SISR_MI | SISR_SRB_REPLY, olympic_mmio+SISR_MASK); /* more ints later, doesn't stop arb cmd interrupt */
-
-	writel(LISR_LIE,olympic_mmio+LISR); /* more ints later */
-
-	/* adapter is closed, so SRB is pointed to by LAPWWO */
-
-	writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
-	init_srb=olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWO)) & (~0xf800));
-	
-#if OLYMPIC_DEBUG
-	printk("LAPWWO: %x, LAPA: %x\n",readl(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA));
-	printk("SISR Mask = %04x\n", readl(olympic_mmio+SISR_MASK));
-	printk("Before the open command \n");
-#endif	
-	do {
-		int i;
-
-		save_flags(flags);
-		cli();
-		for(i=0;i<SRB_COMMAND_SIZE;i+=4)
-			writel(0,init_srb+i);
-		if(SRB_COMMAND_SIZE & 2)
-			writew(0,init_srb+(SRB_COMMAND_SIZE & ~3));
-		if(SRB_COMMAND_SIZE & 1)
-			writeb(0,init_srb+(SRB_COMMAND_SIZE & ~1));
-
-		writeb(SRB_OPEN_ADAPTER,init_srb) ; 	/* open */
-		writeb(OLYMPIC_CLEAR_RET_CODE,init_srb+2);
-
-		/* If Network Monitor, instruct card to copy MAC frames through the ARB */
-
-#if OLYMPIC_NETWORK_MONITOR
-		writew(ntohs(OPEN_ADAPTER_ENABLE_FDX | OPEN_ADAPTER_PASS_ADC_MAC | OPEN_ADAPTER_PASS_ATT_MAC | OPEN_ADAPTER_PASS_BEACON),init_srb+8);
-#else
-		writew(OPEN_ADAPTER_ENABLE_FDX,init_srb+8);
-#endif		
-
-		if (olympic_priv->olympic_laa[0]) {
-			writeb(olympic_priv->olympic_laa[0],init_srb+12);
-			writeb(olympic_priv->olympic_laa[1],init_srb+13);
-			writeb(olympic_priv->olympic_laa[2],init_srb+14);
-			writeb(olympic_priv->olympic_laa[3],init_srb+15);
-			writeb(olympic_priv->olympic_laa[4],init_srb+16);
-			writeb(olympic_priv->olympic_laa[5],init_srb+17);
-			memcpy(dev->dev_addr,olympic_priv->olympic_laa,dev->addr_len) ;  
-		} 	
-		writeb(1,init_srb+30);
-	
-		olympic_priv->srb_queued=1;
-
-		writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
-
- 		while(olympic_priv->srb_queued) {        
-        		interruptible_sleep_on_timeout(&olympic_priv->srb_wait, 60*HZ);
-        		if(signal_pending(current))	{            
-				printk(KERN_WARNING "%s: SRB timed out.\n",
-                			dev->name);
-            			printk(KERN_WARNING "SISR=%x MISR=%x\n",
-                			readl(olympic_mmio+SISR),
-                			readl(olympic_mmio+LISR));
-            			olympic_priv->srb_queued=0;
-            			break;
-        		}
-    		}
-		restore_flags(flags);
-#if OLYMPIC_DEBUG
-		printk("init_srb(%p): ",init_srb);
-		for(i=0;i<20;i++)
-			printk("%x ",readb(init_srb+i));
-		printk("\n");
-#endif
-		
-		/* If we get the same return response as we set, the interrupt wasn't raised and the open
-                 * timed out.
-		 */
-
-		if(readb(init_srb+2)== OLYMPIC_CLEAR_RET_CODE) {
-			printk(KERN_WARNING "%s: Adapter Open time out or error.\n", dev->name) ; 
-			return -EIO ; 
-		}	
-
-		if(readb(init_srb+2)!=0) {
-			if (readb(init_srb+2) == 0x07) {  
-				if (!olympic_priv->olympic_ring_speed && open_finished) { /* Autosense , first time around */
-					printk(KERN_WARNING "%s: Retrying at different ring speed \n", dev->name); 
-					open_finished = 0 ;  
-				} else {
-
-					strcpy(open_error, open_maj_error[(readb(init_srb+7) & 0xf0) >> 4]) ; 
-					strcat(open_error," - ") ; 
-					strcat(open_error, open_min_error[(readb(init_srb+7) & 0x0f)]) ;
-
-					if (!olympic_priv->olympic_ring_speed && ((readb(init_srb+7) & 0x0f) == 0x0d)) { 
-						printk(KERN_WARNING "%s: Tried to autosense ring speed with no monitors present\n",dev->name);
-						printk(KERN_WARNING "%s: Please try again with a specified ring speed \n",dev->name);
-						free_irq(dev->irq, dev);
-						return -EIO ;
-					}
-
-					printk(KERN_WARNING "%s: %s\n",dev->name,open_error);
-					free_irq(dev->irq,dev) ; 
-					return -EIO ; 
- 
-				}	/* if autosense && open_finished */
-			} else {  
-				printk(KERN_WARNING "%s: Bad OPEN response: %x\n", dev->name,init_srb[2]);
-				free_irq(dev->irq, dev);
-				return -EIO;
-			} 
-		} else 
-			open_finished = 1 ; 
-	} while (!(open_finished)) ; /* Will only loop if ring speed mismatch re-open attempted && autosense is on */	
-
-	if (readb(init_srb+18) & (1<<3)) 
-		if (olympic_priv->olympic_message_level) 
-			printk(KERN_INFO "%s: Opened in FDX Mode\n",dev->name);
-
-	if (readb(init_srb+18) & (1<<1))
-		olympic_priv->olympic_ring_speed = 100 ; 
-	else if (readb(init_srb+18) & 1)
-		olympic_priv->olympic_ring_speed = 16 ; 
-	else
-		olympic_priv->olympic_ring_speed = 4 ; 
-
-	if (olympic_priv->olympic_message_level) 
-		printk(KERN_INFO "%s: Opened in %d Mbps mode\n",dev->name, olympic_priv->olympic_ring_speed);
-
-	olympic_priv->asb=ntohs(readw(init_srb+8));
-	olympic_priv->srb=ntohs(readw(init_srb+10));
-	olympic_priv->arb=ntohs(readw(init_srb+12));
-	olympic_priv->trb=ntohs(readw(init_srb+16));
-
-	olympic_priv->olympic_receive_options = 0x01 ; 
-	olympic_priv->olympic_copy_all_options = 0 ; 
-	
-	/* setup rx ring */
-	
-	writel((3<<16),olympic_mmio+BMCTL_RWM); /* Ensure end of frame generated interrupts */ 
-
-	writel(BMCTL_RX_DIS|3,olympic_mmio+BMCTL_RWM); /* Yes, this the enables RX channel */
-
-	for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) {
-
-		struct sk_buff *skb;
-		
-		skb=dev_alloc_skb(olympic_priv->pkt_buf_sz);
-		if(skb == NULL)
-			break;
-
-		skb->dev = dev;
-
-		olympic_priv->olympic_rx_ring[i].buffer=virt_to_bus(skb->data);
-		olympic_priv->olympic_rx_ring[i].res_length = olympic_priv->pkt_buf_sz ; 
-		olympic_priv->rx_ring_skb[i]=skb;
-	}
-
-	if (i==0) {
-		printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers. Adapter disabled\n",dev->name);
-		free_irq(dev->irq, dev);
-		return -EIO;
-	}
-
-	writel(virt_to_bus(&olympic_priv->olympic_rx_ring[0]),olympic_mmio+RXDESCQ);
-	writel(virt_to_bus(&olympic_priv->olympic_rx_ring[0]),olympic_mmio+RXCDA);
-	writew(i,olympic_mmio+RXDESCQCNT);
-		
-	writel(virt_to_bus(&olympic_priv->olympic_rx_status_ring[0]),olympic_mmio+RXSTATQ);
-	writel(virt_to_bus(&olympic_priv->olympic_rx_status_ring[0]),olympic_mmio+RXCSA);
-	
- 	olympic_priv->rx_ring_last_received=OLYMPIC_RX_RING_SIZE-1;	/* last processed rx status */
-	olympic_priv->rx_status_last_received = OLYMPIC_RX_RING_SIZE-1;  
-
-	writew(i,olympic_mmio+RXSTATQCNT);
-
-#if OLYMPIC_DEBUG 
-	printk("# of rx buffers: %d, RXENQ: %x\n",i, readw(olympic_mmio+RXENQ));
-	printk("RXCSA: %x, rx_status_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCSA)),&olympic_priv->olympic_rx_status_ring[0]);
-	printk(" stat_ring[1]: %p, stat_ring[2]: %p, stat_ring[3]: %p\n", &(olympic_priv->olympic_rx_status_ring[1]), &(olympic_priv->olympic_rx_status_ring[2]), &(olympic_priv->olympic_rx_status_ring[3]) );
-	printk(" stat_ring[4]: %p, stat_ring[5]: %p, stat_ring[6]: %p\n", &(olympic_priv->olympic_rx_status_ring[4]), &(olympic_priv->olympic_rx_status_ring[5]), &(olympic_priv->olympic_rx_status_ring[6]) );
-	printk(" stat_ring[7]: %p\n", &(olympic_priv->olympic_rx_status_ring[7])  );
-
-	printk("RXCDA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCDA)),&olympic_priv->olympic_rx_ring[0]);
-#endif
-
-	writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) | i,olympic_mmio+RXENQ);
-
-#if OLYMPIC_DEBUG 
-	printk("# of rx buffers: %d, RXENQ: %x\n",i, readw(olympic_mmio+RXENQ));
-	printk("RXCSA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCSA)),&olympic_priv->olympic_rx_status_ring[0]);
-	printk("RXCDA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCDA)),&olympic_priv->olympic_rx_ring[0]);
-#endif 
-
-	writel(SISR_RX_STATUS | SISR_RX_NOBUF,olympic_mmio+SISR_MASK_SUM);
-
-	/* setup tx ring */
-
-	writel(BMCTL_TX1_DIS,olympic_mmio+BMCTL_RWM); /* Yes, this enables TX channel 1 */
-	for(i=0;i<OLYMPIC_TX_RING_SIZE;i++) 
-		olympic_priv->olympic_tx_ring[i].buffer=0xdeadbeef;
-
-	olympic_priv->free_tx_ring_entries=OLYMPIC_TX_RING_SIZE;
-	writel(virt_to_bus(&olympic_priv->olympic_tx_ring[0]),olympic_mmio+TXDESCQ_1);
-	writel(virt_to_bus(&olympic_priv->olympic_tx_ring[0]),olympic_mmio+TXCDA_1);
-	writew(OLYMPIC_TX_RING_SIZE,olympic_mmio+TXDESCQCNT_1);
-	
-	writel(virt_to_bus(&olympic_priv->olympic_tx_status_ring[0]),olympic_mmio+TXSTATQ_1);
-	writel(virt_to_bus(&olympic_priv->olympic_tx_status_ring[0]),olympic_mmio+TXCSA_1);
-	writew(OLYMPIC_TX_RING_SIZE,olympic_mmio+TXSTATQCNT_1);
-		
-	olympic_priv->tx_ring_free=0; /* next entry in tx ring to use */
-	olympic_priv->tx_ring_last_status=OLYMPIC_TX_RING_SIZE-1; /* last processed tx status */
-
-	writel(SISR_TX1_EOF | SISR_ADAPTER_CHECK | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_ASB_FREE,olympic_mmio+SISR_MASK_SUM);
-
-#if OLYMPIC_DEBUG 
-	printk("BMCTL: %x\n",readl(olympic_mmio+BMCTL_SUM));
-	printk("SISR MASK: %x\n",readl(olympic_mmio+SISR_MASK));
-#endif
-
-#if OLYMPIC_NETWORK_MONITOR
-	oat = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; 
-	opt = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; 
-
-	printk("%s: Node Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, 
-		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), 
-		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1),
-		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2),
-		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3),
-		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4),
-		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5));
-	printk("%s: Functional Address: %02x:%02x:%02x:%02x\n",dev->name, 
-		    readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), 
-		    readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1),
-		    readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2),
-		    readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3));
-
-	printk("%s: NAUN Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, 
-			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)),
-			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1),
-			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2),
-			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3),
-			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4),
-			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5));
-
-
-#endif 	
-	
-	dev->start = 1;
-	dev->interrupt=0;
-	dev->tbusy=0;
-
-	MOD_INC_USE_COUNT ;
-	return 0;
-	
-}	
-
-/*
- *	When we enter the rx routine we do not know how many frames have been 
- *	queued on the rx channel.  Therefore we start at the next rx status
- *	position and travel around the receive ring until we have completed
- *	all the frames.
- *
- *	This means that we may process the frame before we receive the end
- *	of frame interrupt. This is why we always test the status instead
- *	of blindly processing the next frame.
- *	
- */
-static void olympic_rx(struct net_device *dev)
-{
-	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
-	__u8 *olympic_mmio=olympic_priv->olympic_mmio;
-	struct olympic_rx_status *rx_status;
-	struct olympic_rx_desc *rx_desc ; 
-	int rx_ring_last_received,length, buffer_cnt, cpy_length, frag_len;
-	struct sk_buff *skb, *skb2;
-	int i;
-
-	rx_status=&(olympic_priv->olympic_rx_status_ring[(olympic_priv->rx_status_last_received + 1) & (OLYMPIC_RX_RING_SIZE - 1)]) ; 
- 
-	while (rx_status->status_buffercnt) { 
-
-		olympic_priv->rx_status_last_received++ ;
-		olympic_priv->rx_status_last_received &= (OLYMPIC_RX_RING_SIZE -1);
-#if OLYMPIC_DEBUG
-		printk(" stat_ring addr: %x \n", &(olympic_priv->olympic_rx_status_ring[olympic_priv->rx_status_last_received]) ); 
-		printk("rx status: %x rx len: %x \n",rx_status->status_buffercnt,rx_status->fragmentcnt_framelen);	
-#endif
-		length=rx_status->fragmentcnt_framelen & 0xffff;
-		buffer_cnt = rx_status->status_buffercnt & 0xffff ; 
-		i = buffer_cnt ; /* Need buffer_cnt later for rxenq update */ 
-		frag_len = rx_status->fragmentcnt_framelen >> 16 ; 
-
-#if OLYMPIC_DEBUG 
-		printk("length: %x, frag_len: %x, buffer_cnt: %x\n",length,frag_len,buffer_cnt);
-#endif
-
-		if(rx_status->status_buffercnt & 0xC0000000) {
-			if (rx_status->status_buffercnt & 0x3B000000) {
-				if (olympic_priv->olympic_message_level) {
-					if (rx_status->status_buffercnt & (1<<29))  /* Rx Frame Truncated */
-						printk(KERN_WARNING "%s: Rx Frame Truncated \n",dev->name);
-					if (rx_status->status_buffercnt & (1<<28)) /*Rx receive overrun */
-						printk(KERN_WARNING "%s: Rx Frame Receive overrun \n",dev->name);
-					if (rx_status->status_buffercnt & (1<<27)) /* No receive buffers */
-						printk(KERN_WARNING "%s: No receive buffers \n",dev->name);
-					if (rx_status->status_buffercnt & (1<<25)) /* Receive frame error detect */
-						printk(KERN_WARNING "%s: Receive frame error detect \n",dev->name);
-					if (rx_status->status_buffercnt & (1<<24)) /* Received Error Detect */
-						printk(KERN_WARNING "%s: Received Error Detect \n",dev->name);
-				} 
-				olympic_priv->rx_ring_last_received += i ; 
-				olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1) ; 
-				olympic_priv->olympic_stats.rx_errors++;	 
-			} else {	
-			
-				if (buffer_cnt == 1) {
-					skb = dev_alloc_skb(olympic_priv->pkt_buf_sz) ; 
-				} else {
-					skb = dev_alloc_skb(length) ; 
-				}
-
-				if (skb == NULL) {
-					printk(KERN_WARNING "%s: Not enough memory to copy packet to upper layers. \n",dev->name) ;
-					olympic_priv->olympic_stats.rx_dropped++ ; 
-					/* Update counters even though we don't transfer the frame */
-					olympic_priv->rx_ring_last_received += i ; 
-					olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1) ;  
-				} else  {
-					skb->dev = dev ; 
-
-					/* Optimise based upon number of buffers used. 
-			   	   	   If only one buffer is used we can simply swap the buffers around.
-			   	   	   If more than one then we must use the new buffer and copy the information
-			   	   	   first. Ideally all frames would be in a single buffer, this can be tuned by
-                               	   	   altering the buffer size. */
-				
- 					if (buffer_cnt==1) {
-						olympic_priv->rx_ring_last_received++ ; 
-						olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1);
-						rx_ring_last_received = olympic_priv->rx_ring_last_received ;
-						skb2=olympic_priv->rx_ring_skb[rx_ring_last_received] ; 
-						skb_put(skb2,length);
-						skb2->protocol = tr_type_trans(skb2,dev);
-						olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer=virt_to_bus(skb->data);
-						olympic_priv->olympic_rx_ring[rx_ring_last_received].res_length = olympic_priv->pkt_buf_sz ; 
-						olympic_priv->rx_ring_skb[rx_ring_last_received] = skb ; 
-						netif_rx(skb2) ; 
-					} else {
-						do { /* Walk the buffers */ 
-							olympic_priv->rx_ring_last_received++ ; 
-							olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1);
-							rx_ring_last_received = olympic_priv->rx_ring_last_received ; 
-							rx_desc = &(olympic_priv->olympic_rx_ring[rx_ring_last_received]);
-							cpy_length = (i == 1 ? frag_len : rx_desc->res_length); 
-							memcpy(skb_put(skb, cpy_length), bus_to_virt(rx_desc->buffer), cpy_length) ; 
-						} while (--i) ; 
-		
-						skb->protocol = tr_type_trans(skb,dev);
-						netif_rx(skb) ; 
-					} 
-					olympic_priv->olympic_stats.rx_packets++ ; 
-					olympic_priv->olympic_stats.rx_bytes += length ; 
-				} /* if skb == null */
-			} /* If status & 0x3b */
-
-		} else { /*if buffercnt & 0xC */
-			olympic_priv->rx_ring_last_received += i ; 
-			olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE - 1) ; 
-		} 
-
-		rx_status->fragmentcnt_framelen = 0 ; 
-		rx_status->status_buffercnt = 0 ; 
-		rx_status = &(olympic_priv->olympic_rx_status_ring[(olympic_priv->rx_status_last_received+1) & (OLYMPIC_RX_RING_SIZE -1) ]);
-
-		writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) |  buffer_cnt , olympic_mmio+RXENQ); 
-	} /* while */
-
-}
-
-static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs) 
-{
-	struct net_device *dev= (struct net_device *)dev_id;
-	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
-	__u8 *olympic_mmio=olympic_priv->olympic_mmio;
-	__u32 sisr;
-	__u8 *adapter_check_area ; 
-	
-	sisr=readl(olympic_mmio+SISR_RR) ; /* Reset sisr */ 
-	
-	if (!(sisr & SISR_MI)) /* Interrupt isn't for us */ 
-		return ;
-
-	if (dev->interrupt) 
-		printk(KERN_WARNING "%s: Re-entering interrupt \n",dev->name) ; 
-
-	dev->interrupt = 1 ; 
-
-	if (sisr & (SISR_SRB_REPLY | SISR_TX1_EOF | SISR_RX_STATUS | SISR_ADAPTER_CHECK |  
-			SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_RX_NOBUF)) {  
-	
-		if(sisr & SISR_SRB_REPLY) {
-			if(olympic_priv->srb_queued==1) {
-				wake_up_interruptible(&olympic_priv->srb_wait);
-			} else if (olympic_priv->srb_queued==2) { 
-				olympic_srb_bh(dev) ; 
-			}
-			olympic_priv->srb_queued=0;
-		} /* SISR_SRB_REPLY */
-
-		if (sisr & SISR_TX1_EOF) {
-			olympic_priv->tx_ring_last_status++;
-			olympic_priv->tx_ring_last_status &= (OLYMPIC_TX_RING_SIZE-1);
-			olympic_priv->free_tx_ring_entries++;
-			olympic_priv->olympic_stats.tx_bytes += olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]->len;
-			olympic_priv->olympic_stats.tx_packets++ ; 
-			dev_kfree_skb(olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]);
-			olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer=0xdeadbeef;
-			olympic_priv->olympic_tx_status_ring[olympic_priv->tx_ring_last_status].status=0;
-
-			if(dev->tbusy) {
-				dev->tbusy=0;
-				mark_bh(NET_BH);
-			}
-		} /* SISR_TX1_EOF */
-	
-		if (sisr & SISR_RX_STATUS) {
-			olympic_rx(dev);
-		} /* SISR_RX_STATUS */
-	
-		if (sisr & SISR_ADAPTER_CHECK) {
-			printk(KERN_WARNING "%s: Adapter Check Interrupt Raised, 8 bytes of information follow:\n", dev->name);
-			writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
-			adapter_check_area = (__u8 *)(olympic_mmio+LAPWWO) ; 
-			printk(KERN_WARNING "%s: Bytes %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, readb(adapter_check_area+0), readb(adapter_check_area+1), readb(adapter_check_area+2), readb(adapter_check_area+3), readb(adapter_check_area+4), readb(adapter_check_area+5), readb(adapter_check_area+6), readb(adapter_check_area+7)) ; 
-			dev->interrupt = 0  ; 	
-			free_irq(dev->irq, dev) ; 
-	
-		} /* SISR_ADAPTER_CHECK */
-	
-		if (sisr & SISR_ASB_FREE) {
-			/* Wake up anything that is waiting for the asb response */  
-			if (olympic_priv->asb_queued) {
-				olympic_asb_bh(dev) ; 
-			}
-		} /* SISR_ASB_FREE */
-	
-		if (sisr & SISR_ARB_CMD) {
-			olympic_arb_cmd(dev) ; 
-		} /* SISR_ARB_CMD */
-	
-		if (sisr & SISR_TRB_REPLY) {
-			/* Wake up anything that is waiting for the trb response */
-			if (olympic_priv->trb_queued) {
-				wake_up_interruptible(&olympic_priv->trb_wait);
-			}
-			olympic_priv->trb_queued = 0 ; 
-		} /* SISR_TRB_REPLY */	
-	
-		if (sisr & SISR_RX_NOBUF) {
-			/* According to the documentation, we don't have to do anything, but trapping it keeps it out of
-                  	   	   /var/log/messages.  */
-		} /* SISR_RX_NOBUF */
-	} else { 
-		printk(KERN_WARNING "%s: Unexpected interrupt: %x\n",dev->name, sisr);
-		printk(KERN_WARNING "%s: SISR_MASK: %x\n",dev->name, readl(olympic_mmio+SISR_MASK)) ;
-	} /* One if the interrupts we want */
-
-	dev->interrupt = 0 ;  
-
-	writel(SISR_MI,olympic_mmio+SISR_MASK_SUM);
-
-}	
-
-static int olympic_xmit(struct sk_buff *skb, struct net_device *dev) 
-{
-	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
-    __u8 *olympic_mmio=olympic_priv->olympic_mmio;
-
-	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-		return 1;
-	}
-
-	if(olympic_priv->free_tx_ring_entries) {
-		olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].buffer=virt_to_bus(skb->data);
-		olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].status_length=skb->len | (0x80000000);
-		olympic_priv->tx_ring_skb[olympic_priv->tx_ring_free]=skb;
-		olympic_priv->free_tx_ring_entries--;
-
-        	olympic_priv->tx_ring_free++;
-        	olympic_priv->tx_ring_free &= (OLYMPIC_TX_RING_SIZE-1);
-
-
-		writew((((readw(olympic_mmio+TXENQ_1)) & 0x8000) ^ 0x8000) | 1,olympic_mmio+TXENQ_1);
-
-		dev->tbusy=0;		
-
-		return 0;
-	} else 
-		return 1;
-
-}
-	
-
-static int olympic_close(struct net_device *dev) 
-{
-	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
-    	__u8 *olympic_mmio=olympic_priv->olympic_mmio,*srb;
-	unsigned long flags;
-	int i;
-
-	writel(olympic_priv->srb,olympic_mmio+LAPA);
-	srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800));
-	
-    	writeb(SRB_CLOSE_ADAPTER,srb+0);
-	writeb(0,srb+1);
-	writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
-
-	save_flags(flags);
-	cli();	
-
-	olympic_priv->srb_queued=1;
-
-	writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
-
-	while(olympic_priv->srb_queued) {
-	        interruptible_sleep_on_timeout(&olympic_priv->srb_wait, jiffies+60*HZ);
-        	if(signal_pending(current))	{            
-			printk(KERN_WARNING "%s: SRB timed out.\n",
-                		dev->name);
-            		printk(KERN_WARNING "SISR=%x MISR=%x\n",
-                	readl(olympic_mmio+SISR),
-                	readl(olympic_mmio+LISR));
-            		olympic_priv->srb_queued=0;
-            		break;
-        	}
-    	}
-
-	restore_flags(flags) ; 
-	olympic_priv->rx_status_last_received++;
-	olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
-	
-	for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) {
-		dev_kfree_skb(olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received]);
-		olympic_priv->rx_status_last_received++;
-		olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
-	}
-
-	/* reset tx/rx fifo's and busmaster logic */
-
-	writel(readl(olympic_mmio+BCTL)|(3<<13),olympic_mmio+BCTL);
-	udelay(1);
-	writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL);
-
-#if OLYMPIC_DEBUG
-	printk("srb(%p): ",srb);
-	for(i=0;i<4;i++)
-		printk("%x ",readb(srb+i));
-	printk("\n");
-#endif
-    	dev->start = 0;
-	free_irq(dev->irq,dev);
-
-	MOD_DEC_USE_COUNT ; 
-	return 0;
-	
-}
-
-static void olympic_set_rx_mode(struct net_device *dev) 
-{
-	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; 
-   	__u8 *olympic_mmio = olympic_priv->olympic_mmio ; 
-	__u8 options = 0, set_mc_list = 0 ; 
-	__u8 *srb, *ata ;
-	struct dev_mc_list *dmi ; 
-
-	writel(olympic_priv->srb,olympic_mmio+LAPA);
-	srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800));
-	options = olympic_priv->olympic_copy_all_options; 
-
-	if (dev->flags&IFF_PROMISC)  
-		options |= (3<<5) ; /* All LLC and MAC frames, all through the main rx channel */  
-	else
-		options &= ~(3<<5) ; 
-
-	if (dev->mc_count) {  
-		set_mc_list = 1 ; 
-	}
-
-	/* Only issue the srb if there is a change in options */
-
-	if ((options ^ olympic_priv->olympic_copy_all_options)) { 
-	
-		/* Now to issue the srb command to alter the copy.all.options */
-	
-		writeb(SRB_MODIFY_RECEIVE_OPTIONS,srb);
-		writeb(0,srb+1);
-		writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
-		writeb(0,srb+3);
-		writeb(olympic_priv->olympic_receive_options,srb+4);
-		writeb(options,srb+5);
-
-		olympic_priv->srb_queued=2; /* Can't sleep, use srb_bh */
-
-		writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
-
-		olympic_priv->olympic_copy_all_options = options ;
-		
-		return ;  
-	} 
-
-	if (set_mc_list ^ olympic_priv->olympic_multicast_set) { /* Multicast options have changed */ 
-
-		dmi = dev->mc_list ; 
-
-		if (set_mc_list) { /* Turn multicast on */
-
-			/* RFC 1469 Says we must support using the functional address C0 00 00 04 00 00
-                         * We do this with a set functional address mask.
-			 */
-						
-			ata=olympic_priv->olympic_lap + (olympic_priv->olympic_addr_table_addr) ;
-			if (!(readb(ata+11) & 0x04)) { /* Hmmm, need to set the functional mask */ 
-				writeb(SRB_SET_FUNC_ADDRESS,srb+0);
-				writeb(0,srb+1);
-				writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
-				writeb(0,srb+3);
-				writeb(0,srb+4);
-				writeb(0,srb+5);
-				writeb(readb(ata+10),srb+6);
-				writeb(readb(ata+11)|4,srb+7);
-				writeb(readb(ata+12),srb+8);
-				writeb(readb(ata+13),srb+9);
-			
-				olympic_priv->srb_queued = 2 ; 
-				writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
-
-				olympic_priv->olympic_multicast_set = 1 ;  
-			}    
-
-
-		} else { /* Turn multicast off */
-	
-			ata=olympic_priv->olympic_lap + (olympic_priv->olympic_addr_table_addr) ;
-			if ((readb(ata+11) & 0x04)) { /* Hmmm, need to reset the functional mask */ 
-				writeb(SRB_SET_FUNC_ADDRESS,srb+0);
-				writeb(0,srb+1);
-				writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
-				writeb(0,srb+3);
-				writeb(0,srb+4);
-				writeb(0,srb+5);
-				writeb(readb(ata+10),srb+6);
-				writeb(readb(ata+11) & ~4,srb+7);
-				writeb(readb(ata+12),srb+8);
-				writeb(readb(ata+13),srb+9);
-			
-				olympic_priv->srb_queued = 2 ; 
-				writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);	
-
-				olympic_priv->olympic_multicast_set = 0 ; 
-			}
-		} 		
-
-	}
-
-
-}
-
-static void olympic_srb_bh(struct net_device *dev) 
-{ 
-	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; 
-   	__u8 *olympic_mmio = olympic_priv->olympic_mmio ; 
-	__u8 *srb;
-
-	writel(olympic_priv->srb,olympic_mmio+LAPA);
-	srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800));
-
-	switch (readb(srb)) { 
-
-		/* SRB_MODIFY_RECEIVE_OPTIONS i.e. set_multicast_list options (promiscuous) 
-                 * At some point we should do something if we get an error, such as
-                 * resetting the IFF_PROMISC flag in dev
-		 */
-
-		case SRB_MODIFY_RECEIVE_OPTIONS:
-			switch (readb(srb+2)) { 
-				case 0x01:
-					printk(KERN_WARNING "%s: Unrecognized srb command\n",dev->name) ; 
-					break ; 
-				case 0x04:
-					printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name);
-					break ; 
-				default:
-					if (olympic_priv->olympic_message_level) 
-						printk(KERN_WARNING "%s: Receive Options Modified to %x,%x\n",dev->name,olympic_priv->olympic_copy_all_options, olympic_priv->olympic_receive_options) ; 
-					break ; 	
-			} /* switch srb[2] */ 
-			break ;
-		
-		/* SRB_SET_GROUP_ADDRESS - Multicast group setting 
-                 */
-
-		case SRB_SET_GROUP_ADDRESS:
-			switch (readb(srb+2)) { 
-				case 0x00:
-					olympic_priv->olympic_multicast_set = 1 ; 
-					break ; 
-				case 0x01:
-					printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
-					break ;
-				case 0x04:
-					printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name); 
-					break ;
-				case 0x3c:
-					printk(KERN_WARNING "%s: Group/Functional address indicator bits not set correctly\n",dev->name) ; 
-					break ;
-				case 0x3e: /* If we ever implement individual multicast addresses, will need to deal with this */
-					printk(KERN_WARNING "%s: Group address registers full\n",dev->name) ; 
-					break ;  
-				case 0x55:
-					printk(KERN_INFO "%s: Group Address already set.\n",dev->name) ; 
-					break ;
-				default:
-					break ; 
-			} /* switch srb[2] */ 
-			break ; 
-
-		/* SRB_RESET_GROUP_ADDRESS - Remove a multicast address from group list
- 		 */
-
-		case SRB_RESET_GROUP_ADDRESS:
-			switch (readb(srb+2)) { 
-				case 0x00:
-					olympic_priv->olympic_multicast_set = 0 ; 
-					break ; 
-				case 0x01:
-					printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
-					break ; 
-				case 0x04:
-					printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; 
-					break ; 
-				case 0x39: /* Must deal with this if individual multicast addresses used */
-					printk(KERN_INFO "%s: Group address not found \n",dev->name); 
-					break ;
-				default:
-					break ; 
-			} /* switch srb[2] */
-			break ; 
-
-		
-		/* SRB_SET_FUNC_ADDRESS - Called by the set_rx_mode 
-		 */
-
-		case SRB_SET_FUNC_ADDRESS:
-			switch (readb(srb+2)) { 
-				case 0x00:
-					if (olympic_priv->olympic_message_level)
-						printk(KERN_INFO "%s: Functional Address Mask Set \n",dev->name) ; 
-					break ;
-				case 0x01:
-					printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
-					break ; 
-				case 0x04:
-					printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; 
-					break ; 
-				default:
-					break ; 
-			} /* switch srb[2] */
-			break ; 
-	
-		/* SRB_READ_LOG - Read and reset the adapter error counters
- 		 */
-
-		case SRB_READ_LOG:
-			switch (readb(srb+2)) { 
-				case 0x00: 
-					if (olympic_priv->olympic_message_level) 
-						printk(KERN_INFO "%s: Read Log issued\n",dev->name) ; 
-					break ; 
-				case 0x01:
-					printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
-					break ; 
-				case 0x04:
-					printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; 
-					break ; 
-			
-			} /* switch srb[2] */
-			break ; 
-		
-		/* SRB_READ_SR_COUNTERS - Read and reset the source routing bridge related counters */
-
-		case SRB_READ_SR_COUNTERS:
-			switch (readb(srb+2)) { 
-				case 0x00: 
-					if (olympic_priv->olympic_message_level) 
-						printk(KERN_INFO "%s: Read Source Routing Counters issued\n",dev->name) ; 
-					break ; 
-				case 0x01:
-					printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
-					break ; 
-				case 0x04:
-					printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; 
-					break ; 
-				default:
-					break ; 
-			} /* switch srb[2] */
-			break ;
- 
-		default:
-			printk(KERN_WARNING "%s: Unrecognized srb bh return value.\n",dev->name);
-			break ; 
-	} /* switch srb[0] */
-
-} 
-
-static struct net_device_stats * olympic_get_stats(struct net_device *dev)
-{
-	struct olympic_private *olympic_priv ;
-	olympic_priv=(struct olympic_private *) dev->priv;
-	return (struct net_device_stats *) &olympic_priv->olympic_stats; 
-}
-
-static int olympic_set_mac_address (struct net_device *dev, void *addr) 
-{
-	struct sockaddr *saddr = addr ; 
-	struct olympic_private *olympic_priv = (struct olympic_private *)dev->priv ; 
-
-	if (dev->start) { 
-		printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ; 
-		return -EIO ; 
-	}
-
-	memcpy(olympic_priv->olympic_laa, saddr->sa_data,dev->addr_len) ; 
-	
-	if (olympic_priv->olympic_message_level) { 
- 		printk(KERN_INFO "%s: MAC/LAA Set to  = %x.%x.%x.%x.%x.%x\n",dev->name, olympic_priv->olympic_laa[0],
-		olympic_priv->olympic_laa[1], olympic_priv->olympic_laa[2],
-		olympic_priv->olympic_laa[3], olympic_priv->olympic_laa[4],
-		olympic_priv->olympic_laa[5]);
-	} 
-
-	return 0 ; 
-}
-
-static void olympic_arb_cmd(struct net_device *dev)
-{
-	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv;
-    	__u8 *olympic_mmio=olympic_priv->olympic_mmio;
-	__u8 *arb_block, *asb_block, *srb  ; 
-	__u8 header_len ; 
-	__u16 frame_len, buffer_len ;
-	struct sk_buff *mac_frame ;  
-	__u8 *buf_ptr ;
-	__u8 *frame_data ;  
-	__u16 buff_off ; 
-	__u16 lan_status = 0, lan_status_diff  ; /* Initialize to stop compiler warning */
-	__u8 fdx_prot_error ; 
-	__u16 next_ptr;
-
-#if OLYMPIC_NETWORK_MONITOR
-	struct trh_hdr *mac_hdr ; 
-#endif
-
-	arb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; 
-	asb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; 
-	srb = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->srb) ; 
-	writel(readl(olympic_mmio+LAPA),olympic_mmio+LAPWWO);
-
-	if (readb(arb_block+0) == ARB_RECEIVE_DATA) { /* Receive.data, MAC frames */
-
-		header_len = readb(arb_block+8) ; /* 802.5 Token-Ring Header Length */	
-		frame_len = ntohs(readw(arb_block + 10)) ; 
-
-		buff_off = ntohs(readw(arb_block + 6)) ;
-		
-		buf_ptr = olympic_priv->olympic_lap + buff_off ; 
-
-#if OLYMPIC_DEBUG
-{
-		int i;
-		frame_data = buf_ptr+offsetof(struct mac_receive_buffer,frame_data) ; 
-
-		for (i=0 ;  i < 14 ; i++) { 
-			printk("Loc %d = %02x\n",i,readb(frame_data + i)); 
-		}
-
-		printk("next %04x, fs %02x, len %04x \n",readw(buf_ptr+offsetof(struct mac_receive_buffer,next)), readb(buf_ptr+offsetof(struct mac_receive_buffer,frame_status)), readw(buf_ptr+offsetof(struct mac_receive_buffer,buffer_length))); 
-}
-#endif 
-		mac_frame = dev_alloc_skb(frame_len) ; 
-
-		/* Walk the buffer chain, creating the frame */
-
-		do {
-			frame_data = buf_ptr+offsetof(struct mac_receive_buffer,frame_data) ; 
-			buffer_len = ntohs(readw(buf_ptr+offsetof(struct mac_receive_buffer,buffer_length))); 
-			memcpy_fromio(skb_put(mac_frame, buffer_len), frame_data , buffer_len ) ;
-			next_ptr=readw(buf_ptr+offsetof(struct mac_receive_buffer,next)); 
-
-		} while (next_ptr && (buf_ptr=olympic_priv->olympic_lap + ntohs(next_ptr)));
-
-#if OLYMPIC_NETWORK_MONITOR
-		printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name) ;
-		mac_hdr = (struct trh_hdr *)mac_frame->data ; 
-		printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->daddr[0], mac_hdr->daddr[1], mac_hdr->daddr[2], mac_hdr->daddr[3], mac_hdr->daddr[4], mac_hdr->daddr[5]) ; 
-		printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->saddr[0], mac_hdr->saddr[1], mac_hdr->saddr[2], mac_hdr->saddr[3], mac_hdr->saddr[4], mac_hdr->saddr[5]) ; 
-#endif
-		mac_frame->dev = dev ; 
-		mac_frame->protocol = tr_type_trans(mac_frame,dev);
-		netif_rx(mac_frame) ; 	
-
-		/* Now tell the card we have dealt with the received frame */
-
-		/* Set LISR Bit 1 */
-		writel(LISR_ARB_FREE,olympic_priv->olympic_lap + LISR_SUM);
-
-		/* Is the ASB free ? */ 	
-		
-		if (!(readl(olympic_priv->olympic_mmio + SISR) & SISR_ASB_FREE)) {
-			olympic_priv->asb_queued = 1 ; 
-			writel(LISR_ASB_FREE_REQ,olympic_priv->olympic_mmio+LISR_SUM); 
-			return ; 	
-			/* Drop out and wait for the bottom half to be run */
-		}
-		
-		writeb(ASB_RECEIVE_DATA,asb_block); /* Receive data */
-		writeb(OLYMPIC_CLEAR_RET_CODE,asb_block+2); /* Necessary ?? */
-		writeb(readb(arb_block+6),asb_block+6); /* Must send the address back to the adapter */
-		writeb(readb(arb_block+7),asb_block+7); /* To let it know we have dealt with the data */		
-
-		writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ,olympic_priv->olympic_mmio+LISR_SUM);
-		
-		olympic_priv->asb_queued = 2 ; 
-	
-		return ; 	
-		
-	} else if (readb(arb_block) == ARB_LAN_CHANGE_STATUS) { /* Lan.change.status */
-		lan_status = readw(arb_block+6);
-		fdx_prot_error = readb(arb_block+8) ; 
-		
-		/* Issue ARB Free */
-		writel(LISR_ARB_FREE,olympic_priv->olympic_mmio+LISR_SUM);
-
-		lan_status_diff = olympic_priv->olympic_lan_status ^ lan_status ; 
-
-		if (lan_status_diff & (LSC_LWF | LSC_ARW | LSC_FPE | LSC_RR) ) { 
-			if (lan_status_diff & LSC_LWF) 
-					printk(KERN_WARNING "%s: Short circuit detected on the lobe\n",dev->name);
-			if (lan_status_diff & LSC_ARW) 
-					printk(KERN_WARNING "%s: Auto removal error\n",dev->name);
-			if (lan_status_diff & LSC_FPE)
-					printk(KERN_WARNING "%s: FDX Protocol Error\n",dev->name);
-			if (lan_status_diff & LSC_RR) 
-					printk(KERN_WARNING "%s: Force remove MAC frame received\n",dev->name);
-		
-			/* Adapter has been closed by the hardware */
-		
-			/* reset tx/rx fifo's and busmaster logic */
-
-			writel(readl(olympic_mmio+BCTL)|(3<<13),olympic_mmio+BCTL);
-			udelay(1);
-			writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL);
-			dev->tbusy = 1 ;
-			dev->interrupt = 1 ; 
-			dev->start = 0 ; 
-			olympic_priv->srb = readw(olympic_priv->olympic_lap + LAPWWO) ; 
-			free_irq(dev->irq,dev);
-			
-			printk(KERN_WARNING "%s: Adapter has been closed \n", dev->name) ; 
-	
-		} /* If serious error */
-		
-		if (olympic_priv->olympic_message_level) { 
-			if (lan_status_diff & LSC_SIG_LOSS) 
-					printk(KERN_WARNING "%s: No receive signal detected \n", dev->name) ; 
-			if (lan_status_diff & LSC_HARD_ERR)
-					printk(KERN_INFO "%s: Beaconing \n",dev->name);
-			if (lan_status_diff & LSC_SOFT_ERR)
-					printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame \n",dev->name);
-			if (lan_status_diff & LSC_TRAN_BCN) 
-					printk(KERN_INFO "%s: We are tranmitting the beacon, aaah\n",dev->name);
-			if (lan_status_diff & LSC_SS) 
-					printk(KERN_INFO "%s: Single Station on the ring \n", dev->name);
-			if (lan_status_diff & LSC_RING_REC)
-					printk(KERN_INFO "%s: Ring recovery ongoing\n",dev->name);
-			if (lan_status_diff & LSC_FDX_MODE)
-					printk(KERN_INFO "%s: Operating in FDX mode\n",dev->name);
-		} 	
-		
-		if (lan_status_diff & LSC_CO) { 
-					
-				if (olympic_priv->olympic_message_level) 
-					printk(KERN_INFO "%s: Counter Overflow \n", dev->name);
-					
-				/* Issue READ.LOG command */
-
-				writeb(SRB_READ_LOG, srb);
-				writeb(0,srb+1);
-				writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
-				writeb(0,srb+3);
-				writeb(0,srb+4);
-				writeb(0,srb+5);
-					
-				olympic_priv->srb_queued=2; /* Can't sleep, use srb_bh */
-
-				writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
-					
-		}
-
-		if (lan_status_diff & LSC_SR_CO) { 
-
-				if (olympic_priv->olympic_message_level)
-					printk(KERN_INFO "%s: Source routing counters overflow\n", dev->name);
-
-				/* Issue a READ.SR.COUNTERS */
-				
-				writeb(SRB_READ_SR_COUNTERS,srb);
-				writeb(0,srb+1);
-				writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
-				writeb(0,srb+3);
-				
-				olympic_priv->srb_queued=2; /* Can't sleep, use srb_bh */
-
-				writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
-
-		}
-
-		olympic_priv->olympic_lan_status = lan_status ; 
-	
-	}  /* Lan.change.status */
-	else
-		printk(KERN_WARNING "%s: Unknown arb command \n", dev->name);
-}
-
-static void olympic_asb_bh(struct net_device *dev) 
-{
-	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; 
-	__u8 *arb_block, *asb_block ; 
-
-	arb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; 
-	asb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; 
-
-	if (olympic_priv->asb_queued == 1) {   /* Dropped through the first time */
-
-		writeb(ASB_RECEIVE_DATA,asb_block); /* Receive data */
-		writeb(OLYMPIC_CLEAR_RET_CODE,asb_block+2); /* Necessary ?? */
-		writeb(readb(arb_block+6),asb_block+6); /* Must send the address back to the adapter */
-		writeb(readb(arb_block+7),asb_block+7); /* To let it know we have dealt with the data */		
-
-		writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ,olympic_priv->olympic_mmio+LISR_SUM);
-		olympic_priv->asb_queued = 2 ; 
-
-		return ; 
-	}
-
-	if (olympic_priv->asb_queued == 2) { 
-		switch (readb(asb_block+2)) {
-			case 0x01:
-				printk(KERN_WARNING "%s: Unrecognized command code \n", dev->name);
-				break ;
-			case 0x26:
-				printk(KERN_WARNING "%s: Unrecognized buffer address \n", dev->name);
-				break ;
-			case 0xFF:
-				/* Valid response, everything should be ok again */
-				break ;
-			default:
-				printk(KERN_WARNING "%s: Invalid return code in asb\n",dev->name);
-				break ;
-		}
-	}
-	olympic_priv->asb_queued = 0 ; 
-}
- 
-static int olympic_change_mtu(struct net_device *dev, int mtu) 
-{
-	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv;
-	__u16 max_mtu ; 
-
-	if (olympic_priv->olympic_ring_speed == 4)
-		max_mtu = 4500 ; 
-	else
-		max_mtu = 18000 ; 
-	
-	if (mtu > max_mtu)
-		return -EINVAL ; 
-	if (mtu < 100) 
-		return -EINVAL ; 
-
-	dev->mtu = mtu ; 
-	olympic_priv->pkt_buf_sz = mtu + TR_HLEN ; 
-
-	return 0 ; 
-}
-
-#if OLYMPIC_NETWORK_MONITOR
-#ifdef CONFIG_PROC_FS
-static int olympic_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
-{
-	struct pci_dev *pci_device = NULL ;
-	int len=0;
-	off_t begin=0;
-	off_t pos=0;
-	int size;
-	
-	struct net_device *dev;
-
-
-	size = sprintf(buffer, 
-		"IBM Pit/Pit-Phy/Olympic Chipset Token Ring Adapters\n");
-	
-	pos+=size;
-	len+=size;
-	
-
-	while((pci_device=pci_find_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR_WAKE, pci_device))) {
-	
-		for (dev = dev_base; dev != NULL; dev = dev->next) 
-		{
-			if (dev->base_addr == pci_device->resource[0].start ) { /* Yep, an Olympic device */	
-				size = sprintf_info(buffer+len, dev);
-				len+=size;
-				pos=begin+len;
-				
-				if(pos<offset)
-				{
-					len=0;
-					begin=pos;
-				}
-				if(pos>offset+length)
-					break;
-			} /* if */
-		} /* for */
-	} /* While */
-
-	*start=buffer+(offset-begin);	/* Start of wanted data */
-	len-=(offset-begin);		/* Start slop */
-	if(len>length)
-		len=length;		/* Ending slop */
-	return len;
-}
-
-static int sprintf_info(char *buffer, struct net_device *dev)
-{
-	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
-	__u8 *oat = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; 
-	__u8 *opt = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; 
-	int size = 0 ; 
-		
-	size = sprintf(buffer, "\n%6s: Adapter Address   : Node Address      : Functional Addr\n",
- 	   dev->name); 
-
-	size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x\n",
-	   dev->name,
-           dev->dev_addr[0],
-	   dev->dev_addr[1],
-	   dev->dev_addr[2],
- 	   dev->dev_addr[3],
-	   dev->dev_addr[4],
-	   dev->dev_addr[5],
-	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), 
-	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1),
-	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2),
-	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3),
-	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4),
-	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5),
-	   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), 
-	   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1),
-	   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2),
-	   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3));
-	 
-	size += sprintf(buffer+size, "\n%6s: Token Ring Parameters Table:\n", dev->name);
-
-	size += sprintf(buffer+size, "%6s: Physical Addr : Up Node Address   : Poll Address      : AccPri : Auth Src : Att Code :\n",
-	  dev->name) ; 
-	   
-	size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x   : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %04x   : %04x     :  %04x    :\n",
-	  dev->name,
-	  readb(opt+offsetof(struct olympic_parameters_table, phys_addr)),
-	  readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+1),
-	  readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+2),
-	  readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+3),
-	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)),
-	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1),
-	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2),
-	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3),
-	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4),
-	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5),
-	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)),
-	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+1),
-	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+2),
-	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+3),
-	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+4),
-	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+5),
-	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, acc_priority))),
-	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, auth_source_class))),
-	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, att_code))));
-
-	size += sprintf(buffer+size, "%6s: Source Address    : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n",
-	  dev->name) ; 
-	
-	size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %04x  : %04x   : %04x   : %04x   : %04x    :     %04x     : \n",
-	  dev->name,
-	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)),
-	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)+1),
-	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)+2),
-	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)+3),
-	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)+4),
-	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)+5),
-	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, beacon_type))),
-	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, major_vector))),
-	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, lan_status))),
-	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, local_ring))),
-	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, mon_error))),
-	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, frame_correl))));
-
-	size += sprintf(buffer+size, "%6s: Beacon Details :  Tx  :  Rx  : NAUN Node Address : NAUN Node Phys : \n",
-	  dev->name) ; 
-
-	size += sprintf(buffer+size, "%6s:                :  %02x  :  %02x  : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x    : \n",
-	  dev->name,
-	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, beacon_transmit))),
-	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, beacon_receive))),
-	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)),
-	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+1),
-	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+2),
-	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+3),
-	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+4),
-	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+5),
-	  readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)),
-	  readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+1),
-	  readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+2),
-	  readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+3));
-
- 
-	return size;
-}
-#endif
-#endif 
-
-#ifdef MODULE
-
-static struct net_device* dev_olympic[OLYMPIC_MAX_ADAPTERS];
-
-int init_module(void)
-{
-        int i;
-
-#if OLYMPIC_NETWORK_MONITOR
-#ifdef CONFIG_PROC_FS
-	struct proc_dir_entry *ent ; 
-
-	ent = create_proc_entry("net/olympic_tr",0,0); 
-	ent->read_proc = &olympic_proc_info ; 
-#endif
-#endif
-        for (i = 0; (i<OLYMPIC_MAX_ADAPTERS); i++) {
-		dev_olympic[i] = NULL;
-                dev_olympic[i] = init_trdev(dev_olympic[i], 0);
-                if (dev_olympic[i] == NULL)
-                        return -ENOMEM;
-
-		dev_olympic[i]->init      = &olympic_probe;
-
-	        if (register_trdev(dev_olympic[i]) != 0) {
-			kfree_s(dev_olympic[i], sizeof(struct net_device));
-			dev_olympic[i] = NULL;
-		        if (i == 0) {
-			        printk("Olympic: No IBM PCI Token Ring cards found in system.\n");
-		                return -EIO;
-			} else {
-			       	printk("Olympic: %d IBM PCI Token Ring card(s) found in system.\n",i) ; 
-				return 0;
-			}
-	        }
-	}
-
-	return 0;
-}
-
-void cleanup_module(void)
-{
-        int i;
-
-        for (i = 0; i < OLYMPIC_MAX_ADAPTERS; i++)
-	        if (dev_olympic[i]) {
-			 unregister_trdev(dev_olympic[i]);
-			 release_region(dev_olympic[i]->base_addr, OLYMPIC_IO_SPACE);
-			 kfree_s(dev_olympic[i]->priv, sizeof(struct olympic_private));
-			 kfree_s(dev_olympic[i], sizeof(struct net_device));
-			 dev_olympic[i] = NULL;
-                }
-
-#if OLYMPIC_NETWORK_MONITOR
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry("net/olympic_tr", NULL) ; 
-#endif 
-#endif
-}
-#endif /* MODULE */
-
diff -u --recursive --new-file v2.3.20/linux/drivers/net/olympic.h linux/drivers/net/olympic.h
--- v2.3.20/linux/drivers/net/olympic.h	Wed Aug 18 16:24:11 1999
+++ linux/drivers/net/olympic.h	Wed Dec 31 16:00:00 1969
@@ -1,304 +0,0 @@
-/*
- *  olympic.h (c) 1999 Peter De Schrijver All Rights Reserved
- *                1999 Mike Phillips (phillim@amtrak.com)
- *
- *  Linux driver for IBM PCI tokenring cards based on the olympic and the PIT/PHY chipset.
- *
- *  Base Driver Skeleton:
- *      Written 1993-94 by Donald Becker.
- *
- *      Copyright 1993 United States Government as represented by the
- *      Director, National Security Agency.
- *
- *  This software may be used and distributed according to the terms
- *  of the GNU Public License, incorporated herein by reference.
- */
-
-#define CID 0x4e
-
-#define BCTL 0x70
-#define BCTL_SOFTRESET (1<<15)
-#define BCTL_MIMREB (1<<6)
-
-#define GPR 0x4a
-#define GPR_OPTI_BF (1<<6)
-#define GPR_NEPTUNE_BF (1<<4) 
-#define GPR_AUTOSENSE (1<<2)
-#define GPR_16MBPS (1<<3) 
-
-#define PAG 0x85
-#define LBC 0x8e
-
-#define LISR 0x10
-#define LISR_SUM 0x14
-#define LISR_RWM 0x18
-
-#define LISR_LIE (1<<15)
-#define LISR_SLIM (1<<13)
-#define LISR_SLI (1<<12)
-#define LISR_PCMSRMASK (1<<11)
-#define LISR_PCMSRINT (1<<10)
-#define LISR_WOLMASK (1<<9)
-#define LISR_WOL (1<<8)
-#define LISR_SRB_CMD (1<<5)
-#define LISR_ASB_REPLY (1<<4)
-#define LISR_ASB_FREE_REQ (1<<2)
-#define LISR_ARB_FREE (1<<1)
-#define LISR_TRB_FRAME (1<<0)
-
-#define SISR 0x20
-#define SISR_SUM 0x24
-#define SISR_RWM 0x28
-#define SISR_RR 0x2C
-#define SISR_RESMASK 0x30
-#define SISR_MASK 0x54
-#define SISR_MASK_SUM 0x58
-#define SISR_MASK_RWM 0x5C
-
-#define SISR_TX2_IDLE (1<<31)
-#define SISR_TX2_HALT (1<<29)
-#define SISR_TX2_EOF (1<<28)
-#define SISR_TX1_IDLE (1<<27)
-#define SISR_TX1_HALT (1<<25)
-#define SISR_TX1_EOF (1<<24)
-#define SISR_TIMEOUT (1<<23)
-#define SISR_RX_NOBUF (1<<22)
-#define SISR_RX_STATUS (1<<21)
-#define SISR_RX_HALT (1<<18)
-#define SISR_RX_EOF_EARLY (1<<16)
-#define SISR_MI (1<<15)
-#define SISR_PI (1<<13)
-#define SISR_ERR (1<<9)
-#define SISR_ADAPTER_CHECK (1<<6)
-#define SISR_SRB_REPLY (1<<5)
-#define SISR_ASB_FREE (1<<4)
-#define SISR_ARB_CMD (1<<3)
-#define SISR_TRB_REPLY (1<<2)
-
-#define EISR 0x34
-#define EISR_RWM 0x38
-#define EISR_MASK 0x3c
-
-#define LAPA 0x60
-#define LAPWWO 0x64
-#define LAPWWC 0x68
-#define LAPCTL 0x6C
-#define LAIPD 0x78
-#define LAIPDDINC 0x7C
-
-#define TIMER 0x50
-
-#define CLKCTL 0x74
-
-#define PM_CON 0x4
-
-#define BMCTL_SUM 0x40
-#define BMCTL_RWM 0x44
-#define BMCTL_TX2_DIS (1<<30) 
-#define BMCTL_TX1_DIS (1<<26) 
-#define BMCTL_RX_DIS (1<<22) 
-
-#define BMASR 0xcc
-
-#define RXDESCQ 0x90
-#define RXDESCQCNT 0x94
-#define RXCDA 0x98
-#define RXENQ 0x9C
-#define RXSTATQ 0xA0
-#define RXSTATQCNT 0xA4
-#define RXCSA 0xA8
-#define RXCLEN 0xAC
-#define RXHLEN 0xAE
-
-#define TXDESCQ_1 0xb0
-#define TXDESCQ_2 0xd0
-#define TXDESCQCNT_1 0xb4
-#define TXDESCQCNT_2 0xd4
-#define TXCDA_1 0xb8
-#define TXCDA_2 0xd8
-#define TXENQ_1 0xbc
-#define TXENQ_2 0xdc
-#define TXSTATQ_1 0xc0
-#define TXSTATQ_2 0xe0
-#define TXSTATQCNT_1 0xc4
-#define TXSTATQCNT_2 0xe4
-#define TXCSA_1 0xc8
-#define TXCSA_2 0xe8
-
-#define OLYMPIC_IO_SPACE 256
-
-#define SRB_COMMAND_SIZE 50
-
-#define OLYMPIC_MAX_ADAPTERS 8 /* 0x08 __MODULE_STRING can't hand 0xnn */
-
-/* Defines for LAN STATUS CHANGE reports */
-#define LSC_SIG_LOSS 0x8000
-#define LSC_HARD_ERR 0x4000
-#define LSC_SOFT_ERR 0x2000
-#define LSC_TRAN_BCN 0x1000
-#define LSC_LWF      0x0800
-#define LSC_ARW      0x0400
-#define LSC_FPE      0x0200
-#define LSC_RR       0x0100
-#define LSC_CO       0x0080
-#define LSC_SS       0x0040
-#define LSC_RING_REC 0x0020
-#define LSC_SR_CO    0x0010
-#define LSC_FDX_MODE 0x0004
-
-/* Defines for OPEN ADAPTER command */
-
-#define OPEN_ADAPTER_EXT_WRAP (1<<15)
-#define OPEN_ADAPTER_DIS_HARDEE (1<<14)
-#define OPEN_ADAPTER_DIS_SOFTERR (1<<13)
-#define OPEN_ADAPTER_PASS_ADC_MAC (1<<12)
-#define OPEN_ADAPTER_PASS_ATT_MAC (1<<11)
-#define OPEN_ADAPTER_ENABLE_EC (1<<10)
-#define OPEN_ADAPTER_CONTENDER (1<<8)
-#define OPEN_ADAPTER_PASS_BEACON (1<<7)
-#define OPEN_ADAPTER_ENABLE_FDX (1<<6)
-#define OPEN_ADAPTER_ENABLE_RPL (1<<5)
-#define OPEN_ADAPTER_INHIBIT_ETR (1<<4)
-#define OPEN_ADAPTER_INTERNAL_WRAP (1<<3)
-#define OPEN_ADAPTER_USE_OPTS2 (1<<0)
-
-#define OPEN_ADAPTER_2_ENABLE_ONNOW (1<<15)
-
-/* Defines for SRB Commands */
-
-#define SRB_ACCESS_REGISTER 0x1f
-#define SRB_CLOSE_ADAPTER 0x04
-#define SRB_CONFIGURE_BRIDGE 0x0c
-#define SRB_CONFIGURE_WAKEUP_EVENT 0x1a
-#define SRB_MODIFY_BRIDGE_PARMS 0x15
-#define SRB_MODIFY_OPEN_OPTIONS 0x01
-#define SRB_MODIFY_RECEIVE_OPTIONS 0x17
-#define SRB_NO_OPERATION 0x00
-#define SRB_OPEN_ADAPTER 0x03
-#define SRB_READ_LOG 0x08
-#define SRB_READ_SR_COUNTERS 0x16
-#define SRB_RESET_GROUP_ADDRESS 0x02
-#define SRB_SAVE_CONFIGURATION 0x1b
-#define SRB_SET_BRIDGE_PARMS 0x09
-#define SRB_SET_BRIDGE_TARGETS 0x10
-#define SRB_SET_FUNC_ADDRESS 0x07
-#define SRB_SET_GROUP_ADDRESS 0x06
-#define SRB_SET_GROUP_ADDR_OPTIONS 0x11
-#define SRB_UPDATE_WAKEUP_PATTERN 0x19
-
-/* Clear return code */
-
-#define OLYMPIC_CLEAR_RET_CODE 0xfe 
-
-/* ARB Commands */
-#define ARB_RECEIVE_DATA 0x81
-#define ARB_LAN_CHANGE_STATUS 0x84
-/* ASB Response commands */
-
-#define ASB_RECEIVE_DATA 0x81
-
-
-/* Olympic defaults for buffers */
- 
-#define OLYMPIC_RX_RING_SIZE 16 /* should be a power of 2 */
-#define OLYMPIC_TX_RING_SIZE 8 /* should be a power of 2 */
-
-#define PKT_BUF_SZ 4096 /* Default packet size */
-
-/* Olympic data structures */
-
-struct olympic_tx_desc {
-	__u32 buffer;
-	__u32 status_length;
-};
-
-struct olympic_tx_status {
-	__u32 status;
-};
-
-struct olympic_rx_desc {
-	__u32 buffer;
-	__u32 res_length ; 
-};
-
-struct olympic_rx_status {
-	__u32 fragmentcnt_framelen;
-	__u32 status_buffercnt;
-};
-
-struct mac_receive_buffer {
-	__u16 next ; 
-	__u8 padding ; 
-	__u8 frame_status ;
-	__u16 buffer_length ; 
-	__u8 frame_data ; 
-};
-
-struct olympic_private {
-	
-	__u16 srb;
-	__u16 trb;
-	__u16 arb;
-	__u16 asb;
-
-	__u8 *olympic_mmio;
-	__u8 *olympic_lap;
-	char *olympic_card_name ; 
-
-	volatile int srb_queued;    /* True if an SRB is still posted */	
-	wait_queue_head_t srb_wait;
-
-	volatile int asb_queued;    /* True if an ASB is posted */
-
-	volatile int trb_queued;   /* True if a TRB is posted */
-	wait_queue_head_t trb_wait ; 
-
-	struct olympic_rx_desc olympic_rx_ring[OLYMPIC_RX_RING_SIZE];
-	struct olympic_tx_desc olympic_tx_ring[OLYMPIC_TX_RING_SIZE];
-	struct olympic_rx_status olympic_rx_status_ring[OLYMPIC_RX_RING_SIZE];	
-	struct olympic_tx_status olympic_tx_status_ring[OLYMPIC_TX_RING_SIZE];	
-	struct sk_buff *tx_ring_skb[OLYMPIC_TX_RING_SIZE], *rx_ring_skb[OLYMPIC_RX_RING_SIZE];	
-	int tx_ring_free, tx_ring_last_status, rx_ring_last_received,rx_status_last_received, free_tx_ring_entries;
-
-	struct net_device_stats olympic_stats ;
-	__u16 olympic_lan_status ;
-	__u8 olympic_ring_speed ;
-	__u16 pkt_buf_sz ; 
-	__u8 olympic_receive_options, olympic_copy_all_options, olympic_message_level;  
-	__u8 olympic_multicast_set ; 
-	__u16 olympic_addr_table_addr, olympic_parms_addr ; 
-	__u8 olympic_laa[6] ; 
-};
-
-struct olympic_adapter_addr_table {
-
-	__u8 node_addr[6] ; 
-	__u8 reserved[4] ; 
-	__u8 func_addr[4] ; 
-} ; 
-
-struct olympic_parameters_table { 
-	
-	__u8  phys_addr[4] ; 
-	__u8  up_node_addr[6] ; 
-	__u8  up_phys_addr[6] ; 
-	__u8  poll_addr[6] ; 
-	__u16 reserved ; 
-	__u16 acc_priority ; 
-	__u16 auth_source_class ; 
-	__u16 att_code ; 
-	__u8  source_addr[6] ; 
-	__u16 beacon_type ; 
-	__u16 major_vector ; 
-	__u16 lan_status ; 
-	__u16 soft_error_time ; 
- 	__u16 reserved1 ; 
-	__u16 local_ring ; 
-	__u16 mon_error ; 
-	__u16 beacon_transmit ; 
-	__u16 beacon_receive ; 
-	__u16 frame_correl ; 
-	__u8  beacon_naun[6] ; 
-	__u32 reserved2 ; 
-	__u8  beacon_phys[4] ; 	
-}; 
diff -u --recursive --new-file v2.3.20/linux/drivers/net/sdla.c linux/drivers/net/sdla.c
--- v2.3.20/linux/drivers/net/sdla.c	Wed Aug 18 11:36:42 1999
+++ linux/drivers/net/sdla.c	Wed Dec 31 16:00:00 1969
@@ -1,1696 +0,0 @@
-/*
- * SDLA		An implementation of a driver for the Sangoma S502/S508 series
- *		multi-protocol PC interface card.  Initial offering is with 
- *		the DLCI driver, providing Frame Relay support for linux.
- *
- *		Global definitions for the Frame relay interface.
- *
- * Version:	@(#)sdla.c   0.30	12 Sep 1996
- *
- * Credits:	Sangoma Technologies, for the use of 2 cards for an extended
- *			period of time.
- *		David Mandelstam <dm@sangoma.com> for getting me started on 
- *			this project, and incentive to complete it.
- *		Gene Kozen <74604.152@compuserve.com> for providing me with
- *			important information about the cards.
- *
- * Author:	Mike McLagan <mike.mclagan@linux.org>
- *
- * Changes:
- *		0.15	Mike McLagan	Improved error handling, packet dropping
- *		0.20	Mike McLagan	New transmit/receive flags for config
- *					If in FR mode, don't accept packets from
- *					non DLCI devices.
- *		0.25	Mike McLagan	Fixed problem with rejecting packets
- *					from non DLCI devices.
- *		0.30	Mike McLagan	Fixed kernel panic when used with modified
- *					ifconfig
- *
- *		This program is free software; you can redistribute it and/or
- *		modify it under the terms of the GNU General Public License
- *		as published by the Free Software Foundation; either version
- *		2 of the License, or (at your option) any later version.
- */
-
-#include <linux/config.h> /* for CONFIG_DLCI_MAX */
-#include <linux/module.h>
-
-#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/timer.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/uaccess.h>
-
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/if_frad.h>
-
-#include <linux/sdla.h>
-
-static const char* version = "SDLA driver v0.30, 12 Sep 1996, mike.mclagan@linux.org";
-
-static const char* devname = "sdla";
-
-static unsigned int valid_port[] __initdata = { 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390};
-
-static unsigned int valid_mem[]  __initdata = {
-				    0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, 
-                                    0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000,
-                                    0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000,
-                                    0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, 0xDE000,
-                                    0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000}; 
-
-/*********************************************************
- *
- * these are the core routines that access the card itself 
- *
- *********************************************************/
-
-#define SDLA_WINDOW(dev,addr) outb((((addr) >> 13) & 0x1F), (dev)->base_addr + SDLA_REG_Z80_WINDOW)
-
-static void sdla_read(struct net_device *dev, int addr, void *buf, short len)
-{
-	unsigned long flags;
-	char          *temp, *base;
-	int           offset, bytes;
-
-	temp = buf;
-	while(len)
-	{	
-		offset = addr & SDLA_ADDR_MASK;
-		bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;
-		base = (void *) (dev->mem_start + offset);
-
-		save_flags(flags);
-		cli();
-		SDLA_WINDOW(dev, addr);
-		memcpy(temp, base, bytes);
-		restore_flags(flags);
-
-		addr += bytes;
-		temp += bytes;
-		len  -= bytes;
-	}  
-}
-
-static void sdla_write(struct net_device *dev, int addr, void *buf, short len)
-{
-	unsigned long flags;
-	char          *temp, *base;
-	int           offset, bytes;
-
-	temp = buf;
-	while(len)
-	{
-		offset = addr & SDLA_ADDR_MASK;
-		bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;
-		base = (void *) (dev->mem_start + offset);
-		save_flags(flags);
-		cli();
-		SDLA_WINDOW(dev, addr);
-		memcpy(base, temp, bytes);
-		restore_flags(flags);
-		addr += bytes;
-		temp += bytes;
-		len  -= bytes;
-	}
-}
-
-static void sdla_clear(struct net_device *dev)
-{
-	unsigned long flags;
-	char          *base;
-	int           len, addr, bytes;
-
-	len = 65536;	
-	addr = 0;
-	bytes = SDLA_WINDOW_SIZE;
-	base = (void *) dev->mem_start;
-
-	save_flags(flags);
-	cli();
-	while(len)
-	{
-		SDLA_WINDOW(dev, addr);
-		memset(base, 0, bytes);
-
-		addr += bytes;
-		len  -= bytes;
-	}
-	restore_flags(flags);
-}
-
-static char sdla_byte(struct net_device *dev, int addr)
-{
-	unsigned long flags;
-	char          byte, *temp;
-
-	temp = (void *) (dev->mem_start + (addr & SDLA_ADDR_MASK));
-
-	save_flags(flags);
-	cli();
-	SDLA_WINDOW(dev, addr);
-	byte = *temp;
-	restore_flags(flags);
-
-	return(byte);
-}
-
-void sdla_stop(struct net_device *dev)
-{
-	struct frad_local *flp;
-
-	flp = dev->priv;
-	switch(flp->type)
-	{
-		case SDLA_S502A:
-			outb(SDLA_S502A_HALT, dev->base_addr + SDLA_REG_CONTROL);
-			flp->state = SDLA_HALT;
-			break;
-		case SDLA_S502E:
-			outb(SDLA_HALT, dev->base_addr + SDLA_REG_Z80_CONTROL);
-			outb(SDLA_S502E_ENABLE, dev->base_addr + SDLA_REG_CONTROL);
-			flp->state = SDLA_S502E_ENABLE;
-			break;
-		case SDLA_S507:
-			flp->state &= ~SDLA_CPUEN;
-			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-			break;
-		case SDLA_S508:
-			flp->state &= ~SDLA_CPUEN;
-			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-			break;
-	}
-}
-
-void sdla_start(struct net_device *dev)
-{
-	struct frad_local *flp;
-
-	flp = dev->priv;
-	switch(flp->type)
-	{
-		case SDLA_S502A:
-			outb(SDLA_S502A_NMI, dev->base_addr + SDLA_REG_CONTROL);
-			outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
-			flp->state = SDLA_S502A_START;
-			break;
-		case SDLA_S502E:
-			outb(SDLA_S502E_CPUEN, dev->base_addr + SDLA_REG_Z80_CONTROL);
-			outb(0x00, dev->base_addr + SDLA_REG_CONTROL);
-			flp->state = 0;
-			break;
-		case SDLA_S507:
-			flp->state |= SDLA_CPUEN;
-			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-			break;
-		case SDLA_S508:
-			flp->state |= SDLA_CPUEN;
-			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-			break;
-	}
-}
-
-/****************************************************
- *
- * this is used for the S502A/E cards to determine
- * the speed of the onboard CPU.  Calibration is
- * necessary for the Frame Relay code uploaded 
- * later.  Incorrect results cause timing problems
- * with link checks & status messages
- *
- ***************************************************/
-
-int sdla_z80_poll(struct net_device *dev, int z80_addr, int jiffs, char resp1, char resp2)
-{
-	unsigned long start, done, now;
-	char          resp, *temp;
-
-	start = now = jiffies;
-	done = jiffies + jiffs;
-
-	temp = (void *)dev->mem_start;
-	temp += z80_addr & SDLA_ADDR_MASK;
-	
-	resp = ~resp1;
-	while (time_before(jiffies, done) && (resp != resp1) && (!resp2 || (resp != resp2)))
-	{
-		if (jiffies != now)
-		{
-			SDLA_WINDOW(dev, z80_addr);
-			now = jiffies;
-			resp = *temp;
-		}
-	}
-	return(time_before(jiffies, done) ? jiffies - start : -1);
-}
-
-/* constants for Z80 CPU speed */
-#define Z80_READY 		'1'	/* Z80 is ready to begin */
-#define LOADER_READY 		'2'	/* driver is ready to begin */
-#define Z80_SCC_OK 		'3'	/* SCC is on board */
-#define Z80_SCC_BAD	 	'4'	/* SCC was not found */
-
-static int sdla_cpuspeed(struct net_device *dev, struct ifreq *ifr)
-{
-	int  jiffs;
-	char data;
-
-	sdla_start(dev);
-	if (sdla_z80_poll(dev, 0, 3*HZ, Z80_READY, 0) < 0)
-		return(-EIO);
-
-	data = LOADER_READY;
-	sdla_write(dev, 0, &data, 1);
-
-	if ((jiffs = sdla_z80_poll(dev, 0, 8*HZ, Z80_SCC_OK, Z80_SCC_BAD)) < 0)
-		return(-EIO);
-
-	sdla_stop(dev);
-	sdla_read(dev, 0, &data, 1);
-
-	if (data == Z80_SCC_BAD)
-	{
-		printk("%s: SCC bad\n", dev->name);
-		return(-EIO);
-	}
-
-	if (data != Z80_SCC_OK)
-		return(-EINVAL);
-
-	if (jiffs < 165)
-		ifr->ifr_mtu = SDLA_CPU_16M;
-	else if (jiffs < 220)
-		ifr->ifr_mtu = SDLA_CPU_10M;
-	else if (jiffs < 258)
-		ifr->ifr_mtu = SDLA_CPU_8M;
-	else if (jiffs < 357)
-		ifr->ifr_mtu = SDLA_CPU_7M;
-	else if (jiffs < 467)
-		ifr->ifr_mtu = SDLA_CPU_5M;
-	else
-		ifr->ifr_mtu = SDLA_CPU_3M;
- 
-	return(0);
-}
-
-/************************************************
- *
- *  Direct interaction with the Frame Relay code 
- *  starts here.
- *
- ************************************************/
-
-struct _dlci_stat 
-{
-	short dlci		__attribute__((packed));
-	char  flags		__attribute__((packed));
-};
-
-struct _frad_stat 
-{
-	char    flags;
-	struct _dlci_stat dlcis[SDLA_MAX_DLCI];
-};
-
-static void sdla_errors(struct net_device *dev, int cmd, int dlci, int ret, int len, void *data) 
-{
-	struct _dlci_stat *pstatus;
-	short             *pdlci;
-	int               i;
-	char              *state, line[30];
-
-	switch (ret)
-	{
-		case SDLA_RET_MODEM:
-			state = data;
-			if (*state & SDLA_MODEM_DCD_LOW)
-				printk(KERN_INFO "%s: Modem DCD unexpectedly low!\n", dev->name);
-			if (*state & SDLA_MODEM_CTS_LOW)
-				printk(KERN_INFO "%s: Modem CTS unexpectedly low!\n", dev->name);
-			/* I should probably do something about this! */
-			break;
-
-		case SDLA_RET_CHANNEL_OFF:
-			printk(KERN_INFO "%s: Channel became inoperative!\n", dev->name);
-			/* same here */
-			break;
-
-		case SDLA_RET_CHANNEL_ON:
-			printk(KERN_INFO "%s: Channel became operative!\n", dev->name);
-			/* same here */
-			break;
-
-		case SDLA_RET_DLCI_STATUS:
-			printk(KERN_INFO "%s: Status change reported by Access Node.\n", dev->name);
-			len /= sizeof(struct _dlci_stat);
-			for(pstatus = data, i=0;i < len;i++,pstatus++)
-			{
-				if (pstatus->flags & SDLA_DLCI_NEW)
-					state = "new";
-				else if (pstatus->flags & SDLA_DLCI_DELETED)
-					state = "deleted";
-				else if (pstatus->flags & SDLA_DLCI_ACTIVE)
-					state = "active";
-				else
-				{
-					sprintf(line, "unknown status: %02X", pstatus->flags);
-					state = line;
-				}
-				printk(KERN_INFO "%s: DLCI %i: %s.\n", dev->name, pstatus->dlci, state);
-				/* same here */
-			}
-			break;
-
-		case SDLA_RET_DLCI_UNKNOWN:
-			printk(KERN_INFO "%s: Received unknown DLCIs:", dev->name);
-			len /= sizeof(short);
-			for(pdlci = data,i=0;i < len;i++,pdlci++)
-				printk(" %i", *pdlci);
-			printk("\n");
-			break;
-
-		case SDLA_RET_TIMEOUT:
-			printk(KERN_ERR "%s: Command timed out!\n", dev->name);
-			break;
-
-		case SDLA_RET_BUF_OVERSIZE:
-			printk(KERN_INFO "%s: Bc/CIR overflow, acceptable size is %i\n", dev->name, len);
-			break;
-
-		case SDLA_RET_BUF_TOO_BIG:
-			printk(KERN_INFO "%s: Buffer size over specified max of %i\n", dev->name, len);
-			break;
-
-		case SDLA_RET_CHANNEL_INACTIVE:
-		case SDLA_RET_DLCI_INACTIVE:
-		case SDLA_RET_CIR_OVERFLOW:
-		case SDLA_RET_NO_BUFS:
-			if (cmd == SDLA_INFORMATION_WRITE)
-				break;
-
-		default: 
-			printk(KERN_DEBUG "%s: Cmd 0x%2.2X generated return code 0x%2.2X\n", dev->name, cmd, ret);
-			/* Further processing could be done here */
-			break;
-	}
-}
-
-static int sdla_cmd(struct net_device *dev, int cmd, short dlci, short flags, 
-                        void *inbuf, short inlen, void *outbuf, short *outlen)
-{
-	static struct _frad_stat status;
-	struct frad_local        *flp;
-	struct sdla_cmd          *cmd_buf;
-	unsigned long            pflags;
-	int                      jiffs, ret, waiting, len;
-	long                     window;
-
-	flp = dev->priv;
-	window = flp->type == SDLA_S508 ? SDLA_508_CMD_BUF : SDLA_502_CMD_BUF;
-	cmd_buf = (struct sdla_cmd *)(dev->mem_start + (window & SDLA_ADDR_MASK));
-	ret = 0;
-	len = 0;
-	jiffs = jiffies + HZ;  /* 1 second is plenty */
-	save_flags(pflags);
-	cli();
-	SDLA_WINDOW(dev, window);
-	cmd_buf->cmd = cmd;
-	cmd_buf->dlci = dlci;
-	cmd_buf->flags = flags;
-
-	if (inbuf)
-		memcpy(cmd_buf->data, inbuf, inlen);
-
-	cmd_buf->length = inlen;
-
-	cmd_buf->opp_flag = 1;
-	restore_flags(pflags);
-
-	waiting = 1;
-	len = 0;
-	while (waiting && time_before_eq(jiffies, jiffs))
-	{
-		if (waiting++ % 3) 
-		{
-			save_flags(pflags);
-			cli();
-			SDLA_WINDOW(dev, window);
-			waiting = ((volatile int)(cmd_buf->opp_flag));
-			restore_flags(pflags);
-		}
-	}
-	
-	if (!waiting)
-	{
-		save_flags(pflags);
-		cli();
-		SDLA_WINDOW(dev, window);
-		ret = cmd_buf->retval;
-		len = cmd_buf->length;
-		if (outbuf && outlen)
-		{
-			*outlen = *outlen >= len ? len : *outlen;
-
-			if (*outlen)
-				memcpy(outbuf, cmd_buf->data, *outlen);
-		}
-
-		/* This is a local copy that's used for error handling */
-		if (ret)
-			memcpy(&status, cmd_buf->data, len > sizeof(status) ? sizeof(status) : len);
-
-		restore_flags(pflags);
-	}
-	else
-		ret = SDLA_RET_TIMEOUT;
-
-	if (ret != SDLA_RET_OK)
-	   	sdla_errors(dev, cmd, dlci, ret, len, &status);
-
-	return(ret);
-}
-
-/***********************************************
- *
- * these functions are called by the DLCI driver 
- *
- ***********************************************/
-
-static int sdla_reconfig(struct net_device *dev);
-
-int sdla_activate(struct net_device *slave, struct net_device *master)
-{
-	struct frad_local *flp;
-	int i;
-
-	flp = slave->priv;
-
-	for(i=0;i<CONFIG_DLCI_MAX;i++)
-		if (flp->master[i] == master)
-			break;
-
-	if (i == CONFIG_DLCI_MAX)
-		return(-ENODEV);
-
-	flp->dlci[i] = abs(flp->dlci[i]);
-
-	if (slave->start && (flp->config.station == FRAD_STATION_NODE))
-		sdla_cmd(slave, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
-
-	return(0);
-}
-
-int sdla_deactivate(struct net_device *slave, struct net_device *master)
-{
-	struct frad_local *flp;
-	int               i;
-
-	flp = slave->priv;
-
-	for(i=0;i<CONFIG_DLCI_MAX;i++)
-		if (flp->master[i] == master)
-			break;
-
-	if (i == CONFIG_DLCI_MAX)
-		return(-ENODEV);
-
-	flp->dlci[i] = -abs(flp->dlci[i]);
-
-	if (slave->start && (flp->config.station == FRAD_STATION_NODE))
-		sdla_cmd(slave, SDLA_DEACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
-
-	return(0);
-}
-
-int sdla_assoc(struct net_device *slave, struct net_device *master)
-{
-	struct frad_local *flp;
-	int               i;
-
-	if (master->type != ARPHRD_DLCI)
-		return(-EINVAL);
-
-	flp = slave->priv;
-
-	for(i=0;i<CONFIG_DLCI_MAX;i++)
-	{
-		if (!flp->master[i])
-			break;
-		if (abs(flp->dlci[i]) == *(short *)(master->dev_addr))
-			return(-EADDRINUSE);
-	} 
-
-	if (i == CONFIG_DLCI_MAX)
-		return(-EMLINK);  /* #### Alan: Comments on this ?? */
-
-	MOD_INC_USE_COUNT;
-
-	flp->master[i] = master;
-	flp->dlci[i] = -*(short *)(master->dev_addr);
-	master->mtu = slave->mtu;
-
-	if (slave->start) {
-		if (flp->config.station == FRAD_STATION_CPE)
-			sdla_reconfig(slave);
-		else
-			sdla_cmd(slave, SDLA_ADD_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
-	}
-
-	return(0);
-}
-
-int sdla_deassoc(struct net_device *slave, struct net_device *master)
-{
-	struct frad_local *flp;
-	int               i;
-
-	flp = slave->priv;
-
-	for(i=0;i<CONFIG_DLCI_MAX;i++)
-		if (flp->master[i] == master)
-			break;
-
-	if (i == CONFIG_DLCI_MAX)
-		return(-ENODEV);
-
-	flp->master[i] = NULL;
-	flp->dlci[i] = 0;
-
-	MOD_DEC_USE_COUNT;
-
-	if (slave->start) {
-		if (flp->config.station == FRAD_STATION_CPE)
-			sdla_reconfig(slave);
-		else
-			sdla_cmd(slave, SDLA_DELETE_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
-	}
-
-	return(0);
-}
-
-int sdla_dlci_conf(struct net_device *slave, struct net_device *master, int get)
-{
-	struct frad_local *flp;
-	struct dlci_local *dlp;
-	int               i;
-	short             len, ret;
-
-	flp = slave->priv;
-
-	for(i=0;i<CONFIG_DLCI_MAX;i++)
-		if (flp->master[i] == master)
-			break;
-
-	if (i == CONFIG_DLCI_MAX)
-		return(-ENODEV);
-
-	dlp = master->priv;
-
-	ret = SDLA_RET_OK;
-	len = sizeof(struct dlci_conf);
-	if (slave->start) {
-		if (get)
-			ret = sdla_cmd(slave, SDLA_READ_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,  
-			            NULL, 0, &dlp->config, &len);
-		else
-			ret = sdla_cmd(slave, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,  
-			            &dlp->config, sizeof(struct dlci_conf) - 4 * sizeof(short), NULL, NULL);
-	}
-
-	return(ret == SDLA_RET_OK ? 0 : -EIO);
-}
-
-/**************************
- *
- * now for the Linux driver 
- *
- **************************/
-
-/* NOTE: the DLCI driver deals with freeing the SKB!! */
-static int sdla_transmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct frad_local *flp;
-	int               ret, addr, accept;
-	short             size;
-	unsigned long     flags;
-	struct buf_entry  *pbuf;
-
-	flp = dev->priv;
-	ret = 0;
-	accept = 1;
-
-	if (dev->tbusy) 
-		return(1);
-
-	if (skb == NULL) 
-		return(0);
-
-	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
-		printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
-	else
-	{
-		/*
-		 * stupid GateD insists on setting up the multicast router thru us
-		 * and we're ill equipped to handle a non Frame Relay packet at this
-		 * time!
-		 */
-
-		accept = 1;
-		switch (dev->type)
-		{
-			case ARPHRD_FRAD:
-				if (skb->dev->type != ARPHRD_DLCI)
-				{
-					printk(KERN_WARNING "%s: Non DLCI device, type %i, tried to send on FRAD module.\n", dev->name, skb->dev->type);
-					accept = 0;
-				}
-				break;
-
-			default:
-				printk(KERN_WARNING "%s: unknown firmware type 0x%4.4X\n", dev->name, dev->type);
-				accept = 0;
-				break;
-		}
-
-		if (accept)
-		{
-			/* this is frame specific, but till there's a PPP module, it's the default */
-			switch (flp->type)
-			{
-				case SDLA_S502A:
-				case SDLA_S502E:
-					ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, skb->data, skb->len, NULL, NULL);
-					break;
-
-				case SDLA_S508:
-					size = sizeof(addr);
-					ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, NULL, skb->len, &addr, &size);
-					if (ret == SDLA_RET_OK)
-					{
-						save_flags(flags); 
-						cli();
-						SDLA_WINDOW(dev, addr);
-						pbuf = (void *)(((int) dev->mem_start) + (addr & SDLA_ADDR_MASK));
-
-						sdla_write(dev, pbuf->buf_addr, skb->data, skb->len);
-
-						SDLA_WINDOW(dev, addr);
-						pbuf->opp_flag = 1;
-						restore_flags(flags);
-					}
-					break;
-			}
-
-			switch (ret)
-			{
-				case SDLA_RET_OK:
-					flp->stats.tx_packets++;
-					ret = DLCI_RET_OK;
-					break;
-
-				case SDLA_RET_CIR_OVERFLOW:
-				case SDLA_RET_BUF_OVERSIZE:
-				case SDLA_RET_NO_BUFS:
-					flp->stats.tx_dropped++;
-					ret = DLCI_RET_DROP;
-					break;
-
-				default:
-					flp->stats.tx_errors++;
-					ret = DLCI_RET_ERR;
-					break;
-			}
-		}
-		dev->tbusy = 0;
-	}
-	return(ret);
-}
-
-static void sdla_receive(struct net_device *dev)
-{
-	struct net_device	  *master;
-	struct frad_local *flp;
-	struct dlci_local *dlp;
-	struct sk_buff	 *skb;
-
-	struct sdla_cmd	*cmd;
-	struct buf_info	*pbufi;
-	struct buf_entry  *pbuf;
-
-	unsigned long	  flags;
-	int               i, received, success, addr, buf_base, buf_top;
-	short             dlci, len, len2, split;
-
-	flp = dev->priv;
-	success = 1;
-	received = addr = buf_top = buf_base = 0;
-	len = dlci = 0;
-	skb = NULL;
-	master = NULL;
-	cmd = NULL;
-	pbufi = NULL;
-	pbuf = NULL;
-
-	save_flags(flags);
-	cli();
-
-	switch (flp->type)
-	{
-		case SDLA_S502A:
-		case SDLA_S502E:
-			cmd = (void *) (dev->mem_start + (SDLA_502_RCV_BUF & SDLA_ADDR_MASK));
-			SDLA_WINDOW(dev, SDLA_502_RCV_BUF);
-			success = cmd->opp_flag;
-			if (!success)
-				break;
-
-			dlci = cmd->dlci;
-			len = cmd->length;
-			break;
-
-		case SDLA_S508:
-			pbufi = (void *) (dev->mem_start + (SDLA_508_RXBUF_INFO & SDLA_ADDR_MASK));
-			SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
-			pbuf = (void *) (dev->mem_start + ((pbufi->rse_base + flp->buffer * sizeof(struct buf_entry)) & SDLA_ADDR_MASK));
-			success = pbuf->opp_flag;
-			if (!success)
-				break;
-
-			buf_top = pbufi->buf_top;
-			buf_base = pbufi->buf_base;
-			dlci = pbuf->dlci;
-			len = pbuf->length;
-			addr = pbuf->buf_addr;
-			break;
-	}
-
-	/* common code, find the DLCI and get the SKB */
-	if (success)
-	{
-		for (i=0;i<CONFIG_DLCI_MAX;i++)
-			if (flp->dlci[i] == dlci)
-				break;
-
-		if (i == CONFIG_DLCI_MAX)
-		{
-			printk(KERN_NOTICE "%s: Received packet from invalid DLCI %i, ignoring.", dev->name, dlci);
-			flp->stats.rx_errors++;
-			success = 0;
-		}
-	}
-
-	if (success)
-	{
-		master = flp->master[i];
-		skb = dev_alloc_skb(len + sizeof(struct frhdr));
-		if (skb == NULL) 
-		{
-			printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
-			flp->stats.rx_dropped++; 
-			success = 0;
-		}
-		else
-			skb_reserve(skb, sizeof(struct frhdr));
-	}
-
-	/* pick up the data */
-	switch (flp->type)
-	{
-		case SDLA_S502A:
-		case SDLA_S502E:
-			if (success)
-				sdla_read(dev, SDLA_502_RCV_BUF + SDLA_502_DATA_OFS, skb_put(skb,len), len);
-
-			SDLA_WINDOW(dev, SDLA_502_RCV_BUF);
-			cmd->opp_flag = 0;
-			break;
-
-		case SDLA_S508:
-			if (success)
-			{
-				/* is this buffer split off the end of the internal ring buffer */
-				split = addr + len > buf_top + 1 ? len - (buf_top - addr + 1) : 0;
-				len2 = len - split;
-
-				sdla_read(dev, addr, skb_put(skb, len2), len2);
-				if (split)
-					sdla_read(dev, buf_base, skb_put(skb, split), split);
-			}
-
-			/* increment the buffer we're looking at */
-			SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
-			flp->buffer = (flp->buffer + 1) % pbufi->rse_num;
-			pbuf->opp_flag = 0;
-			break;
-	}
-
-	if (success)
-	{
-		flp->stats.rx_packets++;
-		dlp = master->priv;
-		(*dlp->receive)(skb, master);
-	}
-
-	restore_flags(flags);
-}
-
-static void sdla_isr(int irq, void *dev_id, struct pt_regs * regs)
-{
-	struct net_device     *dev;
-	struct frad_local *flp;
-	char              byte;
-
-	dev = dev_id;
-
-	if (dev == NULL)
-	{
-		printk(KERN_WARNING "sdla_isr(): irq %d for unknown device.\n", irq);
-		return;
-	}
-
-	flp = dev->priv;
-
-	if (!flp->initialized)
-	{
-		printk(KERN_WARNING "%s: irq %d for uninitialized device.\n", dev->name, irq);
-		return;
-	}
-
-	dev->interrupt = 1;
-	byte = sdla_byte(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE);
-	switch (byte)
-	{
-		case SDLA_INTR_RX:
-			sdla_receive(dev);
-			break;
-
-		/* the command will get an error return, which is processed above */
-		case SDLA_INTR_MODEM:
-		case SDLA_INTR_STATUS:
-			sdla_cmd(dev, SDLA_READ_DLC_STATUS, 0, 0, NULL, 0, NULL, NULL);
-			break;
-
-		case SDLA_INTR_TX:
-		case SDLA_INTR_COMPLETE:
-		case SDLA_INTR_TIMER:
-			printk(KERN_WARNING "%s: invalid irq flag 0x%02X.\n", dev->name, byte);
-			break;
-	}
-
-	/* the S502E requires a manual acknowledgement of the interrupt */ 
-	if (flp->type == SDLA_S502E)
-	{
-		flp->state &= ~SDLA_S502E_INTACK;
-		outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-		flp->state |= SDLA_S502E_INTACK;
-		outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-	}
-
-	/* this clears the byte, informing the Z80 we're done */
-	byte = 0;
-	sdla_write(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE, &byte, sizeof(byte));
-	dev->interrupt = 0;
-}
-
-static void sdla_poll(unsigned long device)
-{
-	struct net_device	  *dev;
-	struct frad_local *flp;
-
-	dev = (struct net_device *) device;
-	flp = dev->priv;
-
-	if (sdla_byte(dev, SDLA_502_RCV_BUF))
-		sdla_receive(dev);
-
-	flp->timer.expires = 1;
-	add_timer(&flp->timer);
-}
-
-static int sdla_close(struct net_device *dev)
-{
-	struct frad_local *flp;
-	struct intr_info  intr;
-	int               len, i;
-	short             dlcis[CONFIG_DLCI_MAX];
-
-	flp = dev->priv;
-
-	len = 0;
-	for(i=0;i<CONFIG_DLCI_MAX;i++)
-		if (flp->dlci[i])
-			dlcis[len++] = abs(flp->dlci[i]);
-	len *= 2;
-
-	if (flp->config.station == FRAD_STATION_NODE)
-	{
-		for(i=0;i<CONFIG_DLCI_MAX;i++)
-			if (flp->dlci[i] > 0) 
-				sdla_cmd(dev, SDLA_DEACTIVATE_DLCI, 0, 0, dlcis, len, NULL, NULL);
-		sdla_cmd(dev, SDLA_DELETE_DLCI, 0, 0, &flp->dlci[i], sizeof(flp->dlci[i]), NULL, NULL);
-	}
-
-	memset(&intr, 0, sizeof(intr));
-	/* let's start up the reception */
-	switch(flp->type)
-	{
-		case SDLA_S502A:
-			del_timer(&flp->timer); 
-			break;
-
-		case SDLA_S502E:
-			sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(char) + sizeof(short), NULL, NULL);
-			flp->state &= ~SDLA_S502E_INTACK;
-			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-			break;
-
-		case SDLA_S507:
-			break;
-
-		case SDLA_S508:
-			sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(struct intr_info), NULL, NULL);
-			flp->state &= ~SDLA_S508_INTEN;
-			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-			break;
-	}
-
-	sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
-
-	dev->tbusy = 1;
-	dev->start = 0;
-
-	MOD_DEC_USE_COUNT;
-
-	return(0);
-}
-
-struct conf_data {
-	struct frad_conf config;
-	short            dlci[CONFIG_DLCI_MAX];
-};
-
-static int sdla_open(struct net_device *dev)
-{
-	struct frad_local *flp;
-	struct dlci_local *dlp;
-	struct conf_data  data;
-	struct intr_info  intr;
-	int               len, i;
-	char              byte;
-
-	flp = dev->priv;
-
-	if (!flp->initialized)
-		return(-EPERM);
-
-	if (!flp->configured)
-		return(-EPERM);
-
-	/* time to send in the configuration */
-	len = 0;
-	for(i=0;i<CONFIG_DLCI_MAX;i++)
-		if (flp->dlci[i])
-			data.dlci[len++] = abs(flp->dlci[i]);
-	len *= 2;
-
-	memcpy(&data.config, &flp->config, sizeof(struct frad_conf));
-	len += sizeof(struct frad_conf);
-
-	sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
-	sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, 0, 0, &data, len, NULL, NULL);
-
-	if (flp->type == SDLA_S508)
-		flp->buffer = 0;
-
-	sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
-
-	/* let's start up the reception */
-	memset(&intr, 0, sizeof(intr));
-	switch(flp->type)
-	{
-		case SDLA_S502A:
-			flp->timer.expires = 1;
-			add_timer(&flp->timer);
-			break;
-
-		case SDLA_S502E:
-			flp->state |= SDLA_S502E_ENABLE;
-			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-			flp->state |= SDLA_S502E_INTACK;
-			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-			byte = 0;
-			sdla_write(dev, SDLA_502_IRQ_INTERFACE, &byte, sizeof(byte));
-			intr.flags = SDLA_INTR_RX | SDLA_INTR_STATUS | SDLA_INTR_MODEM;
-			sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(char) + sizeof(short), NULL, NULL);
-			break;
-
-		case SDLA_S507:
-			break;
-
-		case SDLA_S508:
-			flp->state |= SDLA_S508_INTEN;
-			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-			byte = 0;
-			sdla_write(dev, SDLA_508_IRQ_INTERFACE, &byte, sizeof(byte));
-			intr.flags = SDLA_INTR_RX | SDLA_INTR_STATUS | SDLA_INTR_MODEM;
-			intr.irq = dev->irq;
-			sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(struct intr_info), NULL, NULL);
-			break;
-	}
-
-	if (flp->config.station == FRAD_STATION_CPE)
-	{
-		byte = SDLA_ICS_STATUS_ENQ;
-		sdla_cmd(dev, SDLA_ISSUE_IN_CHANNEL_SIGNAL, 0, 0, &byte, sizeof(byte), NULL, NULL);
-	}
-	else
-	{
-		sdla_cmd(dev, SDLA_ADD_DLCI, 0, 0, data.dlci, len - sizeof(struct frad_conf), NULL, NULL);
-		for(i=0;i<CONFIG_DLCI_MAX;i++)
-			if (flp->dlci[i] > 0)
-				sdla_cmd(dev, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], 2*sizeof(flp->dlci[i]), NULL, NULL);
-	}
-
-	/* configure any specific DLCI settings */
-	for(i=0;i<CONFIG_DLCI_MAX;i++)
-		if (flp->dlci[i])
-		{
-			dlp = flp->master[i]->priv;
-			if (dlp->configured)
-				sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0, &dlp->config, sizeof(struct dlci_conf), NULL, NULL);
-		}
-
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 1;
-
-	MOD_INC_USE_COUNT;
-
-	return(0);
-}
-
-static int sdla_config(struct net_device *dev, struct frad_conf *conf, int get)
-{
-	struct frad_local *flp;
-	struct conf_data  data;
-	int               i;
-	short             size;
-
-	if (dev->type == 0xFFFF)
-		return(-EUNATCH);
-
-	flp = dev->priv;
-
-	if (!get)
-	{
-		if (dev->start)
-			return(-EBUSY);
-
-		if(copy_from_user(&data.config, conf, sizeof(struct frad_conf)))
-			return -EFAULT;
-
-		if (data.config.station & ~FRAD_STATION_NODE)
-			return(-EINVAL);
-
-		if (data.config.flags & ~FRAD_VALID_FLAGS)
-			return(-EINVAL);
-
-		if ((data.config.kbaud < 0) || 
-			 ((data.config.kbaud > 128) && (flp->type != SDLA_S508)))
-			return(-EINVAL);
-
-		if (data.config.clocking & ~(FRAD_CLOCK_INT | SDLA_S508_PORT_RS232))
-			return(-EINVAL);
-
-		if ((data.config.mtu < 0) || (data.config.mtu > SDLA_MAX_MTU))
-			return(-EINVAL);
-
-		if ((data.config.T391 < 5) || (data.config.T391 > 30))
-			return(-EINVAL);
-
-		if ((data.config.T392 < 5) || (data.config.T392 > 30))
-			return(-EINVAL);
-
-		if ((data.config.N391 < 1) || (data.config.N391 > 255))
-			return(-EINVAL);
-
-		if ((data.config.N392 < 1) || (data.config.N392 > 10))
-			return(-EINVAL);
-
-		if ((data.config.N393 < 1) || (data.config.N393 > 10))
-			return(-EINVAL);
-
-		memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
-		flp->config.flags |= SDLA_DIRECT_RECV;
-
-		if (flp->type == SDLA_S508)
-			flp->config.flags |= SDLA_TX70_RX30;
-
-		if (dev->mtu != flp->config.mtu)
-		{
-			/* this is required to change the MTU */
-			dev->mtu = flp->config.mtu;
-			for(i=0;i<CONFIG_DLCI_MAX;i++)
-				if (flp->master[i])
-					flp->master[i]->mtu = flp->config.mtu;
-		}
-
-		flp->config.mtu += sizeof(struct frhdr);
-
-		/* off to the races! */
-		if (!flp->configured)
-			sdla_start(dev);
-
-		flp->configured = 1;
-	}
-	else
-	{
-		/* no sense reading if the CPU isn't started */
-		if (dev->start)
-		{
-			size = sizeof(data);
-			if (sdla_cmd(dev, SDLA_READ_DLCI_CONFIGURATION, 0, 0, NULL, 0, &data, &size) != SDLA_RET_OK)
-				return(-EIO);
-		}
-		else
-			if (flp->configured)
-				memcpy(&data.config, &flp->config, sizeof(struct frad_conf));
-			else
-				memset(&data.config, 0, sizeof(struct frad_conf));
-
-		memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
-		data.config.flags &= FRAD_VALID_FLAGS;
-		data.config.mtu -= data.config.mtu > sizeof(struct frhdr) ? sizeof(struct frhdr) : data.config.mtu;
-		return copy_to_user(conf, &data.config, sizeof(struct frad_conf))?-EFAULT:0;
-	}
-
-	return(0);
-}
-
-static int sdla_xfer(struct net_device *dev, struct sdla_mem *info, int read)
-{
-	struct sdla_mem mem;
-	char	*temp;
-
-	if(copy_from_user(&mem, info, sizeof(mem)))
-		return -EFAULT;
-		
-	if (read)
-	{	
-		temp = kmalloc(mem.len, GFP_KERNEL);
-		if (!temp)
-			return(-ENOMEM);
-		sdla_read(dev, mem.addr, temp, mem.len);
-		if(copy_to_user(mem.data, temp, mem.len))
-			return -EFAULT;
-		kfree(temp);
-	}
-	else
-	{
-		temp = kmalloc(mem.len, GFP_KERNEL);
-		if (!temp)
-			return(-ENOMEM);
-		if(copy_from_user(temp, mem.data, mem.len))
-			return -EFAULT;
-		sdla_write(dev, mem.addr, temp, mem.len);
-		kfree(temp);
-	}
-	return(0);
-}
-
-static int sdla_reconfig(struct net_device *dev)
-{
-	struct frad_local *flp;
-	struct conf_data  data;
-	int               i, len;
-
-	flp = dev->priv;
-
-	len = 0;
-	for(i=0;i<CONFIG_DLCI_MAX;i++)
-		if (flp->dlci[i])
-			data.dlci[len++] = flp->dlci[i];
-	len *= 2;
-
-	memcpy(&data, &flp->config, sizeof(struct frad_conf));
-	len += sizeof(struct frad_conf);
-
-	sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
-	sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, 0, 0, &data, len, NULL, NULL);
-	sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
-
-	return(0);
-}
-
-static int sdla_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-	struct frad_local *flp;
-
-	if(!suser())
-		return -EPERM;
-		
-	flp = dev->priv;
-
-	if (!flp->initialized)
-		return(-EINVAL);
-
-	switch (cmd)
-	{
-		case FRAD_GET_CONF:
-		case FRAD_SET_CONF:
-			return(sdla_config(dev, (struct frad_conf *)ifr->ifr_data, cmd == FRAD_GET_CONF));
-
-		case SDLA_IDENTIFY:
-			ifr->ifr_flags = flp->type;
-			break;
-
-		case SDLA_CPUSPEED:
-			return(sdla_cpuspeed(dev, ifr)); 
-
-/* ==========================================================
-NOTE:  This is rather a useless action right now, as the
-       current driver does not support protocols other than
-       FR.  However, Sangoma has modules for a number of
-       other protocols in the works.
-============================================================*/
-		case SDLA_PROTOCOL:
-			if (flp->configured)
-				return(-EALREADY);
-
-			switch (ifr->ifr_flags)
-			{
-				case ARPHRD_FRAD:
-					dev->type = ifr->ifr_flags;
-					break;
-				default:
-					return(-ENOPROTOOPT);
-			}
-			break;
-
-		case SDLA_CLEARMEM:
-			sdla_clear(dev);
-			break;
-
-		case SDLA_WRITEMEM:
-		case SDLA_READMEM:
-			return(sdla_xfer(dev, (struct sdla_mem *)ifr->ifr_data, cmd == SDLA_READMEM));
-
-		case SDLA_START:
-			sdla_start(dev);
-			break;
-
-		case SDLA_STOP:
-			sdla_stop(dev);
-			break;
-
-		default:
-			return(-EOPNOTSUPP);
-	}
-	return(0);
-}
-
-int sdla_change_mtu(struct net_device *dev, int new_mtu)
-{
-	struct frad_local *flp;
-
-	flp = dev->priv;
-
-	if (dev->start)
-		return(-EBUSY);
-
-	/* for now, you can't change the MTU! */
-	return(-EOPNOTSUPP);
-}
-
-int sdla_set_config(struct net_device *dev, struct ifmap *map)
-{
-	struct frad_local *flp;
-	int               i;
-	char              byte;
-
-	flp = dev->priv;
-
-	if (flp->initialized)
-		return(-EINVAL);
-
-	for(i=0;i < sizeof(valid_port) / sizeof (int) ; i++)
-		if (valid_port[i] == map->base_addr)
-			break;   
-
-	if (i == sizeof(valid_port) / sizeof(int))
-		return(-EINVAL);
-
-	dev->base_addr = map->base_addr;
-	request_region(dev->base_addr, SDLA_IO_EXTENTS, dev->name);
-
-	/* test for card types, S502A, S502E, S507, S508                 */
-	/* these tests shut down the card completely, so clear the state */
-	flp->type = SDLA_UNKNOWN;
-	flp->state = 0;
-   
-	for(i=1;i<SDLA_IO_EXTENTS;i++)
-		if (inb(dev->base_addr + i) != 0xFF)
-			break;
-
-	if (i == SDLA_IO_EXTENTS)
-	{   
-		outb(SDLA_HALT, dev->base_addr + SDLA_REG_Z80_CONTROL);
-		if ((inb(dev->base_addr + SDLA_S502_STS) & 0x0F) == 0x08)
-		{
-			outb(SDLA_S502E_INTACK, dev->base_addr + SDLA_REG_CONTROL);
-			if ((inb(dev->base_addr + SDLA_S502_STS) & 0x0F) == 0x0C)
-			{
-				outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
-				flp->type = SDLA_S502E;
-			}
-		}
-	}
-
-	if (flp->type == SDLA_UNKNOWN)
-	{
-		for(byte=inb(dev->base_addr),i=0;i<SDLA_IO_EXTENTS;i++)
-			if (inb(dev->base_addr + i) != byte)
-				break;
-
-		if (i == SDLA_IO_EXTENTS)
-		{
-			outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
-			if ((inb(dev->base_addr + SDLA_S502_STS) & 0x7E) == 0x30)
-			{
-				outb(SDLA_S507_ENABLE, dev->base_addr + SDLA_REG_CONTROL);
-				if ((inb(dev->base_addr + SDLA_S502_STS) & 0x7E) == 0x32)
-				{
-					outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
-					flp->type = SDLA_S507;
-				}
-			}
-		}
-	}
-
-	if (flp->type == SDLA_UNKNOWN)
-	{
-		outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
-		if ((inb(dev->base_addr + SDLA_S508_STS) & 0x3F) == 0x00)
-		{
-			outb(SDLA_S508_INTEN, dev->base_addr + SDLA_REG_CONTROL);
-			if ((inb(dev->base_addr + SDLA_S508_STS) & 0x3F) == 0x10)
-			{
-				outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
-				flp->type = SDLA_S508;
-			}
-		}
-	}
-
-	if (flp->type == SDLA_UNKNOWN)
-	{
-		outb(SDLA_S502A_HALT, dev->base_addr + SDLA_REG_CONTROL);
-		if (inb(dev->base_addr + SDLA_S502_STS) == 0x40)
-		{
-			outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
-			if (inb(dev->base_addr + SDLA_S502_STS) == 0x40)
-			{
-				outb(SDLA_S502A_INTEN, dev->base_addr + SDLA_REG_CONTROL);
-				if (inb(dev->base_addr + SDLA_S502_STS) == 0x44)
-				{
-					outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
-					flp->type = SDLA_S502A;
-				}
-			}
-		}
-	}
-
-	if (flp->type == SDLA_UNKNOWN)
-	{
-		printk(KERN_NOTICE "%s: Unknown card type\n", dev->name);
-		return(-ENODEV);
-	}
-
-	switch(dev->base_addr)
-	{
-		case 0x270:
-		case 0x280:
-		case 0x380: 
-		case 0x390:
-			if ((flp->type != SDLA_S508) && (flp->type != SDLA_S507))
-				return(-EINVAL);
-	}
-
-	switch (map->irq)
-	{
-		case 2:
-			if (flp->type != SDLA_S502E)
-				return(-EINVAL);
-			break;
-
-		case 10:
-		case 11:
-		case 12:
-		case 15:
-		case 4:
-			if ((flp->type != SDLA_S508) && (flp->type != SDLA_S507))
-				return(-EINVAL);
-
-		case 3:
-		case 5:
-		case 7:
-			if (flp->type == SDLA_S502A)
-				return(-EINVAL);
-			break;
-
-		default:
-			return(-EINVAL);
-	}
-	dev->irq = map->irq;
-
-	if (request_irq(dev->irq, &sdla_isr, 0, dev->name, dev)) 
-		return(-EAGAIN);
-
-	if (flp->type == SDLA_S507)
-	{
-		switch(dev->irq)
-		{
-			case 3:
-				flp->state = SDLA_S507_IRQ3;
-				break;
-			case 4:
-				flp->state = SDLA_S507_IRQ4;
-				break;
-			case 5:
-				flp->state = SDLA_S507_IRQ5;
-				break;
-			case 7:
-				flp->state = SDLA_S507_IRQ7;
-				break;
-			case 10:
-				flp->state = SDLA_S507_IRQ10;
-				break;
-			case 11:
-				flp->state = SDLA_S507_IRQ11;
-				break;
-			case 12:
-				flp->state = SDLA_S507_IRQ12;
-				break;
-			case 15:
-				flp->state = SDLA_S507_IRQ15;
-				break;
-		}
-	}
-
-	for(i=0;i < sizeof(valid_mem) / sizeof (int) ; i++)
-		if (valid_mem[i] == map->mem_start)
-			break;   
-
-	if (i == sizeof(valid_mem) / sizeof(int))
-	/*
-	 *	FIXME:
-	 *	BUG BUG BUG: MUST RELEASE THE IRQ WE ALLOCATED IN
-	 *	ALL THESE CASES
-	 *
-	 */
-		return(-EINVAL);
-
-	if ((flp->type == SDLA_S502A) && (((map->mem_start & 0xF000) >> 12) == 0x0E))
-		return(-EINVAL);
-
-	if ((flp->type != SDLA_S507) && ((map->mem_start >> 16) == 0x0B))
-		return(-EINVAL);
-
-	if ((flp->type == SDLA_S507) && ((map->mem_start >> 16) == 0x0D))
-		return(-EINVAL);
-
-	dev->mem_start = map->mem_start;
-	dev->mem_end = dev->mem_start + 0x2000;
-
-	byte = flp->type != SDLA_S508 ? SDLA_8K_WINDOW : 0;
-	byte |= (map->mem_start & 0xF000) >> (12 + (flp->type == SDLA_S508 ? 1 : 0));
-	switch(flp->type)
-	{
-		case SDLA_S502A:
-		case SDLA_S502E:
-			switch (map->mem_start >> 16)
-			{
-				case 0x0A:
-					byte |= SDLA_S502_SEG_A;
-					break;
-				case 0x0C:
-					byte |= SDLA_S502_SEG_C;
-					break;
-				case 0x0D:
-					byte |= SDLA_S502_SEG_D;
-					break;
-				case 0x0E:
-					byte |= SDLA_S502_SEG_E;
-					break;
-			}
-			break;
-		case SDLA_S507:
-			switch (map->mem_start >> 16)
-			{
-				case 0x0A:
-					byte |= SDLA_S507_SEG_A;
-					break;
-				case 0x0B:
-					byte |= SDLA_S507_SEG_B;
-					break;
-				case 0x0C:
-					byte |= SDLA_S507_SEG_C;
-					break;
-				case 0x0E:
-					byte |= SDLA_S507_SEG_E;
-					break;
-			}
-			break;
-		case SDLA_S508:
-			switch (map->mem_start >> 16)
-			{
-				case 0x0A:
-					byte |= SDLA_S508_SEG_A;
-					break;
-				case 0x0C:
-					byte |= SDLA_S508_SEG_C;
-					break;
-				case 0x0D:
-					byte |= SDLA_S508_SEG_D;
-					break;
-				case 0x0E:
-					byte |= SDLA_S508_SEG_E;
-					break;
-			}
-			break;
-	}
-
-	/* set the memory bits, and enable access */
-	outb(byte, dev->base_addr + SDLA_REG_PC_WINDOW);
-
-	switch(flp->type)
-	{
-		case SDLA_S502E:
-			flp->state = SDLA_S502E_ENABLE;
-			break;
-		case SDLA_S507:
-			flp->state |= SDLA_MEMEN;
-			break;
-		case SDLA_S508:
-			flp->state = SDLA_MEMEN;
-			break;
-	}
-	outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-
-	flp->initialized = 1;
-	return(0);
-}
- 
-static struct net_device_stats *sdla_stats(struct net_device *dev)
-{
-	struct frad_local *flp;
-	flp = dev->priv;
-
-	return(&flp->stats);
-}
-
-int __init sdla_init(struct net_device *dev)
-{
-	struct frad_local *flp;
-
-	/* allocate the private data structure */
-	flp = kmalloc(sizeof(struct frad_local), GFP_KERNEL);
-	if (!flp)
-		return(-ENOMEM);
-
-	memset(flp, 0, sizeof(struct frad_local));
-	dev->priv = flp;
-
-	dev->flags		= 0;
-	dev->open		= sdla_open;
-	dev->stop		= sdla_close;
-	dev->do_ioctl		= sdla_ioctl;
-	dev->set_config		= sdla_set_config;
-	dev->get_stats		= sdla_stats;
-	dev->hard_start_xmit	= sdla_transmit;
-	dev->change_mtu		= sdla_change_mtu;
-
-	dev->type		= 0xFFFF;
-	dev->hard_header_len = 0;
-	dev->addr_len		= 0;
-	dev->mtu		= SDLA_MAX_MTU;
-
-	dev_init_buffers(dev);
-   
-	flp->activate		= sdla_activate;
-	flp->deactivate		= sdla_deactivate;
-	flp->assoc		= sdla_assoc;
-	flp->deassoc		= sdla_deassoc;
-	flp->dlci_conf		= sdla_dlci_conf;
-
-	init_timer(&flp->timer);
-	flp->timer.expires	= 1;
-	flp->timer.data		= (unsigned long) dev;
-	flp->timer.function	= sdla_poll;
-
-	return(0);
-}
-
-void __init sdla_setup(void)
-{
-	printk("%s.\n", version);
-	register_frad(devname);
-}
-
-#ifdef MODULE
-static struct net_device sdla0 = {"sdla0", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, sdla_init};
-
-int init_module(void)
-{
-	int result;
-
-	sdla_setup();
-	if ((result = register_netdev(&sdla0)) != 0)
-		return result;
-	return 0;
-}
-
-void cleanup_module(void)
-{
-	unregister_netdev(&sdla0);
-	if (sdla0.priv)
-		kfree(sdla0.priv);
-	if (sdla0.irq)
-		free_irq(sdla0.irq, &sdla0);
-}
-#endif /* MODULE */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/sdla_fr.c linux/drivers/net/sdla_fr.c
--- v2.3.20/linux/drivers/net/sdla_fr.c	Wed Aug 18 11:36:42 1999
+++ linux/drivers/net/sdla_fr.c	Wed Dec 31 16:00:00 1969
@@ -1,3127 +0,0 @@
-/*****************************************************************************
-* sdla_fr.c	WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module.
-*
-* Author(s):	Gene Kozin	
-*		Jaspreet Singh		<jaspreet@sangoma.com>
-*
-* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
-*
-*		This program is free software; you can redistribute it and/or
-*		modify it under the terms of the GNU General Public License
-*		as published by the Free Software Foundation; either version
-*		2 of the License, or (at your option) any later version.
-* ============================================================================
-* Nov 26, 1997	Jaspreet Singh	o Improved load sharing with multiple boards
-*				o Added Cli() to protect enabling of interrupts
-*				  while polling is called.
-* Nov 24, 1997	Jaspreet Singh	o Added counters to avoid enabling of interrupts
-*				  when they have been disabled by another
-*				  interface or routine (eg. wpf_poll).
-* Nov 06, 1997	Jaspreet Singh	o Added INTR_TEST_MODE to avoid polling	
-*				  routine disable interrupts during interrupt
-*				  testing.
-* Oct 20, 1997  Jaspreet Singh  o Added hooks in for Router UP time.
-* Oct 16, 1997  Jaspreet Singh  o The critical flag is used to maintain flow
-*                                 control by avoiding RACE conditions.  The
-*                                 cli() and restore_flags() are taken out.
-*                                 The fr_channel structure is appended for 
-*                                 Driver Statistics.
-* Oct 15, 1997  Farhan Thawar    o updated if_send() and receive for IPX
-* Aug 29, 1997  Farhan Thawar    o Removed most of the cli() and sti()
-*                                o Abstracted the UDP management stuff
-*                                o Now use tbusy and critical more intelligently
-* Jul 21, 1997  Jaspreet Singh	 o Can configure T391, T392, N391, N392 & N393
-*				   through router.conf.
-*				 o Protected calls to sdla_peek() by adDing 
-*				   save_flags(), cli() and restore_flags().
-*				 o Added error message for Inactive DLCIs in
-*				   fr_event() and update_chan_state().
-*				 o Fixed freeing up of buffers using kfree() 
-*			           when packets are received.
-* Jul 07, 1997	Jaspreet Singh	 o Added configurable TTL for UDP packets 
-*				 o Added ability to discard multicast and 
-*				   broadcast source addressed packets
-* Jun 27, 1997	Jaspreet Singh	 o Added FT1 monitor capabilities 
-*				   New case (0x44) statement in if_send routine *				   Added a global variable rCount to keep track
-*			 	   of FT1 status enabled on the board.
-* May 29, 1997	Jaspreet Singh	 o Fixed major Flow Control Problem
-*				   With multiple boards a problem was seen where
-*				   the second board always stopped transmitting
-*				   packet after running for a while. The code
-*				   got into a stage where the interrupts were
-*				   disabled and dev->tbusy was set to 1.
-*                  		   This caused the If_send() routine to get into*                                  the if clause for it(0,dev->tbusy) 
-*				   forever.
-*				   The code got into this stage due to an 
-*				   interrupt occurring within the if clause for 
-*				   set_bit(0,dev->tbusy).  Since an interrupt 
-*				   disables furhter transmit interrupt and 
-* 				   makes dev->tbusy = 0, this effect was undone *                                  by making dev->tbusy = 1 in the if clause.
-*				   The Fix checks to see if Transmit interrupts
-*				   are disabled then do not make dev->tbusy = 1
-* 	   			   Introduced a global variable: int_occur and
-*				   added tx_int_enabled in the wan_device 
-*				   structure.	
-* May 21, 1997  Jaspreet Singh   o Fixed UDP Management for multiple
-*                                  boards.
-*
-* Apr 25, 1997  Farhan Thawar    o added UDP Management stuff
-*                                o fixed bug in if_send() and tx_intr() to
-*                                  sleep and wakeup all devices
-* Mar 11, 1997  Farhan Thawar   Version 3.1.1
-*                                o fixed (+1) bug in fr508_rx_intr()
-*                                o changed if_send() to return 0 if
-*                                  wandev.critical() is true
-*                                o free socket buffer in if_send() if
-*                                  returning 0 
-*                                o added tx_intr() routine
-* Jan 30, 1997	Gene Kozin	Version 3.1.0
-*				 o implemented exec() entry point
-*				 o fixed a bug causing driver configured as
-*				   a FR switch to be stuck in WAN_
-*				   mode
-* Jan 02, 1997	Gene Kozin	Initial version.
-*****************************************************************************/
-
-#include <linux/kernel.h>	/* printk(), and other useful stuff */
-#include <linux/stddef.h>	/* offsetof(), etc. */
-#include <linux/errno.h>	/* return codes */
-#include <linux/string.h>	/* inline memset(), etc. */
-#include <linux/malloc.h>	/* kmalloc(), kfree() */
-#include <linux/wanrouter.h>	/* WAN router definitions */
-#include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
-#include <linux/if_arp.h>	/* ARPHRD_* defines */
-#include <asm/byteorder.h>	/* htons(), etc. */
-#include <asm/io.h>		/* for inb(), outb(), etc. */
-#include <linux/time.h>		/* for do_gettimeofday */
-#define	_GNUC_
-#include <linux/sdla_fr.h>	/* frame relay firmware API definitions */
-#include <asm/uaccess.h>
-
-/****** Defines & Macros ****************************************************/
-
-#define	MAX_CMD_RETRY	10	/* max number of firmware retries */
-#define	FR_HEADER_LEN	8	/* max encapsulation header size */
-#define	FR_CHANNEL_MTU	1500	/* unfragmented logical channel MTU */
-
-/* Q.922 frame types */
-
-#define	Q922_UI		0x03	/* Unnumbered Info frame */
-#define	Q922_XID	0xAF	/* ??? */
-
-/* DLCI configured or not */
-
-#define DLCI_NOT_CONFIGURED	0x00
-#define DLCI_CONFIG_PENDING	0x01
-#define DLCI_CONFIGURED		0x02
-
-/* CIR enabled or not */
-
-#define CIR_ENABLED	0x00
-#define CIR_DISABLED	0x01
-
-/* Interrupt mode for DLCI = 0 */
-
-#define BUFFER_INTR_MODE	0x00
-#define DLCI_LIST_INTR_MODE	0x01
-
-/* Transmit Interrupt Status */
-
-#define DISABLED 		0x00
-#define WAITING_TO_BE_ENABLED	0x01
-
-/* For handle_IPXWAN() */
-
-#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b)))
-
-/****** Data Structures *****************************************************/
-
-/* This is an extention of the 'struct net_device' we create for each network
- * interface to keep the rest of channel-specific data.
- */
-typedef struct fr_channel {
-	char name[WAN_IFNAME_SZ + 1];	/* interface name, ASCIIZ */
-	unsigned dlci_configured;	/* check whether configured or not */
-	unsigned cir_status;	/* check whether CIR enabled or not */
-	unsigned dlci;		/* logical channel number */
-	unsigned cir;		/* committed information rate */
-	unsigned bc;		/* committed burst size */
-	unsigned be;		/* excess burst size */
-	unsigned mc;		/* multicast support on or off */
-	unsigned tx_int_status;	/* Transmit Interrupt Status */
-	unsigned short pkt_length;	/* Packet Length */
-	unsigned long router_start_time;	/* Router start time in seconds */
-	unsigned long tick_counter;	/* counter for transmit time out */
-	char dev_pending_devtint;	/* interface pending dev_tint() */
-	char state;		/* channel state */
-	void *dlci_int_interface;	/* pointer to the DLCI Interface */
-	unsigned long IB_addr;	/* physical address of Interface Byte */
-	unsigned long state_tick;	/* time of the last state change */
-	sdla_t *card;		/* -> owner */
-	struct net_device_stats ifstats;		/* interface statistics */
-	unsigned long if_send_entry;
-	unsigned long if_send_skb_null;
-	unsigned long if_send_broadcast;
-	unsigned long if_send_multicast;
-	unsigned long if_send_critical_ISR;
-	unsigned long if_send_critical_non_ISR;
-	unsigned long if_send_busy;
-	unsigned long if_send_busy_timeout;
-	unsigned long if_send_FPIPE_request;
-	unsigned long if_send_DRVSTATS_request;
-	unsigned long if_send_wan_disconnected;
-	unsigned long if_send_dlci_disconnected;
-	unsigned long if_send_no_bfrs;
-	unsigned long if_send_adptr_bfrs_full;
-	unsigned long if_send_bfrs_passed_to_adptr;
-	unsigned long rx_intr_no_socket;
-	unsigned long rx_intr_dev_not_started;
-	unsigned long rx_intr_FPIPE_request;
-	unsigned long rx_intr_DRVSTATS_request;
-	unsigned long rx_intr_bfr_not_passed_to_stack;
-	unsigned long rx_intr_bfr_passed_to_stack;
-	unsigned long UDP_FPIPE_mgmt_kmalloc_err;
-	unsigned long UDP_FPIPE_mgmt_direction_err;
-	unsigned long UDP_FPIPE_mgmt_adptr_type_err;
-	unsigned long UDP_FPIPE_mgmt_adptr_cmnd_OK;
-	unsigned long UDP_FPIPE_mgmt_adptr_cmnd_timeout;
-	unsigned long UDP_FPIPE_mgmt_adptr_send_passed;
-	unsigned long UDP_FPIPE_mgmt_adptr_send_failed;
-	unsigned long UDP_FPIPE_mgmt_not_passed_to_stack;
-	unsigned long UDP_FPIPE_mgmt_passed_to_stack;
-	unsigned long UDP_FPIPE_mgmt_no_socket;
-	unsigned long UDP_DRVSTATS_mgmt_kmalloc_err;
-	unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
-	unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
-	unsigned long UDP_DRVSTATS_mgmt_adptr_send_passed;
-	unsigned long UDP_DRVSTATS_mgmt_adptr_send_failed;
-	unsigned long UDP_DRVSTATS_mgmt_not_passed_to_stack;
-	unsigned long UDP_DRVSTATS_mgmt_passed_to_stack;
-	unsigned long UDP_DRVSTATS_mgmt_no_socket;
-	unsigned long router_up_time;
-} fr_channel_t;
-
-typedef struct dlci_status {
-	unsigned short dlci PACKED;
-	unsigned char state PACKED;
-} dlci_status_t;
-
-typedef struct dlci_IB_mapping {
-	unsigned short dlci PACKED;
-	unsigned long addr_value PACKED;
-} dlci_IB_mapping_t;
-
-/* This structure is used for DLCI list Tx interrupt mode.  It is used to
-   enable interrupt bit and set the packet length for transmission
- */
-
-typedef struct fr_dlci_interface {
-	unsigned char gen_interrupt PACKED;
-	unsigned short packet_length PACKED;
-	unsigned char reserved PACKED;
-} fr_dlci_interface_t;
-
-static unsigned short num_frames;
-static unsigned long curr_trace_addr;
-static unsigned long start_trace_addr;
-static unsigned short available_buffer_space;
-static char TracingEnabled; /* variable for keeping track of enabling/disabling FT1 monitor status */
-static int rCount = 0;
-extern void disable_irq(unsigned int);
-extern void enable_irq(unsigned int);
-
-/* variable for keeping track of number of interrupts generated during 
- * interrupt test routine 
- */
-static int Intr_test_counter;
-
-/****** Function Prototypes *************************************************/
-
-/* WAN link driver entry points. These are called by the WAN router module. */
-static int update(wan_device_t * wandev);
-static int new_if(wan_device_t * wandev, struct net_device *dev,
-		  wanif_conf_t * conf);
-static int del_if(wan_device_t * wandev, struct net_device *dev);
-/* WANPIPE-specific entry points */
-static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data);
-/* Network device interface */
-static int if_init(struct net_device *dev);
-static int if_open(struct net_device *dev);
-static int if_close(struct net_device *dev);
-static int if_header(struct sk_buff *skb, struct net_device *dev,
-	    unsigned short type, void *daddr, void *saddr, unsigned len);
-static int if_rebuild_hdr(struct sk_buff *skb);
-static int if_send(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *if_stats(struct net_device *dev);
-/* Interrupt handlers */
-static void fr502_isr(sdla_t * card);
-static void fr508_isr(sdla_t * card);
-static void fr502_rx_intr(sdla_t * card);
-static void fr508_rx_intr(sdla_t * card);
-static void tx_intr(sdla_t * card);
-static void spur_intr(sdla_t * card);
-/* Background polling routines */
-static void wpf_poll(sdla_t * card);
-/* Frame relay firmware interface functions */
-static int fr_read_version(sdla_t * card, char *str);
-static int fr_configure(sdla_t * card, fr_conf_t * conf);
-static int fr_dlci_configure(sdla_t * card, fr_dlc_conf_t * conf, unsigned dlci);
-static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu);
-static int fr_comm_enable(sdla_t * card);
-static int fr_comm_disable(sdla_t * card);
-static int fr_get_err_stats(sdla_t * card);
-static int fr_get_stats(sdla_t * card);
-static int fr_add_dlci(sdla_t * card, int dlci, int num);
-static int fr_activate_dlci(sdla_t * card, int dlci, int num);
-static int fr_issue_isf(sdla_t * card, int isf);
-static int fr502_send(sdla_t * card, int dlci, int attr, int len, void *buf);
-static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf);
-/* Firmware asynchronous event handlers */
-static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox);
-static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox);
-static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox);
-/* Miscellaneous functions */
-static int update_chan_state(struct net_device *dev);
-static void set_chan_state(struct net_device *dev, int state);
-static struct net_device *find_channel(sdla_t * card, unsigned dlci);
-static int is_tx_ready(sdla_t * card, fr_channel_t * chan);
-static unsigned int dec_to_uint(unsigned char *str, int len);
-static int reply_udp(unsigned char *data, unsigned int mbox_len);
-static int intr_test(sdla_t * card);
-static void init_chan_statistics(fr_channel_t * chan);
-static void init_global_statistics(sdla_t * card);
-static void read_DLCI_IB_mapping(sdla_t * card, fr_channel_t * chan);
-/* Udp management functions */
-static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, int dlci, fr_channel_t * chan);
-static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, int dlci, fr_channel_t * chan);
-static int udp_pkt_type(struct sk_buff *skb, sdla_t * card);
-/* IPX functions */
-static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming);
-static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number);
-
-/****** Public Functions ****************************************************/
-
-/*============================================================================
- * Frame relay protocol initialization routine.
- *
- * This routine is called by the main WANPIPE module during setup.  At this
- * point adapter is completely initialized and firmware is running.
- *  o read firmware version (to make sure it's alive)
- *  o configure adapter
- *  o initialize protocol-specific fields of the adapter data space.
- *
- * Return:	0	o.k.
- *		< 0	failure.
- */
-int wpf_init(sdla_t * card, wandev_conf_t * conf)
-{
-	union {
-		char str[80];
-		fr_conf_t cfg;
-	} u;
-	int i;
-	/* Verify configuration ID */
-	if (conf->config_id != WANCONFIG_FR) 
-	{
-		printk(KERN_INFO "%s: invalid configuration ID %u!\n",
-		       card->devname, conf->config_id);
-		return -EINVAL;
-	}
-	/* Initialize protocol-specific fields of adapter data space */
-	switch (card->hw.fwid) 
-	{
-		case SFID_FR502:
-			card->mbox = (void *) (card->hw.dpmbase + FR502_MBOX_OFFS);
-			card->rxmb = (void *) (card->hw.dpmbase + FR502_RXMB_OFFS);
-			card->flags = (void *) (card->hw.dpmbase + FR502_FLAG_OFFS);
-			card->isr = &fr502_isr;
-			break;
-		case SFID_FR508:
-			card->mbox = (void *) (card->hw.dpmbase + FR508_MBOX_OFFS);
-			card->flags = (void *) (card->hw.dpmbase + FR508_FLAG_OFFS);
-			card->isr = &fr508_isr;
-			break;
-		default:
-			return -EINVAL;
-	}
-	/* Read firmware version.  Note that when adapter initializes, it
-	 * clears the mailbox, so it may appear that the first command was
-	 * executed successfully when in fact it was merely erased. To work
-	 * around this, we execute the first command twice.
-	 */
-	if (fr_read_version(card, NULL) || fr_read_version(card, u.str))
-		return -EIO;
-	printk(KERN_INFO "%s: running frame relay firmware v%s\n",
-	       card->devname, u.str);
-	/* Adjust configuration */
-	conf->mtu = max(min(conf->mtu, 4080), FR_CHANNEL_MTU + FR_HEADER_LEN);
-	conf->bps = min(conf->bps, 2048000);
-	/* Configure adapter firmware */
-	memset(&u.cfg, 0, sizeof(u.cfg));
-	u.cfg.mtu = conf->mtu;
-	u.cfg.kbps = conf->bps / 1000;
-	u.cfg.cir_fwd = u.cfg.cir_bwd = 16;
-	u.cfg.bc_fwd = u.cfg.bc_bwd = 16;
-	if (conf->station == WANOPT_CPE) 
-	{
-		u.cfg.options = 0x0080;
-		printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname);
-	}
-	else
-	{
-		u.cfg.options = 0x0081;
-	}
-	switch (conf->u.fr.signalling) 
-	{
-		case WANOPT_FR_Q933:
-			u.cfg.options |= 0x0200;
-			break;
-		case WANOPT_FR_LMI:
-			u.cfg.options |= 0x0400;
-			break;
-	}
-	if (conf->station == WANOPT_CPE) 
-	{
-		u.cfg.options |= 0x8000;	/* auto config DLCI */
-		card->u.f.dlci_num = 0;
-	}
-	else
-	{
-		u.cfg.station = 1;	/* switch emulation mode */
-		/* For switch emulation we have to create a list of dlci(s)
-		 * that will be sent to be global SET_DLCI_CONFIGURATION 
-		 * command in fr_configure() routine. 
-		 */
-		card->u.f.dlci_num = min(max(conf->u.fr.dlci_num, 1), 100);
-		for (i = 0; i < card->u.f.dlci_num; i++) 
-		{
-			card->u.f.node_dlci[i] = (unsigned short)
-			    conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16;
-		}
-	}
-	if (conf->clocking == WANOPT_INTERNAL)
-		u.cfg.port |= 0x0001;
-	if (conf->interface == WANOPT_RS232)
-		u.cfg.port |= 0x0002;
-	if (conf->u.fr.t391)
-		u.cfg.t391 = min(conf->u.fr.t391, 30);
-	else
-		u.cfg.t391 = 5;
-	if (conf->u.fr.t392)
-		u.cfg.t392 = min(conf->u.fr.t392, 30);
-	else
-		u.cfg.t392 = 15;
-	if (conf->u.fr.n391)
-		u.cfg.n391 = min(conf->u.fr.n391, 255);
-	else
-		u.cfg.n391 = 2;
-	if (conf->u.fr.n392)
-		u.cfg.n392 = min(conf->u.fr.n392, 10);
-	else
-		u.cfg.n392 = 3;
-	if (conf->u.fr.n393)
-		u.cfg.n393 = min(conf->u.fr.n393, 10);
-	else
-		u.cfg.n393 = 4;
-	if (fr_configure(card, &u.cfg))
-		return -EIO;
-	if (card->hw.fwid == SFID_FR508) 
-	{
-		fr_buf_info_t *buf_info =
-		(void *) (card->hw.dpmbase + FR508_RXBC_OFFS);
-		card->rxmb = (void *) (buf_info->rse_next - FR_MB_VECTOR + card->hw.dpmbase);
-		card->u.f.rxmb_base = (void *) (buf_info->rse_base - FR_MB_VECTOR + card->hw.dpmbase);
-		card->u.f.rxmb_last = (void *) (buf_info->rse_base + (buf_info->rse_num - 1) * 
-				sizeof(fr_buf_ctl_t) - FR_MB_VECTOR + card->hw.dpmbase);
-		card->u.f.rx_base = buf_info->buf_base;
-		card->u.f.rx_top = buf_info->buf_top;
-	}
-	card->wandev.mtu = conf->mtu;
-	card->wandev.bps = conf->bps;
-	card->wandev.interface = conf->interface;
-	card->wandev.clocking = conf->clocking;
-	card->wandev.station = conf->station;
-	card->poll = &wpf_poll;
-	card->exec = &wpf_exec;
-	card->wandev.update = &update;
-	card->wandev.new_if = &new_if;
-	card->wandev.del_if = &del_if;
-	card->wandev.state = WAN_DISCONNECTED;
-	card->wandev.ttl = conf->ttl;
-	card->wandev.udp_port = conf->udp_port;
-	card->wandev.enable_tx_int = 0;
-	card->irq_dis_if_send_count = 0;
-	card->irq_dis_poll_count = 0;
-	card->wandev.enable_IPX = conf->enable_IPX;
-	if (conf->network_number)
-		card->wandev.network_number = conf->network_number;
-	else
-		card->wandev.network_number = 0xDEADBEEF;
-	/* Intialize global statistics for a card */
-	init_global_statistics(card);
-	TracingEnabled = 0;
-	return 0;
-}
-
-/******* WAN Device Driver Entry Points *************************************/
-
-/*============================================================================
- * Update device status & statistics.
- */
-
-static int update(wan_device_t * wandev)
-{
-	sdla_t *card;
-	/* sanity checks */
-	if ((wandev == NULL) || (wandev->private == NULL))
-		return -EFAULT;
-	if (wandev->state == WAN_UNCONFIGURED)
-		return -ENODEV;
-	if (test_and_set_bit(0, (void *) &wandev->critical))
-		return -EAGAIN;
-	card = wandev->private;
-	fr_get_err_stats(card);
-	fr_get_stats(card);
-	wandev->critical = 0;
-	return 0;
-}
-
-/*============================================================================
- * Create new logical channel.
- * This routine is called by the router when ROUTER_IFNEW IOCTL is being
- * handled.
- * o parse media- and hardware-specific configuration
- * o make sure that a new channel can be created
- * o allocate resources, if necessary
- * o prepare network device structure for registaration.
- *
- * Return:	0	o.k.
- *		< 0	failure (channel will not be created)
- */
-
-static int new_if(wan_device_t * wandev, struct net_device *dev, wanif_conf_t * conf)
-{
-	sdla_t *card = wandev->private;
-	fr_channel_t *chan;
-	int err = 0;
-	if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) 
-	{
-		printk(KERN_INFO "%s: invalid interface name!\n",
-		       card->devname);
-		return -EINVAL;
-	}
-	/* allocate and initialize private data */
-	chan = kmalloc(sizeof(fr_channel_t), GFP_KERNEL);
-	if (chan == NULL)
-		return -ENOMEM;
-	memset(chan, 0, sizeof(fr_channel_t));
-	strcpy(chan->name, conf->name);
-	chan->card = card;
-	/* verify media address */
-	if (is_digit(conf->addr[0])) 
-	{
-		int dlci = dec_to_uint(conf->addr, 0);
-		if (dlci && (dlci <= 4095)) 
-		{
-			chan->dlci = dlci;
-		}
-		else
-		{
-			printk(KERN_ERR "%s: invalid DLCI %u on interface %s!\n",
-			       wandev->name, dlci, chan->name);
-			err = -EINVAL;
-		}
-	} 
-	else 
-	{
-		printk(KERN_ERR "%s: invalid media address on interface %s!\n",
-		       wandev->name, chan->name);
-		err = -EINVAL;
-	}
-	if (err) 
-	{
-		kfree(chan);
-		return err;
-	}
-	/* place cir,be,bc and other channel specific information into the
-	 * chan structure 
-	 */
-	if (conf->cir) 
-	{
-		chan->cir = max(1, min(conf->cir, 512));
-		chan->cir_status = CIR_ENABLED;
-		if (conf->bc)
-			chan->bc = max(1, min(conf->bc, 512));
-		if (conf->be)
-			chan->be = max(0, min(conf->be, 511));
-	}
-	else
-		chan->cir_status = CIR_DISABLED;
-	chan->mc = conf->mc;
-	chan->dlci_configured = DLCI_NOT_CONFIGURED;
-	chan->tx_int_status = DISABLED;
-	init_chan_statistics(chan);
-	/* prepare network device data space for registration */
-	dev->name = chan->name;
-	dev->init = &if_init;
-	dev->priv = chan;
-	return 0;
-}
-/*============================================================================
- * Delete logical channel.
- */
-static int del_if(wan_device_t * wandev, struct net_device *dev)
-{
-	if (dev->priv) 
-	{
-		kfree(dev->priv);
-		dev->priv = NULL;
-	}
-	return 0;
-}
-
-/****** WANPIPE-specific entry points ***************************************/
-
-/*============================================================================
- * Execute adapter interface command.
- */
-static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data)
-{
-	fr_mbox_t *mbox = card->mbox;
-	int retry = MAX_CMD_RETRY;
-	int err, len;
-	fr_cmd_t cmd;
-	if(copy_from_user((void *) &cmd, u_cmd, sizeof(cmd)))
-		return -EFAULT;		
-	/* execute command */
-	do 
-	{
-		memcpy(&mbox->cmd, &cmd, sizeof(cmd));
-		if (cmd.length)
-		{
-			if(copy_from_user((void *) &mbox->data, u_data, cmd.length))
-				return -EFAULT;
-		}
-		if (sdla_exec(mbox))
-			err = mbox->cmd.result;
-		else
-			return -EIO;
-	} 
-	while (err && retry-- && fr_event(card, err, mbox));
-
-	/* return result */
-
-	if(copy_to_user(u_cmd, (void *) &mbox->cmd, sizeof(fr_cmd_t)))
-		return -EFAULT;
-	len = mbox->cmd.length;
-	if (len && u_data && copy_to_user(u_data, (void *) &mbox->data, len))
-		return -EFAULT;
-	return 0;
-}
-
-/****** Network Device Interface ********************************************/
-/*============================================================================
- * Initialize Linux network interface.
- *
- * This routine is called only once for each interface, during Linux network
- * interface registration.  Returning anything but zero will fail interface
- * registration.
- */
-static int if_init(struct net_device *dev)
-{
-	fr_channel_t *chan = dev->priv;
-	sdla_t *card = chan->card;
-	wan_device_t *wandev = &card->wandev;
-
-	/* Initialize device driver entry points */
-	dev->open = &if_open;
-	dev->stop = &if_close;
-	dev->hard_header = &if_header;
-	dev->rebuild_header = &if_rebuild_hdr;
-	dev->hard_start_xmit = &if_send;
-	dev->get_stats = &if_stats;
-	/* Initialize media-specific parameters */
-	dev->type = ARPHRD_DLCI;			/* ARP h/w type */
-	dev->mtu = FR_CHANNEL_MTU;
-	dev->hard_header_len = FR_HEADER_LEN;		/* media header length */
-	dev->addr_len = 2;				/* hardware address length */
-	*(unsigned short *) dev->dev_addr = htons(chan->dlci);
-	/* Initialize hardware parameters (just for reference) */
-	dev->irq = wandev->irq;
-	dev->dma = wandev->dma;
-	dev->base_addr = wandev->ioport;
-	dev->mem_start = (unsigned long)wandev->maddr;
-	dev->mem_end = dev->mem_start + wandev->msize - 1;
-	/* Set transmit buffer queue length */
-	dev->tx_queue_len = 10;
-	/* Initialize socket buffers */
-	dev_init_buffers(dev);
-	set_chan_state(dev, WAN_DISCONNECTED);
-	return 0;
-}
-
-/*============================================================================
- * Open network interface.
- * o if this is the first open, then enable communications and interrupts.
- * o prevent module from unloading by incrementing use count
- *
- * Return 0 if O.k. or errno.
- */
-
-static int if_open(struct net_device *dev)
-{
-	fr_channel_t *chan = dev->priv;
-	sdla_t *card = chan->card;
-	struct net_device *dev2;
-	int err = 0;
-	fr508_flags_t *flags = card->flags;
-	struct timeval tv;
-	if (dev->start)
-		return -EBUSY;	/* only one open is allowed */
-	if (test_and_set_bit(0, (void *) &card->wandev.critical))
-		return -EAGAIN;
-	if (!card->open_cnt) 
-	{
-		Intr_test_counter = 0;
-		card->intr_mode = INTR_TEST_MODE;
-		err = intr_test(card);
-		if ((err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) {
-			printk(KERN_INFO
-			       "%s: Interrupt Test Failed, Counter: %i\n",
-			       card->devname, Intr_test_counter);
-			err = -EIO;
-			card->wandev.critical = 0;
-			return err;
-		}
-		printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n"
-		       ,card->devname, Intr_test_counter);
-		/* The following allocates and intializes a circular
-		 * link list of interfaces per card.
-		 */
-		card->devs_struct = kmalloc(sizeof(load_sharing_t), GFP_KERNEL);
-		if (card->devs_struct == NULL)
-			return -ENOMEM;
-		card->dev_to_devtint_next = card->devs_struct;
-		for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) {
-			(card->devs_struct)->dev_ptr = dev2;
-			if (dev2->slave == NULL)
-				(card->devs_struct)->next = card->dev_to_devtint_next;
-			else {
-				(card->devs_struct)->next = kmalloc(
-				     sizeof(load_sharing_t), GFP_KERNEL);
-				if ((card->devs_struct)->next == NULL)
-					return -ENOMEM;
-				card->devs_struct = (card->devs_struct)->next;
-			}
-		}
-		card->devs_struct = card->dev_to_devtint_next;
-		card->intr_mode = BUFFER_INTR_MODE;
-		/* 
-		   check all the interfaces for the device to see if CIR has
-		   been enabled for any DLCI(s). If so then use the DLCI list
-		   Interrupt mode for fr_set_intr_mode(), otherwise use the                     default global interrupt mode
-		 */
-		for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) {
-			if (((fr_channel_t *) dev2->priv)->cir_status
-			    == CIR_ENABLED) {
-				card->intr_mode = DLCI_LIST_INTR_MODE;
-				break;
-			}
-		}
-		/* 
-		   If you enable comms and then set ints, you get a Tx int as you
-		   perform the SET_INT_TRIGGERS command. So, we only set int
-		   triggers and then adjust the interrupt mask (to disable Tx ints)             before enabling comms. 
-		 */
-		if (card->intr_mode == BUFFER_INTR_MODE) {
-			if (fr_set_intr_mode(card, 0x03, card->wandev.mtu)) {
-				err = -EIO;
-				card->wandev.critical = 0;
-				return err;
-			}
-			printk(KERN_INFO
-			       "%s: Global Buffering Tx Interrupt Mode\n"
-			       ,card->devname);
-		} else if (card->intr_mode == DLCI_LIST_INTR_MODE) {
-			if (fr_set_intr_mode(card, 0x83, card->wandev.mtu)) {
-				err = -EIO;
-				card->wandev.critical = 0;
-				return err;
-			}
-			printk(KERN_INFO
-			       "%s: DLCI list Tx Interrupt Mode\n",
-			       card->devname);
-		}
-		flags->imask &= ~0x02;
-		if (fr_comm_enable(card)) {
-			err = -EIO;
-			card->wandev.critical = 0;
-			return err;
-		}
-		wanpipe_set_state(card, WAN_CONNECTED);
-		if (card->wandev.station == WANOPT_CPE) {
-			/* CPE: issue full status enquiry */
-			fr_issue_isf(card, FR_ISF_FSE);
-		} else {	/* FR switch: activate DLCI(s) */
-			/* For Switch emulation we have to ADD and ACTIVATE
-			 * the DLCI(s) that were configured with the SET_DLCI_
-			 * CONFIGURATION command. Add and Activate will fail if
-			 * DLCI specified is not included in the list.
-			 *
-			 * Also If_open is called once for each interface. But
-			 * it does not get in here for all the interface. So
-			 * we have to pass the entire list of DLCI(s) to add 
-			 * activate routines.  
-			 */
-			fr_add_dlci(card,
-			     card->u.f.node_dlci[0], card->u.f.dlci_num);
-			fr_activate_dlci(card,
-			     card->u.f.node_dlci[0], card->u.f.dlci_num);
-		}
-	}
-	dev->mtu = min(dev->mtu, card->wandev.mtu - FR_HEADER_LEN);
-	dev->interrupt = 0;
-	dev->tbusy = 0;
-	dev->start = 1;
-	wanpipe_open(card);
-	update_chan_state(dev);
-	do_gettimeofday(&tv);
-	chan->router_start_time = tv.tv_sec;
-	card->wandev.critical = 0;
-	return err;
-}
-
-/*============================================================================
- * Close network interface.
- * o if this is the last open, then disable communications and interrupts.
- * o reset flags.
- */
-
-static int if_close(struct net_device *dev)
-{
-	fr_channel_t *chan = dev->priv;
-	sdla_t *card = chan->card;
-	if (test_and_set_bit(0, (void *) &card->wandev.critical))
-		return -EAGAIN;
-	dev->start = 0;
-	wanpipe_close(card);
-	if (!card->open_cnt) 
-	{
-		wanpipe_set_state(card, WAN_DISCONNECTED);
-		fr_set_intr_mode(card, 0, 0);
-		fr_comm_disable(card);
-	}
-	card->wandev.critical = 0;
-	return 0;
-}
-
-/*============================================================================
- * Build media header.
- * o encapsulate packet according to encapsulation type.
- *
- * The trick here is to put packet type (Ethertype) into 'protocol' field of
- * the socket buffer, so that we don't forget it.  If encapsulation fails,
- * set skb->protocol to 0 and discard packet later.
- *
- * Return:	media header length.
- */
-
-static int if_header(struct sk_buff *skb, struct net_device *dev,
-	     unsigned short type, void *daddr, void *saddr, unsigned len)
-{
-	int hdr_len = 0;
-	skb->protocol = type;
-	hdr_len = wanrouter_encapsulate(skb, dev);
-	if (hdr_len < 0) 
-	{
-		hdr_len = 0;
-		skb->protocol = 0;
-	}
-	skb_push(skb, 1);
-	skb->data[0] = Q922_UI;
-	++hdr_len;
-	return hdr_len;
-}
-
-/*============================================================================
- * Re-build media header.
- *
- * Return:	1	physical address resolved.
- *		0	physical address not resolved
- */
-
-static int if_rebuild_hdr(struct sk_buff *skb)
-{
-	struct net_device *dev=skb->dev;
-	fr_channel_t *chan = dev->priv;
-	sdla_t *card = chan->card;
-	printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
-	       card->devname, dev->name);
-	return 1;
-}
-
-/*============================================================================
- * Send a packet on a network interface.
- * o set tbusy flag (marks start of the transmission) to block a timer-based
- *   transmit from overlapping.
- * o check link state. If link is not up, then drop the packet.
- * o check channel status. If it's down then initiate a call.
- * o pass a packet to corresponding WAN device.
- * o free socket buffer
- *
- * Return:	0	complete (socket buffer must be freed)
- *		non-0	packet may be re-transmitted (tbusy must be set)
- *
- * Notes:
- * 1. This routine is called either by the protocol stack or by the "net
- *    bottom half" (with interrupts enabled).
- * 2. Setting tbusy flag will inhibit further transmit requests from the
- *    protocol stack and can be used for flow control with protocol layer.
- */
-
-static int if_send(struct sk_buff *skb, struct net_device *dev)
-{
-	fr_channel_t *chan = dev->priv;
-	sdla_t *card = chan->card;
-	int retry = 0, err;
-	unsigned char *sendpacket;
-	struct net_device *dev2;
-	unsigned long check_braddr, check_mcaddr;
-	fr508_flags_t *adptr_flags = card->flags;
-	int udp_type, send_data;
-	fr_dlci_interface_t *dlci_interface = chan->dlci_int_interface;
-	unsigned long host_cpu_flags;
-	++chan->if_send_entry;
-
-	if (dev->tbusy) 
-	{
-		/* If our device stays busy for at least 5 seconds then we will
-		 * kick start the device by making dev->tbusy = 0.  We expect
-		 * that our device never stays busy more than 5 seconds. So this                 * is only used as a last resort.
-		 */
-		++chan->if_send_busy;
-		++chan->ifstats.collisions;
-		if ((jiffies - chan->tick_counter) < (5 * HZ))
-			return 1;
-
-		printk(KERN_INFO "%s: Transmit timed out\n", chan->name);
-		++chan->if_send_busy_timeout;
-		/* unbusy all the interfaces on the card */
-		for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave)
-			dev2->tbusy = 0;
-	}
-	sendpacket = skb->data;
-	udp_type = udp_pkt_type(skb, card);
-	if (udp_type == UDP_DRVSTATS_TYPE) 
-	{
-		++chan->if_send_DRVSTATS_request;
-		process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev, 0,
-					chan);
-		dev_kfree_skb(skb);
-		return 0;
-	}
-	else if (udp_type == UDP_FPIPE_TYPE)
-		++chan->if_send_FPIPE_request;
-	/* retreive source address in two forms: broadcast & multicast */
-	check_braddr = sendpacket[17];
-	check_mcaddr = sendpacket[14];
-	check_braddr = check_braddr << 8;
-	check_mcaddr = check_mcaddr << 8;
-	check_braddr |= sendpacket[16];
-	check_mcaddr |= sendpacket[15];
-	check_braddr = check_braddr << 8;
-	check_mcaddr = check_mcaddr << 8;
-	check_braddr |= sendpacket[15];
-	check_mcaddr |= sendpacket[16];
-	check_braddr = check_braddr << 8;
-	check_mcaddr = check_mcaddr << 8;
-	check_braddr |= sendpacket[14];
-	check_mcaddr |= sendpacket[17];
-	/* if the Source Address is a Multicast address */
-	if ((chan->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001) &&
-	    (check_mcaddr <= 0xFFFFFFFE)) 
-	{
-		printk(KERN_INFO "%s: Multicast Src. Addr. silently discarded\n"
-		       ,card->devname);
-		dev_kfree_skb(skb);
-		++chan->ifstats.tx_dropped;
-		++chan->if_send_multicast;
-		return 0;
-	}
-	disable_irq(card->hw.irq);
-	++card->irq_dis_if_send_count;
-	if (test_and_set_bit(0, (void *) &card->wandev.critical)) 
-	{
-		if (card->wandev.critical == CRITICAL_IN_ISR) 
-		{
-			++chan->if_send_critical_ISR;
-			if (card->intr_mode == DLCI_LIST_INTR_MODE) 
-			{
-				/* The enable_tx_int flag is set here so that if
-				 * the critical flag is set due to an interrupt 
-				 * then we want to enable transmit interrupts 
-				 * again.
-				 */
-				card->wandev.enable_tx_int = 1;
-				/* Setting this flag to WAITING_TO_BE_ENABLED 
-				 * specifies that interrupt bit has to be 
-				 * enabled for that particular interface. 
-				 * (delayed interrupt)
-				 */
-				chan->tx_int_status = WAITING_TO_BE_ENABLED;
-				/* This is used for enabling dynamic calculation
-				 * of CIRs relative to the packet length.
-				 */
-				chan->pkt_length = skb->len;
-				dev->tbusy = 1;
-				chan->tick_counter = jiffies;
-			}
-			else
-			{
-				card->wandev.enable_tx_int = 1;
-				dev->tbusy = 1;
-				chan->tick_counter = jiffies;
-			}
-			save_flags(host_cpu_flags);
-			cli();
-			if ((!(--card->irq_dis_if_send_count)) &&
-			    (!card->irq_dis_poll_count))
-				enable_irq(card->hw.irq);
-			restore_flags(host_cpu_flags);
-			return 1;
-		}
-		++chan->if_send_critical_non_ISR;
-		++chan->ifstats.tx_dropped;
-		dev_kfree_skb(skb);
-		save_flags(host_cpu_flags);
-		cli();
-		if ((!(--card->irq_dis_if_send_count)) &&
-		    (!card->irq_dis_poll_count))
-			enable_irq(card->hw.irq);
-		restore_flags(host_cpu_flags);
-		return 0;
-	}
-	card->wandev.critical = 0x21;
-	if (udp_type == UDP_FPIPE_TYPE) 
-	{
-		err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb,
-					   dev, 0, chan);
-	}
-	else if (card->wandev.state != WAN_CONNECTED) 
-	{
-		++chan->if_send_wan_disconnected;
-		++chan->ifstats.tx_dropped;
-		++card->wandev.stats.tx_dropped;
-	}
-	else if (chan->state != WAN_CONNECTED) 
-	{
-		++chan->if_send_dlci_disconnected;
-		update_chan_state(dev);
-		++chan->ifstats.tx_dropped;
-		++card->wandev.stats.tx_dropped;
-	}
-	else if (!is_tx_ready(card, chan)) 
-	{
-		if (card->intr_mode == DLCI_LIST_INTR_MODE) 
-		{
-			dlci_interface->gen_interrupt |= 0x40;
-			dlci_interface->packet_length = skb->len;
-		}
-		dev->tbusy = 1;
-		chan->tick_counter = jiffies;
-		adptr_flags->imask |= 0x02;
-		++chan->if_send_no_bfrs;
-		retry = 1;
-	}
-	else
-	{
-		send_data = 1;
-		/* If it's an IPX packet */
-		if (sendpacket[1] == 0x00 &&
-		    sendpacket[2] == 0x80 &&
-		    sendpacket[6] == 0x81 &&
-		    sendpacket[7] == 0x37) 
-		{
-			if (card->wandev.enable_IPX) 
-			{
-				switch_net_numbers(sendpacket,
-					 card->wandev.network_number, 0);
-			} 
-			else 
-			{
-				/* increment some statistic here! */
-				send_data = 0;
-			}
-		}
-		if (send_data) 
-		{
-			err = (card->hw.fwid == SFID_FR508) ?
-			    fr508_send(card, chan->dlci, 0, skb->len, skb->data) :
-			    fr502_send(card, chan->dlci, 0, skb->len, skb->data);
-			if (err) 
-			{
-				if (card->intr_mode == DLCI_LIST_INTR_MODE) 
-				{
-					dlci_interface->gen_interrupt |= 0x40;
-					dlci_interface->packet_length = skb->len;
-				}
-				dev->tbusy = 1;
-				chan->tick_counter = jiffies;
-				adptr_flags->imask |= 0x02;
-				retry = 1;
-				++chan->if_send_adptr_bfrs_full;
-				++chan->ifstats.tx_errors;
-				++card->wandev.stats.tx_errors;
-			}
-			else 
-			{
-				++chan->if_send_bfrs_passed_to_adptr;
-				++chan->ifstats.tx_packets;
-				++card->wandev.stats.tx_packets;
-				chan->ifstats.tx_bytes += skb->len;
-				card->wandev.stats.tx_bytes += skb->len;
-			}
-		}
-	}
-	if (!retry)
-		dev_kfree_skb(skb);
-
-	card->wandev.critical = 0;
-	save_flags(host_cpu_flags);
-	cli();
-	if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count))
-		enable_irq(card->hw.irq);
-	restore_flags(host_cpu_flags);
-	return retry;
-}
-
-/*============================================================================
- * Reply to UDP Management system.
- * Return nothing.
- */
-
-static int reply_udp(unsigned char *data, unsigned int mbox_len)
-{
-	unsigned short len, udp_length, temp, i, ip_length;
-	unsigned long sum;
-	/* Set length of packet */
-	len = mbox_len + 62;
-	/* fill in UDP reply */
-	data[38] = 0x02;
-	/* fill in UDP length */
-	udp_length = mbox_len + 40;
-	/* put it on an even boundary */
-	if (udp_length & 0x0001) 
-	{
-		udp_length += 1;
-		len += 1;
-	}
-	temp = (udp_length << 8) | (udp_length >> 8);
-	memcpy(&data[26], &temp, 2);
-	/* swap UDP ports */
-	memcpy(&temp, &data[22], 2);
-	memcpy(&data[22], &data[24], 2);
-	memcpy(&data[24], &temp, 2);
-	/* add UDP pseudo header */
-	temp = 0x1100;
-	memcpy(&data[udp_length + 22], &temp, 2);
-	temp = (udp_length << 8) | (udp_length >> 8);
-	memcpy(&data[udp_length + 24], &temp, 2);
-	/* calculate UDP checksum */
-	data[28] = data[29] = 0;
-	sum = 0;
-	for (i = 0; i < udp_length + 12; i += 2) 
-	{
-		memcpy(&temp, &data[14 + i], 2);
-		sum += (unsigned long) temp;
-	}
-	while (sum >> 16)
-		sum = (sum & 0xffffUL) + (sum >> 16);
-
-	temp = (unsigned short) sum;
-	temp = ~temp;
-	if (temp == 0)
-		temp = 0xffff;
-	memcpy(&data[28], &temp, 2);
-	/* fill in IP length */
-	ip_length = udp_length + 20;
-	temp = (ip_length << 8) | (ip_length >> 8);
-	memcpy(&data[4], &temp, 2);
-	/* swap IP addresses */
-	memcpy(&temp, &data[14], 2);
-	memcpy(&data[14], &data[18], 2);
-	memcpy(&data[18], &temp, 2);
-	memcpy(&temp, &data[16], 2);
-	memcpy(&data[16], &data[20], 2);
-	memcpy(&data[20], &temp, 2);
-	/* fill in IP checksum */
-	data[12] = data[13] = 0;
-	sum = 0;
-	for (i = 0; i < 20; i += 2) 
-	{
-		memcpy(&temp, &data[2 + i], 2);
-		sum += (unsigned long) temp;
-	}
-	while (sum >> 16)
-		sum = (sum & 0xffffUL) + (sum >> 16);
-	temp = (unsigned short) sum;
-	temp = ~temp;
-	if (temp == 0)
-		temp = 0xffff;
-	memcpy(&data[12], &temp, 2);
-	return len;
-}				/* reply_udp */
-/*
-   If incoming is 0 (outgoing)- if the net numbers is ours make it 0
-   if incoming is 1 - if the net number is 0 make it ours 
- */
-
-static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming)
-{
-	unsigned long pnetwork_number;
-	pnetwork_number = (unsigned long) ((sendpacket[14] << 24) +
-			 (sendpacket[15] << 16) + (sendpacket[16] << 8) +
-					   sendpacket[17]);
-	if (!incoming) {
-		/* If the destination network number is ours, make it 0 */
-		if (pnetwork_number == network_number) {
-			sendpacket[14] = sendpacket[15] = sendpacket[16] =
-			    sendpacket[17] = 0x00;
-		}
-	} else {
-		/* If the incoming network is 0, make it ours */
-		if (pnetwork_number == 0) 
-		{
-			sendpacket[14] = (unsigned char) (network_number >> 24);
-			sendpacket[15] = (unsigned char) ((network_number &
-						      0x00FF0000) >> 16);
-			sendpacket[16] = (unsigned char) ((network_number &
-						       0x0000FF00) >> 8);
-			sendpacket[17] = (unsigned char) (network_number &
-							  0x000000FF);
-		}
-	}
-	pnetwork_number = (unsigned long) ((sendpacket[26] << 24) +
-			 (sendpacket[27] << 16) + (sendpacket[28] << 8) +
-					   sendpacket[29]);
-	if (!incoming) {
-		/* If the source network is ours, make it 0 */
-		if (pnetwork_number == network_number) 
-		{
-			sendpacket[26] = sendpacket[27] = sendpacket[28] =
-			    sendpacket[29] = 0x00;
-		}
-	} else {
-		/* If the source network is 0, make it ours */
-		if (pnetwork_number == 0) {
-			sendpacket[26] = (unsigned char) (network_number >> 24);
-			sendpacket[27] = (unsigned char) ((network_number &
-						      0x00FF0000) >> 16);
-			sendpacket[28] = (unsigned char) ((network_number &
-						       0x0000FF00) >> 8);
-			sendpacket[29] = (unsigned char) (network_number &
-							  0x000000FF);
-		}
-	}
-}				/* switch_net_numbers */
-
-/*============================================================================
- * Get Ethernet-style interface statistics.
- * Return a pointer to struct net_device_stats.
- */
-
-static struct net_device_stats *if_stats(struct net_device *dev)
-{
-	fr_channel_t *chan = dev->priv;
-	if(chan==NULL)
-		return NULL;
-		
-	return &chan->ifstats;
-}
-
-/****** Interrupt Handlers **************************************************/
-/*============================================================================
- * S502 frame relay interrupt service routine.
- */
-
-static void fr502_isr(sdla_t * card)
-{
-	fr502_flags_t *flags = card->flags;
-	switch (flags->iflag) 
-	{
-		case 0x01:		/* receive interrupt */
-			fr502_rx_intr(card);
-			break;
-		case 0x02:		/* transmit interrupt */
-			flags->imask &= ~0x02;
-			tx_intr(card);
-			break;
-		default:
-			spur_intr(card);
-	}
-	flags->iflag = 0;
-}
-/*============================================================================
- * S508 frame relay interrupt service routine.
- */
-
-static void fr508_isr(sdla_t * card)
-{
-	fr508_flags_t *flags = card->flags;
-	fr_buf_ctl_t *bctl;
-	char *ptr = &flags->iflag;
-	struct net_device *dev = card->wandev.dev;
-	struct net_device *dev2;
-	int i;
-	unsigned long host_cpu_flags;
-	unsigned disable_tx_intr = 1;
-	fr_channel_t *chan;
-	fr_dlci_interface_t *dlci_interface;
-	/* This flag prevents nesting of interrupts.  See sdla_isr() routine
-	 * in sdlamain.c. 
-	 */
-	card->in_isr = 1;
-	++card->statistics.isr_entry;
-	if (test_and_set_bit(0, (void *) &card->wandev.critical)) 
-	{
-		printk(KERN_INFO "fr508_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, flags->iflag);
-		++card->statistics.isr_already_critical;
-		card->in_isr = 0;
-		return;
-	}
-	/* For all interrupts set the critical flag to CRITICAL_RX_INTR.
-	 * If the if_send routine is called with this flag set it will set
-	 * the enable transmit flag to 1. (for a delayed interrupt)
-	 */
-	card->wandev.critical = CRITICAL_IN_ISR;
-	card->dlci_int_mode_unbusy = 0;
-	card->buff_int_mode_unbusy = 0;
-	switch (flags->iflag) 
-	{
-		case 0x01:		/* receive interrupt */
-			++card->statistics.isr_rx;
-			fr508_rx_intr(card);
-			break;
-		case 0x02:		/* transmit interrupt */
-			++card->statistics.isr_tx;
-			bctl = (void *) (flags->tse_offs - FR_MB_VECTOR +
-				 card->hw.dpmbase);
-			bctl->flag = 0xA0;
-			if (card->intr_mode == DLCI_LIST_INTR_MODE) 
-			{
-				/* Find the structure and make it unbusy */
-				dev = find_channel(card, flags->dlci);
-				dev->tbusy = 0;
-				/* This is used to perform devtint at the
-				 * end of the isr 
-				 */
-				card->dlci_int_mode_unbusy = 1;
-				/* check to see if any other interfaces are
-				 * busy. If so then do not disable the tx
-				 * interrupts 
-				 */
-				for (dev2 = card->wandev.dev; dev2;
-					dev2 = dev2->slave) 
-				{
-					if (dev2->tbusy == 1) 
-					{
-						disable_tx_intr = 0;
-						break;
-					}
-				}
-				if (disable_tx_intr)
-					flags->imask &= ~0x02;
-			} 
-			else if (card->intr_mode == BUFFER_INTR_MODE) 
-			{
-				for (dev2 = card->wandev.dev; dev2;
-					dev2 = dev2->slave) 
-				{
-					if (!dev2 || !dev2->start) 
-					{
-						++card->statistics.tx_intr_dev_not_started;
-						continue;
-					}
-					if (dev2->tbusy) 
-					{
-						card->buff_int_mode_unbusy = 1;
-						((fr_channel_t *) dev2->priv)->dev_pending_devtint = 1;
-						dev2->tbusy = 0;
-					} 
-					else
-						((fr_channel_t *) dev2->priv)->dev_pending_devtint = 0;
-				}
-				flags->imask &= ~0x02;
-			}
-			break;
-		case 0x08:
-			Intr_test_counter++;
-			++card->statistics.isr_intr_test;
-			break;
-		default:
-			++card->statistics.isr_spurious;
-			spur_intr(card);
-			printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n",
-			       card->devname, flags->iflag);
-			printk(KERN_INFO "%s: ID Bytes = ", card->devname);
-			for (i = 0; i < 8; i++)
-				printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
-			printk(KERN_INFO "\n");
-			break;
-	}
-	card->wandev.critical = CRITICAL_INTR_HANDLED;
-	if (card->wandev.enable_tx_int) 
-	{
-		if (card->intr_mode == DLCI_LIST_INTR_MODE) 
-		{
-			for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) 
-			{
-				chan = dev2->priv;
-				if (chan->tx_int_status == WAITING_TO_BE_ENABLED) 
-				{
-					dlci_interface = chan->dlci_int_interface;
-					dlci_interface->gen_interrupt |= 0x40;
-					dlci_interface->packet_length = chan->pkt_length;
-					chan->tx_int_status = DISABLED;
-				}
-			}
-		}
-		card->wandev.enable_tx_int = 0;
-		flags->imask |= 0x02;
-		++card->statistics.isr_enable_tx_int;
-	}
-	save_flags(host_cpu_flags);
-	cli();
-	card->in_isr = 0;
-	card->wandev.critical = 0xD1;
-	flags->iflag = 0;
-	card->wandev.critical = 0;
-	restore_flags(host_cpu_flags);
-	/* Device is now ready to send. The instant this is executed the If_Send
-	   routine is called. That is why this is put at the bottom of the ISR
-	   to prevent a endless loop condition caused by repeated Interrupts and
-	   enable_tx_int flag.
-	 */
-	if (card->dlci_int_mode_unbusy)
-		mark_bh(NET_BH);
-	if (card->buff_int_mode_unbusy) 
-	{
-		for (;;) 
-		{
-			if (((fr_channel_t *) ((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint == 1) 
-			{
-				((fr_channel_t *) ((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint = 0;
-				mark_bh(NET_BH);
-			}
-			if ((card->devs_struct)->next == card->dev_to_devtint_next)
-				break;
-			card->devs_struct = (card->devs_struct)->next;
-		}
-		card->devs_struct = (card->dev_to_devtint_next)->next;
-		card->dev_to_devtint_next = card->devs_struct;
-	}
-}
-/*============================================================================
- * Receive interrupt handler.
- */
-
-static void fr502_rx_intr(sdla_t * card)
-{
-	fr_mbox_t *mbox = card->rxmb;
-	struct sk_buff *skb;
-	struct net_device *dev;
-	fr_channel_t *chan;
-	unsigned dlci, len;
-	void *buf;
-	unsigned char *sendpacket;
-	unsigned char buf2[3];
-	int udp_type;
-	sdla_mapmem(&card->hw, FR502_RX_VECTOR);
-	dlci = mbox->cmd.dlci;
-	len = mbox->cmd.length;
-	/* Find network interface for this packet */
-	dev = find_channel(card, dlci);
-	if (dev == NULL) 
-	{
-		/* Invalid channel, discard packet */
-		printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n",
-		       card->devname, dlci);
-		sdla_mapmem(&card->hw, FR_MB_VECTOR);
-	}
-	chan = dev->priv;
-	if (!dev->start) 
-	{
-		++chan->ifstats.rx_dropped;
-		sdla_mapmem(&card->hw, FR_MB_VECTOR);
-	}
-	/* Allocate socket buffer */
-	skb = dev_alloc_skb(len);
-	if (skb == NULL) 
-	{
-		printk(KERN_INFO "%s: no socket buffers available!\n",
-		       card->devname);
-		++chan->ifstats.rx_dropped;
-		sdla_mapmem(&card->hw, FR_MB_VECTOR);
-	}
-	/* Copy data to the socket buffer */
-	buf = skb_put(skb, len);
-	memcpy(buf, mbox->data, len);
-	sdla_mapmem(&card->hw, FR_MB_VECTOR);
-	/* Check if it's a UDP management packet */
-	sendpacket = skb->data;
-	memcpy(&buf2, &card->wandev.udp_port, 2);
-	udp_type = udp_pkt_type(skb, card);
-	if ((udp_type == UDP_FPIPE_TYPE) || (udp_type == UDP_DRVSTATS_TYPE)) 
-	{
-		if (udp_type == UDP_DRVSTATS_TYPE) 
-		{
-			++chan->rx_intr_DRVSTATS_request;
-			process_udp_driver_call(UDP_PKT_FRM_NETWORK, card, skb,
-						dev, dlci, chan);
-		}
-		else
-		{
-			++chan->rx_intr_FPIPE_request;
-			process_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, card, skb,
-					     dev, dlci, chan);
-		}
-	}
-	else
-	{
-		/* Decapsulate packet and pass it up the protocol stack */
-		skb->dev = dev;
-		buf = skb_pull(skb, 1);		/* remove hardware header */
-		if (!wanrouter_type_trans(skb, dev)) 
-		{
-			/* can't decapsulate packet */
-			dev_kfree_skb(skb);
-			++chan->ifstats.rx_errors;
-			++card->wandev.stats.rx_errors;
-		}
-		else 
-		{
-			netif_rx(skb);
-			++chan->ifstats.rx_packets;
-			++card->wandev.stats.rx_packets;
-			chan->ifstats.rx_bytes += skb->len;
-			card->wandev.stats.rx_bytes += skb->len;
-		}
-	}
-	sdla_mapmem(&card->hw, FR_MB_VECTOR);
-}
-/*============================================================================
- * Receive interrupt handler.
- */
-
-static void fr508_rx_intr(sdla_t * card)
-{
-	fr_buf_ctl_t *frbuf = card->rxmb;
-	struct sk_buff *skb;
-	struct net_device *dev;
-	fr_channel_t *chan;
-	unsigned dlci, len, offs;
-	void *buf;
-	unsigned rx_count = 0;
-	fr508_flags_t *flags = card->flags;
-	char *ptr = &flags->iflag;
-	int i, err, udp_type;
-	if (frbuf->flag != 0x01) 
-	{
-		printk(KERN_INFO
-		       "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n",
-		       card->devname, (unsigned) frbuf, frbuf->flag);
-		printk(KERN_INFO "%s: ID Bytes = ", card->devname);
-		for (i = 0; i < 8; i++)
-			printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
-		printk(KERN_INFO "\n");
-		++card->statistics.rx_intr_corrupt_rx_bfr;
-		return;
-	}
-	
-	do 
-	{
-		len = frbuf->length;
-		dlci = frbuf->dlci;
-		offs = frbuf->offset;
-		/* Find network interface for this packet */
-		dev = find_channel(card, dlci);
-		chan = dev->priv;
-		if (dev == NULL) 
-		{
-			/* Invalid channel, discard packet */
-			printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n"
-			       ,card->devname, dlci);
-			++card->statistics.rx_intr_on_orphaned_DLCI;
-		}
-		else
-		{
-			skb = dev_alloc_skb(len);
-			if (!dev->start || (skb == NULL)) 
-			{
-				++chan->ifstats.rx_dropped;
-				if (dev->start) 
-				{
-					printk(KERN_INFO
-					       "%s: no socket buffers available!\n",
-					       card->devname);
-					++chan->rx_intr_no_socket;
-				} else
-					++chan->rx_intr_dev_not_started;
-			}
-			else
-			{
-				/* Copy data to the socket buffer */
-				if ((offs + len) > card->u.f.rx_top + 1) 
-				{
-					unsigned tmp = card->u.f.rx_top - offs + 1;
-					buf = skb_put(skb, tmp);
-					sdla_peek(&card->hw, offs, buf, tmp);
-					offs = card->u.f.rx_base;
-					len -= tmp;
-				}
-				buf = skb_put(skb, len);
-				sdla_peek(&card->hw, offs, buf, len);
-				udp_type = udp_pkt_type(skb, card);
-				if (udp_type == UDP_DRVSTATS_TYPE) 
-				{
-					++chan->rx_intr_DRVSTATS_request;
-					process_udp_driver_call(
-					  UDP_PKT_FRM_NETWORK, card, skb,
-							dev, dlci, chan);
-				}
-				else if (udp_type == UDP_FPIPE_TYPE) 
-				{
-					++chan->rx_intr_FPIPE_request;
-					err = process_udp_mgmt_pkt(
-					       UDP_PKT_FRM_NETWORK, card,
-						   skb, dev, dlci, chan);
-				}
-				else if (handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number)) 
-				{
-					if (card->wandev.enable_IPX) 
-						fr508_send(card, dlci, 0, skb->len, skb->data);
-				} 
-				else
-				{
-					/* Decapsulate packet and pass it up the
-					   protocol stack */
-					skb->dev = dev;
-					/* remove hardware header */
-					buf = skb_pull(skb, 1);
-					if (!wanrouter_type_trans(skb, dev)) 
-					{
-						/* can't decapsulate packet */
-						dev_kfree_skb(skb);
-						++chan->
-						    rx_intr_bfr_not_passed_to_stack;
-						++chan->
-						    ifstats.rx_errors;
-						++card->
-						    wandev.stats.rx_errors;
-					}
-					else
-					{
-						netif_rx(skb);
-						++chan->rx_intr_bfr_passed_to_stack;
-						++chan->ifstats.rx_packets;
-						++card->wandev.stats.rx_packets;
-						chan->ifstats.rx_bytes += skb->len;
-						card->wandev.stats.rx_bytes += skb->len;
-					}
-				}
-			}
-		}
-		/* Release buffer element and calculate a pointer to the next 
-		   one */
-		frbuf->flag = 0;
-		card->rxmb = ++frbuf;
-		if ((void *) frbuf > card->u.f.rxmb_last)
-			card->rxmb = card->u.f.rxmb_base;
-		/* The loop put in is temporary, that is why the break is
-		 * placed here. (?????)
-		 */
-		break;
-		frbuf = card->rxmb;
-	}
-	while (frbuf->flag && ((++rx_count) < 4));
-}
-/*============================================================================
- * Transmit interrupt handler.
- * o print a warning
- * o 
- * If number of spurious interrupts exceeded some limit, then ???
- */
-static void tx_intr(sdla_t * card)
-{
-	struct net_device *dev = card->wandev.dev;
-	if (card->intr_mode == BUFFER_INTR_MODE) 
-	{
-		for (; dev; dev = dev->slave) 
-		{
-			if (!dev || !dev->start) 
-			{
-				++card->statistics.tx_intr_dev_not_started;
-				continue;
-			}
-			dev->tbusy = 0;
-			mark_bh(NET_BH);
-		}
-	}
-	else
-	{
-		dev->tbusy = 0;
-		mark_bh(NET_BH);
-	}
-}
-
-/*============================================================================
- * Spurious interrupt handler.
- * o print a warning
- * o 
- * If number of spurious interrupts exceeded some limit, then ???
- */
-
-static void spur_intr(sdla_t * card)
-{
-	printk(KERN_INFO "%s: spurious interrupt!\n", card->devname);
-}
-
-/*
-   Return 0 for non-IPXWAN packet
-   1 for IPXWAN packet or IPX is not enabled!
- */
-
-static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number)
-{
-	int i;
-	if (sendpacket[1] == 0x00 &&
-	    sendpacket[2] == 0x80 &&
-	    sendpacket[6] == 0x81 &&
-	    sendpacket[7] == 0x37) 
-	{
-		/* It's an IPX packet */
-		if (!enable_IPX) {
-			/* Return 1 so we don't pass it up the stack. */
-			return 1;
-		}
-	}
-	else
-	{
-		/* It's not IPX so return and pass it up the stack. */
-		return 0;
-	}
-	if (sendpacket[24] == 0x90 &&
-	    sendpacket[25] == 0x04) 
-	{
-		/* It's IPXWAN */
-		if (sendpacket[10] == 0x02 &&
-		    sendpacket[42] == 0x00) 
-		{
-			/* It's a timer request packet */
-			printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", devname);
-			/* Go through the routing options and answer no to every */
-			/* option except Unnumbered RIP/SAP */
-			for (i = 49; sendpacket[i] == 0x00; i += 5) 
-			{
-				/* 0x02 is the option for Unnumbered RIP/SAP */
-				if (sendpacket[i + 4] != 0x02) 
-				{
-					sendpacket[i + 1] = 0;
-				}
-			}
-			/* Skip over the extended Node ID option */
-			if (sendpacket[i] == 0x04) 
-				i += 8;
-			/* We also want to turn off all header compression opt. */
-			for (; sendpacket[i] == 0x80;) 
-			{
-				sendpacket[i + 1] = 0;
-				i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4;
-			}
-			/* Set the packet type to timer response */
-			sendpacket[42] = 0x01;
-			printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", devname);
-		}
-		else if (sendpacket[42] == 0x02) 
-		{
-			/* This is an information request packet */
-			printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n", devname);
-			/* Set the packet type to information response */
-			sendpacket[42] = 0x03;
-			/* Set the router name */
-			sendpacket[59] = 'F';
-			sendpacket[60] = 'P';
-			sendpacket[61] = 'I';
-			sendpacket[62] = 'P';
-			sendpacket[63] = 'E';
-			sendpacket[64] = '-';
-			sendpacket[65] = CVHexToAscii(network_number >> 28);
-			sendpacket[66] = CVHexToAscii((network_number & 0x0F000000) >> 24);
-			sendpacket[67] = CVHexToAscii((network_number & 0x00F00000) >> 20);
-			sendpacket[68] = CVHexToAscii((network_number & 0x000F0000) >> 16);
-			sendpacket[69] = CVHexToAscii((network_number & 0x0000F000) >> 12);
-			sendpacket[70] = CVHexToAscii((network_number & 0x00000F00) >> 8);
-			sendpacket[71] = CVHexToAscii((network_number & 0x000000F0) >> 4);
-			sendpacket[72] = CVHexToAscii(network_number & 0x0000000F);
-			for (i = 73; i < 107; i += 1) 
-				sendpacket[i] = 0;
-			printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", devname);
-		}
-		else
-		{
-			printk(KERN_INFO "%s: Unknown IPXWAN packet!\n", devname);
-			return 0;
-		}
-		/* Set the WNodeID to our network address */
-		sendpacket[43] = (unsigned char) (network_number >> 24);
-		sendpacket[44] = (unsigned char) ((network_number & 0x00FF0000) >> 16);
-		sendpacket[45] = (unsigned char) ((network_number & 0x0000FF00) >> 8);
-		sendpacket[46] = (unsigned char) (network_number & 0x000000FF);
-		return 1;
-	}
-	/* If we get here, its an IPX-data packet so it'll get passed up the stack. */
-	/* switch the network numbers */
-	switch_net_numbers(sendpacket, network_number, 1);
-	return 0;
-}
-
-/****** Background Polling Routines  ****************************************/
-
-/*============================================================================
- * Main polling routine.
- * This routine is repeatedly called by the WANPIPE 'thead' to allow for
- * time-dependent housekeeping work.
- *
- * o fetch asynchronous network events.
- *
- * Notes:
- * 1. This routine may be called on interrupt context with all interrupts
- *    enabled. Beware!
- */
-
-static void wpf_poll(sdla_t * card)
-{
-/*      struct net_device* dev = card->wandev.dev;  */
-	fr508_flags_t *flags = card->flags;
-	unsigned long host_cpu_flags;
-	++card->statistics.poll_entry;
-	if (((jiffies - card->state_tick) < HZ) ||
-	    (card->intr_mode == INTR_TEST_MODE))
-		return;
-	disable_irq(card->hw.irq);
-	++card->irq_dis_poll_count;
-	if (test_and_set_bit(0, (void *) &card->wandev.critical)) 
-	{
-		++card->statistics.poll_already_critical;
-		save_flags(host_cpu_flags);
-		cli();
-		if ((!card->irq_dis_if_send_count) &&
-		    (!(--card->irq_dis_poll_count)))
-			enable_irq(card->hw.irq);
-		restore_flags(host_cpu_flags);
-		return;
-	}
-	card->wandev.critical = 0x11;
-	++card->statistics.poll_processed;
-	/* This is to be changed later ??? */
-	/*
-	   if( dev && dev->tbusy && !(flags->imask & 0x02) ) {
-	   printk(KERN_INFO "%s: Wpf_Poll: tbusy = 0x01, imask = 0x%02X\n",             card->devname, flags->imask);
-	   }
-	 */
-	if (flags->event) 
-	{
-		fr_mbox_t *mbox = card->mbox;
-		int err;
-		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
-		mbox->cmd.command = FR_READ_STATUS;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-		if (err)
-			fr_event(card, err, mbox);
-	}
-	card->wandev.critical = 0;
-	save_flags(host_cpu_flags);
-	cli();
-	if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count)))
-		enable_irq(card->hw.irq);
-	restore_flags(host_cpu_flags);
-	card->state_tick = jiffies;
-}
-
-/****** Frame Relay Firmware-Specific Functions *****************************/
-
-/*============================================================================
- * Read firmware code version.
- * o fill string str with firmware version info. 
- */
-
-static int fr_read_version(sdla_t * card, char *str)
-{
-	fr_mbox_t *mbox = card->mbox;
-	int retry = MAX_CMD_RETRY;
-	int err;
-	do 
-	{
-		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
-		mbox->cmd.command = FR_READ_CODE_VERSION;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	} while (err && retry-- && fr_event(card, err, mbox));
-	
-	if (!err && str) 
-	{
-		int len = mbox->cmd.length;
-		memcpy(str, mbox->data, len);
-		str[len] = '\0';
-	}
-	return err;
-}
-/*============================================================================
- * Set global configuration.
- */
- 
-static int fr_configure(sdla_t * card, fr_conf_t * conf)
-{
-	fr_mbox_t *mbox = card->mbox;
-	int retry = MAX_CMD_RETRY;
-	int dlci_num = card->u.f.dlci_num;
-	int err, i;
-	do 
-	{
-		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
-		memcpy(mbox->data, conf, sizeof(fr_conf_t));
-		if (dlci_num)
-			for (i = 0; i < dlci_num; ++i)
-				((fr_conf_t *) mbox->data)->dlci[i] =
-				    card->u.f.node_dlci[i];
-		mbox->cmd.command = FR_SET_CONFIG;
-		mbox->cmd.length =
-		    sizeof(fr_conf_t) + dlci_num * sizeof(short);
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry-- && fr_event(card, err, mbox));
-	
-	return err;
-}
-/*============================================================================
- * Set DLCI configuration.
- */
-static int fr_dlci_configure(sdla_t * card, fr_dlc_conf_t * conf, unsigned dlci)
-{
-	fr_mbox_t *mbox = card->mbox;
-	int retry = MAX_CMD_RETRY;
-	int err;
-	do
-	{
-		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
-		memcpy(mbox->data, conf, sizeof(fr_dlc_conf_t));
-		mbox->cmd.dlci = (unsigned short) dlci;
-		mbox->cmd.command = FR_SET_CONFIG;
-		mbox->cmd.length = 0x0E;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry--);
-	return err;
-}
-/*============================================================================
- * Set interrupt mode.
- */
-static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu)
-{
-	fr_mbox_t *mbox = card->mbox;
-	int retry = MAX_CMD_RETRY;
-	int err;
-	do
-	{
-		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
-		if (card->hw.fwid == SFID_FR502) 
-		{
-			fr502_intr_ctl_t *ictl = (void *) mbox->data;
-			memset(ictl, 0, sizeof(fr502_intr_ctl_t));
-			ictl->mode = mode;
-			ictl->tx_len = mtu;
-			mbox->cmd.length = sizeof(fr502_intr_ctl_t);
-		}
-		else
-		{
-			fr508_intr_ctl_t *ictl = (void *) mbox->data;
-			memset(ictl, 0, sizeof(fr508_intr_ctl_t));
-			ictl->mode = mode;
-			ictl->tx_len = mtu;
-			ictl->irq = card->hw.irq;
-			mbox->cmd.length = sizeof(fr508_intr_ctl_t);
-		}
-		mbox->cmd.command = FR_SET_INTR_MODE;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry-- && fr_event(card, err, mbox));
-	
-	return err;
-}
-/*============================================================================
- * Enable communications.
- */
-static int fr_comm_enable(sdla_t * card)
-{
-	fr_mbox_t *mbox = card->mbox;
-	int retry = MAX_CMD_RETRY;
-	int err;
-	do 
-	{
-		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
-		mbox->cmd.command = FR_COMM_ENABLE;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry-- && fr_event(card, err, mbox));
-	
-	return err;
-}
-/*============================================================================
- * Disable communications. 
- */
-static int fr_comm_disable(sdla_t * card)
-{
-	fr_mbox_t *mbox = card->mbox;
-	int retry = MAX_CMD_RETRY;
-	int err;
-	do
-	{
-		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
-		mbox->cmd.command = FR_COMM_DISABLE;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry-- && fr_event(card, err, mbox));
-	
-	return err;
-}
-/*============================================================================
- * Get communications error statistics. 
- */
-static int fr_get_err_stats(sdla_t * card)
-{
-	fr_mbox_t *mbox = card->mbox;
-	int retry = MAX_CMD_RETRY;
-	int err;
-	
-	do
-	{
-		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
-		mbox->cmd.command = FR_READ_ERROR_STATS;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry-- && fr_event(card, err, mbox));
-	
-	if (!err) 
-	{
-		fr_comm_stat_t *stats = (void *) mbox->data;
-		card->wandev.stats.rx_over_errors = stats->rx_overruns;
-		card->wandev.stats.rx_crc_errors = stats->rx_bad_crc;
-		card->wandev.stats.rx_missed_errors = stats->rx_aborts;
-		card->wandev.stats.rx_length_errors = stats->rx_too_long;
-		card->wandev.stats.tx_aborted_errors = stats->tx_aborts;
-	}
-	return err;
-}
-/*============================================================================
- * Get statistics. 
- */
-static int fr_get_stats(sdla_t * card)
-{
-	fr_mbox_t *mbox = card->mbox;
-	int retry = MAX_CMD_RETRY;
-	int err;
-	do 
-	{
-		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
-		mbox->cmd.command = FR_READ_STATISTICS;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry-- && fr_event(card, err, mbox));
-	
-	if (!err) 
-	{
-		fr_link_stat_t *stats = (void *) mbox->data;
-		card->wandev.stats.rx_frame_errors = stats->rx_bad_format;
-		card->wandev.stats.rx_dropped = stats->rx_dropped + stats->rx_dropped2;
-	}
-	return err;
-}
-/*============================================================================
- * Add DLCI(s) (Access Node only!).
- * This routine will perform the ADD_DLCIs command for the specified DLCI.
- */
-static int fr_add_dlci(sdla_t * card, int dlci, int num)
-{
-	fr_mbox_t *mbox = card->mbox;
-	int retry = MAX_CMD_RETRY;
-	int err, i;
-	do 
-	{
-		unsigned short *dlci_list = (void *) mbox->data;
-		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
-		for (i = 0; i < num; ++i)
-			dlci_list[i] = card->u.f.node_dlci[i];
-		mbox->cmd.length = num * sizeof(short);
-		mbox->cmd.command = FR_ADD_DLCI;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry-- && fr_event(card, err, mbox));
-	
-	return err;
-}
-/*============================================================================
- * Activate DLCI(s) (Access Node only!). 
- * This routine will perform the ACTIVATE_DLCIs command with a list of DLCIs. 
- */
-static int fr_activate_dlci(sdla_t * card, int dlci, int num)
-{
-	fr_mbox_t *mbox = card->mbox;
-	int retry = MAX_CMD_RETRY;
-	int err, i;
-	do
-	{
-		unsigned short *dlci_list = (void *) mbox->data;
-		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
-		for (i = 0; i < num; ++i)
-			dlci_list[i] = card->u.f.node_dlci[i];
-		mbox->cmd.length = num * sizeof(short);
-		mbox->cmd.command = FR_ACTIVATE_DLCI;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry-- && fr_event(card, err, mbox));
-	
-	return err;
-}
-/*============================================================================
- * Issue in-channel signalling frame. 
- */
-static int fr_issue_isf(sdla_t * card, int isf)
-{
-	fr_mbox_t *mbox = card->mbox;
-	int retry = MAX_CMD_RETRY;
-	int err;
-	do
-	{
-		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
-		mbox->data[0] = isf;
-		mbox->cmd.length = 1;
-		mbox->cmd.command = FR_ISSUE_IS_FRAME;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry-- && fr_event(card, err, mbox));
-	
-	return err;
-}
-/*============================================================================
- * Send a frame (S502 version). 
- */
-static int fr502_send(sdla_t * card, int dlci, int attr, int len, void *buf)
-{
-	fr_mbox_t *mbox = card->mbox;
-	int retry = MAX_CMD_RETRY;
-	int err;
-	
-	do 
-	{
-		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
-		memcpy(mbox->data, buf, len);
-		mbox->cmd.dlci = dlci;
-		mbox->cmd.attr = attr;
-		mbox->cmd.length = len;
-		mbox->cmd.command = FR_WRITE;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry-- && fr_event(card, err, mbox));
-	
-	return err;
-}
-/*============================================================================
- * Send a frame (S508 version). 
- */
-static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf)
-{
-	fr_mbox_t *mbox = card->mbox;
-	int retry = MAX_CMD_RETRY;
-	int err;
-	
-	do
-	{
-		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
-		mbox->cmd.dlci = dlci;
-		mbox->cmd.attr = attr;
-		mbox->cmd.length = len;
-		mbox->cmd.command = FR_WRITE;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry-- && fr_event(card, err, mbox));
-	
-	if (!err) 
-	{
-		fr_buf_ctl_t *frbuf = (void *) (*(unsigned long *) mbox->data -
-					FR_MB_VECTOR + card->hw.dpmbase);
-		sdla_poke(&card->hw, frbuf->offset, buf, len);
-		frbuf->flag = 0x01;
-	}
-	return err;
-}
-
-/****** Firmware Asynchronous Event Handlers ********************************/
-
-/*============================================================================
- * Main asynchronous event/error handler.
- *	This routine is called whenever firmware command returns non-zero
- *	return code.
- *
- * Return zero if previous command has to be cancelled.
- */
-
-static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox)
-{
-	fr508_flags_t *flags = card->flags;
-	char *ptr = &flags->iflag;
-	int i;
-	switch (event) 
-	{
-		case FRRES_MODEM_FAILURE:
-			return fr_modem_failure(card, mbox);
-		case FRRES_CHANNEL_DOWN:
-			wanpipe_set_state(card, WAN_DISCONNECTED);
-			return 1;
-		case FRRES_CHANNEL_UP:
-			wanpipe_set_state(card, WAN_CONNECTED);
-			return 1;
-		case FRRES_DLCI_CHANGE:
-			return fr_dlci_change(card, mbox);
-		case FRRES_DLCI_MISMATCH:
-			printk(KERN_INFO "%s: DLCI list mismatch!\n",
-			       card->devname);
-			return 1;
-		case CMD_TIMEOUT:
-			printk(KERN_ERR "%s: command 0x%02X timed out!\n",
-			       card->devname, mbox->cmd.command);
-			printk(KERN_INFO "%s: ID Bytes = ", card->devname);
-			for (i = 0; i < 8; i++)
-				printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
-			printk(KERN_INFO "\n");
-			break;
-		case FRRES_DLCI_INACTIVE:
-			printk(KERN_ERR "%s: DLCI %u is inactive!\n",
-			       card->devname, mbox->cmd.dlci);
-			break;
-		case FRRES_CIR_OVERFLOW:
-			break;
-		case FRRES_BUFFER_OVERFLOW:
-			break;
-		default:
-			printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n"
-			       ,card->devname, mbox->cmd.command, event);
-	}
-	return 0;
-}
-
-/*============================================================================
- * Handle modem error.
- *
- * Return zero if previous command has to be cancelled.
- */
-static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox)
-{
-	printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)\n",
-	       card->devname, mbox->data[0]);
-	switch (mbox->cmd.command) 
-	{
-		case FR_WRITE:
-		case FR_READ:
-			return 0;
-	}
-	return 1;
-}
-/*============================================================================
- * Handle DLCI status change.
- *
- * Return zero if previous command has to be cancelled.
- */
-static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox)
-{
-	dlci_status_t *status = (void *) mbox->data;
-	int cnt = mbox->cmd.length / sizeof(dlci_status_t);
-	fr_dlc_conf_t cfg;
-	fr_channel_t *chan;
-	struct net_device *dev2;
-	for (; cnt; --cnt, ++status) 
-	{
-		unsigned short dlci = status->dlci;
-		struct net_device *dev = find_channel(card, dlci);
-		if (dev == NULL) 
-		{
-			printk(KERN_INFO
-			       "%s: CPE contains unconfigured DLCI= %d\n",
-			       card->devname, dlci);
-		}
-		else 
-		{
-			if (status->state & 0x01) 
-			{
-				printk(KERN_INFO
-				       "%s: DLCI %u has been deleted!\n",
-				       card->devname, dlci);
-				if (dev && dev->start)
-					set_chan_state(dev, WAN_DISCONNECTED);
-			}
-			else if (status->state & 0x02) 
-			{
-				printk(KERN_INFO
-				       "%s: DLCI %u becomes active!\n",
-				       card->devname, dlci);
-				chan = dev->priv;
-				/* This flag is used for configuring specific 
-				   DLCI(s) when they become active.
-				 */
-				chan->dlci_configured = DLCI_CONFIG_PENDING;
-				if (dev && dev->start)
-					set_chan_state(dev, WAN_CONNECTED);
-			}
-		}
-	}
-	for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) 
-	{
-		chan = dev2->priv;
-		if (chan->dlci_configured == DLCI_CONFIG_PENDING) 
-		{
-			memset(&cfg, 0, sizeof(cfg));
-			if (chan->cir_status == CIR_DISABLED) 
-			{
-				cfg.cir_fwd = cfg.cir_bwd = 16;
-				cfg.bc_fwd = cfg.bc_bwd = 16;
-				cfg.conf_flags = 0x0001;
-				printk(KERN_INFO "%s: CIR Disabled for %s\n",
-				       card->devname, chan->name);
-			} else if (chan->cir_status == CIR_ENABLED) {
-				cfg.cir_fwd = cfg.cir_bwd = chan->cir;
-				cfg.bc_fwd = cfg.bc_bwd = chan->bc;
-				cfg.be_fwd = cfg.be_bwd = chan->be;
-				cfg.conf_flags = 0x0000;
-				printk(KERN_INFO "%s: CIR Enabled for %s\n",
-				       card->devname, chan->name);
-			}
-			if (fr_dlci_configure(card, &cfg, chan->dlci)) 
-			{
-				printk(KERN_INFO
-				    "%s: DLCI Configure failed for %d\n",
-				       card->devname, chan->dlci);
-				return 1;
-			}
-			chan->dlci_configured = DLCI_CONFIGURED;
-			/* Read the interface byte mapping into the channel 
-			   structure.
-			 */
-			if (card->intr_mode == DLCI_LIST_INTR_MODE)
-				read_DLCI_IB_mapping(card, chan);
-		}
-	}
-	return 1;
-}
-/******* Miscellaneous ******************************************************/
-
-/*============================================================================
- * Update channel state. 
- */
-static int update_chan_state(struct net_device *dev)
-{
-	fr_channel_t *chan = dev->priv;
-	sdla_t *card = chan->card;
-	fr_mbox_t *mbox = card->mbox;
-	int retry = MAX_CMD_RETRY;
-	int err;
-	int dlci_found = 0;
-
-	do 
-	{
-		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
-		mbox->cmd.command = FR_LIST_ACTIVE_DLCI;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry-- && fr_event(card, err, mbox));
-
-	if (!err) 
-	{
-		unsigned short *list = (void *) mbox->data;
-		int cnt = mbox->cmd.length / sizeof(short);
-		for (; cnt; --cnt, ++list) 
-		{
-			if (*list == chan->dlci) 
-			{
-				dlci_found = 1;
-				set_chan_state(dev, WAN_CONNECTED);
-				break;
-			}
-		}
-		if (!dlci_found)
-			printk(KERN_INFO "%s: DLCI %u is inactive\n",
-			       card->devname, chan->dlci);
-	}
-	
-	return err;
-}
-/*============================================================================
- * Set channel state.
- */
-static void set_chan_state(struct net_device *dev, int state)
-{
-	fr_channel_t *chan = dev->priv;
-	sdla_t *card = chan->card;
-	unsigned long flags;
-	
-	save_flags(flags);
-	cli();
-	
-	if (chan->state != state) 
-	{
-		switch (state) 
-		{
-			case WAN_CONNECTED:
-				printk(KERN_INFO "%s: interface %s connected!\n"
-				       ,card->devname, dev->name);
-				break;
-			case WAN_CONNECTING:
-				printk(KERN_INFO
-				       "%s: interface %s connecting...\n",
-				       card->devname, dev->name);
-				break;
-			case WAN_DISCONNECTED:
-				printk(KERN_INFO
-				       "%s: interface %s disconnected!\n",
-				       card->devname, dev->name);
-				break;
-		}
-		chan->state = state;
-	}
-	chan->state_tick = jiffies;
-	restore_flags(flags);
-}
-
-/*============================================================================
- * Find network device by its channel number.
- */
-static struct net_device *find_channel(sdla_t * card, unsigned dlci)
-{
-	struct net_device *dev;
-	for (dev = card->wandev.dev; dev; dev = dev->slave)
-		if (((fr_channel_t *) dev->priv)->dlci == dlci)
-			break;
-	return dev;
-}
-/*============================================================================
- * Check to see if a frame can be sent. If no transmit buffers available,
- * enable transmit interrupts.
- *
- * Return:	1 - Tx buffer(s) available
- *		0 - no buffers available
- */
-
-static int is_tx_ready(sdla_t * card, fr_channel_t * chan)
-{
-	if (card->hw.fwid == SFID_FR508) 
-	{
-		unsigned char sb = inb(card->hw.port);
-		if (sb & 0x02)
-			return 1;
-	}
-	else 
-	{
-		fr502_flags_t *flags = card->flags;
-		if (flags->tx_ready)
-			return 1;
-		flags->imask |= 0x02;
-	}
-	return 0;
-}
-
-/*============================================================================
- * Convert decimal string to unsigned integer.
- * If len != 0 then only 'len' characters of the string are converted.
- */
-static unsigned int dec_to_uint(unsigned char *str, int len)
-{
-	unsigned val;
-	if (!len)
-		len = strlen(str);
-	for (val = 0; len && is_digit(*str); ++str, --len)
-		val = (val * 10) + (*str - (unsigned) '0');
-	return val;
-}
-
-/*==============================================================================
- * Process UDP call of type FPIPE8ND
- */
-
-static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, int dlci, fr_channel_t * chan)
-{
-	int c_retry = MAX_CMD_RETRY;
-	unsigned char *data;
-	unsigned char *buf;
-	unsigned char buf2[5];
-	unsigned int loops, frames, len;
-	unsigned long data_ptr;
-	unsigned short real_len, buffer_length;
-	struct sk_buff *new_skb;
-	unsigned char *sendpacket;
-	fr_mbox_t *mbox = card->mbox;
-	int err;
-	struct timeval tv;
-	int udp_mgmt_req_valid = 1;
-	sendpacket = skb->data;
-	memcpy(&buf2, &card->wandev.udp_port, 2);
-	if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) 
-	{
-		printk(KERN_INFO
-		       "%s: Error allocating memory for UDP management cmnd 0x%02X",
-		       card->devname, data[47]);
-		++chan->UDP_FPIPE_mgmt_kmalloc_err;
-		return 1;
-	}
-	memcpy(data, sendpacket, skb->len);
-	switch (data[47]) 
-	{
-		/* FPIPE_ENABLE_TRACE */
-		case 0x41:
-		/* FPIPE_DISABLE_TRACE */
-		case 0x42:
-		/* FPIPE_GET_TRACE_INFO */
-		case 0x43:
-		/* SET FT1 MODE */
-		case 0x81:
-			if (udp_pkt_src == UDP_PKT_FRM_NETWORK) 
-			{
-				++chan->UDP_FPIPE_mgmt_direction_err;
-				udp_mgmt_req_valid = 0;
-				break;
-			}
-		/* FPIPE_FT1_READ_STATUS */
-		case 0x44:
-		/* FT1 MONITOR STATUS */
-		case 0x80:
-			if (card->hw.fwid != SFID_FR508) 
-			{
-				++chan->UDP_FPIPE_mgmt_adptr_type_err;
-				udp_mgmt_req_valid = 0;
-			}
-			break;
-		default:
-			break;
-	}
-	if (!udp_mgmt_req_valid) 
-	{
-		/* set length to 0 */
-		data[48] = data[49] = 0;
-		/* set return code */
-		data[50] = (card->hw.fwid != SFID_FR508) ? 0x1F : 0xCD;
-	}
-	else
-	{
-		switch (data[47]) 
-		{
-			/* FPIPE_ENABLE_TRACE */
-			case 0x41:
-				if (!TracingEnabled) 
-				{
-					do 
-					{
-						/* SET_TRACE_CONFIGURATION */
-						mbox->cmd.command = 0x60;
-						mbox->cmd.length = 1;
-						mbox->cmd.dlci = 0x00;
-						mbox->data[0] = 0x37;
-						err = sdla_exec(mbox) ?
-							mbox->cmd.result : CMD_TIMEOUT;
-					}
-					while (err && c_retry-- && fr_event(card, err, mbox));
-	
-					if (err) 
-					{
-						TracingEnabled = 0;
-						/* set the return code */
-						data[50] = mbox->cmd.result;
-						mbox->cmd.length = 0;
-						break;
-					}
-					/* get num_frames */
-					sdla_peek(&card->hw, 0x9000, &num_frames, 2);
-					sdla_peek(&card->hw, 0x9002, &curr_trace_addr,4);
-					start_trace_addr = curr_trace_addr;
-					/* MAX_SEND_BUFFER_SIZE - 
-					 * sizeof(UDP_MGMT_PACKET) - 41 */
-					available_buffer_space = 1926;
-					/* set return code */
-					data[50] = 0;
-				} 
-				else
-				{
-					/* set return code to line trace already 
-					   enabled */
-					data[50] = 1;
-				}
-				mbox->cmd.length = 0;
-				TracingEnabled = 1;
-				break;
-			/* FPIPE_DISABLE_TRACE */
-			case 0x42:
-				if (TracingEnabled) 
-				{
-					do 
-					{
-						/* SET_TRACE_CONFIGURATION */
-						mbox->cmd.command = 0x60;
-						mbox->cmd.length = 1;
-						mbox->cmd.dlci = 0x00;
-						mbox->data[0] = 0x36;
-						err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-					}
-					while (err && c_retry-- && fr_event(card, err, mbox));
-				}
-				/* set return code */
-				data[50] = 0;
-				mbox->cmd.length = 0;
-				TracingEnabled = 0;
-				break;
-			/* FPIPE_GET_TRACE_INFO */
-			case 0x43:
-				/* Line trace cannot be performed on the 502 */
-				if (!TracingEnabled) 
-				{
-					/* set return code */
-					data[50] = 1;
-					mbox->cmd.length = 0;
-					break;
-				}
-				buffer_length = 0;
-				loops = (num_frames < 20) ? num_frames : 20;
-				for (frames = 0; frames < loops; frames += 1) 
-				{
-					sdla_peek(&card->hw, curr_trace_addr, &buf2, 1);
-					/* no data on board so exit */
-					if (buf2[0] == 0x00)
-						break;
-					/* 1+sizeof(FRAME_DATA) = 9 */
-					if ((available_buffer_space - buffer_length) < 9) 
-					{
-						/* indicate we have more frames on board
-						   and exit */
-						data[62] |= 0x02;
-						break;
-					}
-					/* get frame status */
-					sdla_peek(&card->hw, curr_trace_addr + 0x05, &data[62 + buffer_length], 1);
-					/* get time stamp */
-					sdla_peek(&card->hw, curr_trace_addr + 0x06, &data[66 + buffer_length], 2);
-					/* get frame length */
-					sdla_peek(&card->hw, curr_trace_addr + 0x01, &data[64 + buffer_length], 2);
-					/* get pointer to real data */
-					sdla_peek(&card->hw, curr_trace_addr + 0x0C,&data_ptr, 4);
-					/* see if we can fit the frame into the user buffer */
-					memcpy(&real_len, &data[64 + buffer_length], 2);
-					if (data_ptr == 0 || real_len + 8 > available_buffer_space) 
-					{
-						data[63 + buffer_length] = 0x00;
-					}
-					else
-					{
-						/* we can take it next time */
-						if (available_buffer_space - buffer_length < real_len + 8) 
-						{
-							data[62] |= 0x02;
-							break;
-						}
-						/* ok, get the frame */
-						data[63 + buffer_length] = 0x01;
-						/* get the data */
-						sdla_peek(&card->hw, data_ptr, &data[68 + buffer_length], real_len);
-						/* zero the opp flag to show we got the frame */
-						buf2[0] = 0x00;
-						sdla_poke(&card->hw, curr_trace_addr, &buf2, 1);
-						/* now move onto the next frame */
-						curr_trace_addr += 16;
-						/* check if we passed the last address */
-						if (curr_trace_addr >= (start_trace_addr + num_frames * 16)) 
-							curr_trace_addr = start_trace_addr;
-						/* update buffer length and make sure 
-						   its even */
-						if (data[63 + buffer_length] == 0x01) 
-							buffer_length += real_len - 1;
-						/* for the header */
-						buffer_length += 8;
-						if (buffer_length & 0x0001)
-							buffer_length += 1;
-					}
-				}
-				/* ok now set the total number of frames passed in the 
-				   high 5 bits */
-				data[62] = (frames << 3) | data[62];
-				/* set the data length */
-				mbox->cmd.length = buffer_length;
-				memcpy(&data[48], &buffer_length, 2);
-				data[50] = 0;
-				break;
-			/* FPIPE_FT1_READ_STATUS */
-			case 0x44:
-				sdla_peek(&card->hw, 0xF020, &data[62], 2);
-				data[48] = 2;
-				data[49] = 0;
-				data[50] = 0;
-				mbox->cmd.length = 2;
-				break;
-			/* FPIPE_FLUSH_DRIVER_STATS */
-			case 0x48:
-				init_chan_statistics(chan);
-				init_global_statistics(card);
-				mbox->cmd.length = 0;
-				break;
-			case 0x49:
-				do_gettimeofday(&tv);
-				chan->router_up_time = tv.tv_sec - chan->router_start_time;
-				*(unsigned long *) &data[62] = chan->router_up_time;
-				mbox->cmd.length = 4;
-				break;
-			/* FPIPE_KILL_BOARD */
-			case 0x50:
-				break;
-			/* FT1 MONITOR STATUS */
-			case 0x80:
-				if (data[62] == 1) 
-				{
-					if (rCount++ != 0) 
-					{
-						data[50] = 0;
-						mbox->cmd.length = 1;
-						break;
-					}
-				}
-				/* Disable FT1 MONITOR STATUS */
-				if (data[62] == 0) 
-				{
-					if (--rCount != 0) 
-					{
-						data[50] = 0;
-						mbox->cmd.length = 1;
-						break;
-					}
-				}
-			default:
-				do 
-				{
-					memcpy(&mbox->cmd, &sendpacket[47], sizeof(fr_cmd_t));
-					if (mbox->cmd.length) 
-						memcpy(&mbox->data, &sendpacket[62],mbox->cmd.length);
-					err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-				}
-				while (err && c_retry-- && fr_event(card, err, mbox));
-			
-				if (!err) 
-				{
-					++chan->UDP_FPIPE_mgmt_adptr_cmnd_OK;
-					memcpy(data, sendpacket, skb->len);
-					memcpy(&data[47], &mbox->cmd, sizeof(fr_cmd_t));
-					if (mbox->cmd.length) 
-					{
-						memcpy(&data[62], &mbox->data,mbox->cmd.length);
-					}
-				}
-				else
-				{
-					++chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout;
-				}
-			}
-	}
-	/* Fill UDP TTL */
-	data[10] = card->wandev.ttl;
-	len = reply_udp(data, mbox->cmd.length);
-	if (udp_pkt_src == UDP_PKT_FRM_NETWORK) 
-	{
-		err = fr508_send(card, dlci, 0, len, data);
-		if (err)
-			++chan->UDP_FPIPE_mgmt_adptr_send_passed;
-		else
-			++chan->UDP_FPIPE_mgmt_adptr_send_failed;
-		dev_kfree_skb(skb);
-	}
-	else 
-	{
-		/* Allocate socket buffer */
-		if ((new_skb = dev_alloc_skb(len)) != NULL) 
-		{
-			/* copy data into new_skb */
-			buf = skb_put(new_skb, len);
-			memcpy(buf, data, len);
-			/* Decapsulate packet and pass it up the protocol 
-			   stack */
-			new_skb->dev = dev;
-			buf = skb_pull(new_skb, 1);	/* remove hardware header */
-			if (!wanrouter_type_trans(new_skb, dev)) 
-			{
-				++chan->UDP_FPIPE_mgmt_not_passed_to_stack;
-				/* can't decapsulate packet */
-				dev_kfree_skb(new_skb);
-			}
-			else 
-			{
-				++chan->UDP_FPIPE_mgmt_passed_to_stack;
-				netif_rx(new_skb);
-			}
-		}
-		else 
-		{
-			++chan->UDP_FPIPE_mgmt_no_socket;
-			printk(KERN_INFO
-			       "%s: UDP mgmt cmnd, no socket buffers available!\n",
-			       card->devname);
-		}
-	}
-	kfree(data);
-	return 0;
-}
-/*==============================================================================
- * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_
- * TEST_COUNTER times.
- */
- 
-static int intr_test(sdla_t * card)
-{
-	fr_mbox_t *mb = card->mbox;
-	int err, i;
-	/* The critical flag is unset here because we want to get into the
-	   ISR without the flag already set. The If_open sets the flag.
-	 */
-	card->wandev.critical = 0;
-	err = fr_set_intr_mode(card, 0x08, card->wandev.mtu);
-	if (err == CMD_OK) 
-	{
-		for (i = 0; i < MAX_INTR_TEST_COUNTER; i++) 
-		{
-			/* Run command READ_CODE_VERSION */
-			memset(&mb->cmd, 0, sizeof(fr_cmd_t));
-			mb->cmd.length = 0;
-			mb->cmd.command = 0x40;
-			err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-			if (err != CMD_OK)
-				fr_event(card, err, mb);
-		}
-	} 
-	else 
-	{
-		return err;
-	}
-	err = fr_set_intr_mode(card, 0, card->wandev.mtu);
-	if (err != CMD_OK)
-		return err;
-	card->wandev.critical = 1;
-	return 0;
-}
-/*============================================================================
- * Process UDP call of type DRVSTATS.  
- */
-static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, int dlci, fr_channel_t * chan)
-{
-	int c_retry = MAX_CMD_RETRY;
-	unsigned char *sendpacket;
-	unsigned char buf2[5];
-	unsigned char *data;
-	unsigned char *buf;
-	unsigned int len;
-	fr_mbox_t *mbox = card->mbox;
-	struct sk_buff *new_skb;
-	int err;
-	sendpacket = skb->data;
-	memcpy(&buf2, &card->wandev.udp_port, 2);
-	if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) 
-	{
-		printk(KERN_INFO
-		       "%s: Error allocating memory for UDP DRIVER STATS cmnd0x%02X"
-		       ,card->devname, data[45]);
-		++chan->UDP_DRVSTATS_mgmt_kmalloc_err;
-		return 1;
-	}
-	memcpy(data, sendpacket, skb->len);
-	switch (data[47]) 
-	{
-		case 0x45:
-			*(unsigned long *) &data[62] = chan->if_send_entry;
-			*(unsigned long *) &data[66] = chan->if_send_skb_null;
-			*(unsigned long *) &data[70] = chan->if_send_broadcast;
-			*(unsigned long *) &data[74] = chan->if_send_multicast;
-			*(unsigned long *) &data[78] = chan->if_send_critical_ISR;
-			*(unsigned long *) &data[82] = chan->if_send_critical_non_ISR;
-			*(unsigned long *) &data[86] = chan->if_send_busy;
-			*(unsigned long *) &data[90] = chan->if_send_busy_timeout;
-			*(unsigned long *) &data[94] = chan->if_send_DRVSTATS_request;
-			*(unsigned long *) &data[98] = chan->if_send_FPIPE_request;
-			*(unsigned long *) &data[102] = chan->if_send_wan_disconnected;
-			*(unsigned long *) &data[106] = chan->if_send_dlci_disconnected;
-			*(unsigned long *) &data[110] = chan->if_send_no_bfrs;
-			*(unsigned long *) &data[114] = chan->if_send_adptr_bfrs_full;
-			*(unsigned long *) &data[118] = chan->if_send_bfrs_passed_to_adptr;
-			*(unsigned long *) &data[120] = card->irq_dis_if_send_count;
-			mbox->cmd.length = 62;
-			break;
-		case 0x46:
-			*(unsigned long *) &data[62] = card->statistics.isr_entry;
-			*(unsigned long *) &data[66] = card->statistics.isr_already_critical;
-			*(unsigned long *) &data[70] = card->statistics.isr_rx;
-			*(unsigned long *) &data[74] = card->statistics.isr_tx;
-			*(unsigned long *) &data[78] = card->statistics.isr_intr_test;
-			*(unsigned long *) &data[82] = card->statistics.isr_spurious;
-			*(unsigned long *) &data[86] = card->statistics.isr_enable_tx_int;
-			*(unsigned long *) &data[90] = card->statistics.tx_intr_dev_not_started;
-			*(unsigned long *) &data[94] = card->statistics.rx_intr_corrupt_rx_bfr;
-			*(unsigned long *) &data[98] = card->statistics.rx_intr_on_orphaned_DLCI;
-			*(unsigned long *) &data[102] = chan->rx_intr_no_socket;
-			*(unsigned long *) &data[106] = chan->rx_intr_dev_not_started;
-			*(unsigned long *) &data[110] = chan->rx_intr_DRVSTATS_request;
-			*(unsigned long *) &data[114] = chan->rx_intr_FPIPE_request;
-			*(unsigned long *) &data[118] = chan->rx_intr_bfr_not_passed_to_stack;
-			*(unsigned long *) &data[122] = chan->rx_intr_bfr_passed_to_stack;
-			mbox->cmd.length = 64;
-			break;
-		case 0x47:
-			*(unsigned long *) &data[62] = chan->UDP_FPIPE_mgmt_kmalloc_err;
-			*(unsigned long *) &data[66] = chan->UDP_FPIPE_mgmt_adptr_type_err;
-			*(unsigned long *) &data[70] = chan->UDP_FPIPE_mgmt_direction_err;
-			*(unsigned long *) &data[74] = chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout;
-			*(unsigned long *) &data[78] = chan->UDP_FPIPE_mgmt_adptr_cmnd_OK;
-			*(unsigned long *) &data[82] = chan->UDP_FPIPE_mgmt_adptr_send_passed;
-			*(unsigned long *) &data[86] = chan->UDP_FPIPE_mgmt_adptr_send_failed;
-			*(unsigned long *) &data[90] = chan->UDP_FPIPE_mgmt_no_socket;
-			*(unsigned long *) &data[94] = chan->UDP_FPIPE_mgmt_not_passed_to_stack;
-			*(unsigned long *) &data[98] = chan->UDP_FPIPE_mgmt_passed_to_stack;
-			*(unsigned long *) &data[102] = chan->UDP_DRVSTATS_mgmt_kmalloc_err;
-			*(unsigned long *) &data[106] = chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
-			*(unsigned long *) &data[110] = chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
-			*(unsigned long *) &data[114] = chan->UDP_DRVSTATS_mgmt_adptr_send_passed;
-			*(unsigned long *) &data[118] = chan->UDP_DRVSTATS_mgmt_adptr_send_failed;
-			*(unsigned long *) &data[122] = chan->UDP_DRVSTATS_mgmt_no_socket;
-			*(unsigned long *) &data[126] = chan->UDP_DRVSTATS_mgmt_not_passed_to_stack;
-			*(unsigned long *) &data[130] = chan->UDP_DRVSTATS_mgmt_passed_to_stack;
-			*(unsigned long *) &data[134] = card->statistics.poll_entry;
-			*(unsigned long *) &data[138] = card->statistics.poll_already_critical;
-			*(unsigned long *) &data[142] = card->statistics.poll_processed;
-			*(unsigned long *) &data[144] = card->irq_dis_poll_count;
-			mbox->cmd.length = 86;
-			break;
-		default:
-			do 
-			{
-				memcpy(&mbox->cmd, &sendpacket[47], sizeof(fr_cmd_t));
-				if (mbox->cmd.length) 
-					memcpy(&mbox->data, &sendpacket[62], mbox->cmd.length);
-				err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-			} 
-			while (err && c_retry-- && fr_event(card, err, mbox));
-			
-			if (!err) 
-			{
-				++chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
-				memcpy(data, sendpacket, skb->len);
-				memcpy(&data[47], &mbox->cmd, sizeof(fr_cmd_t));
-				if (mbox->cmd.length) 
-					memcpy(&data[62], &mbox->data, mbox->cmd.length);
-			} 
-			else 
-			{
-				++chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
-			}
-	}
-	/* Fill UDP TTL */
-	data[10] = card->wandev.ttl;
-	len = reply_udp(data, mbox->cmd.length);
-	if (udp_pkt_src == UDP_PKT_FRM_NETWORK) 
-	{
-		err = fr508_send(card, dlci, 0, len, data);
-		if (err)
-			++chan->UDP_DRVSTATS_mgmt_adptr_send_failed;
-		else
-			++chan->UDP_DRVSTATS_mgmt_adptr_send_passed;
-		dev_kfree_skb(skb);
-	}
-	else
-	{
-		/* Allocate socket buffer */
-		if ((new_skb = dev_alloc_skb(len)) != NULL) 
-		{
-			/* copy data into new_skb */
-			buf = skb_put(new_skb, len);
-			memcpy(buf, data, len);
-			/* Decapsulate packet and pass it up the 
-			   protocol stack */
-			new_skb->dev = dev;
-			/* remove hardware header */
-			buf = skb_pull(new_skb, 1);
-			if (!wanrouter_type_trans(new_skb, dev)) 
-			{
-				/* can't decapsulate packet */
-				++chan->UDP_DRVSTATS_mgmt_not_passed_to_stack;
-				dev_kfree_skb(new_skb);
-			}
-			else
-			{
-				++chan->UDP_DRVSTATS_mgmt_passed_to_stack;
-				netif_rx(new_skb);
-			}
-		}
-		else
-		{
-			++chan->UDP_DRVSTATS_mgmt_no_socket;
-			printk(KERN_INFO "%s: UDP mgmt cmnd, no socket buffers available!\n", card->devname);
-		}
-	}
-	kfree(data);
-	return 0;
-}
-
-/*==============================================================================
- * Determine what type of UDP call it is. DRVSTATS or FPIPE8ND ?
- */
-
-static int udp_pkt_type(struct sk_buff *skb, sdla_t * card)
-{
-	unsigned char *sendpacket;
-	unsigned char buf2[5];
-	sendpacket = skb->data;
-	memcpy(&buf2, &card->wandev.udp_port, 2);
-	if (sendpacket[2] == 0x45 &&	/* IP packet */
-	    sendpacket[11] == 0x11 &&	/* UDP packet */
-	    sendpacket[24] == buf2[1] &&	/* UDP Port */
-	    sendpacket[25] == buf2[0] &&
-	    sendpacket[38] == 0x01) 
-	{
-		if (sendpacket[30] == 0x46 &&	/* FPIPE8ND: Signature */
-		    sendpacket[31] == 0x50 &&
-		    sendpacket[32] == 0x49 &&
-		    sendpacket[33] == 0x50 &&
-		    sendpacket[34] == 0x45 &&
-		    sendpacket[35] == 0x38 &&
-		    sendpacket[36] == 0x4E &&
-		    sendpacket[37] == 0x44) 
-		{
-			return UDP_FPIPE_TYPE;
-		} else if (sendpacket[30] == 0x44 &&	/* DRVSTATS: Signature */
-			   sendpacket[31] == 0x52 &&
-			   sendpacket[32] == 0x56 &&
-			   sendpacket[33] == 0x53 &&
-			   sendpacket[34] == 0x54 &&
-			   sendpacket[35] == 0x41 &&
-			   sendpacket[36] == 0x54 &&
-			   sendpacket[37] == 0x53) 
-		{
-			return UDP_DRVSTATS_TYPE;
-		}
-		else
-			return UDP_INVALID_TYPE;
-	}
-	else
-		return UDP_INVALID_TYPE;
-}
-/*==============================================================================
- * Initializes the Statistics values in the fr_channel structure.
- */
- 
-void init_chan_statistics(fr_channel_t * chan)
-{
-	chan->if_send_entry = 0;
-	chan->if_send_skb_null = 0;
-	chan->if_send_broadcast = 0;
-	chan->if_send_multicast = 0;
-	chan->if_send_critical_ISR = 0;
-	chan->if_send_critical_non_ISR = 0;
-	chan->if_send_busy = 0;
-	chan->if_send_busy_timeout = 0;
-	chan->if_send_FPIPE_request = 0;
-	chan->if_send_DRVSTATS_request = 0;
-	chan->if_send_wan_disconnected = 0;
-	chan->if_send_dlci_disconnected = 0;
-	chan->if_send_no_bfrs = 0;
-	chan->if_send_adptr_bfrs_full = 0;
-	chan->if_send_bfrs_passed_to_adptr = 0;
-	chan->rx_intr_no_socket = 0;
-	chan->rx_intr_dev_not_started = 0;
-	chan->rx_intr_FPIPE_request = 0;
-	chan->rx_intr_DRVSTATS_request = 0;
-	chan->rx_intr_bfr_not_passed_to_stack = 0;
-	chan->rx_intr_bfr_passed_to_stack = 0;
-	chan->UDP_FPIPE_mgmt_kmalloc_err = 0;
-	chan->UDP_FPIPE_mgmt_direction_err = 0;
-	chan->UDP_FPIPE_mgmt_adptr_type_err = 0;
-	chan->UDP_FPIPE_mgmt_adptr_cmnd_OK = 0;
-	chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout = 0;
-	chan->UDP_FPIPE_mgmt_adptr_send_passed = 0;
-	chan->UDP_FPIPE_mgmt_adptr_send_failed = 0;
-	chan->UDP_FPIPE_mgmt_not_passed_to_stack = 0;
-	chan->UDP_FPIPE_mgmt_passed_to_stack = 0;
-	chan->UDP_FPIPE_mgmt_no_socket = 0;
-	chan->UDP_DRVSTATS_mgmt_kmalloc_err = 0;
-	chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK = 0;
-	chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout = 0;
-	chan->UDP_DRVSTATS_mgmt_adptr_send_passed = 0;
-	chan->UDP_DRVSTATS_mgmt_adptr_send_failed = 0;
-	chan->UDP_DRVSTATS_mgmt_not_passed_to_stack = 0;
-	chan->UDP_DRVSTATS_mgmt_passed_to_stack = 0;
-	chan->UDP_DRVSTATS_mgmt_no_socket = 0;
-}
-/*==============================================================================
- * Initializes the Statistics values in the Sdla_t structure.
- */
-
-void init_global_statistics(sdla_t * card)
-{
-	/* Intialize global statistics for a card */
-	card->statistics.isr_entry = 0;
-	card->statistics.isr_already_critical = 0;
-	card->statistics.isr_rx = 0;
-	card->statistics.isr_tx = 0;
-	card->statistics.isr_intr_test = 0;
-	card->statistics.isr_spurious = 0;
-	card->statistics.isr_enable_tx_int = 0;
-	card->statistics.rx_intr_corrupt_rx_bfr = 0;
-	card->statistics.rx_intr_on_orphaned_DLCI = 0;
-	card->statistics.tx_intr_dev_not_started = 0;
-	card->statistics.poll_entry = 0;
-	card->statistics.poll_already_critical = 0;
-	card->statistics.poll_processed = 0;
-}
-
-static void read_DLCI_IB_mapping(sdla_t * card, fr_channel_t * chan)
-{
-	fr_mbox_t *mbox = card->mbox;
-	int retry = MAX_CMD_RETRY;
-	dlci_IB_mapping_t *result;
-	int err, counter, found;
-	do 
-	{
-		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
-		mbox->cmd.command = FR_READ_DLCI_IB_MAPPING;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry-- && fr_event(card, err, mbox));
-	
-	if (mbox->cmd.result != 0)
-		printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", chan->name);
-
-	counter = mbox->cmd.length / sizeof(dlci_IB_mapping_t);
-	result = (void *) mbox->data;
-	found = 0;
-	for (; counter; --counter, ++result) 
-	{
-		if (result->dlci == chan->dlci) 
-		{
-			printk(KERN_INFO "%s: DLCI= %d, IB addr = %lx for %s\n"
-			 ,card->devname, result->dlci, result->addr_value ,chan->name);
-			chan->IB_addr = result->addr_value;
-			chan->dlci_int_interface = (void *) (card->hw.dpmbase +
-					   (chan->IB_addr & 0x00001FFF));
-			found = 1;
-			break;
-		}
-	}
-	if (!found)
-		printk(KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n",
-		       card->devname, chan->dlci);
-}
-
-/****** End *****************************************************************/
diff -u --recursive --new-file v2.3.20/linux/drivers/net/sdla_ppp.c linux/drivers/net/sdla_ppp.c
--- v2.3.20/linux/drivers/net/sdla_ppp.c	Wed Aug 18 11:36:42 1999
+++ linux/drivers/net/sdla_ppp.c	Wed Dec 31 16:00:00 1969
@@ -1,2261 +0,0 @@
-/*****************************************************************************
-* sdla_ppp.c	WANPIPE(tm) Multiprotocol WAN Link Driver. PPP module.
-*
-* Author: 	Jaspreet Singh 	<jaspreet@sangoma.com>
-*
-* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
-*
-*		This program is free software; you can redistribute it and/or
-*		modify it under the terms of the GNU General Public License
-*		as published by the Free Software Foundation; either version
-*		2 of the License, or (at your option) any later version.
-* ============================================================================
-* Mar 15, 1998  Alan Cox	o 2.1.8x basic port.
-* Nov 27, 1997	Jaspreet Singh	o Added protection against enabling of irqs 
-*				  while they have been disabled.
-* Nov 24, 1997  Jaspreet Singh  o Fixed another RACE condition caused by
-*                                 disabling and enabling of irqs.
-*                               o Added new counters for stats on disable/enable*                                 IRQs.
-* Nov 10, 1997	Jaspreet Singh	o Initialized 'skb->mac.raw' to 'skb->data'
-*				  before every netif_rx().
-*				o Free up the device structure in del_if().
-* Nov 07, 1997	Jaspreet Singh	o Changed the delay to zero for Line tracing
-*				  command.
-* Oct 20, 1997 	Jaspreet Singh	o Added hooks in for Router UP time.
-* Oct 16, 1997	Jaspreet Singh  o The critical flag is used to maintain flow
-*				  control by avoiding RACE conditions.  The 
-*				  cli() and restore_flags() are taken out.
-*				  A new structure, "ppp_private_area", is added 
-*				  to provide Driver Statistics.   
-* Jul 21, 1997 	Jaspreet Singh	o Protected calls to sdla_peek() by adding 
-*				  save_flags(), cli() and restore_flags().
-* Jul 07, 1997	Jaspreet Singh  o Added configurable TTL for UDP packets
-*				o Added ability to discard mulitcast and
-*				  broacast source addressed packets.
-* Jun 27, 1997 	Jaspreet Singh	o Added FT1 monitor capabilities
-*				  New case (0x25) statement in if_send routine.
-*				  Added a global variable rCount to keep track
-*				  of FT1 status enabled on the board.
-* May 22, 1997	Jaspreet Singh	o Added change in the PPP_SET_CONFIG command for
-*				508 card to reflect changes in the new 
-*				ppp508.sfm for supporting:continous transmission
-*				of Configure-Request packets without receiving a
-*				reply 				
-*				OR-ed 0x300 to conf_flags 
-*			        o Changed connect_tmout from 900 to 0
-* May 21, 1997	Jaspreet Singh  o Fixed UDP Management for multiple boards
-* Apr 25, 1997  Farhan Thawar    o added UDP Management stuff
-* Mar 11, 1997  Farhan Thawar   Version 3.1.1
-*                                o fixed (+1) bug in rx_intr()
-*                                o changed if_send() to return 0 if
-*                                  wandev.critical() is true
-*                                o free socket buffer in if_send() if
-*                                  returning 0 
-* Jan 15, 1997	Gene Kozin	Version 3.1.0
-*				 o implemented exec() entry point
-* Jan 06, 1997	Gene Kozin	Initial version.
-*****************************************************************************/
-
-#include <linux/kernel.h>	/* printk(), and other useful stuff */
-#include <linux/stddef.h>	/* offsetof(), etc. */
-#include <linux/errno.h>	/* return codes */
-#include <linux/string.h>	/* inline memset(), etc. */
-#include <linux/malloc.h>	/* kmalloc(), kfree() */
-#include <linux/wanrouter.h>	/* WAN router definitions */
-#include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
-#include <linux/if_arp.h>	/* ARPHRD_* defines */
-#include <asm/byteorder.h>	/* htons(), etc. */
-#include <asm/uaccess.h>	/* copyto/from user */
-#define	_GNUC_
-#include <linux/sdla_ppp.h>	/* PPP firmware API definitions */
-
-/****** Defines & Macros ****************************************************/
-
-#ifdef	_DEBUG_
-#define	STATIC
-#else
-#define	STATIC		static
-#endif
-#define	PPP_DFLT_MTU	1500	/* default MTU */
-#define	PPP_MAX_MTU	4000	/* maximum MTU */
-#define PPP_HDR_LEN	1
-#define	CONNECT_TIMEOUT	(90*HZ)	/* link connection timeout */
-#define	HOLD_DOWN_TIME	(30*HZ)	/* link hold down time */
-
-/* For handle_IPXWAN() */
-#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b)))
-
-/******Data Structures*****************************************************/
-/* This structure is placed in the private data area of the device structure.
- * The card structure used to occupy the private area but now the following 
- * structure will incorporate the card structure along with PPP specific data
- */
-
-typedef struct ppp_private_area 
-{
-	sdla_t *card;
-	unsigned long router_start_time;	/*router start time in sec */
-	unsigned long tick_counter;	/*used for 5 second counter */
-	unsigned mc;		/*multicast support on or off */
-	/* PPP specific statistics */
-	unsigned long if_send_entry;
-	unsigned long if_send_skb_null;
-	unsigned long if_send_broadcast;
-	unsigned long if_send_multicast;
-	unsigned long if_send_critical_ISR;
-	unsigned long if_send_critical_non_ISR;
-	unsigned long if_send_busy;
-	unsigned long if_send_busy_timeout;
-	unsigned long if_send_DRVSTATS_request;
-	unsigned long if_send_PTPIPE_request;
-	unsigned long if_send_wan_disconnected;
-	unsigned long if_send_adptr_bfrs_full;
-	unsigned long if_send_protocol_error;
-	unsigned long if_send_tx_int_enabled;
-	unsigned long if_send_bfr_passed_to_adptr;
-	unsigned long rx_intr_no_socket;
-	unsigned long rx_intr_DRVSTATS_request;
-	unsigned long rx_intr_PTPIPE_request;
-	unsigned long rx_intr_bfr_not_passed_to_stack;
-	unsigned long rx_intr_bfr_passed_to_stack;
-	unsigned long UDP_PTPIPE_mgmt_kmalloc_err;
-	unsigned long UDP_PTPIPE_mgmt_adptr_type_err;
-	unsigned long UDP_PTPIPE_mgmt_direction_err;
-	unsigned long UDP_PTPIPE_mgmt_adptr_cmnd_timeout;
-	unsigned long UDP_PTPIPE_mgmt_adptr_cmnd_OK;
-	unsigned long UDP_PTPIPE_mgmt_passed_to_adptr;
-	unsigned long UDP_PTPIPE_mgmt_passed_to_stack;
-	unsigned long UDP_PTPIPE_mgmt_no_socket;
-	unsigned long UDP_DRVSTATS_mgmt_kmalloc_err;
-	unsigned long UDP_DRVSTATS_mgmt_adptr_type_err;
-	unsigned long UDP_DRVSTATS_mgmt_direction_err;
-	unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
-	unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
-	unsigned long UDP_DRVSTATS_mgmt_passed_to_adptr;
-	unsigned long UDP_DRVSTATS_mgmt_passed_to_stack;
-	unsigned long UDP_DRVSTATS_mgmt_no_socket;
-	unsigned long router_up_time;
-} ppp_private_area_t;
-
-/* variable for keeping track of enabling/disabling FT1 monitor status */
-
-static int rCount = 0;
-extern void disable_irq(unsigned int);
-extern void enable_irq(unsigned int);
-
-/****** Function Prototypes *************************************************/
-
-/* WAN link driver entry points. These are called by the WAN router module. */
-static int update(wan_device_t * wandev);
-static int new_if(wan_device_t * wandev, struct net_device *dev,
-		  wanif_conf_t * conf);
-static int del_if(wan_device_t * wandev, struct net_device *dev);
-/* WANPIPE-specific entry points */
-static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data);
-/* Network device interface */
-static int if_init(struct net_device *dev);
-static int if_open(struct net_device *dev);
-static int if_close(struct net_device *dev);
-static int if_header(struct sk_buff *skb, struct net_device *dev,
-	    unsigned short type, void *daddr, void *saddr, unsigned len);
-static int if_rebuild_hdr(struct sk_buff *skb);
-static int if_send(struct sk_buff *skb, struct net_device *dev);
-static struct enet_statistics *if_stats(struct net_device *dev);
-/* PPP firmware interface functions */
-static int ppp_read_version(sdla_t * card, char *str);
-static int ppp_configure(sdla_t * card, void *data);
-static int ppp_set_intr_mode(sdla_t * card, unsigned mode);
-static int ppp_comm_enable(sdla_t * card);
-static int ppp_comm_disable(sdla_t * card);
-static int ppp_get_err_stats(sdla_t * card);
-static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto);
-static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb);
-/* Interrupt handlers */
-STATIC void wpp_isr(sdla_t * card);
-static void rx_intr(sdla_t * card);
-static void tx_intr(sdla_t * card);
-/* Background polling routines */
-static void wpp_poll(sdla_t * card);
-static void poll_active(sdla_t * card);
-static void poll_connecting(sdla_t * card);
-static void poll_disconnected(sdla_t * card);
-/* Miscellaneous functions */
-static int config502(sdla_t * card);
-static int config508(sdla_t * card);
-static void show_disc_cause(sdla_t * card, unsigned cause);
-static unsigned char bps_to_speed_code(unsigned long bps);
-static int reply_udp(unsigned char *data, unsigned int mbox_len);
-static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, ppp_private_area_t * ppp_priv_area);
-static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, ppp_private_area_t * ppp_priv_area);
-static void init_ppp_tx_rx_buff(sdla_t * card);
-static int intr_test(sdla_t * card);
-static int udp_pkt_type(struct sk_buff *skb, sdla_t * card);
-static void init_ppp_priv_struct(ppp_private_area_t * ppp_priv_area);
-static void init_global_statistics(sdla_t * card);
-static int Intr_test_counter;
-static char TracingEnabled;
-static unsigned long curr_trace_addr;
-static unsigned long start_trace_addr;
-static unsigned short available_buffer_space;
-/* IPX functions */
-static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming);
-static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto);
-
-/****** Public Functions ****************************************************/
-
-/*============================================================================
- * PPP protocol initialization routine.
- *
- * This routine is called by the main WANPIPE module during setup.  At this
- * point adapter is completely initialized and firmware is running.
- *  o read firmware version (to make sure it's alive)
- *  o configure adapter
- *  o initialize protocol-specific fields of the adapter data space.
- *
- * Return:	0	o.k.
- *		< 0	failure.
- */
-int wpp_init(sdla_t * card, wandev_conf_t * conf)
-{
-	union {
-		char str[80];
-	} u;
-	/* Verify configuration ID */
-	if (conf->config_id != WANCONFIG_PPP) {
-		printk(KERN_INFO "%s: invalid configuration ID %u!\n",
-		       card->devname, conf->config_id);
-		return -EINVAL;
-	}
-	/* Initialize protocol-specific fields */
-	switch (card->hw.fwid) {
-	case SFID_PPP502:
-		card->mbox = (void *) (card->hw.dpmbase + PPP502_MB_OFFS);
-		card->flags = (void *) (card->hw.dpmbase + PPP502_FLG_OFFS);
-		break;
-	case SFID_PPP508:
-		card->mbox = (void *) (card->hw.dpmbase + PPP508_MB_OFFS);
-		card->flags = (void *) (card->hw.dpmbase + PPP508_FLG_OFFS);
-		break;
-	default:
-		return -EINVAL;
-	}
-	/* Read firmware version.  Note that when adapter initializes, it
-	 * clears the mailbox, so it may appear that the first command was
-	 * executed successfully when in fact it was merely erased. To work
-	 * around this, we execute the first command twice.
-	 */
-	if (ppp_read_version(card, NULL) || ppp_read_version(card, u.str))
-		return -EIO;
-	printk(KERN_INFO "%s: running PPP firmware v%s\n", card->devname, u.str);
-	/* Adjust configuration and set defaults */
-	card->wandev.mtu = (conf->mtu) ?
-	    min(conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU;
-	card->wandev.bps = conf->bps;
-	card->wandev.interface = conf->interface;
-	card->wandev.clocking = conf->clocking;
-	card->wandev.station = conf->station;
-	card->isr = &wpp_isr;
-	card->poll = &wpp_poll;
-	card->exec = &wpp_exec;
-	card->wandev.update = &update;
-	card->wandev.new_if = &new_if;
-	card->wandev.del_if = &del_if;
-	card->wandev.state = WAN_DISCONNECTED;
-	card->wandev.udp_port = conf->udp_port;
-	card->wandev.ttl = conf->ttl;
-	card->irq_dis_if_send_count = 0;
-	card->irq_dis_poll_count = 0;
-	TracingEnabled = 0;
-	card->wandev.enable_IPX = conf->enable_IPX;
-	if (conf->network_number)
-		card->wandev.network_number = conf->network_number;
-	else
-		card->wandev.network_number = 0xDEADBEEF;
-	/* initialize global statistics */
-	init_global_statistics(card);
-	return 0;
-}
-
-/******* WAN Device Driver Entry Points *************************************/
-
-/*============================================================================
- * Update device status & statistics.
- */
-static int update(wan_device_t * wandev)
-{
-	sdla_t *card;
-	/* sanity checks */
-	if ((wandev == NULL) || (wandev->private == NULL))
-		return -EFAULT;
-	if (wandev->state == WAN_UNCONFIGURED)
-		return -ENODEV;
-	if (test_and_set_bit(0, (void *) &wandev->critical))
-		return -EAGAIN;
-	card = wandev->private;
-	ppp_get_err_stats(card);
-	wandev->critical = 0;
-	return 0;
-}
-
-/*============================================================================
- * Create new logical channel.
- * This routine is called by the router when ROUTER_IFNEW IOCTL is being
- * handled.
- * o parse media- and hardware-specific configuration
- * o make sure that a new channel can be created
- * o allocate resources, if necessary
- * o prepare network device structure for registaration.
- *
- * Return:	0	o.k.
- *		< 0	failure (channel will not be created)
- */
-
-static int new_if(wan_device_t * wandev, struct net_device *dev, wanif_conf_t * conf)
-{
-	sdla_t *card = wandev->private;
-	ppp_private_area_t *ppp_priv_area;
-	if (wandev->ndev)
-		return -EEXIST;
-	if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) {
-		printk(KERN_INFO "%s: invalid interface name!\n",
-		       card->devname);
-		return -EINVAL;
-	}
-	/* allocate and initialize private data */
-	ppp_priv_area = kmalloc(sizeof(ppp_private_area_t), GFP_KERNEL);
-	if (ppp_priv_area == NULL)
-		return -ENOMEM;
-	memset(ppp_priv_area, 0, sizeof(ppp_private_area_t));
-	ppp_priv_area->card = card;
-	/* initialize data */
-	strcpy(card->u.p.if_name, conf->name);
-	/* initialize data in ppp_private_area structure */
-	init_ppp_priv_struct(ppp_priv_area);
-	ppp_priv_area->mc = conf->mc;
-	/* prepare network device data space for registration */
-	dev->name = card->u.p.if_name;
-	dev->init = &if_init;
-	dev->priv = ppp_priv_area;
-	return 0;
-}
-
-/*============================================================================
- * Delete logical channel.
- */
-
-static int del_if(wan_device_t * wandev, struct net_device *dev)
-{
-	if (dev->priv) {
-		kfree(dev->priv);
-		dev->priv = NULL;
-	}
-	return 0;
-}
-
-/****** WANPIPE-specific entry points ***************************************/
-
-/*============================================================================
- * Execute adapter interface command.
- */
-
-static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data)
-{
-	ppp_mbox_t *mbox = card->mbox;
-	int len;
-	if(copy_from_user((void *) &mbox->cmd, u_cmd, sizeof(ppp_cmd_t)))
-		return -EFAULT;
-	len = mbox->cmd.length;
-	if (len) {
-		if(copy_from_user((void *) &mbox->data, u_data, len))
-			return -EFAULT;
-	}
-	/* execute command */
-	if (!sdla_exec(mbox))
-		return -EIO;
-	/* return result */
-	if(copy_to_user(u_cmd, (void *) &mbox->cmd, sizeof(ppp_cmd_t)))
-		return -EFAULT;
-	len = mbox->cmd.length;
-	if (len && u_data && copy_to_user(u_data, (void *) &mbox->data, len))
-		return -EFAULT;
-	return 0;
-}
-
-/****** Network Device Interface ********************************************/
-
-/*============================================================================
- * Initialize Linux network interface.
- *
- * This routine is called only once for each interface, during Linux network
- * interface registration.  Returning anything but zero will fail interface
- * registration.
- */
-
-static int if_init(struct net_device *dev)
-{
-	ppp_private_area_t *ppp_priv_area = dev->priv;
-	sdla_t *card = ppp_priv_area->card;
-	wan_device_t *wandev = &card->wandev;
-
-	/* Initialize device driver entry points */
-	dev->open = &if_open;
-	dev->stop = &if_close;
-	dev->hard_header = &if_header;
-	dev->rebuild_header = &if_rebuild_hdr;
-	dev->hard_start_xmit = &if_send;
-	dev->get_stats = &if_stats;
-	/* Initialize media-specific parameters */
-	dev->type = ARPHRD_PPP;	/* ARP h/w type */
-	dev->mtu = wandev->mtu;
-	dev->hard_header_len = PPP_HDR_LEN;	/* media header length */
-	/* Initialize hardware parameters (just for reference) */
-	dev->irq = wandev->irq;
-	dev->dma = wandev->dma;
-	dev->base_addr = wandev->ioport;
-	dev->mem_start = (unsigned long)wandev->maddr;
-	dev->mem_end = dev->mem_start + wandev->msize - 1;
-	/* Set transmit buffer queue length */
-	dev->tx_queue_len = 100;
-	/* Initialize socket buffers */
-	dev_init_buffers(dev);
-	return 0;
-}
-
-/*============================================================================
- * Open network interface.
- * o enable communications and interrupts.
- * o prevent module from unloading by incrementing use count
- *
- * Return 0 if O.k. or errno.
- */
-
-static int if_open(struct net_device *dev)
-{
-	ppp_private_area_t *ppp_priv_area = dev->priv;
-	sdla_t *card = ppp_priv_area->card;
-	ppp_flags_t *flags = card->flags;
-	struct timeval tv;
-	int err = 0;
-	if (dev->start)
-		return -EBUSY;	/* only one open is allowed */
-	if (test_and_set_bit(0, (void *) &card->wandev.critical))
-		return -EAGAIN;
-	if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card)) {
-		err = -EIO;
-		card->wandev.critical = 0;
-		return err;
-	}
-	Intr_test_counter = 0;
-	err = intr_test(card);
-	if ((err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) {
-		printk(KERN_INFO "%s: Interrupt Test Failed, Counter: %i\n",
-		       card->devname, Intr_test_counter);
-		err = -EIO;
-		card->wandev.critical = 0;
-		return err;
-	}
-	printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n",
-	       card->devname, Intr_test_counter);
-	/* Initialize Rx/Tx buffer control fields */
-	init_ppp_tx_rx_buff(card);
-	if (ppp_set_intr_mode(card, 0x03)) {
-		err = -EIO;
-		card->wandev.critical = 0;
-		return err;
-	}
-	flags->imask &= ~0x02;
-	if (ppp_comm_enable(card)) {
-		err = -EIO;
-		card->wandev.critical = 0;
-		return err;
-	}
-	wanpipe_set_state(card, WAN_CONNECTING);
-	wanpipe_open(card);
-	dev->mtu = min(dev->mtu, card->wandev.mtu);
-	dev->interrupt = 0;
-	dev->tbusy = 0;
-	dev->start = 1;
-	do_gettimeofday(&tv);
-	ppp_priv_area->router_start_time = tv.tv_sec;
-	card->wandev.critical = 0;
-	return err;
-}
-
-/*============================================================================
- * Close network interface.
- * o if this is the last open, then disable communications and interrupts.
- * o reset flags.
- */
-
-static int if_close(struct net_device *dev)
-{
-	ppp_private_area_t *ppp_priv_area = dev->priv;
-	sdla_t *card = ppp_priv_area->card;
-	if (test_and_set_bit(0, (void *) &card->wandev.critical))
-		return -EAGAIN;
-	dev->start = 0;
-	wanpipe_close(card);
-	wanpipe_set_state(card, WAN_DISCONNECTED);
-	ppp_set_intr_mode(card, 0);
-	ppp_comm_disable(card);
-	card->wandev.critical = 0;
-	return 0;
-}
-
-/*============================================================================
- * Build media header.
- *
- * The trick here is to put packet type (Ethertype) into 'protocol' field of
- * the socket buffer, so that we don't forget it.  If packet type is not
- * supported, set skb->protocol to 0 and discard packet later.
- *
- * Return:	media header length.
- */
-
-static int if_header(struct sk_buff *skb, struct net_device *dev,
-	     unsigned short type, void *daddr, void *saddr, unsigned len)
-{
-	switch (type) 
-	{
-		case ETH_P_IP:
-		case ETH_P_IPX:
-			skb->protocol = type;
-			break;
-		default:
-			skb->protocol = 0;
-	}
-	return PPP_HDR_LEN;
-}
-
-/*============================================================================
- * Re-build media header.
- *
- * Return:	1	physical address resolved.
- *		0	physical address not resolved
- */
-
-static int if_rebuild_hdr(struct sk_buff *skb)
-{
-	struct net_device *dev=skb->dev;
-	ppp_private_area_t *ppp_priv_area = dev->priv;
-	sdla_t *card = ppp_priv_area->card;
-	printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
-	       card->devname, dev->name);
-	return 1;
-}
-
-/*============================================================================
- * Send a packet on a network interface.
- * o set tbusy flag (marks start of the transmission) to block a timer-based
- *   transmit from overlapping.
- * o check link state. If link is not up, then drop the packet.
- * o execute adapter send command.
- * o free socket buffer
- *
- * Return:	0	complete (socket buffer must be freed)
- *		non-0	packet may be re-transmitted (tbusy must be set)
- *
- * Notes:
- * 1. This routine is called either by the protocol stack or by the "net
- *    bottom half" (with interrupts enabled).
- * 2. Setting tbusy flag will inhibit further transmit requests from the
- *    protocol stack and can be used for flow control with protocol layer.
- */
-
-static int if_send(struct sk_buff *skb, struct net_device *dev)
-{
-	ppp_private_area_t *ppp_priv_area = dev->priv;
-	sdla_t *card = ppp_priv_area->card;
-	unsigned char *sendpacket;
-	unsigned long check_braddr, check_mcaddr;
-	unsigned long host_cpu_flags;
-	ppp_flags_t *flags = card->flags;
-	int retry = 0;
-	int err, udp_type;
-	++ppp_priv_area->if_send_entry;
-	if (skb == NULL) {
-		/* If we get here, some higher layer thinks we've missed an
-		 * tx-done interrupt.
-		 */
-		printk(KERN_INFO "%s: interface %s got kicked!\n",
-		       card->devname, dev->name);
-		++ppp_priv_area->if_send_skb_null;
-		mark_bh(NET_BH);
-		return 0;
-	}
-	if (dev->tbusy) {
-		/* If our device stays busy for at least 5 seconds then we will
-		 * kick start the device by making dev->tbusy = 0.  We expect 
-		 * that our device never stays busy more than 5 seconds. So this
-		 * is only used as a last resort. 
-		 */
-		++ppp_priv_area->if_send_busy;
-		++card->wandev.stats.collisions;
-		if ((jiffies - ppp_priv_area->tick_counter) < (5 * HZ)) {
-			return 1;
-		}
-		printk(KERN_INFO "%s: Transmit times out\n", card->devname);
-		++ppp_priv_area->if_send_busy_timeout;
-		/* unbusy the card (because only one interface per card) */
-		dev->tbusy = 0;
-	}
-	sendpacket = skb->data;
-	udp_type = udp_pkt_type(skb, card);
-	if (udp_type == UDP_DRVSTATS_TYPE) {
-		++ppp_priv_area->if_send_DRVSTATS_request;
-		process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev,
-					ppp_priv_area);
-		dev_kfree_skb(skb);
-		return 0;
-	} else if (udp_type == UDP_PTPIPE_TYPE)
-		++ppp_priv_area->if_send_PTPIPE_request;
-	/* retreive source address in two forms: broadcast & multicast */
-	check_braddr = sendpacket[15];
-	check_mcaddr = sendpacket[12];
-	check_braddr = check_braddr << 8;
-	check_mcaddr = check_mcaddr << 8;
-	check_braddr |= sendpacket[14];
-	check_mcaddr |= sendpacket[13];
-	check_braddr = check_braddr << 8;
-	check_mcaddr = check_mcaddr << 8;
-	check_braddr |= sendpacket[13];
-	check_mcaddr |= sendpacket[14];
-	check_braddr = check_braddr << 8;
-	check_mcaddr = check_mcaddr << 8;
-	check_braddr |= sendpacket[12];
-	check_mcaddr |= sendpacket[15];
-	/* if the Source Address is a Multicast address */
-	if ((ppp_priv_area->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001)
-	    && (check_mcaddr <= 0xFFFFFFFE)) {
-		printk(KERN_INFO "%s: Mutlicast Src. Addr. silently discarded\n"
-		       ,card->devname);
-		dev_kfree_skb(skb);
-		++ppp_priv_area->if_send_multicast;
-		++card->wandev.stats.tx_dropped;
-		return 0;
-	}
-	disable_irq(card->hw.irq);
-	++card->irq_dis_if_send_count;
-	if (test_and_set_bit(0, (void *) &card->wandev.critical)) {
-		if (card->wandev.critical == CRITICAL_IN_ISR) {
-			/* If the critical flag is set due to an Interrupt
-			 * then set enable transmit interrupt flag to enable
-			 * transmit interrupt. (delay interrupt)
-			 */
-			card->wandev.enable_tx_int = 1;
-			dev->tbusy = 1;
-			/* set the counter to see if we get the interrupt in
-			 * 5 seconds. 
-			 */
-			ppp_priv_area->tick_counter = jiffies;
-			++ppp_priv_area->if_send_critical_ISR;
-			save_flags(host_cpu_flags);
-			cli();
-			if ((!(--card->irq_dis_if_send_count)) &&
-			    (!card->irq_dis_poll_count))
-				enable_irq(card->hw.irq);
-			restore_flags(host_cpu_flags);
-			return 1;
-		}
-		dev_kfree_skb(skb);
-		++ppp_priv_area->if_send_critical_non_ISR;
-		save_flags(host_cpu_flags);
-		cli();
-		if ((!(--card->irq_dis_if_send_count)) &&
-		    (!card->irq_dis_poll_count))
-			enable_irq(card->hw.irq);
-		restore_flags(host_cpu_flags);
-		return 0;
-	}
-	if (udp_type == UDP_PTPIPE_TYPE) {
-		err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb,
-					   dev, ppp_priv_area);
-	} else if (card->wandev.state != WAN_CONNECTED) {
-		++ppp_priv_area->if_send_wan_disconnected;
-		++card->wandev.stats.tx_dropped;
-	} else if (!skb->protocol) {
-		++ppp_priv_area->if_send_protocol_error;
-		++card->wandev.stats.tx_errors;
-	} else {
-		/*If it's IPX change the network numbers to 0 if they're ours. */
-		if (skb->protocol == ETH_P_IPX) {
-			if (card->wandev.enable_IPX) {
-				switch_net_numbers(skb->data,
-					 card->wandev.network_number, 0);
-			} else {
-				++card->wandev.stats.tx_dropped;
-				goto tx_done;
-			}
-		}
-		if (ppp_send(card, skb->data, skb->len, skb->protocol)) {
-			retry = 1;
-			dev->tbusy = 1;
-			++ppp_priv_area->if_send_adptr_bfrs_full;
-			++ppp_priv_area->if_send_tx_int_enabled;
-			ppp_priv_area->tick_counter = jiffies;
-			++card->wandev.stats.tx_errors;
-			flags->imask |= 0x02;	/* unmask Tx interrupts */
-		} else {
-			++ppp_priv_area->if_send_bfr_passed_to_adptr;
-			++card->wandev.stats.tx_packets;
-			card->wandev.stats.tx_bytes += skb->len;
-		}
-	}
-tx_done:
-	if (!retry) {
-		dev_kfree_skb(skb);
-	}
-	card->wandev.critical = 0;
-	save_flags(host_cpu_flags);
-	cli();
-	if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count))
-		enable_irq(card->hw.irq);
-	restore_flags(host_cpu_flags);
-	return retry;
-}
-
-/*============================================================================
- * Reply to UDP Management system.
- * Return length of reply.
- */
-
-static int reply_udp(unsigned char *data, unsigned int mbox_len)
-{
-	unsigned short len, udp_length, temp, i, ip_length;
-	unsigned long sum;
-	/* Set length of packet */
-	len = mbox_len + 60;
-	/* fill in UDP reply */
-	data[36] = 0x02;
-	/* fill in UDP length */
-	udp_length = mbox_len + 40;
-	/* put it on an even boundary */
-	if (udp_length & 0x0001) {
-		udp_length += 1;
-		len += 1;
-	}
-	temp = (udp_length << 8) | (udp_length >> 8);
-	memcpy(&data[24], &temp, 2);
-	/* swap UDP ports */
-	memcpy(&temp, &data[20], 2);
-	memcpy(&data[20], &data[22], 2);
-	memcpy(&data[22], &temp, 2);
-	/* add UDP pseudo header */
-	temp = 0x1100;
-	memcpy(&data[udp_length + 20], &temp, 2);
-	temp = (udp_length << 8) | (udp_length >> 8);
-	memcpy(&data[udp_length + 22], &temp, 2);
-	/* calculate UDP checksum */
-	data[26] = data[27] = 0;
-	sum = 0;
-	for (i = 0; i < udp_length + 12; i += 2) {
-		memcpy(&temp, &data[12 + i], 2);
-		sum += (unsigned long) temp;
-	}
-	while (sum >> 16) {
-		sum = (sum & 0xffffUL) + (sum >> 16);
-	}
-	temp = (unsigned short) sum;
-	temp = ~temp;
-	if (temp == 0)
-		temp = 0xffff;
-	memcpy(&data[26], &temp, 2);
-	/* fill in IP length */
-	ip_length = udp_length + 20;
-	temp = (ip_length << 8) | (ip_length >> 8);
-	memcpy(&data[2], &temp, 2);
-	/* swap IP addresses */
-	memcpy(&temp, &data[12], 2);
-	memcpy(&data[12], &data[16], 2);
-	memcpy(&data[16], &temp, 2);
-	memcpy(&temp, &data[14], 2);
-	memcpy(&data[14], &data[18], 2);
-	memcpy(&data[18], &temp, 2);
-	/* fill in IP checksum */
-	data[10] = data[11] = 0;
-	sum = 0;
-	for (i = 0; i < 20; i += 2) {
-		memcpy(&temp, &data[i], 2);
-		sum += (unsigned long) temp;
-	}
-	while (sum >> 16) {
-		sum = (sum & 0xffffUL) + (sum >> 16);
-	}
-	temp = (unsigned short) sum;
-	temp = ~temp;
-	if (temp == 0)
-		temp = 0xffff;
-	memcpy(&data[10], &temp, 2);
-	return len;
-}				/* reply_udp */
-
-/*
-   If incoming is 0 (outgoing)- if the net numbers is ours make it 0
-   if incoming is 1 - if the net number is 0 make it ours 
- */
-
-static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming)
-{
-	unsigned long pnetwork_number;
-	pnetwork_number = (unsigned long) ((sendpacket[6] << 24) +
-			   (sendpacket[7] << 16) + (sendpacket[8] << 8) +
-					   sendpacket[9]);
-	if (!incoming) {
-		/* If the destination network number is ours, make it 0 */
-		if (pnetwork_number == network_number) {
-			sendpacket[6] = sendpacket[7] = sendpacket[8] =
-			    sendpacket[9] = 0x00;
-		}
-	} else {
-		/* If the incoming network is 0, make it ours */
-		if (pnetwork_number == 0) {
-			sendpacket[6] = (unsigned char) (network_number >> 24);
-			sendpacket[7] = (unsigned char) ((network_number &
-						      0x00FF0000) >> 16);
-			sendpacket[8] = (unsigned char) ((network_number &
-						       0x0000FF00) >> 8);
-			sendpacket[9] = (unsigned char) (network_number &
-							 0x000000FF);
-		}
-	}
-	pnetwork_number = (unsigned long) ((sendpacket[18] << 24) +
-			 (sendpacket[19] << 16) + (sendpacket[20] << 8) +
-					   sendpacket[21]);
-	if (!incoming) {
-		/* If the source network is ours, make it 0 */
-		if (pnetwork_number == network_number) {
-			sendpacket[18] = sendpacket[19] = sendpacket[20] =
-			    sendpacket[21] = 0x00;
-		}
-	} else {
-		/* If the source network is 0, make it ours */
-		if (pnetwork_number == 0) {
-			sendpacket[18] = (unsigned char) (network_number >> 24);
-			sendpacket[19] = (unsigned char) ((network_number &
-						      0x00FF0000) >> 16);
-			sendpacket[20] = (unsigned char) ((network_number &
-						       0x0000FF00) >> 8);
-			sendpacket[21] = (unsigned char) (network_number &
-							  0x000000FF);
-		}
-	}
-}				/* switch_net_numbers */
-
-/*============================================================================
- * Get Ethernet-style interface statistics.
- * Return a pointer to struct enet_statistics.
- */
-
-static struct enet_statistics *if_stats(struct net_device *dev)
-{
-	ppp_private_area_t *ppp_priv_area = dev->priv;
-	sdla_t *card;
-	
-	/*
-	 *	Device is down:No statistics
-	 */
-	 
-	if(ppp_priv_area==NULL)
-		return NULL;
-	
-	card = ppp_priv_area->card;
-	return &card->wandev.stats;
-}
-
-/****** PPP Firmware Interface Functions ************************************/
-
-/*============================================================================
- * Read firmware code version.
- *	Put code version as ASCII string in str. 
- */
-
-static int ppp_read_version(sdla_t * card, char *str)
-{
-	ppp_mbox_t *mb = card->mbox;
-	int err;
-	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
-	mb->cmd.command = PPP_READ_CODE_VERSION;
-	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-	if (err != CMD_OK)
-		ppp_error(card, err, mb);
-	else if (str) {
-		int len = mb->cmd.length;
-		memcpy(str, mb->data, len);
-		str[len] = '\0';
-	}
-	return err;
-}
-
-/*============================================================================
- * Configure PPP firmware.
- */
-
-static int ppp_configure(sdla_t * card, void *data)
-{
-	ppp_mbox_t *mb = card->mbox;
-	int data_len = (card->hw.fwid == SFID_PPP502) ?
-	sizeof(ppp502_conf_t) : sizeof(ppp508_conf_t);
-	int err;
-	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
-	memcpy(mb->data, data, data_len);
-	mb->cmd.length = data_len;
-	mb->cmd.command = PPP_SET_CONFIG;
-	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-	if (err != CMD_OK)
-		ppp_error(card, err, mb);
-	return err;
-}
-
-/*============================================================================
- * Set interrupt mode.
- */
-
-static int ppp_set_intr_mode(sdla_t * card, unsigned mode)
-{
-	ppp_mbox_t *mb = card->mbox;
-	int err;
-	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
-	mb->data[0] = mode;
-	switch (card->hw.fwid) {
-	case SFID_PPP502:
-		mb->cmd.length = 1;
-		break;
-	case SFID_PPP508:
-	default:
-		mb->data[1] = card->hw.irq;
-		mb->cmd.length = 2;
-	}
-	mb->cmd.command = PPP_SET_INTR_FLAGS;
-	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-	if (err != CMD_OK)
-		ppp_error(card, err, mb);
-	return err;
-}
-
-/*============================================================================
- * Enable communications.
- */
-
-static int ppp_comm_enable(sdla_t * card)
-{
-	ppp_mbox_t *mb = card->mbox;
-	int err;
-	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
-	mb->cmd.command = PPP_COMM_ENABLE;
-	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-	if (err != CMD_OK)
-		ppp_error(card, err, mb);
-	return err;
-}
-
-/*============================================================================
- * Disable communications.
- */
-
-static int ppp_comm_disable(sdla_t * card)
-{
-	ppp_mbox_t *mb = card->mbox;
-	int err;
-	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
-	mb->cmd.command = PPP_COMM_DISABLE;
-	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-	if (err != CMD_OK)
-		ppp_error(card, err, mb);
-	return err;
-}
-
-/*============================================================================
- * Get communications error statistics.
- */
-
-static int ppp_get_err_stats(sdla_t * card)
-{
-	ppp_mbox_t *mb = card->mbox;
-	int err;
-	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
-	mb->cmd.command = PPP_READ_ERROR_STATS;
-	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-	if (err == CMD_OK) {
-		ppp_err_stats_t *stats = (void *) mb->data;
-		card->wandev.stats.rx_over_errors = stats->rx_overrun;
-		card->wandev.stats.rx_crc_errors = stats->rx_bad_crc;
-		card->wandev.stats.rx_missed_errors = stats->rx_abort;
-		card->wandev.stats.rx_length_errors = stats->rx_lost;
-		card->wandev.stats.tx_aborted_errors = stats->tx_abort;
-	} else
-		ppp_error(card, err, mb);
-	return err;
-}
-
-/*============================================================================
- * Send packet.
- *	Return:	0 - o.k.
- *		1 - no transmit buffers available
- */
-
-static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto)
-{
-	ppp_buf_ctl_t *txbuf = card->u.p.txbuf;
-	unsigned long addr;
-	if (txbuf->flag)
-		return 1
-		    ;
-	if (card->hw.fwid == SFID_PPP502)
-		addr = (txbuf->buf.o_p[1] << 8) + txbuf->buf.o_p[0];
-	else
-		addr = txbuf->buf.ptr;
-	sdla_poke(&card->hw, addr, data, len);
-	txbuf->length = len;	/* frame length */
-	if (proto == ETH_P_IPX)
-		txbuf->proto = 0x01;	/* protocol ID */
-	txbuf->flag = 1;	/* start transmission */
-	/* Update transmit buffer control fields */
-	card->u.p.txbuf = ++txbuf;
-	if ((void *) txbuf > card->u.p.txbuf_last)
-		card->u.p.txbuf = card->u.p.txbuf_base;
-	return 0;
-}
-
-/****** Firmware Error Handler **********************************************/
-
-/*============================================================================
- * Firmware error handler.
- *	This routine is called whenever firmware command returns non-zero
- *	return code.
- *
- * Return zero if previous command has to be cancelled.
- */
-
-static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb)
-{
-	unsigned cmd = mb->cmd.command;
-	switch (err) {
-	case CMD_TIMEOUT:
-		printk(KERN_ERR "%s: command 0x%02X timed out!\n",
-		       card->devname, cmd);
-		break;
-	default:
-		printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n"
-		       ,card->devname, cmd, err);
-	}
-	return 0;
-}
-
-/****** Interrupt Handlers **************************************************/
-
-/*============================================================================
- * PPP interrupt service routine.
- */
-
-STATIC void wpp_isr(sdla_t * card)
-{
-	ppp_flags_t *flags = card->flags;
-	char *ptr = &flags->iflag;
-	unsigned long host_cpu_flags;
-	struct net_device *dev = card->wandev.dev;
-	int i;
-	card->in_isr = 1;
-	++card->statistics.isr_entry;
-	if (test_and_set_bit(0, (void *) &card->wandev.critical)) {
-		++card->statistics.isr_already_critical;
-		printk(KERN_INFO "%s: Critical while in ISR!\n", card->devname);
-		card->in_isr = 0;
-		return;
-	}
-	/* For all interrupts set the critical flag to CRITICAL_IN_ISR. 
-	 * If the if_send routine is called with this flag set it will set 
-	 * the enable transmit flag to 1. (for a delayed interrupt) 
-	 */
-	card->wandev.critical = CRITICAL_IN_ISR;
-	card->buff_int_mode_unbusy = 0;
-	switch (flags->iflag) {
-	case 0x01:		/* receive interrupt */
-		++card->statistics.isr_rx;
-		rx_intr(card);
-		break;
-	case 0x02:		/* transmit interrupt */
-		++card->statistics.isr_tx;
-		flags->imask &= ~0x02;
-		dev->tbusy = 0;
-		card->buff_int_mode_unbusy = 1;
-		break;
-	case 0x08:
-		++Intr_test_counter;
-		++card->statistics.isr_intr_test;
-		break;
-	default:		/* unexpected interrupt */
-		++card->statistics.isr_spurious;
-		printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n",
-		       card->devname, flags->iflag);
-		printk(KERN_INFO "%s: ID Bytes = ", card->devname);
-		for (i = 0; i < 8; i++)
-			printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
-		printk(KERN_INFO "\n");
-	}
-	/* The critical flag is set to CRITICAL_INTR_HANDLED to let the
-	 * if_send call know that the interrupt is handled so that 
-	 * transmit interrupts are not enabled again.
-	 */
-	card->wandev.critical = CRITICAL_INTR_HANDLED;
-	/* If the enable transmit interrupt flag is set then enable transmit 
-	 * interrupt on the board. This only goes through if if_send is called 
-	 * and the critical flag is set due to an Interrupt. 
-	 */
-	if (card->wandev.enable_tx_int) {
-		flags->imask |= 0x02;
-		card->wandev.enable_tx_int = 0;
-		++card->statistics.isr_enable_tx_int;
-	}
-	save_flags(host_cpu_flags);
-	cli();
-	card->in_isr = 0;
-	flags->iflag = 0;
-	card->wandev.critical = 0;
-	restore_flags(host_cpu_flags);
-	if (card->buff_int_mode_unbusy)
-		mark_bh(NET_BH);
-}
-
-/*============================================================================
- * Receive interrupt handler.
- */
-
-static void rx_intr(sdla_t * card)
-{
-	ppp_buf_ctl_t *rxbuf = card->rxmb;
-	struct net_device *dev = card->wandev.dev;
-	ppp_private_area_t *ppp_priv_area;
-	struct sk_buff *skb;
-	unsigned len;
-	void *buf;
-	int i, err;
-	ppp_flags_t *flags = card->flags;
-	char *ptr = &flags->iflag;
-	int udp_type;
-	if (rxbuf->flag != 0x01) {
-		printk(KERN_INFO
-		       "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n",
-		       card->devname, (unsigned) rxbuf, rxbuf->flag);
-		printk(KERN_INFO "%s: ID Bytes = ", card->devname);
-		for (i = 0; i < 8; i++)
-			printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
-		printk(KERN_INFO "\n");
-		++card->statistics.rx_intr_corrupt_rx_bfr;
-		return;
-	}
-	if (dev && dev->start) {
-		len = rxbuf->length;
-		ppp_priv_area = dev->priv;
-		/* Allocate socket buffer */
-		skb = dev_alloc_skb(len);
-		if (skb != NULL) {
-			/* Copy data to the socket buffer */
-			if (card->hw.fwid == SFID_PPP502) {
-				unsigned addr = (rxbuf->buf.o_p[1] << 8) +
-				rxbuf->buf.o_p[0];
-				buf = skb_put(skb, len);
-				sdla_peek(&card->hw, addr, buf, len);
-			} else {
-				unsigned addr = rxbuf->buf.ptr;
-				if ((addr + len) > card->u.p.rx_top + 1) {
-					unsigned tmp = card->u.p.rx_top - addr
-					+ 1;
-					buf = skb_put(skb, tmp);
-					sdla_peek(&card->hw, addr, buf, tmp);
-					addr = card->u.p.rx_base;
-					len -= tmp;
-				}
-				buf = skb_put(skb, len);
-				sdla_peek(&card->hw, addr, buf, len);
-			}
-			/* Decapsulate packet */
-			switch (rxbuf->proto) {
-			case 0x00:
-				skb->protocol = htons(ETH_P_IP);
-				break;
-			case 0x01:
-				skb->protocol = htons(ETH_P_IPX);
-				break;
-			}
-			udp_type = udp_pkt_type(skb, card);
-			if (udp_type == UDP_DRVSTATS_TYPE) {
-				++ppp_priv_area->rx_intr_DRVSTATS_request;
-				process_udp_driver_call(
-					  UDP_PKT_FRM_NETWORK, card, skb,
-						     dev, ppp_priv_area);
-				dev_kfree_skb(skb);
-			} else if (udp_type == UDP_PTPIPE_TYPE) {
-				++ppp_priv_area->rx_intr_PTPIPE_request;
-				err = process_udp_mgmt_pkt(
-					       UDP_PKT_FRM_NETWORK, card,
-						skb, dev, ppp_priv_area);
-				dev_kfree_skb(skb);
-			} else if (handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) {
-				if (card->wandev.enable_IPX) {
-					ppp_send(card, skb->data, skb->len, ETH_P_IPX);
-					dev_kfree_skb(skb);
-				} else {
-					++card->wandev.stats.rx_dropped;
-				}
-			} else {
-				/* Pass it up the protocol stack */
-				skb->dev = dev;
-				skb->mac.raw = skb->data;
-				netif_rx(skb);
-				++card->wandev.stats.rx_packets;
- 				card->wandev.stats.rx_bytes += skb->len;
-				++ppp_priv_area->rx_intr_bfr_passed_to_stack;
-			}
-		} else {
-			printk(KERN_INFO "%s: no socket buffers available!\n",
-			       card->devname);
-			++card->wandev.stats.rx_dropped;
-			++ppp_priv_area->rx_intr_no_socket;
-		}
-	} else
-		++card->statistics.rx_intr_dev_not_started;
-	/* Release buffer element and calculate a pointer to the next one */
-	rxbuf->flag = (card->hw.fwid == SFID_PPP502) ? 0xFF : 0x00;
-	card->rxmb = ++rxbuf;
-	if ((void *) rxbuf > card->u.p.rxbuf_last)
-		card->rxmb = card->u.p.rxbuf_base;
-}
-
-/*============================================================================
- * Transmit interrupt handler.
- */
-
-static void tx_intr(sdla_t * card)
-{
-	struct net_device *dev = card->wandev.dev;
-	if (!dev || !dev->start) {
-		++card->statistics.tx_intr_dev_not_started;
-		return;
-	}
-	dev->tbusy = 0;
-	mark_bh(NET_BH);
-}
-
-static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto)
-{
-	int i;
-	if (proto == htons(ETH_P_IPX)) {
-		/* It's an IPX packet */
-		if (!enable_IPX) {
-			/* Return 1 so we don't pass it up the stack. */
-			return 1;
-		}
-	} else {
-		/* It's not IPX so pass it up the stack. */
-		return 0;
-	}
-	if (sendpacket[16] == 0x90 &&
-	    sendpacket[17] == 0x04) {
-		/* It's IPXWAN */
-		if (sendpacket[2] == 0x02 &&
-		    sendpacket[34] == 0x00) {
-			/* It's a timer request packet */
-			printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", devname);
-			/* Go through the routing options and answer no to every */
-			/* option except Unnumbered RIP/SAP */
-			for (i = 41; sendpacket[i] == 0x00; i += 5) {
-				/* 0x02 is the option for Unnumbered RIP/SAP */
-				if (sendpacket[i + 4] != 0x02) {
-					sendpacket[i + 1] = 0;
-				}
-			}
-			/* Skip over the extended Node ID option */
-			if (sendpacket[i] == 0x04) {
-				i += 8;
-			}
-			/* We also want to turn off all header compression opt. */
-			for (; sendpacket[i] == 0x80;) {
-				sendpacket[i + 1] = 0;
-				i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4;
-			}
-			/* Set the packet type to timer response */
-			sendpacket[34] = 0x01;
-			printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", devname);
-		} else if (sendpacket[34] == 0x02) {
-			/* This is an information request packet */
-			printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n", devname);
-			/* Set the packet type to information response */
-			sendpacket[34] = 0x03;
-			/* Set the router name */
-			sendpacket[51] = 'P';
-			sendpacket[52] = 'T';
-			sendpacket[53] = 'P';
-			sendpacket[54] = 'I';
-			sendpacket[55] = 'P';
-			sendpacket[56] = 'E';
-			sendpacket[57] = '-';
-			sendpacket[58] = CVHexToAscii(network_number >> 28);
-			sendpacket[59] = CVHexToAscii((network_number & 0x0F000000) >> 24);
-			sendpacket[60] = CVHexToAscii((network_number & 0x00F00000) >> 20);
-			sendpacket[61] = CVHexToAscii((network_number & 0x000F0000) >> 16);
-			sendpacket[62] = CVHexToAscii((network_number & 0x0000F000) >> 12);
-			sendpacket[63] = CVHexToAscii((network_number & 0x00000F00) >> 8);
-			sendpacket[64] = CVHexToAscii((network_number & 0x000000F0) >> 4);
-			sendpacket[65] = CVHexToAscii(network_number & 0x0000000F);
-			for (i = 66; i < 99; i += 1)
-				sendpacket[i] = 0;
-			printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", devname);
-		} else {
-			printk(KERN_INFO "%s: Unknown IPXWAN packet!\n", devname);
-			return 0;
-		}
-		/* Set the WNodeID to our network address */
-		sendpacket[35] = (unsigned char) (network_number >> 24);
-		sendpacket[36] = (unsigned char) ((network_number & 0x00FF0000) >> 16);
-		sendpacket[37] = (unsigned char) ((network_number & 0x0000FF00) >> 8);
-		sendpacket[38] = (unsigned char) (network_number & 0x000000FF);
-		return 1;
-	} else {
-		/* If we get here's its an IPX-data packet, so it'll get passed up the stack. */
-		/* switch the network numbers */
-		switch_net_numbers(sendpacket, network_number, 1);
-		return 0;
-	}
-}
-
-/****** Background Polling Routines  ****************************************/
-
-/*============================================================================
- * Main polling routine.
- * This routine is repeatedly called by the WANPIPE 'thread' to allow for
- * time-dependent housekeeping work.
- *
- * Notes:
- * 1. This routine may be called on interrupt context with all interrupts
- *    enabled. Beware!
- */
-
-static void wpp_poll(sdla_t * card)
-{
-	struct net_device *dev = card->wandev.dev;
-	ppp_flags_t *adptr_flags = card->flags;
-	unsigned long host_cpu_flags;
-	++card->statistics.poll_entry;
-	/* The wpp_poll is called continously by the WANPIPE thread to allow
-	 * for line state housekeeping. However if we are in a connected state
-	 * then we do not need to go through all the checks everytime. When in
-	 * connected state execute wpp_poll once every second.
-	 */
-	if (card->wandev.state == WAN_CONNECTED) {
-		if ((jiffies - card->state_tick) < HZ)
-			return;
-	}
-	disable_irq(card->hw.irq);
-	++card->irq_dis_poll_count;
-	if (test_and_set_bit(0, (void *) &card->wandev.critical)) {
-		++card->statistics.poll_already_critical;
-		printk(KERN_INFO "%s: critical inside wpp_poll\n",
-		       card->devname);
-		save_flags(host_cpu_flags);
-		cli();
-		if ((!card->irq_dis_if_send_count) &&
-		    (!(--card->irq_dis_poll_count)))
-			enable_irq(card->hw.irq);
-		restore_flags(host_cpu_flags);
-		return;
-	}
-	++card->statistics.poll_processed;
-	if (dev && dev->tbusy && !(adptr_flags->imask & 0x02)) {
-		++card->statistics.poll_tbusy_bad_status;
-		printk(KERN_INFO "%s: Wpp_Poll: tbusy = 0x01, imask = 0x%02X\n"
-		       ,card->devname, adptr_flags->imask);
-	}
-	switch (card->wandev.state) {
-	case WAN_CONNECTED:
-		card->state_tick = jiffies;
-		poll_active(card);
-		break;
-	case WAN_CONNECTING:
-		poll_connecting(card);
-		break;
-	case WAN_DISCONNECTED:
-		poll_disconnected(card);
-		break;
-	default:
-		printk(KERN_INFO "%s: Unknown Poll State 0x%02X\n",
-		       card->devname, card->wandev.state);
-		break;
-	}
-	card->wandev.critical = 0;
-	save_flags(host_cpu_flags);
-	cli();
-	if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count)))
-		enable_irq(card->hw.irq);
-	restore_flags(host_cpu_flags);
-}
-
-/*============================================================================
- * Monitor active link phase.
- */
-
-static void poll_active(sdla_t * card)
-{
-	ppp_flags_t *flags = card->flags;
-	/* We check the lcp_state to see if we are in DISCONNECTED state.
-	 * We are considered to be connected for lcp states 0x06, 0x07, 0x08
-	 * and 0x09.
-	 */
-	if ((flags->lcp_state <= 0x05) || (flags->disc_cause & 0x03)) {
-		wanpipe_set_state(card, WAN_DISCONNECTED);
-		show_disc_cause(card, flags->disc_cause);
-	}
-}
-
-/*============================================================================
- * Monitor link establishment phase.
- * o if connection timed out, disconnect the link.
- */
-
-static void poll_connecting(sdla_t * card)
-{
-	ppp_flags_t *flags = card->flags;
-	if (flags->lcp_state == 0x09) {
-		wanpipe_set_state(card, WAN_CONNECTED);
-	} else if (flags->disc_cause & 0x03) {
-		wanpipe_set_state(card, WAN_DISCONNECTED);
-		show_disc_cause(card, flags->disc_cause);
-	}
-}
-
-/*============================================================================
- * Monitor physical link disconnected phase.
- *  o if interface is up and the hold-down timeout has expired, then retry
- *    connection.
- */
-
-static void poll_disconnected(sdla_t * card)
-{
-	struct net_device *dev = card->wandev.dev;
-	if (dev && dev->start &&
-	    ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) {
-		wanpipe_set_state(card, WAN_CONNECTING);
-		if (ppp_comm_enable(card) == CMD_OK)
-			init_ppp_tx_rx_buff(card);
-	}
-}
-
-/****** Miscellaneous Functions *********************************************/
-
-/*============================================================================
- * Configure S502 adapter.
- */
-
-static int config502(sdla_t * card)
-{
-	ppp502_conf_t cfg;
-	/* Prepare PPP configuration structure */
-	memset(&cfg, 0, sizeof(ppp502_conf_t));
-	if (card->wandev.clocking)
-		cfg.line_speed = bps_to_speed_code(card->wandev.bps);
-	cfg.txbuf_num = 4;
-	cfg.mtu_local = card->wandev.mtu;
-	cfg.mtu_remote = card->wandev.mtu;
-	cfg.restart_tmr = 30;
-	cfg.auth_rsrt_tmr = 30;
-	cfg.auth_wait_tmr = 300;
-	cfg.mdm_fail_tmr = 5;
-	cfg.dtr_drop_tmr = 1;
-	cfg.connect_tmout = 0;	/* changed it from 900 */
-	cfg.conf_retry = 10;
-	cfg.term_retry = 2;
-	cfg.fail_retry = 5;
-	cfg.auth_retry = 10;
-	cfg.ip_options = 0x80;
-	cfg.ipx_options = 0xA0;
-	cfg.conf_flags |= 0x0E;
-/*
-   cfg.ip_local         = dev->pa_addr;
-   cfg.ip_remote                = dev->pa_dstaddr;
- */
-	return ppp_configure(card, &cfg);
-}
-
-/*============================================================================
- * Configure S508 adapter.
- */
-
-static int config508(sdla_t * card)
-{
-	ppp508_conf_t cfg;
-	/* Prepare PPP configuration structure */
-	memset(&cfg, 0, sizeof(ppp508_conf_t));
-	if (card->wandev.clocking)
-		cfg.line_speed = card->wandev.bps;
-	if (card->wandev.interface == WANOPT_RS232)
-		cfg.conf_flags |= 0x0020;
-	cfg.conf_flags |= 0x300;	/*send Configure-Request packets forever */
-	cfg.txbuf_percent = 60;	/* % of Tx bufs */
-	cfg.mtu_local = card->wandev.mtu;
-	cfg.mtu_remote = card->wandev.mtu;
-	cfg.restart_tmr = 30;
-	cfg.auth_rsrt_tmr = 30;
-	cfg.auth_wait_tmr = 300;
-	cfg.mdm_fail_tmr = 100;
-	cfg.dtr_drop_tmr = 1;
-	cfg.connect_tmout = 0;	/* changed it from 900 */
-	cfg.conf_retry = 10;
-	cfg.term_retry = 2;
-	cfg.fail_retry = 5;
-	cfg.auth_retry = 10;
-	cfg.ip_options = 0x80;
-	cfg.ipx_options = 0xA0;
-/*
-   cfg.ip_local         = dev->pa_addr;
-   cfg.ip_remote                = dev->pa_dstaddr;
- */
-	return ppp_configure(card, &cfg);
-}
-
-/*============================================================================
- * Show disconnection cause.
- */
-
-static void show_disc_cause(sdla_t * card, unsigned cause)
-{
-	if (cause & 0x0002)
-		printk(KERN_INFO "%s: link terminated by peer\n",
-		       card->devname);
-	else if (cause & 0x0004)
-		printk(KERN_INFO "%s: link terminated by user\n",
-		       card->devname);
-	else if (cause & 0x0008)
-		printk(KERN_INFO "%s: authentication failed\n", card->devname);
-	else if (cause & 0x0010)
-		printk(KERN_INFO
-		       "%s: authentication protocol negotiation failed\n",
-		       card->devname);
-	else if (cause & 0x0020)
-		printk(KERN_INFO
-		       "%s: peer's request for authentication rejected\n",
-		       card->devname);
-	else if (cause & 0x0040)
-		printk(KERN_INFO "%s: MRU option rejected by peer\n",
-		       card->devname);
-	else if (cause & 0x0080)
-		printk(KERN_INFO "%s: peer's MRU was too small\n",
-		       card->devname);
-	else if (cause & 0x0100)
-		printk(KERN_INFO "%s: failed to negotiate peer's LCP options\n",
-		       card->devname);
-	else if (cause & 0x0200)
-		printk(KERN_INFO "%s: failed to negotiate peer's IPCP options\n"
-		       ,card->devname);
-	else if (cause & 0x0400)
-		printk(KERN_INFO
-		       "%s: failed to negotiate peer's IPXCP options\n",
-		       card->devname);
-}
-
-/*============================================================================
- * Convert line speed in bps to a number used by S502 code.
- */
-
-static unsigned char bps_to_speed_code(unsigned long bps)
-{
-	unsigned char number;
-	if (bps <= 1200)
-		number = 0x01;
-	else if (bps <= 2400)
-		number = 0x02;
-	else if (bps <= 4800)
-		number = 0x03;
-	else if (bps <= 9600)
-		number = 0x04;
-	else if (bps <= 19200)
-		number = 0x05;
-	else if (bps <= 38400)
-		number = 0x06;
-	else if (bps <= 45000)
-		number = 0x07;
-	else if (bps <= 56000)
-		number = 0x08;
-	else if (bps <= 64000)
-		number = 0x09;
-	else if (bps <= 74000)
-		number = 0x0A;
-	else if (bps <= 112000)
-		number = 0x0B;
-	else if (bps <= 128000)
-		number = 0x0C;
-	else
-		number = 0x0D;
-	return number;
-}
-
-/*============================================================================
- * Process UDP call of type DRVSTATS.  
- */
-
-static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, ppp_private_area_t * ppp_priv_area)
-{
-	unsigned char *sendpacket;
-	unsigned char buf2[5];
-	unsigned char *data;
-	unsigned char *buf;
-	unsigned int len;
-	ppp_mbox_t *mbox = card->mbox;
-	struct sk_buff *new_skb;
-	int err;
-	sendpacket = skb->data;
-	memcpy(&buf2, &card->wandev.udp_port, 2);
-	if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) {
-		printk(KERN_INFO
-		       "%s: Error allocating memory for UDP DRIVER STATS cmnd0x%02X"
-		       ,card->devname, data[45]);
-		++ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err;
-		return 1;
-	}
-	memcpy(data, sendpacket, skb->len);
-	switch (data[45]) {
-		/* PPIPE_DRIVER_STATISTICS */
-	case 0x26:
-		*(unsigned long *) &data[60] =
-		    ppp_priv_area->if_send_entry;
-		*(unsigned long *) &data[64] =
-		    ppp_priv_area->if_send_skb_null;
-		*(unsigned long *) &data[68] =
-		    ppp_priv_area->if_send_broadcast;
-		*(unsigned long *) &data[72] =
-		    ppp_priv_area->if_send_multicast;
-		*(unsigned long *) &data[76] =
-		    ppp_priv_area->if_send_critical_ISR;
-		*(unsigned long *) &data[80] =
-		    ppp_priv_area->if_send_critical_non_ISR;
-		*(unsigned long *) &data[84] =
-		    ppp_priv_area->if_send_busy;
-		*(unsigned long *) &data[88] =
-		    ppp_priv_area->if_send_busy_timeout;
-		*(unsigned long *) &data[92] =
-		    ppp_priv_area->if_send_DRVSTATS_request;
-		*(unsigned long *) &data[96] =
-		    ppp_priv_area->if_send_PTPIPE_request;
-		*(unsigned long *) &data[100] =
-		    ppp_priv_area->if_send_wan_disconnected;
-		*(unsigned long *) &data[104] =
-		    ppp_priv_area->if_send_adptr_bfrs_full;
-		*(unsigned long *) &data[108] =
-		    ppp_priv_area->if_send_protocol_error;
-		*(unsigned long *) &data[112] =
-		    ppp_priv_area->if_send_tx_int_enabled;
-		*(unsigned long *) &data[116] =
-		    ppp_priv_area->if_send_bfr_passed_to_adptr;
-		*(unsigned long *) &data[118] =
-		    card->irq_dis_if_send_count;
-		mbox->cmd.length = 62;
-		break;
-	case 0x27:
-		*(unsigned long *) &data[60] = card->statistics.isr_entry;
-		*(unsigned long *) &data[64] =
-		    card->statistics.isr_already_critical;
-		*(unsigned long *) &data[68] = card->statistics.isr_rx;
-		*(unsigned long *) &data[72] = card->statistics.isr_tx;
-		*(unsigned long *) &data[76] =
-		    card->statistics.isr_intr_test;
-		*(unsigned long *) &data[80] =
-		    card->statistics.isr_spurious;
-		*(unsigned long *) &data[84] =
-		    card->statistics.isr_enable_tx_int;
-		*(unsigned long *) &data[88] =
-		    card->statistics.rx_intr_corrupt_rx_bfr;
-		*(unsigned long *) &data[92] =
-		    ppp_priv_area->rx_intr_no_socket;
-		*(unsigned long *) &data[96] =
-		    ppp_priv_area->rx_intr_DRVSTATS_request;
-		*(unsigned long *) &data[100] =
-		    ppp_priv_area->rx_intr_PTPIPE_request;
-		*(unsigned long *) &data[104] =
-		    ppp_priv_area->rx_intr_bfr_passed_to_stack;
-		*(unsigned long *) &data[108] =
-		    card->statistics.rx_intr_dev_not_started;
-		*(unsigned long *) &data[112] =
-		    card->statistics.tx_intr_dev_not_started;
-		mbox->cmd.length = 56;
-		break;
-	case 0x28:
-		*(unsigned long *) &data[60] =
-		    ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err;
-		*(unsigned long *) &data[64] =
-		    ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err;
-		*(unsigned long *) &data[68] =
-		    ppp_priv_area->UDP_PTPIPE_mgmt_direction_err;
-		*(unsigned long *) &data[72] =
-		    ppp_priv_area->
-		    UDP_PTPIPE_mgmt_adptr_cmnd_timeout;
-		*(unsigned long *) &data[76] =
-		    ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK;
-		*(unsigned long *) &data[80] =
-		    ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr;
-		*(unsigned long *) &data[84] =
-		    ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack;
-		*(unsigned long *) &data[88] =
-		    ppp_priv_area->UDP_PTPIPE_mgmt_no_socket;
-		*(unsigned long *) &data[92] =
-		    ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err;
-		*(unsigned long *) &data[96] =
-		    ppp_priv_area->
-		    UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
-		*(unsigned long *) &data[100] =
-		    ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
-		*(unsigned long *) &data[104] =
-		    ppp_priv_area->
-		    UDP_DRVSTATS_mgmt_passed_to_adptr;
-		*(unsigned long *) &data[108] =
-		    ppp_priv_area->
-		    UDP_DRVSTATS_mgmt_passed_to_stack;
-		*(unsigned long *) &data[112] =
-		    ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket;
-		*(unsigned long *) &data[116] =
-		    card->statistics.poll_entry;
-		*(unsigned long *) &data[120] =
-		    card->statistics.poll_already_critical;
-		*(unsigned long *) &data[124] =
-		    card->statistics.poll_processed;
-		*(unsigned long *) &data[126] =
-		    card->irq_dis_poll_count;
-		mbox->cmd.length = 70;
-		break;
-	default:
-		/* it's a board command */
-		memcpy(&mbox->cmd, &sendpacket[45], sizeof(ppp_cmd_t));
-		if (mbox->cmd.length) {
-			memcpy(&mbox->data, &sendpacket[60],
-			       mbox->cmd.length);
-		}
-		/* run the command on the board */
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-		if (err != CMD_OK) {
-			ppp_error(card, err, mbox);
-			++ppp_priv_area->
-			    UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
-			break;
-		}
-		++ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
-		/* copy the result back to our buffer */
-		memcpy(data, sendpacket, skb->len);
-		memcpy(&data[45], &mbox->cmd, sizeof(ppp_cmd_t));
-		if (mbox->cmd.length) {
-			memcpy(&data[60], &mbox->data, mbox->cmd.length);
-		}
-	}
-	/* Fill UDP TTL */
-	data[8] = card->wandev.ttl;
-	len = reply_udp(data, mbox->cmd.length);
-	if (udp_pkt_src == UDP_PKT_FRM_NETWORK) {
-		++ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_adptr;
-		ppp_send(card, data, len, skb->protocol);
-	} else {
-		/* Pass it up the stack
-		   Allocate socket buffer */
-		if ((new_skb = dev_alloc_skb(len)) != NULL) {
-			/* copy data into new_skb */
-			buf = skb_put(new_skb, len);
-			memcpy(buf, data, len);
-			++ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack;
-			/* Decapsulate packet and pass it up the protocol 
-			   stack */
-			new_skb->protocol = htons(ETH_P_IP);
-			new_skb->dev = dev;
-			new_skb->mac.raw = new_skb->data;
-			netif_rx(new_skb);
-		} else {
-			++ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket;
-			printk(KERN_INFO "no socket buffers available!\n");
-		}
-	}
-	kfree(data);
-	return 0;
-}
-
-/*=============================================================================
- * Process UDP call of type PTPIPEAB.
- */
-
-static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card,
-				struct sk_buff *skb, struct net_device *dev,
-				ppp_private_area_t * ppp_priv_area)
-{
-	unsigned char *sendpacket;
-	unsigned char buf2[5];
-	unsigned char *data;
-	unsigned char *buf;
-	unsigned int frames, len;
-	struct sk_buff *new_skb;
-	unsigned short buffer_length, real_len;
-	unsigned long data_ptr;
-	int udp_mgmt_req_valid = 1;
-	ppp_mbox_t *mbox = card->mbox;
-	struct timeval tv;
-	int err;
-	sendpacket = skb->data;
-	memcpy(&buf2, &card->wandev.udp_port, 2);
-	if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) {
-		printk(KERN_INFO
-		       "%s: Error allocating memory for UDP management cmnd0x%02X"
-		       ,card->devname, data[45]);
-		++ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err;
-		return 1;
-	}
-	memcpy(data, sendpacket, skb->len);
-	switch (data[45]) {
-		/* FT1 MONITOR STATUS */
-	case 0x80:
-		if (card->hw.fwid != SFID_PPP508) {
-			++ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err;
-			udp_mgmt_req_valid = 0;
-			break;
-		}
-		/* PPIPE_ENABLE_TRACING */
-	case 0x20:
-		/* PPIPE_DISABLE_TRACING */
-	case 0x21:
-		/* PPIPE_GET_TRACE_INFO */
-	case 0x22:
-		/* SET FT1 MODE */
-	case 0x81:
-		if (udp_pkt_src == UDP_PKT_FRM_NETWORK) {
-			++ppp_priv_area->UDP_PTPIPE_mgmt_direction_err;
-			udp_mgmt_req_valid = 0;
-		}
-		break;
-	default:
-		break;
-	}
-	if (!udp_mgmt_req_valid) {
-		/* set length to 0 */
-		data[46] = data[47] = 0;
-		/* set return code */
-		data[48] = 0xCD;
-	} else {
-		switch (data[45]) {
-			/* PPIPE_ENABLE_TRACING */
-		case 0x20:
-			if (!TracingEnabled) {
-				/* OPERATE_DATALINE_MONITOR */
-				mbox->cmd.command = 0x33;
-				mbox->cmd.length = 1;
-				mbox->data[0] = 0x03;
-				err = sdla_exec(mbox) ?
-				    mbox->cmd.result : CMD_TIMEOUT;
-				if (err != CMD_OK) {
-					ppp_error(card, err, mbox);
-					TracingEnabled = 0;
-					/* set the return code */
-					data[48] = mbox->cmd.result;
-					mbox->cmd.length = 0;
-					break;
-				}
-				if (card->hw.fwid == SFID_PPP502) {
-					sdla_peek(&card->hw, 0x9000, &buf2, 2);
-				} else {
-					sdla_peek(&card->hw, 0xC000, &buf2, 2);
-				}
-				curr_trace_addr = 0;
-				memcpy(&curr_trace_addr, &buf2, 2);
-				start_trace_addr = curr_trace_addr;
-				/* MAX_SEND_BUFFER_SIZE -sizeof(UDP_MGMT_PACKET)
-				   - 41 */
-				available_buffer_space = 1926;
-			}
-			data[48] = 0;
-			mbox->cmd.length = 0;
-			TracingEnabled = 1;
-			break;
-			/* PPIPE_DISABLE_TRACING */
-		case 0x21:
-			if (TracingEnabled) {
-				/* OPERATE_DATALINE_MONITOR */
-				mbox->cmd.command = 0x3;
-				mbox->cmd.length = 1;
-				mbox->data[0] = 0x00;
-				err = sdla_exec(mbox) ?
-				    mbox->cmd.result : CMD_TIMEOUT;
-			}
-			/*set return code */
-			data[48] = 0;
-			mbox->cmd.length = 0;
-			TracingEnabled = 0;
-			break;
-			/* PPIPE_GET_TRACE_INFO */
-		case 0x22:
-			if (TracingEnabled) {
-				buffer_length = 0;
-				/* frames < NUM_TRACE_FRAMES */
-				for (frames = 0; frames < 62; frames += 1) {
-					sdla_peek(&card->hw, curr_trace_addr,
-						  &buf2, 1);
-					/* no data on board so exit */
-					if (buf2[0] == 0x00)
-						break;
-					/*1+sizeof(FRAME_DATA) = 9 */
-					if ((available_buffer_space -
-					     buffer_length) < 9) {
-						/*indicate we have more frames 
-						   on board and exit */
-						data[60] |= 0x02;
-						break;
-					}
-					/* get frame status */
-					sdla_peek(&card->hw, curr_trace_addr +
-						  0x01, &data[60 + buffer_length], 1);
-					/* get time stamp */
-					sdla_peek(&card->hw, curr_trace_addr +
-						  0x06, &data[64 + buffer_length], 2);
-					/* get frame length */
-					sdla_peek(&card->hw, curr_trace_addr +
-						  0x02, &data[62 + buffer_length], 2);
-					/* get pointer to real data */
-					sdla_peek(&card->hw, curr_trace_addr +
-						  0x04, &buf2, 2);
-					data_ptr = 0;
-					memcpy(&data_ptr, &buf2, 2);
-					/* see if we can fit the frame into the 
-					   user buffer */
-					memcpy(&real_len,
-					   &data[62 + buffer_length], 2);
-					if ((data_ptr == 0) ||
-					    ((real_len + 8) >
-					     available_buffer_space)) {
-						data[61 + buffer_length] = 0x00;
-					} else {
-						/* we can take it next time */
-						if ((available_buffer_space -
-						     buffer_length) <
-						    (real_len + 8)) {
-							data[60] |= 0x02;
-							break;
-						}
-						/* ok, get the frame */
-						data[61 + buffer_length] = 0x01;
-						/* get the data */
-						sdla_peek(&card->hw, data_ptr,
-						&data[66 + buffer_length],
-							  real_len);
-						/* zero the opp flag to 
-						   show we got the frame */
-						buf2[0] = 0x00;
-						sdla_poke(&card->hw,
-							  curr_trace_addr, &buf2, 1);
-						/* now move onto the next 
-						   frame */
-						curr_trace_addr += 8;
-						/* check if we passed the last 
-						   address */
-						if (curr_trace_addr >=
-						    start_trace_addr + 0x1F0) {
-							curr_trace_addr =
-							    start_trace_addr;
-						}
-						/* update buffer length and make                                                   sure its even */
-						if (data[61 + buffer_length]
-						    == 0x01) {
-							buffer_length +=
-							    real_len - 1;
-						}
-						/* for the header */
-						buffer_length += 8;
-						if (buffer_length & 0x0001)
-							buffer_length += 1;
-					}
-				}
-				/* ok now set the total number of frames passed
-				   in the high 5 bits */
-				data[60] = (frames << 2) | data[60];
-				/* set the data length */
-				mbox->cmd.length = buffer_length;
-				memcpy(&data[46], &buffer_length, 2);
-				/* set return code */
-				data[48] = 0;
-			} else {
-				/* set return code */
-				data[48] = 1;
-				mbox->cmd.length = 0;
-			}
-			break;
-			/* PPIPE_GET_IBA_DATA */
-		case 0x23:
-			mbox->cmd.length = 0x09;
-			if (card->hw.fwid == SFID_PPP502) {
-				sdla_peek(&card->hw, 0xA003, &data[60],
-					  mbox->cmd.length);
-			} else {
-				sdla_peek(&card->hw, 0xF003, &data[60],
-					  mbox->cmd.length);
-			}
-			/* set the length of the data */
-			data[46] = 0x09;
-			/* set return code */
-			data[48] = 0x00;
-			break;
-			/* PPIPE_KILL_BOARD */
-		case 0x24:
-			break;
-			/* PPIPE_FT1_READ_STATUS */
-		case 0x25:
-			sdla_peek(&card->hw, 0xF020, &data[60], 2);
-			data[46] = 2;
-			data[47] = 0;
-			data[48] = 0;
-			mbox->cmd.length = 2;
-			break;
-		case 0x29:
-			init_ppp_priv_struct(ppp_priv_area);
-			init_global_statistics(card);
-			mbox->cmd.length = 0;
-			break;
-		case 0x30:
-			do_gettimeofday(&tv);
-			ppp_priv_area->router_up_time = tv.tv_sec -
-			    ppp_priv_area->router_start_time;
-			*(unsigned long *) &data[60] =
-			    ppp_priv_area->router_up_time;
-			mbox->cmd.length = 4;
-			break;
-			/* FT1 MONITOR STATUS */
-		case 0x80:
-			/* Enable FT1 MONITOR STATUS */
-			if (data[60] == 1) {
-				if (rCount++ != 0) {
-					data[48] = 0;
-					mbox->cmd.length = 1;
-					break;
-				}
-			}
-			/* Disable FT1 MONITOR STATUS */
-			if (data[60] == 0) {
-				if (--rCount != 0) {
-					data[48] = 0;
-					mbox->cmd.length = 1;
-					break;
-				}
-			}
-		default:
-			/* it's a board command */
-			memcpy(&mbox->cmd, &sendpacket[45], sizeof(ppp_cmd_t));
-			if (mbox->cmd.length) {
-				memcpy(&mbox->data, &sendpacket[60],
-				       mbox->cmd.length);
-			}
-			/* run the command on the board */
-			err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-			if (err != CMD_OK) {
-				ppp_error(card, err, mbox);
-				++ppp_priv_area->
-				    UDP_PTPIPE_mgmt_adptr_cmnd_timeout;
-				break;
-			}
-			++ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK;
-			/* copy the result back to our buffer */
-			memcpy(data, sendpacket, skb->len);
-			memcpy(&data[45], &mbox->cmd, sizeof(ppp_cmd_t));
-			if (mbox->cmd.length) {
-				memcpy(&data[60], &mbox->data, mbox->cmd.length);
-			}
-		}		/* end of switch */
-	}			/* end of else */
-	/* Fill UDP TTL */
-	data[8] = card->wandev.ttl;
-	len = reply_udp(data, mbox->cmd.length);
-	if (udp_pkt_src == UDP_PKT_FRM_NETWORK) {
-		++ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr;
-		ppp_send(card, data, len, skb->protocol);
-	} else {
-		/* Pass it up the stack
-		   Allocate socket buffer */
-		if ((new_skb = dev_alloc_skb(len)) != NULL) {
-			/* copy data into new_skb */
-			buf = skb_put(new_skb, len);
-			memcpy(buf, data, len);
-			++ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack;
-			/* Decapsulate packet and pass it up the protocol 
-			   stack */
-			new_skb->protocol = htons(ETH_P_IP);
-			new_skb->dev = dev;
-			new_skb->mac.raw = new_skb->data;
-			netif_rx(new_skb);
-		} else {
-			++ppp_priv_area->UDP_PTPIPE_mgmt_no_socket;
-			printk(KERN_INFO "no socket buffers available!\n");
-		}
-	}
-	kfree(data);
-	return 0;
-}
-
-/*=============================================================================
- * Initial the ppp_private_area structure.
- */
-
-static void init_ppp_priv_struct(ppp_private_area_t * ppp_priv_area)
-{
-	ppp_priv_area->if_send_entry = 0;
-	ppp_priv_area->if_send_skb_null = 0;
-	ppp_priv_area->if_send_broadcast = 0;
-	ppp_priv_area->if_send_multicast = 0;
-	ppp_priv_area->if_send_critical_ISR = 0;
-	ppp_priv_area->if_send_critical_non_ISR = 0;
-	ppp_priv_area->if_send_busy = 0;
-	ppp_priv_area->if_send_busy_timeout = 0;
-	ppp_priv_area->if_send_DRVSTATS_request = 0;
-	ppp_priv_area->if_send_PTPIPE_request = 0;
-	ppp_priv_area->if_send_wan_disconnected = 0;
-	ppp_priv_area->if_send_adptr_bfrs_full = 0;
-	ppp_priv_area->if_send_bfr_passed_to_adptr = 0;
-	ppp_priv_area->rx_intr_no_socket = 0;
-	ppp_priv_area->rx_intr_DRVSTATS_request = 0;
-	ppp_priv_area->rx_intr_PTPIPE_request = 0;
-	ppp_priv_area->rx_intr_bfr_not_passed_to_stack = 0;
-	ppp_priv_area->rx_intr_bfr_passed_to_stack = 0;
-	ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err = 0;
-	ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err = 0;
-	ppp_priv_area->UDP_PTPIPE_mgmt_direction_err = 0;
-	ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_timeout = 0;
-	ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK = 0;
-	ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr = 0;
-	ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack = 0;
-	ppp_priv_area->UDP_PTPIPE_mgmt_no_socket = 0;
-	ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err = 0;
-	ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_type_err = 0;
-	ppp_priv_area->UDP_DRVSTATS_mgmt_direction_err = 0;
-	ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout = 0;
-	ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK = 0;
-	ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_adptr = 0;
-	ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack = 0;
-	ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket = 0;
-}
-
-/*============================================================================
- * Initialize Global Statistics
- */
-
-static void init_global_statistics(sdla_t * card)
-{
-	card->statistics.isr_entry = 0;
-	card->statistics.isr_already_critical = 0;
-	card->statistics.isr_tx = 0;
-	card->statistics.isr_rx = 0;
-	card->statistics.isr_intr_test = 0;
-	card->statistics.isr_spurious = 0;
-	card->statistics.isr_enable_tx_int = 0;
-	card->statistics.rx_intr_corrupt_rx_bfr = 0;
-	card->statistics.rx_intr_dev_not_started = 0;
-	card->statistics.tx_intr_dev_not_started = 0;
-	card->statistics.poll_entry = 0;
-	card->statistics.poll_already_critical = 0;
-	card->statistics.poll_processed = 0;
-	card->statistics.poll_tbusy_bad_status = 0;
-}
-
-/*============================================================================
- * Initialize Receive and Transmit Buffers.
- */
-
-static void init_ppp_tx_rx_buff(sdla_t * card)
-{
-	if (card->hw.fwid == SFID_PPP502) {
-		ppp502_buf_info_t *info =
-		(void *) (card->hw.dpmbase + PPP502_BUF_OFFS);
-		card->u.p.txbuf_base =
-		    (void *) (card->hw.dpmbase + info->txb_offs);
-		card->u.p.txbuf_last = (ppp_buf_ctl_t *) card->u.p.txbuf_base +
-		    (info->txb_num - 1);
-		card->u.p.rxbuf_base =
-		    (void *) (card->hw.dpmbase + info->rxb_offs);
-		card->u.p.rxbuf_last = (ppp_buf_ctl_t *) card->u.p.rxbuf_base +
-		    (info->rxb_num - 1);
-	} else {
-		ppp508_buf_info_t *info =
-		(void *) (card->hw.dpmbase + PPP508_BUF_OFFS);
-		card->u.p.txbuf_base = (void *) (card->hw.dpmbase +
-				       (info->txb_ptr - PPP508_MB_VECT));
-		card->u.p.txbuf_last = (ppp_buf_ctl_t *) card->u.p.txbuf_base +
-		    (info->txb_num - 1);
-		card->u.p.rxbuf_base = (void *) (card->hw.dpmbase +
-				       (info->rxb_ptr - PPP508_MB_VECT));
-		card->u.p.rxbuf_last = (ppp_buf_ctl_t *) card->u.p.rxbuf_base +
-		    (info->rxb_num - 1);
-		card->u.p.rx_base = info->rxb_base;
-		card->u.p.rx_top = info->rxb_end;
-	}
-	card->u.p.txbuf = card->u.p.txbuf_base;
-	card->rxmb = card->u.p.rxbuf_base;
-}
-
-/*=============================================================================
- * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR
- * _TEST_COUNTER times.
- */
-
-static int intr_test(sdla_t * card)
-{
-	ppp_mbox_t *mb = card->mbox;
-	int err, i;
-	/* The critical flag is unset because during initialization (if_open) 
-	 * we want the interrupts to be enabled so that when the wpp_isr is
-	 * called it does not exit due to critical flag set.
-	 */
-	card->wandev.critical = 0;
-	err = ppp_set_intr_mode(card, 0x08);
-	if (err == CMD_OK) {
-		for (i = 0; i < MAX_INTR_TEST_COUNTER; i++) {
-			/* Run command READ_CODE_VERSION */
-			memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
-			mb->cmd.length = 0;
-			mb->cmd.command = 0x10;
-			err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-			if (err != CMD_OK)
-				ppp_error(card, err, mb);
-		}
-	} else
-		return err;
-	err = ppp_set_intr_mode(card, 0);
-	if (err != CMD_OK)
-		return err;
-	card->wandev.critical = 1;
-	return 0;
-}
-
-/*==============================================================================
- * Determine what type of UDP call it is. DRVSTATS or PTPIPEAB ?
- */
-
-static int udp_pkt_type(struct sk_buff *skb, sdla_t * card)
-{
-	unsigned char *sendpacket;
-	unsigned char buf2[5];
-	sendpacket = skb->data;
-	memcpy(&buf2, &card->wandev.udp_port, 2);
-	if (sendpacket[0] == 0x45 &&	/* IP packet */
-	    sendpacket[9] == 0x11 &&	/* UDP packet */
-	    sendpacket[22] == buf2[1] &&	/* UDP Port */
-	    sendpacket[23] == buf2[0] &&
-	    sendpacket[36] == 0x01) {
-		if (sendpacket[28] == 0x50 &&	/* PTPIPEAB: Signature */
-		    sendpacket[29] == 0x54 &&
-		    sendpacket[30] == 0x50 &&
-		    sendpacket[31] == 0x49 &&
-		    sendpacket[32] == 0x50 &&
-		    sendpacket[33] == 0x45 &&
-		    sendpacket[34] == 0x41 &&
-		    sendpacket[35] == 0x42) {
-			return UDP_PTPIPE_TYPE;
-		} else if (sendpacket[28] == 0x44 &&	/* DRVSTATS: Signature */
-			   sendpacket[29] == 0x52 &&
-			   sendpacket[30] == 0x56 &&
-			   sendpacket[31] == 0x53 &&
-			   sendpacket[32] == 0x54 &&
-			   sendpacket[33] == 0x41 &&
-			   sendpacket[34] == 0x54 &&
-			   sendpacket[35] == 0x53) {
-			return UDP_DRVSTATS_TYPE;
-		} else
-			return UDP_INVALID_TYPE;
-	} else
-		return UDP_INVALID_TYPE;
-}
-
-/****** End *****************************************************************/
diff -u --recursive --new-file v2.3.20/linux/drivers/net/sdla_x25.c linux/drivers/net/sdla_x25.c
--- v2.3.20/linux/drivers/net/sdla_x25.c	Wed Aug 18 11:36:42 1999
+++ linux/drivers/net/sdla_x25.c	Wed Dec 31 16:00:00 1969
@@ -1,2435 +0,0 @@
-/*****************************************************************************
-* sdla_x25.c	WANPIPE(tm) Multiprotocol WAN Link Driver.  X.25 module.
-*
-* Author:	Gene Kozin	<genek@compuserve.com>
-*
-* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
-*
-*		This program is free software; you can redistribute it and/or
-*		modify it under the terms of the GNU General Public License
-*		as published by the Free Software Foundation; either version
-*		2 of the License, or (at your option) any later version.
-* ============================================================================
-* Mar 15, 1998  Alan Cox	 o 2.1.x porting
-* Nov 27, 1997	Jaspreet Singh	 o Added protection against enabling of irqs
-*				   when they are disabled.
-* Nov 17, 1997  Farhan Thawar    o Added IPX support
-*				 o Changed if_send() to now buffer packets when
-*				   the board is busy
-*				 o Removed queueing of packets via the polling
-*				   routing
-*				 o Changed if_send() critical flags to properly
-*				   handle race conditions
-* Nov 06, 1997  Farhan Thawar    o Added support for SVC timeouts
-*				 o Changed PVC encapsulation to ETH_P_IP
-* Jul 21, 1997  Jaspreet Singh	 o Fixed freeing up of buffers using kfree()
-*				   when packets are received.
-* Mar 11, 1997  Farhan Thawar   Version 3.1.1
-*                                o added support for V35
-*                                o changed if_send() to return 0 if
-*                                  wandev.critical() is true
-*                                o free socket buffer in if_send() if
-*                                  returning 0
-*                                o added support for single '@' address to
-*                                  accept all incoming calls
-*                                o fixed bug in set_chan_state() to disconnect
-* Jan 15, 1997	Gene Kozin	Version 3.1.0
-*				 o implemented exec() entry point
-* Jan 07, 1997	Gene Kozin	Initial version.
-*****************************************************************************/
-
-
-#include <linux/kernel.h>	/* printk(), and other useful stuff */
-#include <linux/stddef.h>	/* offsetof(), etc. */
-#include <linux/errno.h>	/* return codes */
-#include <linux/string.h>	/* inline memset(), etc. */
-#include <linux/malloc.h>	/* kmalloc(), kfree() */
-#include <linux/wanrouter.h>	/* WAN router definitions */
-#include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
-#include <asm/byteorder.h>	/* htons(), etc. */
-#include <asm/uaccess.h>
-
-#define	_GNUC_
-#include <linux/sdla_x25.h>	/* X.25 firmware API definitions */
-
-/****** Defines & Macros ****************************************************/
-
-#define	CMD_OK		0		/* normal firmware return code */
-#define	CMD_TIMEOUT	0xFF		/* firmware command timed out */
-#define	MAX_CMD_RETRY	10		/* max number of firmware retries */
-
-#define	X25_CHAN_MTU	4096		/* unfragmented logical channel MTU */
-#define	X25_HRDHDR_SZ	7		/* max encapsulation header size */
-#define	X25_CONCT_TMOUT	(90*HZ)		/* link connection timeout */
-#define	X25_RECON_TMOUT	(10*HZ)		/* link connection timeout */
-#define	CONNECT_TIMEOUT	(90*HZ)		/* link connection timeout */
-#define	HOLD_DOWN_TIME	(30*HZ)		/* link hold down time */
-
-/* For IPXWAN */
-#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b)))
-
-/****** Data Structures *****************************************************/
-
-/* This is an extention of the 'struct net_device' we create for each network
- * interface to keep the rest of X.25 channel-specific data.
- */
-typedef struct x25_channel
-{
-	char name[WAN_IFNAME_SZ+1];	/* interface name, ASCIIZ */
-	char addr[WAN_ADDRESS_SZ+1];	/* media address, ASCIIZ */
-	unsigned lcn;			/* logical channel number */
-	unsigned tx_pkt_size;
-	unsigned short protocol;	/* ethertype, 0 - multiplexed */
-	char svc;			/* 0 - permanent, 1 - switched */
-	char state;			/* channel state */
-	char drop_sequence;		/* mark sequence for dropping */
-	unsigned long state_tick;	/* time of the last state change */
-	unsigned idle_timeout;		/* sec, before disconnecting */
-	unsigned long i_timeout_sofar;  /* # of sec's we've been idle */
-	unsigned hold_timeout;		/* sec, before re-connecting */
-	unsigned long tick_counter;	/* counter for transmit time out */
-	char devtint;			/* Weather we should dev_tint() */
-	struct sk_buff* rx_skb;		/* receive socket buffer */
-	struct sk_buff* tx_skb;		/* transmit socket buffer */
-	sdla_t* card;			/* -> owner */
-	int ch_idx;
-	struct net_device_stats ifstats;	/* interface statistics */
-} x25_channel_t;
-
-typedef struct x25_call_info
-{
-	char dest[17];			/* ASCIIZ destination address */
-	char src[17];			/* ASCIIZ source address */
-	char nuser;			/* number of user data bytes */
-	unsigned char user[127];	/* user data */
-	char nfacil;			/* number of facilities */
-	struct
-	{
-		unsigned char code;
-		unsigned char parm;
-	} facil[64];			/* facilities */
-} x25_call_info_t;
-
-/****** Function Prototypes *************************************************/
-
-/* WAN link driver entry points. These are called by the WAN router module. */
-static int update (wan_device_t* wandev);
-static int new_if (wan_device_t* wandev, struct net_device* dev,
-	wanif_conf_t* conf);
-static int del_if (wan_device_t* wandev, struct net_device* dev);
-
-/* WANPIPE-specific entry points */
-static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data);
-
-/* Network device interface */
-static int if_init   (struct net_device* dev);
-static int if_open   (struct net_device* dev);
-static int if_close  (struct net_device* dev);
-static int if_header (struct sk_buff* skb, struct net_device* dev,
-	unsigned short type, void* daddr, void* saddr, unsigned len);
-static int if_rebuild_hdr (struct sk_buff* skb);
-static int if_send (struct sk_buff* skb, struct net_device* dev);
-static struct net_device_stats * if_stats (struct net_device* dev);
-
-/* Interrupt handlers */
-static void wpx_isr	(sdla_t* card);
-static void rx_intr	(sdla_t* card);
-static void tx_intr	(sdla_t* card);
-static void status_intr	(sdla_t* card);
-static void event_intr	(sdla_t* card);
-static void spur_intr	(sdla_t* card);
-
-/* Background polling routines */
-static void wpx_poll (sdla_t* card);
-static void poll_disconnected (sdla_t* card);
-static void poll_connecting (sdla_t* card);
-static void poll_active (sdla_t* card);
-
-/* X.25 firmware interface functions */
-static int x25_get_version (sdla_t* card, char* str);
-static int x25_configure (sdla_t* card, TX25Config* conf);
-static int x25_get_err_stats (sdla_t* card);
-static int x25_get_stats (sdla_t* card);
-static int x25_set_intr_mode (sdla_t* card, int mode);
-static int x25_close_hdlc (sdla_t* card);
-static int x25_open_hdlc (sdla_t* card);
-static int x25_setup_hdlc (sdla_t* card);
-static int x25_set_dtr (sdla_t* card, int dtr);
-static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan);
-static int x25_place_call (sdla_t* card, x25_channel_t* chan);
-static int x25_accept_call (sdla_t* card, int lcn, int qdm);
-static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn);
-static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf);
-static int x25_fetch_events (sdla_t* card);
-static int x25_error (sdla_t* card, int err, int cmd, int lcn);
-
-/* X.25 asynchronous event handlers */
-static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
-static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
-static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
-static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
-static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
-
-/* Miscellaneous functions */
-static int connect (sdla_t* card);
-static int disconnect (sdla_t* card);
-static struct net_device* get_dev_by_lcn(wan_device_t* wandev, unsigned lcn);
-static int chan_connect (struct net_device* dev);
-static int chan_disc (struct net_device* dev);
-static void set_chan_state (struct net_device* dev, int state);
-static int chan_send (struct net_device* dev, struct sk_buff* skb);
-static unsigned char bps_to_speed_code (unsigned long bps);
-static unsigned int dec_to_uint (unsigned char* str, int len);
-static unsigned int hex_to_uint (unsigned char* str, int len);
-static void parse_call_info (unsigned char* str, x25_call_info_t* info);
-
-/* IPX functions */
-static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming);
-static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto);
-
-extern void disable_irq(unsigned int);
-extern void enable_irq(unsigned int);
-
-/****** Global Data **********************************************************
- * Note: All data must be explicitly initialized!!!
- */
-
-/****** Public Functions ****************************************************/
-
-/*============================================================================
- * X.25 Protocol Initialization routine.
- *
- * This routine is called by the main WANPIPE module during setup.  At this
- * point adapter is completely initialized and X.25 firmware is running.
- *  o read firmware version (to make sure it's alive)
- *  o configure adapter
- *  o initialize protocol-specific fields of the adapter data space.
- *
- * Return:	0	o.k.
- *		< 0	failure.
- */
-int wpx_init (sdla_t* card, wandev_conf_t* conf)
-{
-	union
-	{
-		char str[80];
-		TX25Config cfg;
-	} u;
-
-	/* Verify configuration ID */
-	if (conf->config_id != WANCONFIG_X25)
-	{
-		printk(KERN_INFO "%s: invalid configuration ID %u!\n",
-			card->devname, conf->config_id)
-		;
-		return -EINVAL;
-	}
-
-	/* Initialize protocol-specific fields */
-	card->mbox  = (void*)(card->hw.dpmbase + X25_MBOX_OFFS);
-	card->rxmb  = (void*)(card->hw.dpmbase + X25_RXMBOX_OFFS);
-	card->flags = (void*)(card->hw.dpmbase + X25_STATUS_OFFS);
-
-	/* Read firmware version.  Note that when adapter initializes, it
-	 * clears the mailbox, so it may appear that the first command was
-	 * executed successfully when in fact it was merely erased. To work
-	 * around this, we execute the first command twice.
-	 */
-	if (x25_get_version(card, NULL) || x25_get_version(card, u.str))
-		return -EIO
-	;
-	printk(KERN_INFO "%s: running X.25 firmware v%s\n",
-		card->devname, u.str)
-	;
-
-	/* Configure adapter. Here we set resonable defaults, then parse
-	 * device configuration structure and set configuration options.
-	 * Most configuration options are verified and corrected (if
-	 * necessary) since we can't rely on the adapter to do so and don't
-	 * want it to fail either.
-	 */
-	memset(&u.cfg, 0, sizeof(u.cfg));
-	u.cfg.t1		= 3;
-	u.cfg.n2		= 10;
-	u.cfg.autoHdlc		= 1;		/* automatic HDLC connection */
-	u.cfg.hdlcWindow	= 7;
-	u.cfg.pktWindow		= 2;
-	u.cfg.station		= 1;		/* DTE */
-	u.cfg.options		= 0x00B0;	/* disable D-bit pragmatics */
-	u.cfg.ccittCompat	= 1988;
-	u.cfg.t10t20		= 30;
-	u.cfg.t11t21		= 30;
-	u.cfg.t12t22		= 30;
-	u.cfg.t13t23		= 30;
-	u.cfg.t16t26		= 30;
-	u.cfg.t28		= 30;
-	u.cfg.r10r20		= 5;
-	u.cfg.r12r22		= 5;
-	u.cfg.r13r23		= 5;
-	u.cfg.responseOpt	= 1;		/* RR's after every packet */
-
-	if (conf->clocking != WANOPT_EXTERNAL)
-		u.cfg.baudRate = bps_to_speed_code(conf->bps)
-	;
-	if (conf->station != WANOPT_DTE)
-	{
-		u.cfg.station = 0;		/* DCE mode */
-	}
-        if (conf->interface != WANOPT_RS232 ) {
-	        u.cfg.hdlcOptions |= 0x80;      /* V35 mode */
-	} 
-	/* adjust MTU */
-	if (!conf->mtu || (conf->mtu >= 1024))
-		card->wandev.mtu = 1024
-	;
-	else if (conf->mtu >= 512)
-		card->wandev.mtu = 512
-	;
-	else if (conf->mtu >= 256)
-		card->wandev.mtu = 256
-	;
-	else if (conf->mtu >= 128)
-		card->wandev.mtu = 128
-	;
-	else card->wandev.mtu = 64;
-	u.cfg.defPktSize = u.cfg.pktMTU = card->wandev.mtu;
-
-	if (conf->u.x25.hi_pvc)
-	{
-		card->u.x.hi_pvc = min(conf->u.x25.hi_pvc, 4095);
-		card->u.x.lo_pvc = min(conf->u.x25.lo_pvc, card->u.x.hi_pvc);
-	}
-	if (conf->u.x25.hi_svc)
-	{
-		card->u.x.hi_svc = min(conf->u.x25.hi_svc, 4095);
-		card->u.x.lo_svc = min(conf->u.x25.lo_svc, card->u.x.hi_svc);
-	}
-	u.cfg.loPVC	  = card->u.x.lo_pvc;
-	u.cfg.hiPVC	  = card->u.x.hi_pvc;
-	u.cfg.loTwoWaySVC = card->u.x.lo_svc;
-	u.cfg.hiTwoWaySVC = card->u.x.hi_svc;
-
-	if (conf->u.x25.hdlc_window)
-		u.cfg.hdlcWindow = min(conf->u.x25.hdlc_window, 7)
-	;
-	if (conf->u.x25.pkt_window)
-		u.cfg.pktWindow = min(conf->u.x25.pkt_window, 7)
-	;
-	if (conf->u.x25.t1)
-		u.cfg.t1 = min(conf->u.x25.t1, 30)
-	;
-	u.cfg.t2 = min(conf->u.x25.t2, 29);
-	u.cfg.t4 = min(conf->u.x25.t4, 240);
-	if (conf->u.x25.n2)
-		u.cfg.n2 = min(conf->u.x25.n2, 30)
-	;
-	if (conf->u.x25.ccitt_compat)
-		u.cfg.ccittCompat = conf->u.x25.ccitt_compat
-	;
-
-	/* initialize adapter */
-	if ((x25_configure(card, &u.cfg) != CMD_OK) ||
-	    (x25_close_hdlc(card) != CMD_OK) ||		/* close HDLC link */
-	    (x25_set_dtr(card, 0) != CMD_OK))		/* drop DTR */
-		return -EIO
-	;
-
-	/* Initialize protocol-specific fields of adapter data space */
-	card->wandev.bps	= conf->bps;
-	card->wandev.interface	= conf->interface;
-	card->wandev.clocking	= conf->clocking;
-	card->wandev.station	= conf->station;
-	card->isr		= &wpx_isr;
-	card->poll		= &wpx_poll;
-	card->exec		= &wpx_exec;
-	card->wandev.update	= &update;
-	card->wandev.new_if	= &new_if;
-	card->wandev.del_if	= &del_if;
-	card->wandev.state	= WAN_DISCONNECTED;
-	card->wandev.enable_tx_int = 0;
-	card->irq_dis_if_send_count = 0;
-        card->irq_dis_poll_count = 0;
-	card->wandev.enable_IPX = conf->enable_IPX;
-	
-	if (conf->network_number)
-		card->wandev.network_number = conf->network_number;
-	else
-		card->wandev.network_number = 0xDEADBEEF;
-	return 0;
-}
-
-/******* WAN Device Driver Entry Points *************************************/
-
-/*============================================================================
- * Update device status & statistics.
- */
-static int update (wan_device_t* wandev)
-{
-	sdla_t* card;
-
-	/* sanity checks */
-	if ((wandev == NULL) || (wandev->private == NULL))
-		return -EFAULT;
-	if (wandev->state == WAN_UNCONFIGURED)
-		return -ENODEV;
-	if (test_and_set_bit(0, (void*)&wandev->critical))
-		return -EAGAIN;
-	card = wandev->private;
-
-	x25_get_err_stats(card);
-	x25_get_stats(card);
-	wandev->critical = 0;
-	return 0;
-}
-
-/*============================================================================
- * Create new logical channel.
- * This routine is called by the router when ROUTER_IFNEW IOCTL is being
- * handled.
- * o parse media- and hardware-specific configuration
- * o make sure that a new channel can be created
- * o allocate resources, if necessary
- * o prepare network device structure for registaration.
- *
- * Return:	0	o.k.
- *		< 0	failure (channel will not be created)
- */
-static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf)
-{
-	sdla_t* card = wandev->private;
-	x25_channel_t* chan;
-	int err = 0;
-
-	if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ))
-	{
-		printk(KERN_INFO "%s: invalid interface name!\n",
-			card->devname)
-		;
-		return -EINVAL;
-	}
-
-	/* allocate and initialize private data */
-	chan = kmalloc(sizeof(x25_channel_t), GFP_KERNEL);
-	if (chan == NULL)
-		return -ENOMEM
-	;
-	memset(chan, 0, sizeof(x25_channel_t));
-	strcpy(chan->name, conf->name);
-	chan->card = card;
-	chan->protocol = ETH_P_IP;
-	chan->tx_skb = chan->rx_skb = NULL;
-
-	/* verify media address */
-	if (conf->addr[0] == '@')		/* SVC */
-	{
-		chan->svc = 1;
-		strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ);
-
-		/* Set channel timeouts (default if not specified) */
-		chan->idle_timeout = (conf->idle_timeout) ? conf->idle_timeout : 					90;
-		chan->hold_timeout = (conf->hold_timeout) ? conf->hold_timeout :					10;
-	}
-	else if (is_digit(conf->addr[0]))	/* PVC */
-	{
-		int lcn = dec_to_uint(conf->addr, 0);
-
-		if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc))
-		{
-			chan->lcn = lcn;
-		}
-		else
-		{
-			printk(KERN_ERR
-				"%s: PVC %u is out of range on interface %s!\n",
-				wandev->name, lcn, chan->name)
-			;
-			err = -EINVAL;
-		}
-	}
-	else
-	{
-		printk(KERN_ERR
-			"%s: invalid media address on interface %s!\n",
-			wandev->name, chan->name)
-		;
-		err = -EINVAL;
-	}
-	if (err)
-	{
-		kfree(chan);
-		return err;
-	}
-
-	/* prepare network device data space for registration */
-	dev->name = chan->name;
-	dev->init = &if_init;
-	dev->priv = chan;
-	return 0;
-}
-
-/*============================================================================
- * Delete logical channel.
- */
-static int del_if (wan_device_t* wandev, struct net_device* dev)
-{
-	if (dev->priv)
-	{
-		kfree(dev->priv);
-		dev->priv = NULL;
-	}
-	return 0;
-}
-
-/****** WANPIPE-specific entry points ***************************************/
-
-/*============================================================================
- * Execute adapter interface command.
- */
-
-static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data)
-{
-	TX25Mbox* mbox = card->mbox;
-	int retry = MAX_CMD_RETRY;
-	int err, len;
-	TX25Cmd cmd;
-
-	if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd)))
-		return -EFAULT;
-		
-	/* execute command */
-
-	do
-	{
-		memcpy(&mbox->cmd, &cmd, sizeof(cmd));
-		if (cmd.length)
-		{
-			if(copy_from_user((void*)&mbox->data, u_data, cmd.length))
-				return-EFAULT;
-		}
-		if (sdla_exec(mbox))
-			err = mbox->cmd.result
-		;
-		else return -EIO;
-	}
-	while (err && retry-- && x25_error(card, err, cmd.command, cmd.lcn));
-
-	/* return result */
-	if(copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(TX25Cmd)))
-		return -EFAULT;
-	len = mbox->cmd.length;
-	if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len))
-		return -EFAULT;
-	return 0;
-}
-
-/****** Network Device Interface ********************************************/
-
-/*============================================================================
- * Initialize Linux network interface.
- *
- * This routine is called only once for each interface, during Linux network
- * interface registration.  Returning anything but zero will fail interface
- * registration.
- */
-static int if_init (struct net_device* dev)
-{
-	x25_channel_t* chan = dev->priv;
-	sdla_t* card = chan->card;
-	wan_device_t* wandev = &card->wandev;
-
-	/* Initialize device driver entry points */
-	dev->open		= &if_open;
-	dev->stop		= &if_close;
-	dev->hard_header	= &if_header;
-	dev->rebuild_header	= &if_rebuild_hdr;
-	dev->hard_start_xmit	= &if_send;
-	dev->get_stats		= &if_stats;
-
-	/* Initialize media-specific parameters */
-	dev->type		= 30;		/* ARP h/w type */
-	dev->mtu		= X25_CHAN_MTU;
-	dev->hard_header_len	= X25_HRDHDR_SZ; /* media header length */
-	dev->addr_len		= 2;		/* hardware address length */
-	if (!chan->svc)
-		*(unsigned short*)dev->dev_addr = htons(chan->lcn);
-
-	/* Initialize hardware parameters (just for reference) */
-	dev->irq	= wandev->irq;
-	dev->dma	= wandev->dma;
-	dev->base_addr	= wandev->ioport;
-	dev->mem_start	= (unsigned long)wandev->maddr;
-	dev->mem_end	= dev->mem_end + wandev->msize - 1;
-
-        /* Set transmit buffer queue length */
-        dev->tx_queue_len = 10;
-
-	/* Initialize socket buffers */
-	
-	dev_init_buffers(dev);
-	set_chan_state(dev, WAN_DISCONNECTED);
-	return 0;
-}
-
-/*============================================================================
- * Open network interface.
- * o prevent module from unloading by incrementing use count
- * o if link is disconnected then initiate connection
- *
- * Return 0 if O.k. or errno.
- */
-static int if_open (struct net_device* dev)
-{
-	x25_channel_t* chan = dev->priv;
-	sdla_t* card = chan->card;
-
-	if (dev->start)
-		return -EBUSY;		/* only one open is allowed */
-	
-	if (test_and_set_bit(0, (void*)&card->wandev.critical))
-		return -EAGAIN;
-
-	dev->interrupt = 0;
-	dev->tbusy = 0;
-	dev->start = 1;
-	wanpipe_open(card);
-
-	/* If this is the first open, initiate physical connection */
-	if (card->open_cnt == 1)
-		connect(card);
-	card->wandev.critical = 0;
-	return 0;
-}
-
-/*============================================================================
- * Close network interface.
- * o reset flags.
- * o if there's no more open channels then disconnect physical link.
- */
-static int if_close (struct net_device* dev)
-{
-	x25_channel_t* chan = dev->priv;
-	sdla_t* card = chan->card;
-
-	if (test_and_set_bit(0, (void*)&card->wandev.critical))
-		return -EAGAIN;
-
-	dev->start = 0;
-	if ((chan->state == WAN_CONNECTED) || (chan->state == WAN_CONNECTING))
-		chan_disc(dev);
-		
-	wanpipe_close(card);
-
-	/* If this is the last close, disconnect physical link */
-	if (!card->open_cnt)
-		disconnect(card);
-		
-	card->wandev.critical = 0;
-	return 0;
-}
-
-/*============================================================================
- * Build media header.
- * o encapsulate packet according to encapsulation type.
- *
- * The trick here is to put packet type (Ethertype) into 'protocol' field of
- * the socket buffer, so that we don't forget it.  If encapsulation fails,
- * set skb->protocol to 0 and discard packet later.
- *
- * Return:	media header length.
- */
-static int if_header (struct sk_buff* skb, struct net_device* dev,
-	unsigned short type, void* daddr, void* saddr, unsigned len)
-{
-	x25_channel_t* chan = dev->priv;
-	int hdr_len = dev->hard_header_len;
-
-	skb->protocol = type;
-	if (!chan->protocol)
-	{
-		hdr_len = wanrouter_encapsulate(skb, dev);
-		if (hdr_len < 0)
-		{
-			hdr_len = 0;
-			skb->protocol = 0;
-		}
-	}
-	return hdr_len;
-}
-
-/*============================================================================
- * Re-build media header.
- *
- * Return:	1	physical address resolved.
- *		0	physical address not resolved
- */
- 
-static int if_rebuild_hdr (struct sk_buff* skb)
-{
-	struct net_device *dev=skb->dev;
-	x25_channel_t* chan = dev->priv;
-	sdla_t* card = chan->card;
-
-	printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
-		card->devname, dev->name);
-	return 1;
-}
-
-/*============================================================================
- * Send a packet on a network interface.
- * o set tbusy flag (marks start of the transmission).
- * o check link state. If link is not up, then drop the packet.
- * o check channel status. If it's down then initiate a call.
- * o pass a packet to corresponding WAN device.
- * o free socket buffer
- *
- * Return:	0	complete (socket buffer must be freed)
- *		non-0	packet may be re-transmitted (tbusy must be set)
- *
- * Notes:
- * 1. This routine is called either by the protocol stack or by the "net
- *    bottom half" (with interrupts enabled).
- * 2. Setting tbusy flag will inhibit further transmit requests from the
- *    protocol stack and can be used for flow control with protocol layer.
- */
-
-static int if_send (struct sk_buff* skb, struct net_device* dev)
-{
-	x25_channel_t* chan = dev->priv;
-	sdla_t* card = chan->card;
-	struct net_device *dev2;
-	TX25Status* status = card->flags;
-	unsigned long host_cpu_flags;
-
-	if (dev->tbusy)
-	{
-		++chan->ifstats.rx_dropped;	
-		if ((jiffies - chan->tick_counter) < (5*HZ))
-		{
-			return dev->tbusy;
-		}
-		printk(KERN_INFO "%s: Transmit time out %s!\n",
-			card->devname, dev->name)
-		;
-		for( dev2 = card->wandev.dev; dev2; dev2 = dev2->slave)
-		{
-	        	dev2->tbusy = 0;
-		}
-	}
-	chan->tick_counter = jiffies;
-
-	disable_irq(card->hw.irq);
-	++card->irq_dis_if_send_count;
-
-	if (test_and_set_bit(0, (void*)&card->wandev.critical)) 
-	{
-		printk(KERN_INFO "Hit critical in if_send()!\n");
-		if (card->wandev.critical == CRITICAL_IN_ISR) 
-		{
-			card->wandev.enable_tx_int = 1;
-			dev->tbusy = 1;
-			
-			save_flags(host_cpu_flags);
-                        cli();
-                        if ((!(--card->irq_dis_if_send_count)) &&
-                                        (!card->irq_dis_poll_count))
-                                enable_irq(card->hw.irq);
-                        restore_flags(host_cpu_flags);
-			
-			return dev->tbusy;
-		}
-		dev_kfree_skb(skb);
-		
-		save_flags(host_cpu_flags);
-                cli();
-                if ((!(--card->irq_dis_if_send_count)) &&
-                                         (!card->irq_dis_poll_count))
-                        enable_irq(card->hw.irq);
-                restore_flags(host_cpu_flags);
-
-		return dev->tbusy;
-	}
-
-	/* Below is only until we have per-channel IPX going.... */
-	if(!(chan->svc))
-		chan->protocol = skb->protocol;
-
-	if (card->wandev.state != WAN_CONNECTED)
-		++chan->ifstats.tx_dropped;
-
-	/* Below is only until we have per-channel IPX going.... */
-	else if ( (chan->svc) && (chan->protocol && (chan->protocol != skb->protocol)))
-	{
-		printk(KERN_INFO
-			"%s: unsupported Ethertype 0x%04X on interface %s!\n",
-			card->devname, skb->protocol, dev->name);
-		++chan->ifstats.tx_errors;
-	}
-	else switch (chan->state)
-	{
-		case WAN_DISCONNECTED:
-			/* Try to establish connection. If succeded, then start
-			 * transmission, else drop a packet.
-			 */
-			if (chan_connect(dev) != 0)
-			{
-				++chan->ifstats.tx_dropped;
-				++card->wandev.stats.tx_dropped;
-				break;
-			}
-			/* fall through */
-
-		case WAN_CONNECTED:
-			if( skb->protocol == ETH_P_IPX ) 
-			{
-				if(card->wandev.enable_IPX) 
-				{
-					switch_net_numbers( skb->data, 
-						card->wandev.network_number, 0);
-				}
-				else 
-				{
-					++card->wandev.stats.tx_dropped;
-					++chan->ifstats.tx_dropped;
-					goto tx_done;
-				}
-			}
-			dev->trans_start = jiffies;
-			if(chan_send(dev, skb))
-			{
-				dev->tbusy = 1;
-				status->imask |= 0x2;
-			}
-			break;
-
-		default:
-			++chan->ifstats.tx_dropped;	
-			++card->wandev.stats.tx_dropped;
-	}
-tx_done:
-	if (!dev->tbusy)
-		dev_kfree_skb(skb);
-
-	card->wandev.critical = 0;
-	save_flags(host_cpu_flags);
-        cli();
-        if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count))
-                enable_irq(card->hw.irq);
-        restore_flags(host_cpu_flags);
-	return dev->tbusy;
-}
-
-/*============================================================================
- * Get Ethernet-style interface statistics.
- * Return a pointer to struct net_device_stats
- */
- 
-static struct net_device_stats* if_stats (struct net_device* dev)
-{
-	x25_channel_t* chan = dev->priv;
-	if(chan==NULL)
-		return NULL;
-	return &chan->ifstats;
-}
-
-/****** Interrupt Handlers **************************************************/
-
-/*============================================================================
- * X.25 Interrupt Service Routine.
- */
- 
-static void wpx_isr (sdla_t* card)
-{
-	TX25Status* status = card->flags;
-	struct net_device *dev;
-	unsigned long host_cpu_flags;
-
-	card->in_isr = 1;
-	card->buff_int_mode_unbusy = 0;
-
-	if (test_and_set_bit(0, (void*)&card->wandev.critical)) 
-	{
-
- 		printk(KERN_INFO "wpx_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, status->iflags);
-		card->in_isr = 0;
-		return;
-	}
-
-	/* For all interrupts set the critical flag to CRITICAL_RX_INTR.
-         * If the if_send routine is called with this flag set it will set
-         * the enable transmit flag to 1. (for a delayed interrupt)
-         */
-	card->wandev.critical = CRITICAL_IN_ISR;
-
-	switch (status->iflags)
-	{
-		case 0x01:		/* receive interrupt */
-			rx_intr(card);
-			break;
-
-		case 0x02:		/* transmit interrupt */
-			tx_intr(card);
-			card->buff_int_mode_unbusy = 1;
-			status->imask &= ~0x2;
-			break;
-
-		case 0x04:		/* modem status interrupt */
-			status_intr(card);
-			break;
-
-		case 0x10:		/* network event interrupt */
-			event_intr(card);
-			break;
-
-		default:		/* unwanted interrupt */
-			spur_intr(card);
-	}
-	card->wandev.critical = CRITICAL_INTR_HANDLED;
-	if( card->wandev.enable_tx_int)
-	{
-		card->wandev.enable_tx_int = 0;
-		status->imask |= 0x2;
-	}
-	save_flags(host_cpu_flags);
-	cli();
-	card->in_isr = 0;
-	status->iflags = 0;	/* clear interrupt condition */
-	card->wandev.critical = 0;
-	restore_flags(host_cpu_flags);
-
-	if(card->buff_int_mode_unbusy)
-	{
-		for(dev = card->wandev.dev; dev; dev = dev->slave)
-		{
-			if(((x25_channel_t*)dev->priv)->devtint)
-			{
-				mark_bh(NET_BH);
-				return;
-			}	
-		}
-	}
-}
-
-/*============================================================================
- * Receive interrupt handler.
- * This routine handles fragmented IP packets using M-bit according to the
- * RFC1356.
- * o map ligical channel number to network interface.
- * o allocate socket buffer or append received packet to the existing one.
- * o if M-bit is reset (i.e. it's the last packet in a sequence) then 
- *   decapsulate packet and pass socket buffer to the protocol stack.
- *
- * Notes:
- * 1. When allocating a socket buffer, if M-bit is set then more data is
- *    comming and we have to allocate buffer for the maximum IP packet size
- *    expected on this channel.
- * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no
- *    socket buffers available) the whole packet sequence must be discarded.
- */
-
-static void rx_intr (sdla_t* card)
-{
-	TX25Mbox* rxmb = card->rxmb;
-	unsigned lcn = rxmb->cmd.lcn;		/* logical channel number */
-	unsigned len = rxmb->cmd.length;	/* packet length */
-	unsigned qdm = rxmb->cmd.qdm;		/* Q,D and M bits */
-	wan_device_t* wandev = &card->wandev;
-	struct net_device* dev = get_dev_by_lcn(wandev, lcn);
-	x25_channel_t* chan;
-	struct sk_buff* skb;
-	void* bufptr;
-
-	if (dev == NULL)
-	{
-		/* Invalid channel, discard packet */
-		printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n",
-			card->devname, lcn);
-		return;
-	}
-
-	chan = dev->priv;
-	chan->i_timeout_sofar = jiffies;
-	if (chan->drop_sequence)
-	{
-		if (!(qdm & 0x01)) chan->drop_sequence = 0;
-		return;
-	}
-
-	skb = chan->rx_skb;
-	if (skb == NULL)
-	{
-		/* Allocate new socket buffer */
-		int bufsize = (qdm & 0x01) ? dev->mtu : len;
-
-		skb = dev_alloc_skb(bufsize + dev->hard_header_len);
-		if (skb == NULL)
-		{
-			printk(KERN_INFO "%s: no socket buffers available!\n",
-				card->devname);
-			chan->drop_sequence = 1;	/* set flag */
-			++chan->ifstats.rx_dropped;
-			return;
-		}
-		skb->dev = dev;
-		skb->protocol = htons(chan->protocol);
-		chan->rx_skb = skb;
-	}
-
-	if (skb_tailroom(skb) < len)
-	{
-		/* No room for the packet. Call off the whole thing! */
-		dev_kfree_skb(skb);
-		chan->rx_skb = NULL;
-		if (qdm & 0x01) chan->drop_sequence = 1;
-
-		printk(KERN_INFO "%s: unexpectedly long packet sequence "
-			"on interface %s!\n", card->devname, dev->name);
-		++chan->ifstats.rx_length_errors;
-		return;
-	}
-
-	/* Append packet to the socket buffer */
-	bufptr = skb_put(skb, len);
-	memcpy(bufptr, rxmb->data, len);
-
-	if (qdm & 0x01)
-		return;		/* more data is comming */
-
-	dev->last_rx = jiffies;		/* timestamp */
-	chan->rx_skb = NULL;		/* dequeue packet */
-
-	/* Decapsulate packet, if necessary */
-	if (!skb->protocol && !wanrouter_type_trans(skb, dev))
-	{
-		/* can't decapsulate packet */
-		dev_kfree_skb(skb);
-		++chan->ifstats.rx_errors;
-	}
-	else
-	{
-		if( handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol))
-		{
-			if( card->wandev.enable_IPX )
-			{
-				if(chan_send(dev, skb))
-				{
-					chan->tx_skb = skb;
-				}
-				else
-				{
-					dev_kfree_skb(skb);
-				}
-			}
-			else
-			{
-				/* FIXME: increment IPX packet dropped statistic */
-			}
-		}
-		else
-		{
-			netif_rx(skb);
-			++chan->ifstats.rx_packets;
-			chan->ifstats.rx_bytes += skb->len;
-		}
-	}
-}
-
-/*============================================================================
- * Transmit interrupt handler.
- *	o Release socket buffer
- *	o Clear 'tbusy' flag
- */
-
-static void tx_intr (sdla_t* card)
-{
-	struct net_device *dev;
-
-	/* unbusy all devices and then dev_tint(); */
-	for(dev = card->wandev.dev; dev; dev = dev->slave)
-	{
-		((x25_channel_t*)dev->priv)->devtint = dev->tbusy; 
-		dev->tbusy = 0;
-	}
-
-}
-
-/*============================================================================
- * Modem status interrupt handler.
- */
-static void status_intr (sdla_t* card)
-{
-}
-
-/*============================================================================
- * Network event interrupt handler.
- */
-static void event_intr (sdla_t* card)
-{
-}
-
-/*============================================================================
- * Spurious interrupt handler.
- * o print a warning
- * o 
- * If number of spurious interrupts exceeded some limit, then ???
- */
-static void spur_intr (sdla_t* card)
-{
-	printk(KERN_INFO "%s: spurious interrupt!\n", card->devname);
-}
-
-/****** Background Polling Routines  ****************************************/
-
-/*============================================================================
- * Main polling routine.
- * This routine is repeatedly called by the WANPIPE 'thread' to allow for
- * time-dependent housekeeping work.
- *
- * Notes:
- * 1. This routine may be called on interrupt context with all interrupts
- *    enabled. Beware!
- */
-
-static void wpx_poll (sdla_t* card)
-{
-	unsigned long host_cpu_flags;
-
-	disable_irq(card->hw.irq);
-	++card->irq_dis_poll_count;
-
-	if (test_and_set_bit(0, (void*)&card->wandev.critical)) 
-	{
- 		printk(KERN_INFO "%s: critical in polling!\n",card->devname);	
-		save_flags(host_cpu_flags);
-                cli();
-		if ((!card->irq_dis_if_send_count) &&
-                                (!(--card->irq_dis_poll_count)))
-                        enable_irq(card->hw.irq);
-                restore_flags(host_cpu_flags);
-		return;
-	}
-
-	switch(card->wandev.state)
-	{
-		case WAN_CONNECTED:
-			poll_active(card);
-			break;
-
-		case WAN_CONNECTING:
-			poll_connecting(card);
-			break;
-
-		case WAN_DISCONNECTED:
-			poll_disconnected(card);
-	}
-	card->wandev.critical = 0;
-	save_flags(host_cpu_flags);
-        cli();
-        if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count)))
-                enable_irq(card->hw.irq);
-        restore_flags(host_cpu_flags);
-}
-
-/*============================================================================
- * Handle physical link establishment phase.
- * o if connection timed out, disconnect the link.
- */
-static void poll_connecting (sdla_t* card)
-{
-	TX25Status* status = card->flags;
-
-	if (status->gflags & X25_HDLC_ABM)
-	{
-		wanpipe_set_state(card, WAN_CONNECTED);
-		x25_set_intr_mode(card, 0x83);	/* enable Rx interrupts */
-		status->imask &= ~0x2;		/* mask Tx interupts */
-	}
-	else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT)
-	    disconnect(card);
-}
-
-/*============================================================================
- * Handle physical link disconnected phase.
- * o if hold-down timeout has expired and there are open interfaces, connect
- *   link.
- */
-static void poll_disconnected (sdla_t* card)
-{
-	if (card->open_cnt && ((jiffies - card->state_tick) > HOLD_DOWN_TIME))
-		connect(card);
-}
-
-/*============================================================================
- * Handle active link phase.
- * o fetch X.25 asynchronous events.
- * o kick off transmission on all interfaces.
- */
-static void poll_active (sdla_t* card)
-{
-	struct net_device* dev;
-
-	/* Fetch X.25 asynchronous events */
-	x25_fetch_events(card);
-
-	for (dev = card->wandev.dev; dev; dev = dev->slave)
-	{
-		x25_channel_t* chan = dev->priv;
-		struct sk_buff* skb = chan->tx_skb;
-
-		/* If there is a packet queued for transmission then kick
-		 * the channel's send routine. When transmission is complete
-		 * or if error has occurred, release socket buffer and reset
-		 * 'tbusy' flag.
-		 */
-		if (skb && (chan_send(dev, skb) == 0))
-		{
-			chan->tx_skb = NULL;
-			dev->tbusy = 0;
-			dev_kfree_skb(skb);
-		}
-
-		/* If SVC has been idle long enough, close virtual circuit */
-
-		if(( chan->svc )&&( chan->state == WAN_CONNECTED ))
-		{
-			if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout )
-			{
-				/* Close svc */
-				printk(KERN_INFO "%s: Closing down Idle link %s on LCN %d\n",card->devname,chan->name,chan->lcn); 
-				chan->i_timeout_sofar = jiffies;
-				chan_disc(dev);
-			}
-		}
-	}
-}
-
-/****** SDLA Firmware-Specific Functions *************************************
- * Almost all X.25 commands can unexpetedly fail due to so called 'X.25
- * asynchronous events' such as restart, interrupt, incoming call request,
- * call clear request, etc.  They can't be ignored and have to be dealt with
- * immediately.  To tackle with this problem we execute each interface command
- * in a loop until good return code is received or maximum number of retries
- * is reached.  Each interface command returns non-zero return code, an
- * asynchronous event/error handler x25_error() is called.
- */
-
-/*============================================================================
- * Read X.25 firmware version.
- *	Put code version as ASCII string in str. 
- */
-static int x25_get_version (sdla_t* card, char* str)
-{
-	TX25Mbox* mbox = card->mbox;
-  	int retry = MAX_CMD_RETRY;
-	int err;
-
-	do
-	{
-		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
-		mbox->cmd.command = X25_READ_CODE_VERSION;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	} while (err && retry-- &&
-		 x25_error(card, err, X25_READ_CODE_VERSION, 0));
-
-	if (!err && str)
-	{
-		int len = mbox->cmd.length;
-		memcpy(str, mbox->data, len);
-		str[len] = '\0';
-	}
-	return err;
-}
-
-/*============================================================================
- * Configure adapter.
- */
-
-static int x25_configure (sdla_t* card, TX25Config* conf)
-{
-	TX25Mbox* mbox = card->mbox;
-  	int retry = MAX_CMD_RETRY;
-	int err;
-
-	do
-	{
-		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
-		memcpy(mbox->data, (void*)conf, sizeof(TX25Config));
-		mbox->cmd.length  = sizeof(TX25Config);
-		mbox->cmd.command = X25_SET_CONFIGURATION;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	} while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0));
-	return err;
-}
-
-/*============================================================================
- * Get communications error statistics.
- */
-static int x25_get_err_stats (sdla_t* card)
-{
-	TX25Mbox* mbox = card->mbox;
-  	int retry = MAX_CMD_RETRY;
-	int err;
-
-	do
-	{
-		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
-		mbox->cmd.command = X25_HDLC_READ_COMM_ERR;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	} while (err && retry-- && x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0));
-
-	if (!err)
-	{
-		THdlcCommErr* stats = (void*)mbox->data;
-
-		card->wandev.stats.rx_over_errors    = stats->rxOverrun;
-		card->wandev.stats.rx_crc_errors     = stats->rxBadCrc;
-		card->wandev.stats.rx_missed_errors  = stats->rxAborted;
-		card->wandev.stats.tx_aborted_errors = stats->txAborted;
-	}
-	return err;
-}
-
-/*============================================================================
- * Get protocol statistics.
- */
-static int x25_get_stats (sdla_t* card)
-{
-	TX25Mbox* mbox = card->mbox;
-  	int retry = MAX_CMD_RETRY;
-	int err;
-
-	do
-	{
-		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
-		mbox->cmd.command = X25_READ_STATISTICS;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	} while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0));
-	
-	if (!err)
-	{
-		TX25Stats* stats = (void*)mbox->data;
-
-		card->wandev.stats.rx_packets = stats->rxData;
-		card->wandev.stats.tx_packets = stats->rxData;
-	}
-	return err;
-}
-
-/*============================================================================
- * Close HDLC link.
- */
-static int x25_close_hdlc (sdla_t* card)
-{
-	TX25Mbox* mbox = card->mbox;
-  	int retry = MAX_CMD_RETRY;
-	int err;
-
-	do
-	{
-		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
-		mbox->cmd.command = X25_HDLC_LINK_CLOSE;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	} while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_CLOSE, 0));
-
-	return err;
-}
-
-/*============================================================================
- * Open HDLC link.
- */
-static int x25_open_hdlc (sdla_t* card)
-{
-	TX25Mbox* mbox = card->mbox;
-  	int retry = MAX_CMD_RETRY;
-	int err;
-
-	do
-	{
-		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
-		mbox->cmd.command = X25_HDLC_LINK_OPEN;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	} while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_OPEN, 0));
-	
-	return err;
-}
-
-/*============================================================================
- * Setup HDLC link.
- */
-static int x25_setup_hdlc (sdla_t* card)
-{
-	TX25Mbox* mbox = card->mbox;
-  	int retry = MAX_CMD_RETRY;
-	int err;
-
-	do
-	{
-		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
-		mbox->cmd.command = X25_HDLC_LINK_SETUP;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	} while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_SETUP, 0));
-	
-	return err;
-}
-
-/*============================================================================
- * Set (raise/drop) DTR.
- */
-static int x25_set_dtr (sdla_t* card, int dtr)
-{
-	TX25Mbox* mbox = card->mbox;
-  	int retry = MAX_CMD_RETRY;
-	int err;
-
-	do
-	{
-		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
-		mbox->data[0] = 0;
-		mbox->data[2] = 0;
-		mbox->data[1] = dtr ? 0x02 : 0x01;
-		mbox->cmd.length  = 3;
-		mbox->cmd.command = X25_SET_GLOBAL_VARS;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	} while (err && retry-- && x25_error(card, err, X25_SET_GLOBAL_VARS, 0));
-
-	return err;
-}
-
-/*============================================================================
- * Set interrupt mode.
- */
-static int x25_set_intr_mode (sdla_t* card, int mode)
-{
-	TX25Mbox* mbox = card->mbox;
-  	int retry = MAX_CMD_RETRY;
-	int err;
-
-	do
-	{
-		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
-		mbox->data[0] = mode;
-		if (card->hw.fwid == SFID_X25_508)
-		{
-			mbox->data[1] = card->hw.irq;
-			mbox->cmd.length = 2;
-		}
-		else mbox->cmd.length  = 1;
-		mbox->cmd.command = X25_SET_INTERRUPT_MODE;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	} while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)) ;
-	return err;
-}
-
-/*============================================================================
- * Read X.25 channel configuration.
- */
-static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan)
-{
-	TX25Mbox* mbox = card->mbox;
-  	int retry = MAX_CMD_RETRY;
-	int lcn = chan->lcn;
-	int err;
-
-	do
-	{
-		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
-		mbox->cmd.lcn     = lcn;
-		mbox->cmd.command = X25_READ_CHANNEL_CONFIG;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	} while (err && retry-- && x25_error(card, err, X25_READ_CHANNEL_CONFIG, lcn));
-
-	if (!err)
-	{
-		TX25Status* status = card->flags;
-
-		/* calculate an offset into the array of status bytes */
-		if (card->u.x.hi_svc <= 255) 
-			chan->ch_idx = lcn - 1;
-		else
-		{
-			int offset;
-
-			switch (mbox->data[0] && 0x1F)
-			{
-				case 0x01:
-					offset = status->pvc_map; break;
-				case 0x03:
-					offset = status->icc_map; break;
-				case 0x07:
-					offset = status->twc_map; break;
-				case 0x0B: 
-					offset = status->ogc_map; break;
-				default: 
-					offset = 0;
-			}
-			chan->ch_idx = lcn - 1 - offset;
-		}
-
-		/* get actual transmit packet size on this channel */
-		switch(mbox->data[1] & 0x38)
-		{
-			case 0x00:
-				chan->tx_pkt_size = 16;
-				break;
-			case 0x08:
-				chan->tx_pkt_size = 32;
-				break;
-			case 0x10:
-				chan->tx_pkt_size = 64;
-				break;
-			case 0x18:
-				chan->tx_pkt_size = 128;
-				break;
-			case 0x20:
-				chan->tx_pkt_size = 256;
-				break;
-			case 0x28:
-				chan->tx_pkt_size = 512;
-				break;
-			case 0x30:
-				chan->tx_pkt_size = 1024;
-				break;
-		}
-		printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n",
-			card->devname, lcn, chan->tx_pkt_size);
-	}
-	return err;
-}
-
-/*============================================================================
- * Place X.25 call.
- */
-
-static int x25_place_call (sdla_t* card, x25_channel_t* chan)
-{
-	TX25Mbox* mbox = card->mbox;
-  	int retry = MAX_CMD_RETRY;
-	int err;
-	char str[64];
-
-	sprintf(str, "-d%s -uCC", chan->addr);
-	do
-	{
-		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
-		strcpy(mbox->data, str);
-		mbox->cmd.length  = strlen(str);
-		mbox->cmd.command = X25_PLACE_CALL;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	} while (err && retry-- && x25_error(card, err, X25_PLACE_CALL, 0));
-
-	if (!err)
-	{
-		chan->lcn = mbox->cmd.lcn;
-		chan->protocol = ETH_P_IP;
-	}
-	return err;
-}
-
-/*============================================================================
- * Accept X.25 call.
- */
-
-static int x25_accept_call (sdla_t* card, int lcn, int qdm)
-{
-	TX25Mbox* mbox = card->mbox;
-  	int retry = MAX_CMD_RETRY;
-	int err;
-
-	do
-	{
-		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
-		mbox->cmd.lcn     = lcn;
-		mbox->cmd.qdm     = qdm;
-		mbox->cmd.command = X25_ACCEPT_CALL;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	} while (err && retry-- && x25_error(card, err, X25_ACCEPT_CALL, lcn));
-
-	return err;
-}
-
-/*============================================================================
- * Clear X.25 call.
- */
-static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn)
-{
-	TX25Mbox* mbox = card->mbox;
-  	int retry = MAX_CMD_RETRY;
-	int err;
-
-	do
-	{
-		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
-		mbox->cmd.lcn     = lcn;
-		mbox->cmd.cause   = cause;
-		mbox->cmd.diagn   = diagn;
-		mbox->cmd.command = X25_CLEAR_CALL;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	} while (err && retry-- && x25_error(card, err, X25_CLEAR_CALL, lcn));
-
-	return err;
-}
-
-/*============================================================================
- * Send X.25 data packet.
- */
-static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf)
-{
-	TX25Mbox* mbox = card->mbox;
-  	int retry = MAX_CMD_RETRY;
-	int err;
-	
-	do
-	{
-		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
-		memcpy(mbox->data, buf, len);
-		mbox->cmd.length  = len;
-		mbox->cmd.lcn     = lcn;
-		mbox->cmd.qdm     = qdm;
-		mbox->cmd.command = X25_WRITE;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	} while (err && retry-- && x25_error(card, err, X25_WRITE, lcn));
-	return err;
-}
-
-/*============================================================================
- * Fetch X.25 asynchronous events.
- */
-static int x25_fetch_events (sdla_t* card)
-{
-	TX25Status* status = card->flags;
-	TX25Mbox* mbox = card->mbox;
-	int err = 0;
-
-	if (status->gflags & 0x20)
-	{
-		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
-		mbox->cmd.command = X25_IS_DATA_AVAILABLE;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- 		if (err)
- 			x25_error(card, err, X25_IS_DATA_AVAILABLE, 0);
-	}
-	return err;
-}
-
-/*============================================================================
- * X.25 asynchronous event/error handler.
- *	This routine is called each time interface command returns non-zero
- *	return code to handle X.25 asynchronous events and common errors.
- *	Return non-zero to repeat command or zero to cancel it.
- *
- * Notes:
- * 1. This function may be called recursively, as handling some of the
- *    asynchronous events (e.g. call request) requires execution of the
- *    interface command(s) that, in turn, may also return asynchronous
- *    events.  To avoid re-entrancy problems we copy mailbox to dynamically
- *    allocated memory before processing events.
- */
-static int x25_error (sdla_t* card, int err, int cmd, int lcn)
-{
-	int retry = 1;
-	unsigned dlen = ((TX25Mbox*)card->mbox)->cmd.length;
-	TX25Mbox* mb;
-
-	mb = kmalloc(sizeof(TX25Mbox) + dlen, GFP_ATOMIC);
-	if (mb == NULL)
-	{
-		printk(KERN_ERR "%s: x25_error() out of memory!\n",
-			card->devname);
-		return 0;
-	}
-	memcpy(mb, card->mbox, sizeof(TX25Mbox) + dlen);
-	switch (err)
-	{
-		case 0x40:	/* X.25 asynchronous packet was received */
-			mb->data[dlen] = '\0';
-			switch (mb->cmd.pktType & 0x7F)
-			{
-				case 0x30:		/* incoming call */
-					retry = incoming_call(card, cmd, lcn, mb);
-					break;
-
-				case 0x31:		/* connected */
-					retry = call_accepted(card, cmd, lcn, mb);
-					break;
-
-				case 0x02:		/* call clear request */
-					retry = call_cleared(card, cmd, lcn, mb);
-					break;
-
-				case 0x04:		/* reset request */
-					printk(KERN_INFO "%s: X.25 reset request on LCN %d! "
-						"Cause:0x%02X Diagn:0x%02X\n",
-						card->devname, mb->cmd.lcn, mb->cmd.cause,
-						mb->cmd.diagn);
-					break;
-
-				case 0x08:		/* restart request */
-					retry = restart_event(card, cmd, lcn, mb);
-					break;
-
-				default:
-					printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! "
-						"Cause:0x%02X Diagn:0x%02X\n",
-						card->devname, mb->cmd.pktType,
-						mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn);
-			}
-			break;
-
-		case 0x41:	/* X.25 protocol violation indication */
-			printk(KERN_INFO
-				"%s: X.25 protocol violation on LCN %d! "
-				"Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n",
-				card->devname, mb->cmd.lcn,
-				mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn);
-			break;
-
-		case 0x42:	/* X.25 timeout */
-			retry = timeout_event(card, cmd, lcn, mb);
-			break;
-
-		case 0x43:	/* X.25 retry limit exceeded */
-			printk(KERN_INFO
-				"%s: exceeded X.25 retry limit on LCN %d! "
-				"Packet:0x%02X Diagn:0x%02X\n", card->devname,
-				mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn);
-			break;
-
-		case 0x08:	/* modem failure */
-			printk(KERN_INFO "%s: modem failure!\n", card->devname);
-			break;
-
-		case 0x09:	/* N2 retry limit */
-			printk(KERN_INFO "%s: exceeded HDLC retry limit!\n",
-				card->devname);
-			break;
-
-		case 0x06:	/* unnumbered frame was received while in ABM */
-			printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n",
-				card->devname, mb->data[0]);
-			break;
-
-		case CMD_TIMEOUT:
-			printk(KERN_ERR "%s: command 0x%02X timed out!\n",
-				card->devname, cmd);
-			retry = 0;	/* abort command */
-			break;
-
-		default:
-			printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n",
-				card->devname, cmd, err);
-			retry = 0;	/* abort command */
-	}
-	kfree(mb);
-	return retry;
-}
-
-/****** X.25 Asynchronous Event Handlers *************************************
- * These functions are called by the x25_error() and should return 0, if
- * the command resulting in the asynchronous event must be aborted.
- */
-
-/*============================================================================
- * Handle X.25 incoming call request.
- *	RFC 1356 establishes the following rules:
- *	1. The first octet in the Call User Data (CUD) field of the call
- *	   request packet contains NLPID identifying protocol encapsulation.
- *	2. Calls MUST NOT be accepted unless router supports requested
- *	   protocol encapsulation.
- *	3. A diagnostic code 249 defined by ISO/IEC 8208 may be used when
- *	   clearing a call because protocol encapsulation is not supported.
- *	4. If an incoming call is received while a call request is pending
- *	   (i.e. call collision has occurred), the incoming call shall be
- *	   rejected and call request shall be retried.
- */
-
-static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
-{
-	wan_device_t* wandev = &card->wandev;
-	int new_lcn = mb->cmd.lcn;
-	struct net_device* dev = get_dev_by_lcn(wandev, new_lcn);
-	x25_channel_t* chan = NULL;
-	int accept = 0;		/* set to '1' if o.k. to accept call */
-	x25_call_info_t* info;
-
-	/* Make sure there is no call collision */
-	if (dev != NULL)
-	{
-		printk(KERN_INFO
-			"%s: X.25 incoming call collision on LCN %d!\n",
-			card->devname, new_lcn);
-		x25_clear_call(card, new_lcn, 0, 0);
-		return 1;
-	}
-
-	/* Make sure D bit is not set in call request */
-	if (mb->cmd.qdm & 0x02)
-	{
-		printk(KERN_INFO
-			"%s: X.25 incoming call on LCN %d with D-bit set!\n",
-			card->devname, new_lcn);
-		x25_clear_call(card, new_lcn, 0, 0);
-		return 1;
-	}
-
-	/* Parse call request data */
-	info = kmalloc(sizeof(x25_call_info_t), GFP_ATOMIC);
-	if (info == NULL)
-	{
-		printk(KERN_ERR
-			"%s: not enough memory to parse X.25 incoming call "
-			"on LCN %d!\n", card->devname, new_lcn);
-		x25_clear_call(card, new_lcn, 0, 0);
-		return 1;
-	}
-	parse_call_info(mb->data, info);
-	printk(KERN_INFO "%s: X.25 incoming call on LCN %d! Call data: %s\n",
-		card->devname, new_lcn, mb->data);
-
-	/* Find available channel */
-	for (dev = wandev->dev; dev; dev = dev->slave)
-	{
-		chan = dev->priv;
-
-		if (!chan->svc || (chan->state != WAN_DISCONNECTED))
-			continue;
-		if (strcmp(info->src, chan->addr) == 0)
-			break;
-	        /* If just an '@' is specified, accept all incoming calls */
-	        if (strcmp(chan->addr, "") == 0)
-	                break;
-	}
-
-	if (dev == NULL)
-	{
-		printk(KERN_INFO "%s: no channels available!\n",
-			card->devname);
-		x25_clear_call(card, new_lcn, 0, 0);
-	}
-
-	/* Check requested protocol encapsulation */
-	else if (info->nuser == 0)
-	{
-		printk(KERN_INFO
-			"%s: no user data in incoming call on LCN %d!\n",
-			card->devname, new_lcn);
-		x25_clear_call(card, new_lcn, 0, 0);
-	}
-	else switch (info->user[0])
-	{
-		case 0:		/* multiplexed */
-			chan->protocol = 0;
-			accept = 1;
-			break;
-
-		case NLPID_IP:	/* IP datagrams */
-			chan->protocol = ETH_P_IP;
-			accept = 1;
-			break;
-
-		case NLPID_SNAP: /* IPX datagrams */
-			chan->protocol = ETH_P_IPX;
-			accept = 1;
-			break;
-		default:
-			printk(KERN_INFO
-				"%s: unsupported NLPID 0x%02X in incoming call "
-				"on LCN %d!\n", card->devname, info->user[0], new_lcn);
-			x25_clear_call(card, new_lcn, 0, 249);
-	}
-
-	if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK))
-	{
-		chan->lcn = new_lcn;
-		if (x25_get_chan_conf(card, chan) == CMD_OK)
-			set_chan_state(dev, WAN_CONNECTED);
-		else
-			x25_clear_call(card, new_lcn, 0, 0);
-	}
-	kfree(info);
-	return 1;
-}
-
-/*============================================================================
- * Handle accepted call.
- */
-
-static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
-{
-	unsigned new_lcn = mb->cmd.lcn;
-	struct net_device* dev = get_dev_by_lcn(&card->wandev, new_lcn);
-	x25_channel_t* chan;
-
-	printk(KERN_INFO "%s: X.25 call accepted on LCN %d!\n",
-		card->devname, new_lcn);
-	if (dev == NULL)
-	{
-		printk(KERN_INFO
-			"%s: clearing orphaned connection on LCN %d!\n",
-			card->devname, new_lcn);
-		x25_clear_call(card, new_lcn, 0, 0);
-		return 1;
-	}
-
-	/* Get channel configuration and notify router */
-	chan = dev->priv;
-	if (x25_get_chan_conf(card, chan) != CMD_OK)
-	{
-		x25_clear_call(card, new_lcn, 0, 0);
-		return 1;
-	}
-	set_chan_state(dev, WAN_CONNECTED);
-	return 1;
-}
-
-/*============================================================================
- * Handle cleared call.
- */
-
-static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
-{
-	unsigned new_lcn = mb->cmd.lcn;
-	struct net_device* dev = get_dev_by_lcn(&card->wandev, new_lcn);
-
-	printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X "
-		"Diagn:0x%02X\n",
-		card->devname, new_lcn, mb->cmd.cause, mb->cmd.diagn);
-	if (dev == NULL)
-		return 1;
-	set_chan_state(dev, WAN_DISCONNECTED);
-	return ((cmd == X25_WRITE) && (lcn == new_lcn)) ? 0 : 1;
-}
-
-/*============================================================================
- * Handle X.25 restart event.
- */
- 
-static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
-{
-	wan_device_t* wandev = &card->wandev;
-	struct net_device* dev;
-
-	printk(KERN_INFO
-		"%s: X.25 restart request! Cause:0x%02X Diagn:0x%02X\n",
-		card->devname, mb->cmd.cause, mb->cmd.diagn);
-
-	/* down all logical channels */
-	for (dev = wandev->dev; dev; dev = dev->slave)
-		set_chan_state(dev, WAN_DISCONNECTED);
-	return (cmd == X25_WRITE) ? 0 : 1;
-}
-
-/*============================================================================
- * Handle timeout event.
- */
-static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
-{
-	unsigned new_lcn = mb->cmd.lcn;
-
-	if (mb->cmd.pktType == 0x05)	/* call request time out */
-	{
-		struct net_device* dev = get_dev_by_lcn(&card->wandev, new_lcn);
-
-		printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n",
-			card->devname, new_lcn);
-		if (dev)
-			set_chan_state(dev, WAN_DISCONNECTED);
-	}
-	else printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n",
-		card->devname, mb->cmd.pktType, new_lcn);
-	return 1;
-}
-
-/******* Miscellaneous ******************************************************/
-
-/*============================================================================
- * Establish physical connection.
- * o open HDLC and raise DTR
- *
- * Return:	0	connection established
- *		1	connection is in progress
- *		<0	error
- */
-static int connect (sdla_t* card)
-{
-	if (x25_open_hdlc(card) || x25_setup_hdlc(card))
-		return -EIO;
-	wanpipe_set_state(card, WAN_CONNECTING);
-	return 1;
-}
-
-/*============================================================================
- * Tear down physical connection.
- * o close HDLC link
- * o drop DTR
- *
- * Return:	0
- *		<0	error
- */
-static int disconnect (sdla_t* card)
-{
-	wanpipe_set_state(card, WAN_DISCONNECTED);
-	x25_set_intr_mode(card, 0);	/* disable interrupt generation */
-	x25_close_hdlc(card);		/* close HDLC link */
-	x25_set_dtr(card, 0);		/* drop DTR */
-	return 0;
-}
-
-/*============================================================================
- * Find network device by its channel number.
- */
-static struct net_device* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn)
-{
-	struct net_device* dev;
-
-	for (dev = wandev->dev; dev; dev = dev->slave)
-		if (((x25_channel_t*)dev->priv)->lcn == lcn)
-			break;
-	return dev;
-}
-
-/*============================================================================
- * Initiate connection on the logical channel.
- * o for PVC we just get channel configuration
- * o for SVCs place an X.25 call
- *
- * Return:	0	connected
- *		>0	connection in progress
- *		<0	failure
- */
-static int chan_connect (struct net_device* dev)
-{
-	x25_channel_t* chan = dev->priv;
-	sdla_t* card = chan->card;
-
-	if (chan->svc)
-	{
-		if (!chan->addr[0])
-			return -EINVAL;	/* no destination address */
-		printk(KERN_INFO "%s: placing X.25 call to %s ...\n",
-			card->devname, chan->addr);
-		if (x25_place_call(card, chan) != CMD_OK)
-			return -EIO;
-		set_chan_state(dev, WAN_CONNECTING);
-		return 1;
-	}
-	else
-	{
-		if (x25_get_chan_conf(card, chan) != CMD_OK)
-			return -EIO;
-		set_chan_state(dev, WAN_CONNECTED);
-	}
-	return 0;
-}
-
-/*============================================================================
- * Disconnect logical channel.
- * o if SVC then clear X.25 call
- */
-static int chan_disc (struct net_device* dev)
-{
-	x25_channel_t* chan = dev->priv;
-
-	if (chan->svc)
-		x25_clear_call(chan->card, chan->lcn, 0, 0);
-	set_chan_state(dev, WAN_DISCONNECTED);
-	return 0;
-}
-
-/*============================================================================
- * Set logical channel state.
- */
-static void set_chan_state (struct net_device* dev, int state)
-{
-	x25_channel_t* chan = dev->priv;
-	sdla_t* card = chan->card;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	if (chan->state != state)
-	{
-		switch (state)
-		{
-			case WAN_CONNECTED:
-				printk (KERN_INFO "%s: interface %s connected!\n",
-					card->devname, dev->name);
-				*(unsigned short*)dev->dev_addr = htons(chan->lcn);
-				chan->i_timeout_sofar = jiffies;
-				break;
-
-			case WAN_CONNECTING:
-				printk (KERN_INFO "%s: interface %s connecting...\n",
-					card->devname, dev->name);
-				break;
-
-			case WAN_DISCONNECTED:
-				printk (KERN_INFO "%s: interface %s disconnected!\n",
-					card->devname, dev->name);
-				if (chan->svc) 
-				{
-					*(unsigned short*)dev->dev_addr = 0;
-		                	chan->lcn = 0;
-				}
-				break;
-		}
-		chan->state = state;
-	}
-	chan->state_tick = jiffies;
-	restore_flags(flags);
-}
-
-/*============================================================================
- * Send packet on a logical channel.
- *	When this function is called, tx_skb field of the channel data space
- *	points to the transmit socket buffer.  When transmission is complete,
- *	release socket buffer and reset 'tbusy' flag.
- *
- * Return:	0	- transmission complete
- *		1	- busy
- *
- * Notes:
- * 1. If packet length is greater than MTU for this channel, we'll fragment
- *    the packet into 'complete sequence' using M-bit.
- * 2. When transmission is complete, an event notification should be issued
- *    to the router.
- */
-static int chan_send (struct net_device* dev, struct sk_buff* skb)
-{
-	x25_channel_t* chan = dev->priv;
-	sdla_t* card = chan->card;
-	TX25Status* status = card->flags;
-	unsigned len, qdm;
-
-	/* Check to see if channel is ready */
-	if (!(status->cflags[chan->ch_idx] & 0x40))
-		return 1;
-
-	if (skb->len > chan->tx_pkt_size)
-	{
-		len = chan->tx_pkt_size;
-		qdm = 0x01;		/* set M-bit (more data) */
-	}
-	else	/* final packet */
-	{
-		len = skb->len;
-		qdm = 0;
-	}
-	switch(x25_send(card, chan->lcn, qdm, len, skb->data))
-	{
-		case 0x00:	/* success */
-			chan->i_timeout_sofar = jiffies;
-			if (qdm)
-			{
-				skb_pull(skb, len);
-				return 1;
-			}
-			++chan->ifstats.tx_packets;
-			chan->ifstats.tx_bytes += skb->len;
-			break;
-
-		case 0x33:	/* Tx busy */
-			return 1;
-
-		default:	/* failure */
-			++chan->ifstats.tx_errors;
-/*			return 1; */
-	}
-	return 0;
-}
-
-/*============================================================================
- * Parse X.25 call request data and fill x25_call_info_t structure.
- */
-
-static void parse_call_info (unsigned char* str, x25_call_info_t* info)
-{
-	memset(info, 0, sizeof(x25_call_info_t));
-	for (; *str; ++str)
-	{
-		int i;
-		unsigned ch;
-
-		if (*str == '-') switch (str[1])
-		{
-			case 'd':	/* destination address */
-				for (i = 0; i < 16; ++i)
-				{
-					ch = str[2+i];
-					if (!is_digit(ch)) 
-						break;
-					info->dest[i] = ch;
-				}
-				break;
-	
-			case 's':	/* source address */
-				for (i = 0; i < 16; ++i)
-				{
-					ch = str[2+i];
-					if (!is_digit(ch))
-						break;
-					info->src[i] = ch;
-				}
-				break;
-
-			case 'u':	/* user data */
-				for (i = 0; i < 127; ++i)
-				{
-					ch = str[2+2*i];
-					if (!is_hex_digit(ch)) 
-						break;
-					info->user[i] = hex_to_uint(&str[2+2*i], 2);
-				}
-				info->nuser = i;
-				break;
-
-			case 'f':	/* facilities */
-				for (i = 0; i < 64; ++i)
-				{
-					ch = str[2+4*i];
-					if (!is_hex_digit(ch))
-						break;
-					info->facil[i].code =
-						hex_to_uint(&str[2+4*i], 2);
-					ch = str[4+4*i];
-					if (!is_hex_digit(ch))
-						break;
-					info->facil[i].parm =
-						hex_to_uint(&str[4+4*i], 2);
-				}
-				info->nfacil = i;
-				break;
-		}
-	}
-}
-
-/*============================================================================
- * Convert line speed in bps to a number used by S502 code.
- */
-static unsigned char bps_to_speed_code (unsigned long bps)
-{
-	unsigned char	number;
-
-	if (bps <= 1200)        number = 0x01 ;
-	else if (bps <= 2400)   number = 0x02;
-	else if (bps <= 4800)   number = 0x03;
-	else if (bps <= 9600)   number = 0x04;
-	else if (bps <= 19200)  number = 0x05;
-	else if (bps <= 38400)  number = 0x06;
-	else if (bps <= 45000)  number = 0x07;
-	else if (bps <= 56000)  number = 0x08;
-	else if (bps <= 64000)  number = 0x09;
-	else if (bps <= 74000)  number = 0x0A;
-	else if (bps <= 112000) number = 0x0B;
-	else if (bps <= 128000) number = 0x0C;
-	else number = 0x0D;
-
-	return number;
-}
-
-/*============================================================================
- * Convert decimal string to unsigned integer.
- * If len != 0 then only 'len' characters of the string are converted.
- */
-static unsigned int dec_to_uint (unsigned char* str, int len)
-{
-	unsigned val;
-
-	if (!len) len = strlen(str);
-	for (val = 0; len && is_digit(*str); ++str, --len)
-		val = (val * 10) + (*str - (unsigned)'0');
-	return val;
-}
-
-/*============================================================================
- * Convert hex string to unsigned integer.
- * If len != 0 then only 'len' characters of the string are conferted.
- */
-static unsigned int hex_to_uint (unsigned char* str, int len)
-{
-	unsigned val, ch;
-
-	if (!len) len = strlen(str);
-	for (val = 0; len; ++str, --len)
-	{
-		ch = *str;
-		if (is_digit(ch))
-			val = (val << 4) + (ch - (unsigned)'0');
-		else if (is_hex_digit(ch))
-			val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10);
-		else
-			break;
-	}
-	return val;
-}
-
-
-static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto)
-{
-	int i;
-
-	if( proto == htons(ETH_P_IPX) ) {
-		/* It's an IPX packet */
-		if(!enable_IPX) {
-			/* Return 1 so we don't pass it up the stack. */
-			return 1;
-		}
-	} else {
-		/* It's not IPX so pass it up the stack. */
-		return 0;
-	}
-
-	if( sendpacket[16] == 0x90 &&
-	    sendpacket[17] == 0x04)
-	{
-		/* It's IPXWAN */
-
-		if( sendpacket[2] == 0x02 &&
-		    sendpacket[34] == 0x00)
-		{
-			/* It's a timer request packet */
-			printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname);
-
-			/* Go through the routing options and answer no to every
-			 * option except Unnumbered RIP/SAP */
-			for(i = 41; sendpacket[i] == 0x00; i += 5)
-			{
-				/* 0x02 is the option for Unnumbered RIP/SAP */
-				if( sendpacket[i + 4] != 0x02)
-					sendpacket[i + 1] = 0;
-			}
-
-			/* Skip over the extended Node ID option */
-			if( sendpacket[i] == 0x04 )
-				i += 8;
-
-			/* We also want to turn off all header compression opt. */
-			for(; sendpacket[i] == 0x80 ;)
-			{
-				sendpacket[i + 1] = 0;
-				i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4;
-			}
-
-			/* Set the packet type to timer response */
-			sendpacket[34] = 0x01;
-
-			printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname);
-		}
-		else if( sendpacket[34] == 0x02 )
-		{
-			/* This is an information request packet */
-			printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname);
-
-			/* Set the packet type to information response */
-			sendpacket[34] = 0x03;
-
-			/* Set the router name */
-			sendpacket[51] = 'X';
-			sendpacket[52] = 'T';
-			sendpacket[53] = 'P';
-			sendpacket[54] = 'I';
-			sendpacket[55] = 'P';
-			sendpacket[56] = 'E';
-			sendpacket[57] = '-';
-			sendpacket[58] = CVHexToAscii(network_number >> 28);
-			sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24);
-			sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20);
-			sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16);
-			sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12);
-			sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8);
-			sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4);
-			sendpacket[65] = CVHexToAscii(network_number & 0x0000000F);
-			for(i = 66; i < 99; i+= 1)
-				sendpacket[i] = 0;
-
-			printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname);
-		}
-		else
-		{
-			printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname);
-			return 0;
-		}
-
-		/* Set the WNodeID to our network address */
-		sendpacket[35] = (unsigned char)(network_number >> 24);
-		sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16);
-		sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8);
-		sendpacket[38] = (unsigned char)(network_number & 0x000000FF);
-
-		return 1;
-	} else {
-		/* If we get here its an IPX-data packet, so it'll get passed up the stack.
-		   switch the network numbers */
-		switch_net_numbers(sendpacket, network_number, 1);	
-		return 0;
-	}
-}
-
-/*
-   If incoming is 0 (outgoing)- if the net numbers is ours make it 0
-   if incoming is 1 - if the net number is 0 make it ours 
-
-*/
-
-static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming)
-{
-	unsigned long pnetwork_number;
-
-	pnetwork_number = (unsigned long)((sendpacket[6] << 24) + 
-			  (sendpacket[7] << 16) + (sendpacket[8] << 8) + 
-			  sendpacket[9]);
-
-	if (!incoming) 
-	{
-		/* If the destination network number is ours, make it 0 */
-		if( pnetwork_number == network_number) 
-		{
-			sendpacket[6] = sendpacket[7] = sendpacket[8] = 
-					 sendpacket[9] = 0x00;
-		}
-	} 
-	else 
-	{
-		/* If the incoming network is 0, make it ours */
-		if( pnetwork_number == 0) 
-		{
-			sendpacket[6] = (unsigned char)(network_number >> 24);
-			sendpacket[7] = (unsigned char)((network_number & 
-					 0x00FF0000) >> 16);
-			sendpacket[8] = (unsigned char)((network_number & 
-					 0x0000FF00) >> 8);
-			sendpacket[9] = (unsigned char)(network_number & 
-					 0x000000FF);
-		}
-	}
-
-
-	pnetwork_number = (unsigned long)((sendpacket[18] << 24) + 
-			  (sendpacket[19] << 16) + (sendpacket[20] << 8) + 
-			  sendpacket[21]);
-
-	if( !incoming ) 
-	{
-		/* If the source network is ours, make it 0 */
-		if( pnetwork_number == network_number) 
-		{
-			sendpacket[18] = sendpacket[19] = sendpacket[20] = 
-					 sendpacket[21] = 0x00;
-		}
-	}
-	else
-	{
-		/* If the source network is 0, make it ours */
-		if( pnetwork_number == 0 ) 
-		{
-			sendpacket[18] = (unsigned char)(network_number >> 24);
-			sendpacket[19] = (unsigned char)((network_number & 
-					 0x00FF0000) >> 16);
-			sendpacket[20] = (unsigned char)((network_number & 
-					 0x0000FF00) >> 8);
-			sendpacket[21] = (unsigned char)(network_number & 
-					 0x000000FF);
-		}
-	}
-} /* switch_net_numbers */
-
-
-/****** End *****************************************************************/
diff -u --recursive --new-file v2.3.20/linux/drivers/net/sdladrv.c linux/drivers/net/sdladrv.c
--- v2.3.20/linux/drivers/net/sdladrv.c	Wed Jun  2 14:40:22 1999
+++ linux/drivers/net/sdladrv.c	Wed Dec 31 16:00:00 1969
@@ -1,1856 +0,0 @@
-/*****************************************************************************
-* sdladrv.c	SDLA Support Module.  Main module.
-*
-*		This module is a library of common hardware-specific functions
-*		used by all Sangoma drivers.
-*
-* Author:	Gene Kozin	<genek@compuserve.com>
-*
-* Copyright:	(c) 1995-1996 Sangoma Technologies Inc.
-*
-*		This program is free software; you can redistribute it and/or
-*		modify it under the terms of the GNU General Public License
-*		as published by the Free Software Foundation; either version
-*		2 of the License, or (at your option) any later version.
-* ============================================================================
-* May 19, 1999	Arnaldo Melo	wanpipe_init belongs to sdlamain.c
-* Dec 20, 1996	Gene Kozin	Version 3.0.0. Complete overhaul.
-* Jul 12, 1996	Gene Kozin	Changes for Linux 2.0 compatibility.
-* Jun 12, 1996	Gene Kozin 	Added support for S503 card.
-* Apr 30, 1996	Gene Kozin	SDLA hardware interrupt is acknowledged before
-*				calling protocolspecific ISR.
-*				Register I/O ports with Linux kernel.
-*				Miscellaneous bug fixes.
-* Dec 20, 1995	Gene Kozin	Fixed a bug in interrupt routine.
-* Oct 14, 1995	Gene Kozin	Initial version.
-*****************************************************************************/
-
-/*****************************************************************************
- * Notes:
- * ------
- * 1. This code is ment to be system-independent (as much as possible).  To
- *    achive this, various macros are used to hide system-specific interfaces.
- *    To compile this code, one of the following constants must be defined:
- *
- *	Platform	Define
- *	--------	------
- *	Linux		_LINUX_
- *	SCO Unix	_SCO_UNIX_
- *
- * 2. Supported adapter types:
- *
- *	S502A
- *	ES502A (S502E)
- *	S503
- *	S507
- *	S508 (S509)
- *
- * 3. S502A Notes:
- *
- *	There is no separate DPM window enable/disable control in S502A.  It
- *	opens immediately after a window number it written to the HMCR
- *	register.  To close the window, HMCR has to be written a value
- *	????1111b (e.g. 0x0F or 0xFF).
- *
- *	S502A DPM window cannot be located at offset E000 (e.g. 0xAE000).
- *
- *	There should be a delay of ??? before reading back S502A status
- *	register.
- *
- * 4. S502E Notes:
- *
- *	S502E has a h/w bug: although default IRQ line state is HIGH, enabling
- *	interrupts by setting bit 1 of the control register (BASE) to '1'
- *	causes it to go LOW! Therefore, disabling interrupts by setting that
- *	bit to '0' causes low-to-high transition on IRQ line (ghosty
- *	interrupt). The same occurs when disabling CPU by resetting bit 0 of
- *	CPU control register (BASE+3) - see the next note.
- *
- *	S502E CPU and DPM control is limited:
- *
- *	o CPU cannot be stopped independently. Resetting bit 0 of the CPUi
- *	  control register (BASE+3) shuts the board down entirely, including
- *	  DPM;
- *
- *	o DPM access cannot be controlled dynamically. Ones CPU is started,
- *	  bit 1 of the control register (BASE) is used to enable/disable IRQ,
- *	  so that access to shared memory cannot be disabled while CPU is
- *	  running.
- ****************************************************************************/
-
-#define	_LINUX_
-
-#if	defined(_LINUX_)	/****** Linux *******************************/
-
-#include <linux/kernel.h>	/* printk(), and other useful stuff */
-#include <linux/stddef.h>	/* offsetof(), etc. */
-#include <linux/errno.h>	/* return codes */
-#include <linux/string.h>	/* inline memset(), etc. */
-#include <linux/module.h>	/* support for loadable modules */
-#include <linux/sched.h>	/* for jiffies, HZ, etc. */
-#include <linux/sdladrv.h>	/* API definitions */
-#include <linux/sdlasfm.h>	/* SDLA firmware module definitions */
-#include <asm/io.h>		/* for inb(), outb(), etc. */
-#define _INB(port)		(inb(port))
-#define _OUTB(port, byte)	(outb((byte),(port)))
-#define	SYSTEM_TICK		jiffies
-
-#elif	defined(_SCO_UNIX_)	/****** SCO Unix ****************************/
-#if	!defined(INKERNEL)
-#error	This code MUST be compiled in kernel mode!
-#endif
-#include <sys/sdladrv.h>	/* API definitions */
-#include <sys/sdlasfm.h>	/* SDLA firmware module definitions */
-#include <sys/inline.h>		/* for inb(), outb(), etc. */
-#define _INB(port)		(inb(port))
-#define _OUTB(port, byte)	(outb((port),(byte)))
-#define	SYSTEM_TICK		lbolt
-
-#else
-#error	Unknown system type!
-#endif
-
-#define	MOD_VERSION	3
-#define	MOD_RELEASE	0
-
-#define	SDLA_IODELAY	100	/* I/O Rd/Wr delay, 10 works for 486DX2-66 */
-#define	EXEC_DELAY	20	/* shared memory access delay, mks */
-#define	EXEC_TIMEOUT	(HZ*2)	/* command timeout, in ticks */
-
-/* I/O port address range */
-#define S502A_IORANGE	3
-#define S502E_IORANGE	4
-#define S503_IORANGE	3
-#define S507_IORANGE	4
-#define S508_IORANGE	4
-
-/* Maximum amount of memory */
-#define S502_MAXMEM	0x10000L
-#define S503_MAXMEM	0x10000L
-#define S507_MAXMEM	0x40000L
-#define S508_MAXMEM	0x40000L
-
-/* Minimum amount of memory */
-#define S502_MINMEM	0x8000L
-#define S503_MINMEM	0x8000L
-#define S507_MINMEM	0x20000L
-#define S508_MINMEM	0x20000L
-
-/****** Function Prototypes *************************************************/
-
-/* Module entry points. These are called by the OS and must be public. */
-int init_module (void);
-void cleanup_module (void);
-
-/* Hardware-specific functions */
-static int sdla_detect	(sdlahw_t* hw);
-static int sdla_autodpm	(sdlahw_t* hw);
-static int sdla_setdpm	(sdlahw_t* hw);
-static int sdla_load	(sdlahw_t* hw, sfm_t* sfm, unsigned len);
-static int sdla_init	(sdlahw_t* hw);
-static unsigned long sdla_memtest (sdlahw_t* hw);
-static int sdla_bootcfg	(sdlahw_t* hw, sfm_info_t* sfminfo);
-static unsigned char make_config_byte (sdlahw_t* hw);
-static int sdla_start	(sdlahw_t* hw, unsigned addr);
-
-static int init_s502a	(sdlahw_t* hw);
-static int init_s502e	(sdlahw_t* hw);
-static int init_s503	(sdlahw_t* hw);
-static int init_s507	(sdlahw_t* hw);
-static int init_s508	(sdlahw_t* hw);
-
-static int detect_s502a	(int port);
-static int detect_s502e	(int port);
-static int detect_s503	(int port);
-static int detect_s507	(int port);
-static int detect_s508	(int port);
-
-/* Miscellaneous functions */
-static int calibrate_delay (int mks);
-static int get_option_index (unsigned* optlist, unsigned optval);
-static unsigned check_memregion (void* ptr, unsigned len);
-static unsigned	test_memregion (void* ptr, unsigned len);
-static unsigned short checksum (unsigned char* buf, unsigned len);
-
-/****** Global Data **********************************************************
- * Note: All data must be explicitly initialized!!!
- */
-
-/* private data */
-static char modname[]	= "sdladrv";
-static char fullname[]	= "SDLA Support Module";
-static char copyright[]	= "(c) 1995-1996 Sangoma Technologies Inc.";
-static unsigned	exec_idle;
-
-/* Hardware configuration options.
- * These are arrays of configuration options used by verification routines.
- * The first element of each array is its size (i.e. number of options).
- */
-static unsigned	s502_port_options[] =
-	{ 4, 0x250, 0x300, 0x350, 0x360 }
-;
-static unsigned	s503_port_options[] =
-	{ 8, 0x250, 0x254, 0x300, 0x304, 0x350, 0x354, 0x360, 0x364 }
-;
-static unsigned	s508_port_options[] =
-	{ 8, 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390 }
-;
-
-static unsigned s502a_irq_options[] = { 0 };
-static unsigned s502e_irq_options[] = { 4, 2, 3, 5, 7 };
-static unsigned s503_irq_options[]  = { 5, 2, 3, 4, 5, 7 };
-static unsigned s508_irq_options[]  = { 8, 3, 4, 5, 7, 10, 11, 12, 15 };
-
-static unsigned s502a_dpmbase_options[] =
-{
-	28,
-	0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000,
-	0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000,
-	0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000,
-	0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000,
-};
-static unsigned s507_dpmbase_options[] =
-{
-	32,
-	0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000,
-	0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000,
-	0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000,
-	0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000,
-};
-static unsigned s508_dpmbase_options[] =	/* incl. S502E and S503 */
-{
-	32,
-	0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000,
-	0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000,
-	0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, 0xDE000,
-	0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000,
-};
-
-/*
-static unsigned	s502_dpmsize_options[] = { 2, 0x2000, 0x10000 };
-static unsigned	s507_dpmsize_options[] = { 2, 0x2000, 0x4000 };
-static unsigned	s508_dpmsize_options[] = { 1, 0x2000 };
-*/
-
-static unsigned	s502a_pclk_options[] = { 2, 3600, 7200 };
-static unsigned	s502e_pclk_options[] = { 5, 3600, 5000, 7200, 8000, 10000 };
-static unsigned	s503_pclk_options[]  = { 3, 7200, 8000, 10000 };
-static unsigned	s507_pclk_options[]  = { 1, 12288 };
-static unsigned	s508_pclk_options[]  = { 1, 16000 };
-
-/* Host memory control register masks */
-static unsigned char s502a_hmcr[] =
-{
-	0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C,	/* A0000 - AC000 */
-	0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C,	/* C0000 - CC000 */
-	0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C,	/* D0000 - DC000 */
-	0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C,	/* E0000 - EC000 */
-};
-static unsigned char s502e_hmcr[] =
-{
-	0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E,	/* A0000 - AE000 */
-	0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E,	/* C0000 - CE000 */
-	0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,	/* D0000 - DE000 */
-	0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E,	/* E0000 - EE000 */
-};
-static unsigned char s507_hmcr[] =
-{
-	0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,	/* A0000 - AE000 */
-	0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E,	/* B0000 - BE000 */
-	0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E,	/* C0000 - CE000 */
-	0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE,	/* E0000 - EE000 */
-};
-static unsigned char s508_hmcr[] =
-{
-	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,	/* A0000 - AE000 */
-	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,	/* C0000 - CE000 */
-	0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,	/* D0000 - DE000 */
-	0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,	/* E0000 - EE000 */
-};
-
-static unsigned char s507_irqmask[] =
-{
-	0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0
-};
-
-/******* Kernel Loadable Module Entry Points ********************************/
-
-/*============================================================================
- * Module 'insert' entry point.
- * o print announcement
- * o initialize static data
- * o calibrate SDLA shared memory access delay.
- *
- * Return:	0	Ok
- *		< 0	error.
- * Context:	process
- */
-
-#ifdef MODULE
-int init_module (void)
-{
-	printk(KERN_INFO "%s v%u.%u %s\n",
-		fullname, MOD_VERSION, MOD_RELEASE, copyright);
-	exec_idle = calibrate_delay(EXEC_DELAY);
-#ifdef WANDEBUG	
-	printk(KERN_DEBUG "%s: exec_idle = %d\n", modname, exec_idle);
-#endif	
-	return 0;
-}
-
-/*============================================================================
- * Module 'remove' entry point.
- * o release all remaining system resources
- */
-void cleanup_module (void)
-{
-}
-#endif
-
-/******* Kernel APIs ********************************************************/
-
-/*============================================================================
- * Set up adapter.
- * o detect adapter type
- * o verify hardware configuration options
- * o check for hardware conflicts
- * o set up adapter shared memory
- * o test adapter memory
- * o load firmware
- * Return:	0	ok.
- *		< 0	error
- */
- 
-EXPORT_SYMBOL(sdla_setup);
-
-int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len)
-{
-	unsigned* irq_opt	= NULL;	/* IRQ options */
-	unsigned* dpmbase_opt	= NULL;	/* DPM window base options */
-	unsigned* pclk_opt	= NULL;	/* CPU clock rate options */
-	int err;
-
-	if (sdla_detect(hw))
-	{
-		printk(KERN_ERR "%s: adapter S%04u not found at port 0x%X!\n",
-			modname, hw->type, hw->port)
-		;
-		return -EINVAL;
-	}
-	printk(KERN_INFO "%s: found S%04u card at port 0x%X.\n",
-		modname, hw->type, hw->port)
-	;
-
-	hw->dpmsize = SDLA_WINDOWSIZE;
-	switch (hw->type)
-	{
-	case SDLA_S502A:
-		hw->io_range	= S502A_IORANGE;
-		irq_opt		= s502a_irq_options;
-		dpmbase_opt	= s502a_dpmbase_options;
-		pclk_opt	= s502a_pclk_options;
-		break;
-
-	case SDLA_S502E:
-		hw->io_range	= S502E_IORANGE;
-		irq_opt		= s502e_irq_options;
-		dpmbase_opt	= s508_dpmbase_options;
-		pclk_opt	= s502e_pclk_options;
-		break;
-
-	case SDLA_S503:
-		hw->io_range	= S503_IORANGE;
-		irq_opt		= s503_irq_options;
-		dpmbase_opt	= s508_dpmbase_options;
-		pclk_opt	= s503_pclk_options;
-		break;
-
-	case SDLA_S507:
-		hw->io_range	= S507_IORANGE;
-		irq_opt		= s508_irq_options;
-		dpmbase_opt	= s507_dpmbase_options;
-		pclk_opt	= s507_pclk_options;
-		break;
-
-	case SDLA_S508:
-		hw->io_range	= S508_IORANGE;
-		irq_opt		= s508_irq_options;
-		dpmbase_opt	= s508_dpmbase_options;
-		pclk_opt	= s508_pclk_options;
-		break;
-	}
-
-	/* Verify IRQ configuration options */
-	if (!get_option_index(irq_opt, hw->irq))
-	{
-		printk(KERN_ERR "%s: IRQ %d is illegal!\n",
-			modname, hw->irq)
-		;
-		return -EINVAL;
-	} 
-
-	/* Verify CPU clock rate configuration options */
-	if (hw->pclk == 0)
-		hw->pclk = pclk_opt[1]	/* use default */
-	;
-	else if (!get_option_index(pclk_opt, hw->pclk))
-	{
-		printk(KERN_ERR "%s: CPU clock %u is illegal!\n",
-			modname, hw->pclk)
-		;
-		return -EINVAL;
-	} 
-	printk(KERN_INFO "%s: assuming CPU clock rate of %u kHz.\n",
-		modname, hw->pclk)
-	;
-
-	/* Setup adapter dual-port memory window and test memory */
-	if (hw->dpmbase == 0)
-	{
-		err = sdla_autodpm(hw);
-		if (err)
-		{
-			printk(KERN_ERR
-				"%s: can't find available memory region!\n",
-				modname)
-			;
- 			return err;
-		}
-	}
-	else if (!get_option_index(dpmbase_opt, virt_to_phys(hw->dpmbase)))
-	{
-		printk(KERN_ERR "%s: memory address 0x%lX is illegal!\n",
-			modname, virt_to_phys(hw->dpmbase))
-		;
-		return -EINVAL;
-	} 
-	else if (sdla_setdpm(hw))
-	{
-		printk(KERN_ERR
-			"%s: 8K memory region at 0x%lX is not available!\n",
-			modname, virt_to_phys(hw->dpmbase));
-		return -EINVAL;
-	} 
-	printk(KERN_INFO "%s: dual-port memory window is set at 0x%lX.\n",
-		modname, virt_to_phys(hw->dpmbase));
-
-	printk(KERN_INFO "%s: found %luK bytes of on-board memory.\n",
-		modname, hw->memory / 1024);
-
-	/* Load firmware. If loader fails then shut down adapter */
-	err = sdla_load(hw, sfm, len);
-	if (err) sdla_down(hw);		/* shutdown adapter */
-	return err;
-} 
-
-/*============================================================================
- * Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc.
- */
-
-EXPORT_SYMBOL(sdla_down);
-
-int sdla_down (sdlahw_t* hw)
-{
-	unsigned port = hw->port;
-	int i;
-
-	if (!port) return -EFAULT;
-
-	switch (hw->type)
-	{
-	case SDLA_S502A:
-		_OUTB(port, 0x08);		/* halt CPU */
-		_OUTB(port, 0x08);
-		_OUTB(port, 0x08);
-		hw->regs[0] = 0x08;
-		_OUTB(port + 1, 0xFF);		/* close memory window */
-		hw->regs[1] = 0xFF;
-		break;
-
-	case SDLA_S502E:
-		_OUTB(port + 3, 0);		/* stop CPU */
-		_OUTB(port, 0);			/* reset board */
-		for (i = 0; i < S502E_IORANGE; ++i)
-			hw->regs[i] = 0
-		;
-		break;
-
-	case SDLA_S503:
-	case SDLA_S507:
-	case SDLA_S508:
-		_OUTB(port, 0);			/* reset board logic */
-		hw->regs[0] = 0;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-/*============================================================================
- * Map shared memory window into SDLA address space.
- */
-
-EXPORT_SYMBOL(sdla_mapmem);
-
-int sdla_mapmem (sdlahw_t* hw, unsigned long addr)
-{
-	unsigned port = hw->port;
-	register int tmp;
-
-	switch (hw->type)
-	{
-	case SDLA_S502A:
-	case SDLA_S502E:
-		if (addr < S502_MAXMEM)	/* verify parameter */
-		{
-			tmp = addr >> 13;	/* convert to register mask */
-			_OUTB(port + 2, tmp);
-			hw->regs[2] = tmp;
-		}
-		else return -EINVAL;
-		break;
-
-	case SDLA_S503:
-		if (addr < S503_MAXMEM)	/* verify parameter */
-		{
-			tmp = (hw->regs[0] & 0x8F) | ((addr >> 9) & 0x70);
-			_OUTB(port, tmp);
-			hw->regs[0] = tmp;
-		}
-		else return -EINVAL;
-		break;
-
-	case SDLA_S507:
-		if (addr < S507_MAXMEM)
-		{
-			if (!(_INB(port) & 0x02))
-				return -EIO
-			;
-			tmp = addr >> 13;	/* convert to register mask */
-			_OUTB(port + 2, tmp);
-			hw->regs[2] = tmp;
-		}
-		else return -EINVAL;
-		break;
-
-	case SDLA_S508:
-		if (addr < S508_MAXMEM)
-		{
-			tmp = addr >> 13;	/* convert to register mask */
-			_OUTB(port + 2, tmp);
-			hw->regs[2] = tmp;
-		}
-		else return -EINVAL;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-	hw->vector = addr & 0xFFFFE000L;
-	return 0;
-}
-
-/*============================================================================
- * Enable interrupt generation.
- */
- 
-EXPORT_SYMBOL(sdla_inten);
-
-int sdla_inten (sdlahw_t* hw)
-{
-	unsigned port = hw->port;
-	int tmp, i;
-
-	switch (hw->type)
-	{
-	case SDLA_S502E:
-		/* Note thar interrupt control operations on S502E are allowed
-		 * only if CPU is enabled (bit 0 of status register is set).
-		 */
-		if (_INB(port) & 0x01)
-		{
-			_OUTB(port, 0x02);	/* bit1 = 1, bit2 = 0 */
-			_OUTB(port, 0x06);	/* bit1 = 1, bit2 = 1 */
-			hw->regs[0] = 0x06;
-		}
-		else return -EIO;
-		break;
-
-	case SDLA_S503:
-		tmp = hw->regs[0] | 0x04;
-		_OUTB(port, tmp);
-		hw->regs[0] = tmp;		/* update mirror */
-		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-		if (!(_INB(port) & 0x02))		/* verify */
-			return -EIO
-		;
-		break;
-
-	case SDLA_S508:
-		tmp = hw->regs[0] | 0x10;
-		_OUTB(port, tmp);
-		hw->regs[0] = tmp;		/* update mirror */
-		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-		if (!(_INB(port + 1) & 0x10))		/* verify */
-			return -EIO
-		;
-		break;
-
-	case SDLA_S502A:
-	case SDLA_S507:
-		break;
-
-	default:
-		return -EINVAL;
-
-	}
-	return 0;
-}
-
-/*============================================================================
- * Disable interrupt generation.
- */
-
-EXPORT_SYMBOL(sdla_intde);
-
-int sdla_intde (sdlahw_t* hw)
-{
-	unsigned port = hw->port;
-	int tmp, i;
-
-	switch (hw->type)
-	{
-	case SDLA_S502E:
-		/* Notes:
-		 *  1) interrupt control operations are allowed only if CPU is
-		 *     enabled (bit 0 of status register is set).
-		 *  2) disabling interrupts using bit 1 of control register
-		 *     causes IRQ line go high, therefore we are going to use
-		 *     0x04 instead: lower it to inhibit interrupts to PC.
-		 */
-		if (_INB(port) & 0x01)
-		{
-			_OUTB(port, hw->regs[0] & ~0x04);
-			hw->regs[0] &= ~0x04;
-		}
-		else return -EIO;
-		break;
-
-	case SDLA_S503:
-		tmp = hw->regs[0] & ~0x04;
-		_OUTB(port, tmp);
-		hw->regs[0] = tmp;			/* update mirror */
-		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-		if (_INB(port) & 0x02)			/* verify */
-			return -EIO
-		;
-		break;
-
-	case SDLA_S508:
-		tmp = hw->regs[0] & ~0x10;
-		_OUTB(port, tmp);
-		hw->regs[0] = tmp;			/* update mirror */
-		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-		if (_INB(port) & 0x10)			/* verify */
-			return -EIO
-		;
-		break;
-
-	case SDLA_S502A:
-	case SDLA_S507:
-		break;
-
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-/*============================================================================
- * Acknowledge SDLA hardware interrupt.
- */
-
-EXPORT_SYMBOL(sdla_intack);
-
-int sdla_intack (sdlahw_t* hw)
-{
-	unsigned port = hw->port;
-	int tmp;
-
-	switch (hw->type)
-	{
-	case SDLA_S502E:
-		/* To acknoledge hardware interrupt we have to toggle bit 3 of
-		 * control register: \_/
-		 * Note that interrupt control operations on S502E are allowed
-		 * only if CPU is enabled (bit 1 of status register is set).
-		 */
-		if (_INB(port) & 0x01)
-		{
-			tmp = hw->regs[0] & ~0x04;
-			_OUTB(port, tmp);
-			tmp |= 0x04;
-			_OUTB(port, tmp);
-			hw->regs[0] = tmp;
-		}
-		else return -EIO;
-		break;
-
-	case SDLA_S503:
-		if (_INB(port) & 0x04)
-		{
-			tmp = hw->regs[0] & ~0x08;
-			_OUTB(port, tmp);
-			tmp |= 0x08;
-			_OUTB(port, tmp);
-			hw->regs[0] = tmp;
-		}
-		break;
-
-	case SDLA_S502A:
-	case SDLA_S507:
-	case SDLA_S508:
-	break;
-
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-/*============================================================================
- * Generate an interrupt to adapter's CPU.
- */
-
-EXPORT_SYMBOL(sdla_intr);
-
-int sdla_intr (sdlahw_t* hw)
-{
-	unsigned port = hw->port;
-
-	switch (hw->type)
-	{
-	case SDLA_S502A:
-		if (!(_INB(port) & 0x40))
-		{
-			_OUTB(port, 0x10);		/* issue NMI to CPU */
-			hw->regs[0] = 0x10;
-		}
-		else return -EIO;
-		break;
-
-	case SDLA_S507:
-		if ((_INB(port) & 0x06) == 0x06)
-		{
-			_OUTB(port + 3, 0);
-		}
-		else return -EIO;
-		break;
-
-	case SDLA_S508:
-		if (_INB(port + 1) & 0x02)
-		{
-			_OUTB(port, 0x08);
-		}
-		else return -EIO;
-		break;
-
-	case SDLA_S502E:
-	case SDLA_S503:
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-/*============================================================================
- * Execute Adapter Command.
- * o Set exec flag.
- * o Busy-wait until flag is reset.
- * o Return number of loops made, or 0 if command timed out.
- */
-
-EXPORT_SYMBOL(sdla_exec);
-
-int sdla_exec (void* opflag)
-{
-	volatile unsigned char* flag = opflag;
-	unsigned long tstop;
-	int nloops;
-
-	if (*flag) return 0;	/* ???? */
-
-	*flag = 1;
-	tstop = SYSTEM_TICK + EXEC_TIMEOUT;
-	for (nloops = 1; *flag; ++nloops)
-	{
-		unsigned delay = exec_idle;
-		while (--delay);			/* delay */
-		if (SYSTEM_TICK > tstop) return 0;	/* time is up! */
-	}
-	return nloops;
-}
-
-/*============================================================================
- * Read absolute adapter memory.
- * Transfer data from adapter's memory to data buffer.
- *
- * Note:
- * Care should be taken when crossing dual-port memory window boundary.
- * This function is not atomic, so caller must disable interrupt if
- * interrupt routines are accessing adapter shared memory.
- */
- 
-EXPORT_SYMBOL(sdla_peek);
-
-int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len)
-{
-	unsigned long oldvec = hw->vector;
-	unsigned winsize = hw->dpmsize;
-	unsigned curpos, curlen;	/* current offset and block size */
-	unsigned long curvec;		/* current DPM window vector */
-	int err = 0;
-
-	if (addr + len > hw->memory)	/* verify arguments */
-		return -EINVAL
-	;
-	while (len && !err)
-	{
-		curpos = addr % winsize;	/* current window offset */
-		curvec = addr - curpos;		/* current window vector */
-		curlen = (len > (winsize - curpos)) ? (winsize - curpos) : len;
-
-		/* Relocate window and copy block of data */
-		err = sdla_mapmem(hw, curvec);
-		memcpy(buf, (void *)((u8 *)hw->dpmbase + curpos), curlen);
-		addr       += curlen;
-		(char*)buf += curlen;
-		len        -= curlen;
-	}
-
-	/* Restore DPM window position */
-	sdla_mapmem(hw, oldvec);
-	return err;
-}
-
-/*============================================================================
- * Write Absolute Adapter Memory.
- * Transfer data from data buffer to adapter's memory.
- *
- * Note:
- * Care should be taken when crossing dual-port memory window boundary.
- * This function is not atomic, so caller must disable interrupt if
- * interrupt routines are accessing adapter shared memory.
- */
- 
-EXPORT_SYMBOL(sdla_poke);
- 
-int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len)
-{
-	unsigned long oldvec = hw->vector;
-	unsigned winsize = hw->dpmsize;
-	unsigned curpos, curlen;	/* current offset and block size */
-	unsigned long curvec;		/* current DPM window vector */
-	int err = 0;
-
-	if (addr + len > hw->memory)	/* verify arguments */
-		return -EINVAL
-	;
-	while (len && !err)
-	{
-		curpos = addr % winsize;	/* current window offset */
-		curvec = addr - curpos;		/* current window vector */
-		curlen = (len > (winsize - curpos)) ? (winsize - curpos) : len;
-
-		/* Relocate window and copy block of data */
-		sdla_mapmem(hw, curvec);
-		memcpy((void*)((u8 *)hw->dpmbase + curpos), buf, curlen);
-		addr       += curlen;
-		(char*)buf += curlen;
-		len        -= curlen;
-	}
-
-	/* Restore DPM window position */
-	sdla_mapmem(hw, oldvec);
-	return err;
-}
-
-#ifdef	DONT_COMPIPLE_THIS
-#endif	/* DONT_COMPIPLE_THIS */
-
-/****** Hardware-Specific Functions *****************************************/
-
-/*============================================================================
- * Detect adapter type.
- * o if adapter type is specified then call detection routine for that adapter
- *   type.  Otherwise call detection routines for every adapter types until
- *   adapter is detected.
- *
- * Notes:
- * 1) Detection tests are destructive! Adapter will be left in shutdown state
- *    after the test.
- */
-static int sdla_detect (sdlahw_t* hw)
-{
-	unsigned port = hw->port;
-	int err = 0;
-
-	if (!port)
-		return -EFAULT
-	;
-	switch (hw->type)
-	{
-	case SDLA_S502A:
-		if (!detect_s502a(port)) err = -ENODEV;
-		break;
-
-	case SDLA_S502E:
-		if (!detect_s502e(port)) err = -ENODEV;
-		break;
-
-	case SDLA_S503:
-		if (!detect_s503(port)) err = -ENODEV;
-		break;
-
-	case SDLA_S507:
-		if (!detect_s507(port)) err = -ENODEV;
-		break;
-
-	case SDLA_S508:
-		if (!detect_s508(port)) err = -ENODEV;
-		break;
-
-	default:
-		if (detect_s502a(port))
-			hw->type = SDLA_S502A
-		;
-		else if (detect_s502e(port))
-			hw->type = SDLA_S502E
-		;
-		else if (detect_s503(port))
-			hw->type = SDLA_S503
-		;
-		else if (detect_s507(port))
-			hw->type = SDLA_S507
-		;
-		else if (detect_s508(port))
-			hw->type = SDLA_S508
-		;
-		else err = -ENODEV;
-	}
-	return err;
-}
-
-/*============================================================================
- * Autoselect memory region. 
- * o try all available DMP address options from the top down until success.
- */
-static int sdla_autodpm (sdlahw_t* hw)
-{
-	int i, err = -EINVAL;
-	unsigned* opt;
-
-	switch (hw->type)
-	{
-	case SDLA_S502A:
-		opt = s502a_dpmbase_options;
-		break;
-
-	case SDLA_S502E:
-	case SDLA_S503:
-	case SDLA_S508:
-		opt = s508_dpmbase_options;
-		break;
-
-	case SDLA_S507:
-		opt = s507_dpmbase_options;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	for (i = opt[0]; i && err; --i)
-	{
-		hw->dpmbase = phys_to_virt(opt[i]);
-		err = sdla_setdpm(hw);
-	}
-	return err;
-}
-
-/*============================================================================
- * Set up adapter dual-port memory window. 
- * o shut down adapter
- * o make sure that no physical memory exists in this region, i.e entire
- *   region reads 0xFF and is not writable when adapter is shut down.
- * o initialize adapter hardware
- * o make sure that region is usable with SDLA card, i.e. we can write to it
- *   when adapter is configured.
- */
-static int sdla_setdpm (sdlahw_t* hw)
-{
-	int err;
-
-	/* Shut down card and verify memory region */
-	sdla_down(hw);
-	if (check_memregion(hw->dpmbase, hw->dpmsize))
-		return -EINVAL
-	;
-
-	/* Initialize adapter and test on-board memory segment by segment.
-	 * If memory size appears to be less than shared memory window size,
-	 * assume that memory region is unusable.
-	 */
-	err = sdla_init(hw);
-	if (err) return err;
-
-	if (sdla_memtest(hw) < hw->dpmsize)	/* less than window size */
-	{
-		sdla_down(hw);
-		return -EIO;
-	}
-	sdla_mapmem(hw, 0L);	/* set window vector at bottom */
-	return 0;
-}
-
-/*============================================================================
- * Load adapter from the memory image of the SDLA firmware module. 
- * o verify firmware integrity and compatibility
- * o start adapter up
- */
-static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len)
-{
-	int i;
-
-	/* Verify firmware signature */
-	if (strcmp(sfm->signature, SFM_SIGNATURE))
-	{
-		printk(KERN_ERR "%s: not SDLA firmware!\n",
-			modname)
-		;
-		return -EINVAL;
-	}
-
-	/* Verify firmware module format version */
-	if (sfm->version != SFM_VERSION)
-	{
-		printk(KERN_ERR
-			"%s: firmware format %u rejected! Expecting %u.\n",
-			modname, sfm->version, SFM_VERSION)
-		;
-		return -EINVAL;
-	}
-
-	/* Verify firmware module length and checksum */
-	if ((len - offsetof(sfm_t, image) != sfm->info.codesize) ||
-		(checksum((void*)&sfm->info,
-		sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum))
-	{
-		printk(KERN_ERR "%s: firmware corrupted!\n", modname);
-		return -EINVAL;
-	}
-
-	/* Announce */
-	printk(KERN_INFO "%s: loading %s (ID=%u)...\n", modname,
-		(sfm->descr[0] != '\0') ? sfm->descr : "unknown firmware",
-		sfm->info.codeid)
-	;
-
-	/* Scan through the list of compatible adapters and make sure our
-	 * adapter type is listed.
-	 */
-	for (i = 0;
-	     (i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hw->type);
-	     ++i)
-	;
-	if (i == SFM_MAX_SDLA)
-	{
-		printk(KERN_ERR "%s: firmware is not compatible with S%u!\n",
-			modname, hw->type)
-		;
-		return -EINVAL;
-	}
-
-	/* Make sure there is enough on-board memory */
-	if (hw->memory < sfm->info.memsize)
-	{
-		printk(KERN_ERR
-			"%s: firmware needs %lu bytes of on-board memory!\n",
-			modname, sfm->info.memsize)
-		;
-		return -EINVAL;
-	}
-
-	/* Move code onto adapter */
-	if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize))
-	{
-		printk(KERN_ERR "%s: failed to load code segment!\n",
-			modname)
-		;
-		return -EIO;
-	}
-
-	/* Prepare boot-time configuration data and kick-off CPU */
-	sdla_bootcfg(hw, &sfm->info);
-	if (sdla_start(hw, sfm->info.startoffs))
-	{
-		printk(KERN_ERR "%s: Damn... Adapter won't start!\n",
-			modname)
-		;
-		return -EIO;
-	}
-
-	/* position DPM window over the mailbox and enable interrupts */
-        if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw))
-	{
-		printk(KERN_ERR "%s: adapter hardware failure!\n",
-			modname)
-		;
-		return -EIO;
-	}
-	hw->fwid = sfm->info.codeid;		/* set firmware ID */
-	return 0;
-}
-
-/*============================================================================
- * Initialize SDLA hardware: setup memory window, IRQ, etc.
- */
-static int sdla_init (sdlahw_t* hw)
-{
-	int i;
-
-	for (i = 0; i < SDLA_MAXIORANGE; ++i)
-		hw->regs[i] = 0
-	;
-	switch (hw->type)
-	{
-	case SDLA_S502A: return init_s502a(hw);
-	case SDLA_S502E: return init_s502e(hw);
-	case SDLA_S503:  return init_s503(hw);
-	case SDLA_S507:  return init_s507(hw);
-	case SDLA_S508:  return init_s508(hw);
-	}
-	return -EINVAL;
-}
-
-/*============================================================================
- * Test adapter on-board memory.
- * o slide DPM window from the bottom up and test adapter memory segment by
- *   segment.
- * Return adapter memory size.
- */
-static unsigned long sdla_memtest (sdlahw_t* hw)
-{
-	unsigned long memsize;
-	unsigned winsize;
-
-	for (memsize = 0, winsize = hw->dpmsize;
-	     !sdla_mapmem(hw, memsize) &&
-		(test_memregion(hw->dpmbase, winsize) == winsize)
-	     ;
-	     memsize += winsize)
-	;
-	hw->memory = memsize;
-	return memsize;
-}
-
-/*============================================================================
- * Prepare boot-time firmware configuration data.
- * o position DPM window
- * o initialize configuration data area
- */
-static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo)
-{
-	unsigned char* data;
-
-	if (!sfminfo->datasize) return 0;	/* nothing to do */
-
-	if (sdla_mapmem(hw, sfminfo->dataoffs) != 0)
-		return -EIO
-	;
-	data = (void*)((u8 *)hw->dpmbase + (sfminfo->dataoffs - hw->vector));
-	memset(data, 0, sfminfo->datasize);
-
-	data[0x00] = make_config_byte(hw);
-	switch (sfminfo->codeid)
-	{
-	case SFID_X25_502:
-	case SFID_X25_508:
-		data[0x01] = 3;			/* T1 timer */
-		data[0x03] = 10;		/* N2 */
-		data[0x06] = 7;			/* HDLC window size */
-		data[0x0B] = 1;			/* DTE */
-		data[0x0C] = 2;			/* X.25 packet window size */
-		*(short*)&data[0x0D] = 128;	/* default X.25 data size */
-		*(short*)&data[0x0F] = 128;	/* maximum X.25 data size */
-		break;
-	}
-	return 0;
-}
-
-/*============================================================================
- * Prepare configuration byte identifying adapter type and CPU clock rate.
- */
-static unsigned char make_config_byte (sdlahw_t* hw)
-{
-	unsigned char byte = 0;
-
-	switch (hw->pclk)
-	{
-		case 5000:  byte = 0x01; break;
-		case 7200:  byte = 0x02; break;
-		case 8000:  byte = 0x03; break;
-		case 10000: byte = 0x04; break;
-		case 16000: byte = 0x05; break;
-	}
-	switch (hw->type)
-	{
-		case SDLA_S502E: byte |= 0x80; break;
-		case SDLA_S503:  byte |= 0x40; break;
-	}
-	return byte;
-}
-
-/*============================================================================
- * Start adapter's CPU.
- * o calculate a pointer to adapter's cold boot entry point
- * o position DPM window
- * o place boot instruction (jp addr) at cold boot entry point
- * o start CPU
- */
-static int sdla_start (sdlahw_t* hw, unsigned addr)
-{
-	unsigned port = hw->port;
-	unsigned char *bootp;
-	int err, tmp, i;
-
-	if (!port) return -EFAULT;
-
-	switch (hw->type)
-	{
-	case SDLA_S502A:
-		bootp = hw->dpmbase;
-		bootp += 0x66;
-		break;
-
-	case SDLA_S502E:
-	case SDLA_S503:
-	case SDLA_S507:
-	case SDLA_S508:
-		bootp = hw->dpmbase;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	err = sdla_mapmem(hw, 0);
-	if (err) return err;
-
-	*bootp = 0xC3;	 /* Z80: 'jp' opcode */
-	bootp++;
-	*((unsigned short*)(bootp)) = addr;
-
-	switch (hw->type)
-	{
-	case SDLA_S502A:
-		_OUTB(port, 0x10);		/* issue NMI to CPU */
-		hw->regs[0] = 0x10;
-		break;
-
-	case SDLA_S502E:
-		_OUTB(port + 3, 0x01);		/* start CPU */
-		hw->regs[3] = 0x01;
-		for (i = 0; i < SDLA_IODELAY; ++i);
-		if (_INB(port) & 0x01)		/* verify */
-		{
-			/*
-			 * Enabling CPU changes functionality of the
-			 * control register, so we have to reset its
-			 * mirror.
-			 */
-			_OUTB(port, 0);		/* disable interrupts */
-			hw->regs[0] = 0;
-		}
-		else return -EIO;
-		break;
-
-	case SDLA_S503:
-		tmp = hw->regs[0] | 0x09;	/* set bits 0 and 3 */
-		_OUTB(port, tmp);
-		hw->regs[0] = tmp;		/* update mirror */
-		for (i = 0; i < SDLA_IODELAY; ++i);
-		if (!(_INB(port) & 0x01))	/* verify */
-			return -EIO
-		;
-		break;
-
-	case SDLA_S507:
-		tmp = hw->regs[0] | 0x02;
-		_OUTB(port, tmp);
-		hw->regs[0] = tmp;		/* update mirror */
-		for (i = 0; i < SDLA_IODELAY; ++i);
-		if (!(_INB(port) & 0x04))	/* verify */
-			return -EIO
-		;
-		break;
-
-	case SDLA_S508:
-		tmp = hw->regs[0] | 0x02;
-		_OUTB(port, tmp);
-		hw->regs[0] = tmp;	/* update mirror */
-		for (i = 0; i < SDLA_IODELAY; ++i);
-		if (!(_INB(port + 1) & 0x02))	/* verify */
-			return -EIO
-		;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-/*============================================================================
- * Initialize S502A adapter.
- */
-static int init_s502a (sdlahw_t* hw)
-{
-	unsigned port = hw->port;
-	int tmp, i;
-
-	if (!detect_s502a(port))
-		return -ENODEV
-	;
-	hw->regs[0] = 0x08;
-	hw->regs[1] = 0xFF;
-
-	/* Verify configuration options */
-	i = get_option_index(s502a_dpmbase_options, virt_to_phys(hw->dpmbase));
-	if (i == 0)
-		return -EINVAL
-	;
-
-	tmp = s502a_hmcr[i - 1];
-	switch (hw->dpmsize)
-	{
-	case 0x2000:
-		tmp |= 0x01;
-		break;
-
-	case 0x10000L:
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	/* Setup dual-port memory window (this also enables memory access) */
-	_OUTB(port + 1, tmp);
-	hw->regs[1] = tmp;
-	hw->regs[0] = 0x08;
-	return 0;
-}
-
-/*============================================================================
- * Initialize S502E adapter.
- */
-static int init_s502e (sdlahw_t* hw)
-{
-	unsigned port = hw->port;
-	int tmp, i;
-
-	if (!detect_s502e(port))
-		return -ENODEV
-	;
-
-	/* Verify configuration options */
-	i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase));
-	if (i == 0)
-		return -EINVAL
-	;
-
-	tmp = s502e_hmcr[i - 1];
-	switch (hw->dpmsize)
-	{
-	case 0x2000:
-		tmp |= 0x01;
-		break;
-
-	case 0x10000L:
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	/* Setup dual-port memory window */
-	_OUTB(port + 1, tmp);
-	hw->regs[1] = tmp;
-
-	/* Enable memory access */
-	_OUTB(port, 0x02);
-	hw->regs[0] = 0x02;
-	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-	return (_INB(port) & 0x02) ? 0 : -EIO;
-}
-
-/*============================================================================
- * Initialize S503 adapter.
- * ---------------------------------------------------------------------------
- */
-static int init_s503 (sdlahw_t* hw)
-{
-	unsigned port = hw->port;
-	int tmp, i;
-
-	if (!detect_s503(port))
-		return -ENODEV
-	;
-
-	/* Verify configuration options */
-	i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase));
-	if (i == 0)
-		return -EINVAL
-	;
-
-	tmp = s502e_hmcr[i - 1];
-	switch (hw->dpmsize)
-	{
-	case 0x2000:
-		tmp |= 0x01;
-		break;
-
-	case 0x10000L:
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	/* Setup dual-port memory window */
-	_OUTB(port + 1, tmp);
-	hw->regs[1] = tmp;
-
-	/* Enable memory access */
-	_OUTB(port, 0x02);
-	hw->regs[0] = 0x02;	/* update mirror */
-	return 0;
-}
-
-/*============================================================================
- * Initialize S507 adapter.
- */
-static int init_s507 (sdlahw_t* hw)
-{
-	unsigned port = hw->port;
-	int tmp, i;
-
-	if (!detect_s507(port))
-		return -ENODEV
-	;
-
-	/* Verify configuration options */
-	i = get_option_index(s507_dpmbase_options, virt_to_phys(hw->dpmbase));
-	if (i == 0)
-		return -EINVAL
-	;
-
-	tmp = s507_hmcr[i - 1];
-	switch (hw->dpmsize)
-	{
-	case 0x2000:
-		tmp |= 0x01;
-		break;
-
-	case 0x10000L:
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	/* Enable adapter's logic */
-	_OUTB(port, 0x01);
-	hw->regs[0] = 0x01;
-	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-	if (!(_INB(port) & 0x20))
-		return -EIO
-	;
-
-	/* Setup dual-port memory window */
-	_OUTB(port + 1, tmp);
-	hw->regs[1] = tmp;
-
-	/* Enable memory access */
-	tmp = hw->regs[0] | 0x04;
-	if (hw->irq)
-	{
-		i = get_option_index(s508_irq_options, hw->irq);
-		if (i) tmp |= s507_irqmask[i - 1];
-	}
-	_OUTB(port, tmp);
-	hw->regs[0] = tmp;		/* update mirror */
-	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-	return (_INB(port) & 0x08) ? 0 : -EIO;
-}
-
-/*============================================================================
- * Initialize S508 adapter.
- */
-static int init_s508 (sdlahw_t* hw)
-{
-	unsigned port = hw->port;
-	int tmp, i;
-
-	if (!detect_s508(port))
-		return -ENODEV
-	;
-
-	/* Verify configuration options */
-	i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase));
-	if (i == 0)
-		return -EINVAL
-	;
-
-	/* Setup memory configuration */
-	tmp = s508_hmcr[i - 1];
-	_OUTB(port + 1, tmp);
-	hw->regs[1] = tmp;
-
-	/* Enable memory access */
-	_OUTB(port, 0x04);
-	hw->regs[0] = 0x04;		/* update mirror */
-	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-	return (_INB(port + 1) & 0x04) ? 0 : -EIO;
-}
-
-/*============================================================================
- * Detect S502A adapter.
- *	Following tests are used to detect S502A adapter:
- *	1. All registers other than status (BASE) should read 0xFF
- *	2. After writing 00001000b to control register, status register should
- *	   read 01000000b.
- *	3. After writing 0 to control register, status register should still
- *	   read  01000000b.
- *	4. After writing 00000100b to control register, status register should
- *	   read 01000100b.
- *	Return 1 if detected o.k. or 0 if failed.
- *	Note:	This test is destructive! Adapter will be left in shutdown
- *		state after the test.
- */
-static int detect_s502a (int port)
-{
-	int i, j;
-
-	if (!get_option_index(s502_port_options, port))
-		return 0
-	;
-	for (j = 1; j < SDLA_MAXIORANGE; ++j)
-	{
-		if (_INB(port + j) != 0xFF)
-			return 0
-		;
-		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-	}
-
-	_OUTB(port, 0x08);			/* halt CPU */
-	_OUTB(port, 0x08);
-	_OUTB(port, 0x08);
-	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-	if (_INB(port) != 0x40)
-		return 0
-	;
-	_OUTB(port, 0x00);
-	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-	if (_INB(port) != 0x40)
-		return 0
-	;
-	_OUTB(port, 0x04);
-	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-	if (_INB(port) != 0x44)
-		return 0
-	;
-
-	/* Reset adapter */
-	_OUTB(port, 0x08);
-	_OUTB(port, 0x08);
-	_OUTB(port, 0x08);
-	_OUTB(port + 1, 0xFF);
-	return 1;
-}
-
-/*============================================================================
- * Detect S502E adapter.
- *	Following tests are used to verify adapter presence:
- *	1. All registers other than status (BASE) should read 0xFF.
- *	2. After writing 0 to CPU control register (BASE+3), status register
- *	   (BASE) should read 11111000b.
- *	3. After writing 00000100b to port BASE (set bit 2), status register
- *	   (BASE) should read 11111100b.
- *	Return 1 if detected o.k. or 0 if failed.
- *	Note:	This test is destructive! Adapter will be left in shutdown
- *		state after the test.
- */
-static int detect_s502e (int port)
-{
-	int i, j;
-
-	if (!get_option_index(s502_port_options, port))
-		return 0
-	;
-	for (j = 1; j < SDLA_MAXIORANGE; ++j)
-	{
-		if (_INB(port + j) != 0xFF)
-			return 0
-		;
-		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-	}
-
-	_OUTB(port + 3, 0);			/* CPU control reg. */
-	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-	if (_INB(port) != 0xF8)			/* read status */
-		return 0
-	;
-	_OUTB(port, 0x04);			/* set bit 2 */
-	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-	if (_INB(port) != 0xFC)			/* verify */
-		return 0
-	;
-
-	/* Reset adapter */
-	_OUTB(port, 0);
-	return 1;
-}
-
-/*============================================================================
- * Detect s503 adapter.
- *	Following tests are used to verify adapter presence:
- *	1. All registers other than status (BASE) should read 0xFF.
- *	2. After writing 0 to control register (BASE), status register (BASE)
- *	   should read 11110000b.
- *	3. After writing 00000100b (set bit 2) to control register (BASE),
- *	   status register should read 11110010b.
- *	Return 1 if detected o.k. or 0 if failed.
- *	Note:	This test is destructive! Adapter will be left in shutdown
- *		state after the test.
- */
-static int detect_s503 (int port)
-{
-	int i, j;
-
-	if (!get_option_index(s503_port_options, port))
-		return 0
-	;
-	for (j = 1; j < SDLA_MAXIORANGE; ++j)
-	{
-		if (_INB(port + j) != 0xFF)
-			return 0
-		;
-		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-	}
-
-	_OUTB(port, 0);				/* reset control reg.*/
-	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-	if (_INB(port) != 0xF0)			/* read status */
-		return 0
-	;
-	_OUTB(port, 0x04);			/* set bit 2 */
-	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-	if (_INB(port) != 0xF2)			/* verify */
-		return 0
-	;
-
-	/* Reset adapter */
-	_OUTB(port, 0);
-	return 1;
-}
-
-/*============================================================================
- * Detect s507 adapter.
- *	Following tests are used to detect s507 adapter:
- *	1. All ports should read the same value.
- *	2. After writing 0x00 to control register, status register should read
- *	   ?011000?b.
- *	3. After writing 0x01 to control register, status register should read
- *	   ?011001?b.
- *	Return 1 if detected o.k. or 0 if failed.
- *	Note:	This test is destructive! Adapter will be left in shutdown
- *		state after the test.
- */
-static int detect_s507 (int port)
-{
-	int tmp, i, j;
-
-	if (!get_option_index(s508_port_options, port))
-		return 0
-	;
-	tmp = _INB(port);
-	for (j = 1; j < S507_IORANGE; ++j)
-	{
-		if (_INB(port + j) != tmp)
-			return 0
-		;
-		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-	}
-
-	_OUTB(port, 0x00);
-	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-	if ((_INB(port) & 0x7E) != 0x30)
-		return 0
-	;
-	_OUTB(port, 0x01);
-	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-	if ((_INB(port) & 0x7E) != 0x32)
-		return 0
-	;
-
-	/* Reset adapter */
-	_OUTB(port, 0x00);
-	return 1;
-}
-
-/*============================================================================
- * Detect s508 adapter.
- *	Following tests are used to detect s508 adapter:
- *	1. After writing 0x00 to control register, status register should read
- *	   ??000000b.
- *	2. After writing 0x10 to control register, status register should read
- *	   ??010000b
- *	Return 1 if detected o.k. or 0 if failed.
- *	Note:	This test is destructive! Adapter will be left in shutdown
- *		state after the test.
- */
-static int detect_s508 (int port)
-{
-	int i;
-
-	if (!get_option_index(s508_port_options, port))
-		return 0
-	;
-	_OUTB(port, 0x00);
-	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-	if ((_INB(port + 1) & 0x3F) != 0x00)
-		return 0
-	;
-	_OUTB(port, 0x10);
-	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
-	if ((_INB(port + 1) & 0x3F) != 0x10)
-		return 0
-	;
-
-	/* Reset adapter */
-	_OUTB(port, 0x00);
-	return 1;
-}
-
-/******* Miscellaneous ******************************************************/
-
-/*============================================================================
- * Calibrate SDLA memory access delay.
- * Count number of idle loops made within 1 second and then calculate the
- * number of loops that should be made to achive desired delay.
- */
-static int calibrate_delay (int mks)
-{
-	unsigned int delay;
-	unsigned long stop;
-
-	for (delay = 0, stop = SYSTEM_TICK + HZ; SYSTEM_TICK < stop; ++delay);
-	return (delay/(1000000L/mks) + 1);
-}
-
-/*============================================================================
- * Get option's index into the options list.
- *	Return option's index (1 .. N) or zero if option is invalid.
- */
-static int get_option_index (unsigned* optlist, unsigned optval)
-{
-	int i;
-
-	for (i = 1; i <= optlist[0]; ++i)
-		if ( optlist[i] == optval) return i
-	;
-	return 0;
-}
-
-/*============================================================================
- * Check memory region to see if it's available. 
- * Return:	0	ok.
- */
-static unsigned check_memregion (void* ptr, unsigned len)
-{
-	volatile unsigned char* p = ptr;
-
-	for (; len && (*p == 0xFF); --len, ++p)
-	{
-		*p = 0;			/* attempt to write 0 */
-		if (*p != 0xFF)		/* still has to read 0xFF */
-		{
-			*p = 0xFF;	/* restore original value */
-			break;		/* not good */
-		}
-	}
-	return len;
-}
-
-/*============================================================================
- * Test memory region.
- * Return:	size of the region that passed the test.
- * Note:	Region size must be multiple of 2 !
- */
-static unsigned test_memregion (void* ptr, unsigned len)
-{
-	volatile unsigned short* w_ptr;
-	unsigned len_w = len >> 1;	/* region len in words */
-	unsigned i;
-
-	for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
-		*w_ptr = 0xAA55
-	;
-	for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
-		if (*w_ptr != 0xAA55)
-		{
-			len_w = i;
-			break;
-		}
-	;
-	for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
-		*w_ptr = 0x55AA
-	;
-	for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
-		if (*w_ptr != 0x55AA)
-		{
-			len_w = i;
-			break;
-		}
-	;
-	for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) *w_ptr = 0;
-	return len_w << 1;
-}
-
-/*============================================================================
- * Calculate 16-bit CRC using CCITT polynomial.
- */
-static unsigned short checksum (unsigned char* buf, unsigned len)
-{
-	unsigned short crc = 0;
-	unsigned mask, flag;
-
-	for (; len; --len, ++buf)
-	{
-		for (mask = 0x80; mask; mask >>= 1)
-		{
-			flag = (crc & 0x8000);
-			crc <<= 1;
-			crc |= ((*buf & mask) ? 1 : 0);
-			if (flag) crc ^= 0x1021;
-		}
-	}
-	return crc;
-}
-
-
-/****** End *****************************************************************/
diff -u --recursive --new-file v2.3.20/linux/drivers/net/sdlamain.c linux/drivers/net/sdlamain.c
--- v2.3.20/linux/drivers/net/sdlamain.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/net/sdlamain.c	Wed Dec 31 16:00:00 1969
@@ -1,627 +0,0 @@
-/*****************************************************************************
-* sdlamain.c	WANPIPE(tm) Multiprotocol WAN Link Driver.  Main module.
-*
-* Author:	Gene Kozin	<genek@compuserve.com>
-*		Jaspreet Singh	<jaspreet@sangoma.com>
-*
-* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
-*
-*		This program is free software; you can redistribute it and/or
-*		modify it under the terms of the GNU General Public License
-*		as published by the Free Software Foundation; either version
-*		2 of the License, or (at your option) any later version.
-* ============================================================================
-* May 19, 1999  Arnaldo Melo    __init for wanpipe_init
-* Nov 28, 1997	Jaspreet Singh	Changed DRV_RELEASE to 1
-* Nov 10, 1997	Jaspreet Singh	Changed sti() to restore_flags();
-* Nov 06, 1997 	Jaspreet Singh	Changed DRV_VERSION to 4 and DRV_RELEASE to 0
-* Oct 20, 1997 	Jaspreet Singh	Modified sdla_isr routine so that card->in_isr
-*				assignments are taken out and placed in the
-*				sdla_ppp.c, sdla_fr.c and sdla_x25.c isr
-*				routines. Took out 'wandev->tx_int_enabled' and
-*				replaced it with 'wandev->enable_tx_int'. 
-* May 29, 1997	Jaspreet Singh	Flow Control Problem
-*				added "wandev->tx_int_enabled=1" line in the
-*				init module. This line intializes the flag for 
-*				preventing Interrupt disabled with device set to
-*				busy
-* Jan 15, 1997	Gene Kozin	Version 3.1.0
-*				 o added UDP management stuff
-* Jan 02, 1997	Gene Kozin	Initial version.
-*****************************************************************************/
-
-#include <linux/config.h>	/* OS configuration options */
-#include <linux/stddef.h>	/* offsetof(), etc. */
-#include <linux/errno.h>	/* return codes */
-#include <linux/string.h>	/* inline memset(), etc. */
-#include <linux/malloc.h>	/* kmalloc(), kfree() */
-#include <linux/kernel.h>	/* printk(), and other useful stuff */
-#include <linux/module.h>	/* support for loadable modules */
-#include <linux/ioport.h>	/* request_region(), release_region() */
-#include <linux/tqueue.h>	/* for kernel task queues */
-#include <linux/wanrouter.h>	/* WAN router definitions */
-#include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
-#include <asm/uaccess.h>	/* kernel <-> user copy */
-#include <asm/io.h>		/* phys_to_virt() */
-#include <linux/init.h>         /* __init (when not using as a module) */
-
-
-/****** Defines & Macros ****************************************************/
-
-#ifdef	_DEBUG_
-#define	STATIC
-#else
-#define	STATIC		static
-#endif
-
-#define	DRV_VERSION	4		/* version number */
-#define	DRV_RELEASE	1		/* release (minor version) number */
-#define	MAX_CARDS	8		/* max number of adapters */
-
-#ifndef	CONFIG_WANPIPE_CARDS		/* configurable option */
-#define	CONFIG_WANPIPE_CARDS 1
-#endif
-
-#define	CMD_OK		0		/* normal firmware return code */
-#define	CMD_TIMEOUT	0xFF		/* firmware command timed out */
-#define	MAX_CMD_RETRY	10		/* max number of firmware retries */
-
-/****** Function Prototypes *************************************************/
-
-/* Module entry points */
-int init_module (void);
-void cleanup_module (void);
-
-/* WAN link driver entry points */
-static int setup    (wan_device_t* wandev, wandev_conf_t* conf);
-static int shutdown (wan_device_t* wandev);
-static int ioctl    (wan_device_t* wandev, unsigned cmd, unsigned long arg);
-
-/* IOCTL hanlers */
-static int ioctl_dump	(sdla_t* card, sdla_dump_t* u_dump);
-static int ioctl_exec	(sdla_t* card, sdla_exec_t* u_exec);
-
-/* Miscellaneous functions */
-STATIC void sdla_isr	(int irq, void* dev_id, struct pt_regs *regs);
-STATIC void sdla_poll	(void* data);
-
-/****** Global Data **********************************************************
- * Note: All data must be explicitly initialized!!!
- */
-
-/* private data */
-static char drvname[]	= "wanpipe";
-static char fullname[]	= "WANPIPE(tm) Multiprotocol Driver";
-static char copyright[]	= "(c) 1995-1996 Sangoma Technologies Inc.";
-static int ncards = CONFIG_WANPIPE_CARDS;
-static int active = 0;			/* number of active cards */
-static sdla_t* card_array = NULL;	/* adapter data space */
-
-/* Task queue element for creating a 'thread' */
-static struct tq_struct sdla_tq =
-{
-	NULL,		/* .next */
-	0,		/* .sync */
-	&sdla_poll,	/* .routine */
-	NULL		/* .data */
-}; 
-
-/******* Kernel Loadable Module Entry Points ********************************/
-
-/*============================================================================
- * Module 'insert' entry point.
- * o print announcement
- * o allocate adapter data space
- * o initialize static data
- * o register all cards with WAN router
- * o calibrate SDLA shared memory access delay.
- *
- * Return:	0	Ok
- *		< 0	error.
- * Context:	process
- */
- 
-#ifdef MODULE
-int init_module (void)
-#else
-int __init wanpipe_init(void)
-#endif
-{
-	int cnt, err = 0;
-
-	printk(KERN_INFO "%s v%u.%u %s\n",
-		fullname, DRV_VERSION, DRV_RELEASE, copyright)
-	;
-
-	/* Verify number of cards and allocate adapter data space */
-	ncards = min(ncards, MAX_CARDS);
-	ncards = max(ncards, 1);
-	card_array = kmalloc(sizeof(sdla_t) * ncards, GFP_KERNEL);
-	if (card_array == NULL)
-		return -ENOMEM
-	;
-	memset(card_array, 0, sizeof(sdla_t) * ncards);
-
-	/* Register adapters with WAN router */
-	for (cnt = 0; cnt < ncards; ++cnt)
-	{
-		sdla_t* card = &card_array[cnt];
-		wan_device_t* wandev = &card->wandev;
-
-		sprintf(card->devname, "%s%d", drvname, cnt + 1);
-		wandev->magic    = ROUTER_MAGIC;
-		wandev->name     = card->devname;
-		wandev->private  = card;
-		wandev->enable_tx_int = 0;
-		wandev->setup    = &setup;
-		wandev->shutdown = &shutdown;
-		wandev->ioctl    = &ioctl;
-		err = register_wan_device(wandev);
-		if (err)
-		{
-			printk(KERN_ERR
-				"%s: %s registration failed with error %d!\n",
-				drvname, card->devname, err)
-			;
-			break;
-		}
-	}
-	if (cnt)
-		ncards = cnt;	/* adjust actual number of cards */
-	else
-	{
-		kfree(card_array);
-		err = -ENODEV;
-	}
-	return err;
-}
-
-#ifdef MODULE
-/*============================================================================
- * Module 'remove' entry point.
- * o unregister all adapters from the WAN router
- * o release all remaining system resources
- */
-void cleanup_module (void)
-{
-	int i;
-
-	for (i = 0; i < ncards; ++i)
-	{
-		sdla_t* card = &card_array[i];
-		unregister_wan_device(card->devname);
-	}
-	kfree(card_array);
-}
-
-#endif
-
-/******* WAN Device Driver Entry Points *************************************/
-
-/*============================================================================
- * Setup/confugure WAN link driver.
- * o check adapter state
- * o make sure firmware is present in configuration
- * o make sure I/O port and IRQ are specified
- * o make sure I/O region is available
- * o allocate interrupt vector
- * o setup SDLA hardware
- * o call appropriate routine to perform protocol-specific initialization
- * o mark I/O region as used
- * o if this is the first active card, then schedule background task
- *
- * This function is called when router handles ROUTER_SETUP IOCTL. The
- * configuration structure is in kernel memory (including extended data, if
- * any).
- */
- 
-static int setup (wan_device_t* wandev, wandev_conf_t* conf)
-{
-	sdla_t* card;
-	int err = 0;
-	int irq;
-
-	/* Sanity checks */
-	if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL))
-		return -EFAULT;
-		
-	card = wandev->private;
-	if (wandev->state != WAN_UNCONFIGURED)
-		return -EBUSY;		/* already configured */
-
-	if (!conf->data_size || (conf->data == NULL))
-	{
-		printk(KERN_ERR
-			"%s: firmware not found in configuration data!\n",
-			wandev->name);
-		return -EINVAL;
-	}
-	if (conf->ioport <= 0)
-	{
-		printk(KERN_ERR
-			"%s: can't configure without I/O port address!\n",
-			wandev->name);
-		return -EINVAL;
-	}
-	
-	if (conf->irq <= 0)
-	{
-		printk(KERN_ERR "%s: can't configure without IRQ!\n",
-			wandev->name);
-		return -EINVAL;
-	}
-
-	/* Make sure I/O port region is available */
-	if (check_region(conf->ioport, SDLA_MAXIORANGE))
-	{
-		printk(KERN_ERR "%s: I/O region 0x%X - 0x%X is in use!\n",
-			wandev->name, conf->ioport,
-			conf->ioport + SDLA_MAXIORANGE);
-		return -EINVAL;
-	}
-
-	/* Allocate IRQ */
-	irq = (conf->irq == 2) ? 9 : conf->irq;	/* IRQ2 -> IRQ9 */
-	if (request_irq(irq, sdla_isr, 0, wandev->name, card))
-	{
-		printk(KERN_ERR "%s: can't reserve IRQ %d!\n",
-			wandev->name, irq);
-		return -EINVAL;
-	}
-
-	/* Configure hardware, load firmware, etc. */
-	memset(&card->hw, 0, sizeof(sdlahw_t));
-	card->hw.port    = conf->ioport;
-	card->hw.irq     = (conf->irq == 9) ? 2 : conf->irq;
-	/* Compute the virtual address of the card in kernel space */
-	if(conf->maddr)
-		card->hw.dpmbase = phys_to_virt(conf->maddr);
-	else	/* But 0 means NULL */
-		card->hw.dpmbase = (void *)conf->maddr;
-
-	card->hw.dpmsize = SDLA_WINDOWSIZE;
-	card->hw.type    = conf->hw_opt[0];
-	card->hw.pclk    = conf->hw_opt[1];
-	err = sdla_setup(&card->hw, conf->data, conf->data_size);
-	if (err)
-	{
-		free_irq(irq, card);
-		return err;
-	}
-
-	/* Intialize WAN device data space */
-	wandev->irq       = irq;
-	wandev->dma       = 0;
-	wandev->ioport    = card->hw.port;
-	wandev->maddr     = card->hw.dpmbase;
-	wandev->msize     = card->hw.dpmsize;
-	wandev->hw_opt[0] = card->hw.type;
-	wandev->hw_opt[1] = card->hw.pclk;
-	wandev->hw_opt[2] = card->hw.memory;
-	wandev->hw_opt[3] = card->hw.fwid;
-
-	/* Protocol-specific initialization */
-	switch (card->hw.fwid)
-	{
-#ifdef	CONFIG_WANPIPE_X25
-	case SFID_X25_502:
-	case SFID_X25_508:
-		err = wpx_init(card, conf);
-		break;
-#endif
-
-#ifdef	CONFIG_WANPIPE_FR
-	case SFID_FR502:
-	case SFID_FR508:
-		err = wpf_init(card, conf);
-		break;
-#endif
-
-#ifdef	CONFIG_WANPIPE_PPP
-	case SFID_PPP502:
-	case SFID_PPP508:
-		err = wpp_init(card, conf);
-		break;
-#endif
-
-	default:
-		printk(KERN_ERR "%s: this firmware is not supported!\n",
-			wandev->name)
-		;
-		err = -EINVAL;
-	}
-	if (err)
-	{
-		sdla_down(&card->hw);
-		free_irq(irq, card);
-		return err;
-	}
-  	/* Reserve I/O region and schedule background task */
-/*	printk(KERN_INFO "about to request\n");*/
-	request_region(card->hw.port, card->hw.io_range, wandev->name);
-/*	printk(KERN_INFO "request done\n");*/
-	if (++active == 1)
-		queue_task(&sdla_tq, &tq_scheduler);
-		
-	wandev->critical = 0;
-	return 0;
-}
-
-/*============================================================================
- * Shut down WAN link driver. 
- * o shut down adapter hardware
- * o release system resources.
- *
- * This function is called by the router when device is being unregistered or
- * when it handles ROUTER_DOWN IOCTL.
- */
-static int shutdown (wan_device_t* wandev)
-{
-	sdla_t* card;
-
-	/* sanity checks */
-	if ((wandev == NULL) || (wandev->private == NULL))
-		return -EFAULT;
-		
-	if (wandev->state == WAN_UNCONFIGURED)
-		return 0;
-		
-	/* If wee are in a critical section we lose */
-	if (test_and_set_bit(0, (void*)&wandev->critical))
-		return -EAGAIN;
-		
-	card = wandev->private;
-	wandev->state = WAN_UNCONFIGURED;
-
-	if (--active == 0)
-		schedule();	/* stop background thread */
-	
-/*	printk(KERN_INFO "active now %d\n", active);
-
-	printk(KERN_INFO "About to call sdla_down\n");*/
-	sdla_down(&card->hw);
-/*	printk(KERN_INFO "sdla_down done\n");
-	printk(KERN_INFO "About to call free_irq\n");*/
-	free_irq(wandev->irq, card);
-/*	printk(KERN_INFO "free_irq done\n");
-	printk(KERN_INFO "About to call release_region\n");*/
-	release_region(card->hw.port, card->hw.io_range);
-/*	printk(KERN_INFO "release_region done\n");*/
-	wandev->critical = 0;
-	return 0;
-}
-
-/*============================================================================
- * Driver I/O control. 
- * o verify arguments
- * o perform requested action
- *
- * This function is called when router handles one of the reserved user
- * IOCTLs.  Note that 'arg' stil points to user address space.
- */
-static int ioctl (wan_device_t* wandev, unsigned cmd, unsigned long arg)
-{
-	int err;
-
-	/* sanity checks */
-	if ((wandev == NULL) || (wandev->private == NULL))
-		return -EFAULT
-	;
-	if (wandev->state == WAN_UNCONFIGURED)
-		return -ENODEV
-	;
-	if (test_and_set_bit(0, (void*)&wandev->critical))
-		return -EAGAIN
-	;
-	switch (cmd)
-	{
-	case WANPIPE_DUMP:
-		err = ioctl_dump(wandev->private, (void*)arg);
-		break;
-
-	case WANPIPE_EXEC:
-		err = ioctl_exec(wandev->private, (void*)arg);
-		break;
-
-	default:
-		err = -EINVAL;
-	}
-	wandev->critical = 0;
-	return err;
-}
-
-/****** Driver IOCTL Hanlers ************************************************/
-
-/*============================================================================
- * Dump adapter memory to user buffer.
- * o verify request structure
- * o copy request structure to kernel data space
- * o verify length/offset
- * o verify user buffer
- * o copy adapter memory image to user buffer
- *
- * Note: when dumping memory, this routine switches curent dual-port memory
- *	 vector, so care must be taken to avoid racing conditions.
- */
-static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump)
-{
-	sdla_dump_t dump;
-	unsigned winsize;
-	unsigned long oldvec;	/* DPM window vector */
-	unsigned long flags;
-	int err = 0;
-
-	if(copy_from_user((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t)))
-		return -EFAULT;
-		
-	if ((dump.magic != WANPIPE_MAGIC) ||
-	    (dump.offset + dump.length > card->hw.memory))
-		return -EINVAL;
-		
-	winsize = card->hw.dpmsize;
-	save_flags(flags);
-        cli();				/* >>> critical section start <<< */
-	oldvec = card->hw.vector;
-	while (dump.length)
-	{
-		unsigned pos = dump.offset % winsize;	/* current offset */
-		unsigned long vec = dump.offset - pos;	/* current vector */
-		unsigned len = (dump.length > (winsize - pos)) ?
-			(winsize - pos) : dump.length
-		;
-		if (sdla_mapmem(&card->hw, vec) != 0)	/* relocate window */
-		{
-			err = -EIO;
-			break;
-		}
-		/* FIXME::: COPY TO KERNEL BUFFER FIRST ?? */
-		sti();	/* Not ideal but tough we have to do this */
-		if(copy_to_user((void *)dump.ptr,
-			(u8 *)card->hw.dpmbase + pos, len))	
-			return -EFAULT;
-		cli();
-		dump.length     -= len;
-		dump.offset     += len;
-		(char*)dump.ptr += len;
-	}
-	sdla_mapmem(&card->hw, oldvec);	/* restore DPM window position */
-	restore_flags(flags);		/* >>> critical section end <<< */
-	return err;
-}
-
-/*============================================================================
- * Execute adapter firmware command.
- * o verify request structure
- * o copy request structure to kernel data space
- * o call protocol-specific 'exec' function
- */
-static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec)
-{
-	sdla_exec_t exec;
-
-	if (card->exec == NULL)
-		return -ENODEV;
-		
-	if(copy_from_user((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t)))
-		return -EFAULT;
-	if ((exec.magic != WANPIPE_MAGIC) || (exec.cmd == NULL))
-		return -EINVAL;
-	return card->exec(card, exec.cmd, exec.data);
-}
-
-/******* Miscellaneous ******************************************************/
-
-/*============================================================================
- * SDLA Interrupt Service Routine.
- * o acknowledge SDLA hardware interrupt.
- * o call protocol-specific interrupt service routine, if any.
- */
-STATIC void sdla_isr (int irq, void* dev_id, struct pt_regs *regs)
-{
-#define	card	((sdla_t*)dev_id)
-
-	if (!card || (card->wandev.state == WAN_UNCONFIGURED))
-		return
-	;
-	if (card->in_isr)
-	{
-		printk(KERN_WARNING "%s: interrupt re-entrancy on IRQ %d!\n",
-			card->devname, card->wandev.irq)
-		;
-		return;
-	}
-
-	sdla_intack(&card->hw);
-	if (card->isr) 
-		card->isr(card);
-
-#undef	card
-}
-
-/*============================================================================
- * SDLA polling routine.
- * This routine simulates kernel thread to perform various housekeeping job.
- *
- * o for each configured device call its poll() routine
- * o if there is at least one active card, then reschedule itself once again
- */
-STATIC void sdla_poll (void* data)
-{
-	int i;
-
-	for (i = 0; i < ncards; ++i)
-	{
-		sdla_t* card = &card_array[i];
-
-		if ((card->wandev.state != WAN_UNCONFIGURED) && card->poll &&
-		    !card->wandev.critical)
-		{
-			card->poll(card);
-		}
-	}
-	if (active)
-		queue_task(&sdla_tq, &tq_scheduler);
-}
-
-/*============================================================================
- * This routine is called by the protocol-specific modules when network
- * interface is being open.  The only reason we need this, is because we
- * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's
- * defined more than once into the same kernel module.
- */
-void wanpipe_open (sdla_t* card)
-{
-	++card->open_cnt;
-	MOD_INC_USE_COUNT;
-}
-
-/*============================================================================
- * This routine is called by the protocol-specific modules when network
- * interface is being closed.  The only reason we need this, is because we
- * have to call MOD_DEC_USE_COUNT, but cannot include 'module.h' where it's
- * defined more than once into the same kernel module.
- */
-void wanpipe_close (sdla_t* card)
-{
-	--card->open_cnt;
-	MOD_DEC_USE_COUNT;
-}
-
-/*============================================================================
- * Set WAN device state.
- */
-void wanpipe_set_state (sdla_t* card, int state)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	if (card->wandev.state != state)
-	{
-		switch (state)
-		{
-		case WAN_CONNECTED:
-			printk (KERN_INFO "%s: link connected!\n",
-				card->devname)
-			;
-			break;
-
-		case WAN_CONNECTING:
-			printk (KERN_INFO "%s: link connecting...\n",
-				card->devname)
-			;
-			break;
-
-		case WAN_DISCONNECTED:
-			printk (KERN_INFO "%s: link disconnected!\n",
-				card->devname)
-			;
-			break;
-		}
-		card->wandev.state = state;
-	}
-	card->state_tick = jiffies;
-	restore_flags(flags);
-}
-
-/****** End *****************************************************************/
diff -u --recursive --new-file v2.3.20/linux/drivers/net/sealevel.c linux/drivers/net/sealevel.c
--- v2.3.20/linux/drivers/net/sealevel.c	Wed Aug 18 11:36:42 1999
+++ linux/drivers/net/sealevel.c	Wed Dec 31 16:00:00 1969
@@ -1,471 +0,0 @@
-#define LINUX_21
-
-/*
- *	Sealevel Systems 4021 driver.
- *
- *	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.
- *
- *	(c) Copyright 1999 Building Number Three Ltd
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/net.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <net/arp.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/byteorder.h>
-#include "syncppp.h"
-#include "z85230.h"
-
-
-struct slvl_device
-{
-	struct z8530_channel *chan;
-	struct ppp_device netdev;
-	char name[16];
-	int channel;
-};
-
-
-struct slvl_board
-{
-	struct slvl_device dev[2];
-	struct z8530_dev board;
-	int iobase;
-};
-
-/*
- *	Network driver support routines
- */
-
-/*
- *	Frame receive. Simple for our card as we do sync ppp and there
- *	is no funny garbage involved
- */
- 
-static void sealevel_input(struct z8530_channel *c, struct sk_buff *skb)
-{
-	/* Drop the CRC - its not a good idea to try and negotiate it ;) */
-	skb_trim(skb, skb->len-2);
-	skb->protocol=htons(ETH_P_WAN_PPP);
-	skb->mac.raw=skb->data;
-	skb->dev=c->netdevice;
-	/*
-	 *	Send it to the PPP layer. We dont have time to process
-	 *	it right now.
-	 */
-	netif_rx(skb);
-}
- 
-/*
- *	We've been placed in the UP state
- */ 
- 
-static int sealevel_open(struct net_device *d)
-{
-	struct slvl_device *slvl=d->priv;
-	int err = -1;
-	int unit = slvl->channel;
-	
-	/*
-	 *	Link layer up. 
-	 */
-
-	switch(unit)
-	{
-		case 0:
-			err=z8530_sync_dma_open(d, slvl->chan);
-			break;
-		case 1:
-			err=z8530_sync_open(d, slvl->chan);
-			break;
-	}
-	
-	if(err)
-		return err;
-	/*
-	 *	Begin PPP
-	 */
-	err=sppp_open(d);
-	if(err)
-	{
-		switch(unit)
-		{
-			case 0:
-				z8530_sync_dma_close(d, slvl->chan);
-				break;
-			case 1:
-				z8530_sync_close(d, slvl->chan);
-				break;
-		}				
-		return err;
-	}
-	
-	slvl->chan->rx_function=sealevel_input;
-	
-	/*
-	 *	Go go go
-	 */
-	d->tbusy=0;
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-
-static int sealevel_close(struct net_device *d)
-{
-	struct slvl_device *slvl=d->priv;
-	int unit = slvl->channel;
-	
-	/*
-	 *	Discard new frames
-	 */
-	
-	slvl->chan->rx_function=z8530_null_rx;
-		
-	/*
-	 *	PPP off
-	 */
-	sppp_close(d);
-	/*
-	 *	Link layer down
-	 */
-	d->tbusy=1;
-	
-	switch(unit)
-	{
-		case 0:
-			z8530_sync_dma_close(d, slvl->chan);
-			break;
-		case 1:
-			z8530_sync_close(d, slvl->chan);
-			break;
-	}
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-static int sealevel_ioctl(struct net_device *d, struct ifreq *ifr, int cmd)
-{
-	/* struct slvl_device *slvl=d->priv;
-	   z8530_ioctl(d,&slvl->sync.chanA,ifr,cmd) */
-	return sppp_do_ioctl(d, ifr,cmd);
-}
-
-static struct enet_statistics *sealevel_get_stats(struct net_device *d)
-{
-	struct slvl_device *slvl=d->priv;
-	if(slvl)
-		return z8530_get_stats(slvl->chan);
-	else
-		return NULL;
-}
-
-/*
- *	Passed PPP frames, fire them downwind.
- */
- 
-static int sealevel_queue_xmit(struct sk_buff *skb, struct net_device *d)
-{
-	struct slvl_device *slvl=d->priv;
-	return z8530_queue_xmit(slvl->chan, skb);
-}
-
-#ifdef LINUX_21
-static int sealevel_neigh_setup(struct neighbour *n)
-{
-	if (n->nud_state == NUD_NONE) {
-		n->ops = &arp_broken_ops;
-		n->output = n->ops->output;
-	}
-	return 0;
-}
-
-static int sealevel_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p)
-{
-	if (p->tbl->family == AF_INET) {
-		p->neigh_setup = sealevel_neigh_setup;
-		p->ucast_probes = 0;
-		p->mcast_probes = 0;
-	}
-	return 0;
-}
-
-#else
-
-static int return_0(struct net_device *d)
-{
-	return 0;
-}
-
-#endif
-
-/*
- *	Description block for a Comtrol Hostess SV11 card
- */
- 
-static struct slvl_board *slvl_init(int iobase, int irq, int txdma, int rxdma, int slow)
-{
-	struct z8530_dev *dev;
-	struct slvl_device *sv;
-	struct slvl_board *b;
-	
-	int i;
-	unsigned long flags;
-	int u;
-	
-	/*
-	 *	Get the needed I/O space
-	 */
-	 
-	if(check_region(iobase, 8))
-	{	
-		printk(KERN_WARNING "sealevel: I/O 0x%X already in use.\n", iobase);
-		return NULL;
-	}
-	request_region(iobase, 8, "Sealevel 4021");
-	
-	b=(struct slvl_board *)kmalloc(sizeof(struct slvl_board), GFP_KERNEL);
-	if(!b)
-		goto fail3;
-			
-	memset(b, 0, sizeof(*sv));
-
-	b->dev[0].chan = &b->board.chanA;	
-	b->dev[1].chan = &b->board.chanB;
-	
-	dev=&b->board;
-	
-	/*
-	 *	Stuff in the I/O addressing
-	 */
-	 
-	dev->active = 0;
-
-	b->iobase = iobase;
-	
-	/*
-	 *	Select 8530 delays for the old board
-	 */
-	 
-	if(slow)
-		iobase |= Z8530_PORT_SLEEP;
-		
-	dev->chanA.ctrlio=iobase+1;
-	dev->chanA.dataio=iobase;
-	dev->chanB.ctrlio=iobase+3;
-	dev->chanB.dataio=iobase+2;
-	
-	dev->chanA.irqs=&z8530_nop;
-	dev->chanB.irqs=&z8530_nop;
-	
-	/*
-	 *	Assert DTR enable DMA
-	 */
-	 
-	outb(3|(1<<7), b->iobase+4);	
-	
-
-	/* We want a fast IRQ for this device. Actually we'd like an even faster
-	   IRQ ;) - This is one driver RtLinux is made for */
-   
-	if(request_irq(irq, &z8530_interrupt, SA_INTERRUPT, "SeaLevel", dev)<0)
-	{
-		printk(KERN_WARNING "sealevel: IRQ %d already in use.\n", irq);
-		goto fail2;
-	}
-	
-	dev->irq=irq;
-	dev->chanA.private=&b->dev[0];
-	dev->chanB.private=&b->dev[1];
-	dev->chanA.netdevice=&b->dev[0].netdev.dev;
-	dev->chanB.netdevice=&b->dev[1].netdev.dev;
-	dev->chanA.dev=dev;
-	dev->chanB.dev=dev;
-	dev->name=b->dev[0].name;
-
-	dev->chanA.txdma=3;
-	dev->chanA.rxdma=1;
-	if(request_dma(dev->chanA.txdma, "SeaLevel (TX)")!=0)
-		goto fail;
-		
-	if(request_dma(dev->chanA.rxdma, "SeaLevel (RX)")!=0)
-		goto dmafail;
-	
-	save_flags(flags);
-	cli();
-	
-	/*
-	 *	Begin normal initialise
-	 */
-	 
-	if(z8530_init(dev)!=0)
-	{
-		printk(KERN_ERR "Z8530 series device not found.\n");
-		goto dmafail2;
-	}
-	if(dev->type==Z85C30)
-	{
-		z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream);
-		z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream);
-	}
-	else
-	{
-		z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream_85230);
-		z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream_85230);
-	}
-
-	/*
-	 *	Now we can take the IRQ
-	 */
-	
-	restore_flags(flags);
-
-	for(u=0; u<2; u++)
-	{
-		sv=&b->dev[u];
-		sv->channel = u;
-	
-		for(i=0;i<999;i++)
-		{
-			sprintf(sv->name,"hdlc%d", i);
-			if(dev_get(sv->name)==NULL)
-			{
-				struct net_device *d=sv->chan->netdevice;
-	
-				/* 
-				 *	Initialise the PPP components
-				 */
-				sppp_attach(&sv->netdev);
-			
-				/*
-				 *	Local fields
-				 */	
-				sprintf(sv->name,"hdlc%d", i);
-				
-				d->name = sv->name;
-				d->base_addr = iobase;
-				d->irq = irq;
-				d->priv = sv;
-				d->init = NULL;
-			
-				d->open = sealevel_open;
-				d->stop = sealevel_close;
-				d->hard_start_xmit = sealevel_queue_xmit;
-				d->get_stats = sealevel_get_stats;
-				d->set_multicast_list = NULL;
-				d->do_ioctl = sealevel_ioctl;
-#ifdef LINUX_21			
-				d->neigh_setup = sealevel_neigh_setup_dev;
-				dev_init_buffers(d);
-#else
-				d->init = return_0;
-#endif
-				d->set_mac_address = NULL;
-			
-				if(register_netdev(d)==-1)
-				{
-					printk(KERN_ERR "%s: unable to register device.\n",
-						sv->name);
-					goto fail_unit;
-				}				
-
-				break;
-			}
-		}
-	}
-	z8530_describe(dev, "I/O", iobase);
-	dev->active=1;
-	return b;
-
-fail_unit:
-	if(u==1)
-		unregister_netdev(b->dev[0].chan->netdevice);
-	
-dmafail2:
-	free_dma(dev->chanA.rxdma);
-dmafail:
-	free_dma(dev->chanA.txdma);
-fail:
-	free_irq(irq, dev);
-fail2:
-	kfree(b);
-fail3:
-	release_region(iobase,8);
-	return NULL;
-}
-
-static void slvl_shutdown(struct slvl_board *b)
-{
-	int u;
-
-	z8530_shutdown(&b->board);
-	
-	for(u=0; u<2; u++)
-	{
-		sppp_detach(&b->dev[u].netdev.dev);
-		unregister_netdev(&b->dev[u].netdev.dev);
-	}
-	
-	free_irq(b->board.irq, &b->board);
-	free_dma(b->board.chanA.rxdma);
-	free_dma(b->board.chanA.txdma);
-	/* DMA off on the card, drop DTR */
-	outb(0, b->iobase);
-	release_region(b->iobase, 8);
-}
-
-#ifdef MODULE
-
-static int io=0x238;
-static int txdma=1;
-static int rxdma=3;
-static int irq=5;
-static int slow=0;
-
-#ifdef LINUX_21
-MODULE_PARM(io,"i");
-MODULE_PARM_DESC(io, "The I/O base of the Sealevel card");
-MODULE_PARM(txdma,"i");
-MODULE_PARM_DESC(txdma, "Transmit DMA channel");
-MODULE_PARM(rxdma,"i");
-MODULE_PARM_DESC(rxdma, "Receive DMA channel");
-MODULE_PARM(irq,"i");
-MODULE_PARM_DESC(irq, "The interrupt line setting for the SeaLevel card");
-MODULE_PARM(slow,"i");
-MODULE_PARM_DESC(slow, "Set this for an older Sealevel card such as the 4012");
-
-MODULE_AUTHOR("Bulding Number Three Ltd");
-MODULE_DESCRIPTION("Modular driver for the SeaLevel 4021");
-#endif
-
-static struct slvl_board *slvl_unit;
-
-int init_module(void)
-{
-	printk(KERN_INFO "SeaLevel Z85230 Synchronous Driver v 0.01.\n");
-	printk(KERN_INFO "(c) Copyright 1998, Building Number Three Ltd.\n");	
-	if((slvl_unit=slvl_init(io,irq, txdma, rxdma, slow))==NULL)
-		return -ENODEV;
-	return 0;
-}
-
-void cleanup_module(void)
-{
-	if(slvl_unit)
-		slvl_shutdown(slvl_unit);
-}
-
-#endif
-
diff -u --recursive --new-file v2.3.20/linux/drivers/net/sgiseeq.h linux/drivers/net/sgiseeq.h
--- v2.3.20/linux/drivers/net/sgiseeq.h	Thu Jun 26 12:33:39 1997
+++ linux/drivers/net/sgiseeq.h	Mon Oct 11 10:13:24 1999
@@ -1,4 +1,4 @@
-/* $Id: sgiseeq.h,v 1.1 1997/06/09 08:34:32 ralf Exp $
+/* $Id: sgiseeq.h,v 1.3 1998/08/25 09:17:45 ralf Exp $
  * sgiseeq.h: Defines for the Seeq8003 ethernet controller.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
diff -u --recursive --new-file v2.3.20/linux/drivers/net/sk_mca.c linux/drivers/net/sk_mca.c
--- v2.3.20/linux/drivers/net/sk_mca.c	Thu Aug 26 13:05:38 1999
+++ linux/drivers/net/sk_mca.c	Mon Oct 11 10:13:24 1999
@@ -71,6 +71,7 @@
 #include <linux/version.h>
 
 #include <linux/kernel.h>
+#include <linux/version.h>
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.3.20/linux/drivers/net/sktr.c linux/drivers/net/sktr.c
--- v2.3.20/linux/drivers/net/sktr.c	Wed Aug 18 11:36:42 1999
+++ linux/drivers/net/sktr.c	Wed Dec 31 16:00:00 1969
@@ -1,2703 +0,0 @@
-/*
- *  sktr.c: A network driver for the SysKonnect Token Ring ISA/PCI Adapters.
- *
- *  Written 1997 by Christoph Goos
- *
- *  A fine result of the Linux Systems Network Architecture Project.
- *  http://samba.anu.edu.au/linux-sna/
- *
- *  This software may be used and distributed according to the terms
- *  of the GNU Public License, incorporated herein by reference.
- *
- *  This device driver works with the following SysKonnect adapters:
- *	- SysKonnect TR4/16(+) ISA	(SK-4190)
- *	- SysKonnect TR4/16(+) PCI	(SK-4590)
- *	- SysKonnect TR4/16 PCI		(SK-4591)
- *
- *  Sources:
- *  	- The hardware related parts of this driver are take from
- *  	  the SysKonnect Token Ring driver for Windows NT.
- *  	- I used the IBM Token Ring driver 'ibmtr.c' as a base for this
- *  	  driver, as well as the 'skeleton.c' driver by Donald Becker.
- *  	- Also various other drivers in the linux source tree were taken
- *  	  as samples for some tasks.
- *
- *  Maintainer(s):
- *    JS        Jay Schulist            jschlst@samba.anu.edu.au
- *    CG	Christoph Goos		cgoos@syskonnect.de
- *
- *  Modification History:
- *	29-Aug-97	CG	Created
- *	04-Apr-98	CG	Fixed problems caused by tok_timer_check
- *	10-Apr-98	CG	Fixed lockups at cable disconnection
- *	27-May-98	JS	Formated to Linux Kernel Format
- *	31-May-98	JS	Hacked in PCI support
- *	16-Jun-98	JS	Modulized for multiple cards with one driver
- *
- *  To do:
- *    1. Selectable 16 Mbps or 4Mbps
- *    2. Multi/Broadcast packet handling
- *
- */
-
-static const char *version = "sktr.c: v1.01 08/29/97 by Christoph Goos\n";
-
-#ifdef MODULE
-#include <linux/module.h>
-#include <linux/version.h>
-#endif
-
-#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/time.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/irq.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/trdevice.h>
-
-#include "sktr.h"		/* Our Stuff */
-#include "sktr_firmware.h"	/* SysKonnect adapter firmware */
-
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int sktr_portlist[] __initdata = {
-	0x0A20, 0x1A20, 0x0B20, 0x1B20, 0x0980, 0x1980, 0x0900, 0x1900,
-	0
-};
-
-/* A zero-terminated list of IRQs to be probed. 
- * Used again after initial probe for sktr_chipset_init, called from sktr_open.
- */
-static unsigned short sktr_irqlist[] = {
-	3, 5, 9, 10, 11, 12, 15,
-	0
-};
-
-/* A zero-terminated list of DMAs to be probed. */
-static int sktr_dmalist[] __initdata = {
-	5, 6, 7,
-	0
-};
-
-/* Card names */
-static char *pci_cardname = "SK NET TR 4/16 PCI\0";
-static char *isa_cardname = "SK NET TR 4/16 ISA\0";
-static char *AdapterName;
-
-/* Use 0 for production, 1 for verification, 2 for debug, and
- * 3 for very verbose debug.
- */
-#ifndef SKTR_DEBUG
-#define SKTR_DEBUG 1
-#endif
-static unsigned int sktr_debug = SKTR_DEBUG;
-
-/* The number of low I/O ports used by the tokencard. */
-#define SKTR_IO_EXTENT 32
-
-/* Index to functions, as function prototypes.
- * Alphabetical by function name.
- */
-
-/* "B" */
-static int      sktr_bringup_diags(struct net_device *dev);
-/* "C" */
-static void	sktr_cancel_tx_queue(struct net_local* tp);
-static int 	sktr_chipset_init(struct net_device *dev);
-static void 	sktr_chk_irq(struct net_device *dev);
-static unsigned char sktr_chk_frame(struct net_device *dev, unsigned char *Addr);
-static void 	sktr_chk_outstanding_cmds(struct net_device *dev);
-static void 	sktr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr);
-static unsigned char sktr_chk_ssb(struct net_local *tp, unsigned short IrqType);
-static int 	sktr_close(struct net_device *dev);
-static void 	sktr_cmd_status_irq(struct net_device *dev);
-/* "D" */
-static void 	sktr_disable_interrupts(struct net_device *dev);
-static void 	sktr_dump(unsigned char *Data, int length);
-/* "E" */
-static void 	sktr_enable_interrupts(struct net_device *dev);
-static void 	sktr_exec_cmd(struct net_device *dev, unsigned short Command);
-static void 	sktr_exec_sifcmd(struct net_device *dev, unsigned int WriteValue);
-/* "F" */
-static unsigned char *sktr_fix_srouting(unsigned char *buf, short *FrameLen);
-/* "G" */
-static struct enet_statistics *sktr_get_stats(struct net_device *dev);
-/* "H" */
-static void 	sktr_hardware_send_packet(struct net_device *dev,
-			struct net_local* tp);
-/* "I" */
-static int 	sktr_init_adapter(struct net_device *dev);
-static int 	sktr_init_card(struct net_device *dev);
-static void 	sktr_init_ipb(struct net_local *tp);
-static void 	sktr_init_net_local(struct net_device *dev);
-static void 	sktr_init_opb(struct net_local *tp);
-static void 	sktr_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int 	sktr_isa_chk_card(struct net_device *dev, int ioaddr);
-static int      sktr_isa_chk_ioaddr(int ioaddr);
-/* "O" */
-static int 	sktr_open(struct net_device *dev);
-static void	sktr_open_adapter(struct net_device *dev);
-/* "P" */
-static int 	sktr_pci_chk_card(struct net_device *dev);
-int 		sktr_probe(struct net_device *dev);
-static int 	sktr_probe1(struct net_device *dev, int ioaddr);
-/* "R" */
-static void 	sktr_rcv_status_irq(struct net_device *dev);
-static void 	sktr_read_addr(struct net_device *dev, unsigned char *Address);
-static void 	sktr_read_ptr(struct net_device *dev);
-static void 	sktr_read_ram(struct net_device *dev, unsigned char *Data,
-			unsigned short Address, int Length);
-static int 	sktr_reset_adapter(struct net_device *dev);
-static void 	sktr_reset_interrupt(struct net_device *dev);
-static void 	sktr_ring_status_irq(struct net_device *dev);
-/* "S" */
-static int 	sktr_send_packet(struct sk_buff *skb, struct net_device *dev);
-static void 	sktr_set_multicast_list(struct net_device *dev);
-/* "T" */
-static void 	sktr_timer_chk(unsigned long data);
-static void 	sktr_timer_end_wait(unsigned long data);
-static void 	sktr_tx_status_irq(struct net_device *dev);
-/* "U" */
-static void 	sktr_update_rcv_stats(struct net_local *tp,
-			unsigned char DataPtr[], unsigned int Length);
-/* "W" */
-static void 	sktr_wait(unsigned long time);
-static void 	sktr_write_rpl_status(RPL *rpl, unsigned int Status);
-static void 	sktr_write_tpl_status(TPL *tpl, unsigned int Status);
-
-/*
- * Check for a network adapter of this type, and return '0' if one exists.
- * If dev->base_addr == 0, probe all likely locations.
- * If dev->base_addr == 1, always return failure.
- */
-int __init sktr_probe(struct net_device *dev)
-{
-	int i;
-	int base_addr = dev ? dev->base_addr : 0;
-
-	if(base_addr > 0x1ff)    /* Check a single specified location. */
-		return (sktr_probe1(dev, base_addr));
-	else if(base_addr != 0)  /* Don't probe at all. */
-		return (-ENXIO);
-
-	for(i = 0; sktr_portlist[i]; i++)
-	{
-		int ioaddr = sktr_portlist[i];
-		if(check_region(ioaddr, SKTR_IO_EXTENT))
-			continue;
-		if(sktr_probe1(dev, ioaddr))
-		{
-#ifndef MODULE
-                        tr_freedev(dev);
-#endif
-                }
-		else
-			return (0);
-	}
-
-	return (-ENODEV);
-}
-
-/*
- * Detect and setup the PCI SysKonnect TR cards in slot order.
- */
-static int __init sktr_pci_chk_card(struct net_device *dev)
-{
-	static int pci_index = 0;
-	unsigned char pci_bus, pci_device_fn;
-
-	if(!pci_present())
-		return (-1);	/* No PCI present. */
-
-	for(; pci_index < 0xff; pci_index++)
-	{
-		unsigned int pci_irq_line;
-		struct pci_dev *pdev;
-		unsigned short pci_command, new_command, vendor, device;
-		unsigned int pci_ioaddr;
-
-		if(pcibios_find_class(PCI_CLASS_NETWORK_TOKEN_RING << 8,
-			pci_index, &pci_bus, &pci_device_fn)
-			!= PCIBIOS_SUCCESSFUL)
-		{
-			break;
-		}
-
-		pcibios_read_config_word(pci_bus, pci_device_fn,
-						PCI_VENDOR_ID, &vendor);
-		pcibios_read_config_word(pci_bus, pci_device_fn,
-						PCI_DEVICE_ID, &device);
-
-		pdev		= pci_find_slot(pci_bus, pci_device_fn);
-		pci_irq_line 	= pdev->irq;
-		pci_ioaddr 	= pdev->resource[0].start;
-
-		pcibios_read_config_word(pci_bus, pci_device_fn,
-						PCI_COMMAND, &pci_command);
-
-		/* Remove I/O space marker in bit 0. */
-		pci_ioaddr &= ~3;
-
-		if(vendor != PCI_VENDOR_ID_SK)
-			continue;
-		if(device != PCI_DEVICE_ID_SK_TR)
-			continue;
-		if(check_region(pci_ioaddr, SKTR_IO_EXTENT))
-			continue;
-		request_region(pci_ioaddr, SKTR_IO_EXTENT, pci_cardname);
-		if(request_irq(pdev->irq, sktr_interrupt, SA_SHIRQ,
-				pci_cardname, dev))
-			return (-ENODEV); /* continue; ?? */
-
-		AdapterName = pci_cardname;
-
-		new_command = (pci_command|PCI_COMMAND_MASTER|PCI_COMMAND_IO);
-
-		if(pci_command != new_command)
-		{
-			printk("The PCI BIOS has not enabled this"
-				"device! Updating PCI command %4.4x->%4.4x.\n",
-			  	pci_command, new_command);
-			pcibios_write_config_word(pci_bus, pci_device_fn,
-				PCI_COMMAND, new_command);
-		}
-
-		/* At this point we have found a valid PCI TR card. */
-		dev->base_addr	= pci_ioaddr;
-		dev->irq 	= pci_irq_line;
-		dev->dma	= 0;
-
-		printk("%s: %s found at %#4x, using IRQ %d.\n",
-			dev->name, AdapterName, pci_ioaddr, dev->irq);
-
-		return (0);
-	}
-
-	return (-1);
-}
-
-/*
- * Detect and setup the ISA SysKonnect TR cards.
- */
-static int __init sktr_isa_chk_card(struct net_device *dev, int ioaddr)
-{
-	int i, err;
-	unsigned long flags;
-
-	err = sktr_isa_chk_ioaddr(ioaddr);
-	if(err < 0)
-		return (-ENODEV);
-
-        if(virt_to_bus((void*)((unsigned long)dev->priv+sizeof(struct net_local)))
-		> ISA_MAX_ADDRESS)
-        {
-                printk("%s: Memory not accessible for DMA\n", dev->name);
-                kfree(dev->priv);
-                return (-EAGAIN);
-        }
-
-	AdapterName = isa_cardname;
-
-        /* Grab the region so that no one else tries to probe our ioports. */
-        request_region(ioaddr, SKTR_IO_EXTENT, AdapterName);
-        dev->base_addr = ioaddr;
-
-        /* Autoselect IRQ and DMA if dev->irq == 0 */
-        if(dev->irq == 0)
-        {
-                for(i = 0; sktr_irqlist[i] != 0; i++)
-                {
-                        dev->irq = sktr_irqlist[i];
-                        err = request_irq(dev->irq, &sktr_interrupt, 0, AdapterName, dev);
-                        if(!err)
-				break;
-                }
-
-                if(sktr_irqlist[i] == 0)
-                {
-                        printk("%s: AutoSelect no IRQ available\n", dev->name);
-                        return (-EAGAIN);
-                }
-        }
-        else
-        {
-                err = request_irq(dev->irq, &sktr_interrupt, 0, AdapterName, dev);
-		if(err)
-                {
-                        printk("%s: Selected IRQ not available\n", dev->name);
-                        return (-EAGAIN);
-                }
-        }
-
-        /* Always allocate the DMA channel after IRQ and clean up on failure */
-        if(dev->dma == 0)
-        {
-                for(i = 0; sktr_dmalist[i] != 0; i++)
-                {
-			dev->dma = sktr_dmalist[i];
-                        err = request_dma(dev->dma, AdapterName);
-                        if(!err)
-                                break;
-                }
-
-                if(dev->dma == 0)
-                {
-                        printk("%s: AutoSelect no DMA available\n", dev->name);
-                        free_irq(dev->irq, NULL);
-                        return (-EAGAIN);
-                }
-        }
-        else
-        {
-                err = request_dma(dev->dma, AdapterName);
-                if(err)
-                {
-                        printk("%s: Selected DMA not available\n", dev->name);
-                        free_irq(dev->irq, NULL);
-                        return (-EAGAIN);
-                }
-        }
-
-	flags=claim_dma_lock();
-	disable_dma(dev->dma);
-        set_dma_mode(dev->dma, DMA_MODE_CASCADE);
-        enable_dma(dev->dma);
-        release_dma_lock(flags);
-
-	printk("%s: %s found at %#4x, using IRQ %d and DMA %d.\n",
-                dev->name, AdapterName, ioaddr, dev->irq, dev->dma);
-
-	return (0);
-}
-
-static int __init sktr_probe1(struct net_device *dev, int ioaddr)
-{
-	static unsigned version_printed = 0;
-	struct net_local *tp;
-	int err;
-
-	if(sktr_debug && version_printed++ == 0)
-		printk("%s", version);
-
-#ifndef MODULE
-	dev = init_trdev(dev, 0);
-	if(dev == NULL)
-		return (-ENOMEM);
-#endif
-
-	err = sktr_pci_chk_card(dev);
-	if(err < 0)
-	{
-		err = sktr_isa_chk_card(dev, ioaddr);
-		if(err < 0)
-			return (-ENODEV);
-	}
-
-	/* Setup this devices private information structure */
-	tp = (struct net_local *)kmalloc(sizeof(struct net_local), GFP_KERNEL | GFP_DMA);
-	if(tp == NULL)
-		return (-ENOMEM);
-	memset(tp, 0, sizeof(struct net_local));
-	init_waitqueue_head(&tp->wait_for_tok_int);
-	
-	dev->priv		= tp;
-	dev->init               = sktr_init_card;
-        dev->open               = sktr_open;
-        dev->stop               = sktr_close;
-        dev->hard_start_xmit    = sktr_send_packet;
-        dev->get_stats          = sktr_get_stats;
-        dev->set_multicast_list = &sktr_set_multicast_list;
-
-        return (0);
-}
-
-/* Dummy function */
-static int __init sktr_init_card(struct net_device *dev)
-{
-	if(sktr_debug > 3)
-		printk("%s: sktr_init_card\n", dev->name);
-
-	return (0);
-}
-
-/*
- * This function tests if an adapter is really installed at the
- * given I/O address. Return negative if no adapter at IO addr.
- */
-static int __init sktr_isa_chk_ioaddr(int ioaddr)
-{
-	unsigned char old, chk1, chk2;
-
-	old = inb(ioaddr + SIFADR);	/* Get the old SIFADR value */
-
-	chk1 = 0;	/* Begin with check value 0 */
-	do {
-		/* Write new SIFADR value */
-		outb(chk1, ioaddr + SIFADR);
-
-		/* Read, invert and write */
-		chk2 = inb(ioaddr + SIFADD);
-		chk2 ^= 0x0FE;
-		outb(chk2, ioaddr + SIFADR);
-
-		/* Read, invert and compare */
-		chk2 = inb(ioaddr + SIFADD);
-		chk2 ^= 0x0FE;
-
-		if(chk1 != chk2)
-			return (-1);	/* No adapter */
-
-		chk1 -= 2;
-	} while(chk1 != 0);	/* Repeat 128 times (all byte values) */
-
-    	/* Restore the SIFADR value */
-	outb(old, ioaddr + SIFADR);
-
-	return (0);
-}
-
-/*
- * Open/initialize the board. This is called 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 sktr_open(struct net_device *dev)
-{
-	struct net_local *tp = (struct net_local *)dev->priv;
-	int err;
-
-	/* Reset the hardware here. Don't forget to set the station address. */
-	err = sktr_chipset_init(dev);
-	if(err)
-	{
-		printk(KERN_INFO "%s: Chipset initialization error\n", 
-			dev->name);
-		return (-1);
-	}
-
-	dev->addr_len = 6;
-	sktr_read_addr(dev, (unsigned char*)dev->dev_addr);
-
-	init_timer(&tp->timer);
-	tp->timer.expires	= jiffies + 30*HZ;
-	tp->timer.function	= sktr_timer_end_wait;
-	tp->timer.data		= (unsigned long)dev;
-	tp->timer.next		= NULL;
-	tp->timer.prev		= NULL;
-	add_timer(&tp->timer);
-
-	sktr_read_ptr(dev);
-	sktr_enable_interrupts(dev);
-	sktr_open_adapter(dev);
-
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 0;
-
-	/* Wait for interrupt from hardware. If interrupt does not come,
-	 * there will be a timeout from the timer.
-	 */
-	tp->Sleeping = 1;
-	interruptible_sleep_on(&tp->wait_for_tok_int);
-	del_timer(&tp->timer);
-
-	/* If AdapterVirtOpenFlag is 1, the adapter is now open for use */
-	if(tp->AdapterVirtOpenFlag == 0)
-	{
-		sktr_disable_interrupts(dev);
-		return (-1);
-	}
-
-	dev->start = 1;
-
-	tp->StartTime = jiffies;
-
-	/* Start function control timer */
-	tp->timer.expires	= jiffies + 2*HZ;
-	tp->timer.function	= sktr_timer_chk;
-	tp->timer.data		= (unsigned long)dev;
-	add_timer(&tp->timer);
-
-#ifdef MODULE
-	MOD_INC_USE_COUNT;
-#endif
-
-	return (0);
-}
-
-/*
- * Timeout function while waiting for event
- */
-static void sktr_timer_end_wait(unsigned long data)
-{
-	struct net_device *dev = (struct net_device*)data;
-	struct net_local *tp = (struct net_local *)dev->priv;
-
-	if(tp->Sleeping)
-	{
-		tp->Sleeping = 0;
-		wake_up_interruptible(&tp->wait_for_tok_int);
-	}
-
-	return;
-}
-
-/*
- * Initialize the chipset
- */
-static int sktr_chipset_init(struct net_device *dev)
-{
-	struct net_local *tp = (struct net_local *)dev->priv;
-	unsigned char PosReg, Tmp;
-	int i, err;
-
-	sktr_init_ipb(tp);
-	sktr_init_opb(tp);
-	sktr_init_net_local(dev);
-
-	/* Set pos register: selects irq and dma channel.
-	 * Only for ISA bus adapters.
-	 */
-	if(dev->dma > 0)
-	{
-		PosReg = 0;
-		for(i = 0; sktr_irqlist[i] != 0; i++)
-		{
-			if(sktr_irqlist[i] == dev->irq)
-				break;
-		}
-
-		/* Choose default cycle time, 500 nsec   */
-		PosReg |= CYCLE_TIME << 2;
-		PosReg |= i << 4;
-		i = dev->dma - 5;
-		PosReg |= i;
-
-		if(tp->DataRate == SPEED_4)
-			PosReg |= LINE_SPEED_BIT;
-		else
-			PosReg &= ~LINE_SPEED_BIT;
-
-		outb(PosReg, dev->base_addr + POSREG);
-		Tmp = inb(dev->base_addr + POSREG);
-		if((Tmp & ~CYCLE_TIME) != (PosReg & ~CYCLE_TIME))
-			printk(KERN_INFO "%s: POSREG error\n", dev->name);
-	}
-
-	err = sktr_reset_adapter(dev);
-	if(err < 0)
-		return (-1);
-
-	err = sktr_bringup_diags(dev);
-	if(err < 0)
-		return (-1);
-
-	err = sktr_init_adapter(dev);
-	if(err < 0)
-		return (-1);
-
-	return (0);
-}
-
-/*
- * Initializes the net_local structure.
- */
-static void sktr_init_net_local(struct net_device *dev)
-{
-	struct net_local *tp = (struct net_local *)dev->priv;
-	int i;
-
-	tp->scb.CMD	= 0;
-	tp->scb.Parm[0] = 0;
-	tp->scb.Parm[1] = 0;
-
-	tp->ssb.STS	= 0;
-	tp->ssb.Parm[0] = 0;
-	tp->ssb.Parm[1] = 0;
-	tp->ssb.Parm[2] = 0;
-
-	tp->CMDqueue	= 0;
-
-	tp->AdapterOpenFlag	= 0;
-	tp->AdapterVirtOpenFlag = 0;
-	tp->ScbInUse		= 0;
-	tp->OpenCommandIssued	= 0;
-	tp->ReOpenInProgress	= 0;
-	tp->HaltInProgress	= 0;
-	tp->TransmitHaltScheduled = 0;
-	tp->LobeWireFaultLogged	= 0;
-	tp->LastOpenStatus	= 0;
-	tp->MaxPacketSize	= DEFAULT_PACKET_SIZE;
-
-	skb_queue_head_init(&tp->SendSkbQueue);
-	tp->QueueSkb = MAX_TX_QUEUE;
-
-	/* Create circular chain of transmit lists */
-	for (i = 0; i < TPL_NUM; i++)
-	{
-		tp->Tpl[i].NextTPLAddr = htonl((unsigned long) virt_to_bus(&tp->Tpl[(i+1) % TPL_NUM]));
-		tp->Tpl[i].Status	= 0;
-		tp->Tpl[i].FrameSize	= 0;
-		tp->Tpl[i].FragList[0].DataCount	= 0;
-		tp->Tpl[i].FragList[0].DataAddr		= 0;
-		tp->Tpl[i].NextTPLPtr	= &tp->Tpl[(i+1) % TPL_NUM];
-		tp->Tpl[i].MData	= NULL;
-		tp->Tpl[i].TPLIndex	= i;
-		tp->Tpl[i].BusyFlag	= 0;
-	}
-
-	tp->TplFree = tp->TplBusy = &tp->Tpl[0];
-
-	/* Create circular chain of receive lists */
-	for (i = 0; i < RPL_NUM; i++)
-	{
-		tp->Rpl[i].NextRPLAddr = htonl((unsigned long) virt_to_bus(&tp->Rpl[(i+1) % RPL_NUM]));
-		tp->Rpl[i].Status = (RX_VALID | RX_START_FRAME | RX_END_FRAME | RX_FRAME_IRQ);
-		tp->Rpl[i].FrameSize = 0;
-		tp->Rpl[i].FragList[0].DataCount = SWAPB(tp->MaxPacketSize);
-
-		/* Alloc skb and point adapter to data area */
-		tp->Rpl[i].Skb = dev_alloc_skb(tp->MaxPacketSize);
-
-		/* skb == NULL ? then use local buffer */
-		if(tp->Rpl[i].Skb == NULL)
-		{
-			tp->Rpl[i].SkbStat = SKB_UNAVAILABLE;
-			tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[i]));
-			tp->Rpl[i].MData = tp->LocalRxBuffers[i];
-		}
-		else	/* SKB != NULL */
-		{
-			tp->Rpl[i].Skb->dev = dev;
-			skb_put(tp->Rpl[i].Skb, tp->MaxPacketSize);
-
-			/* data unreachable for DMA ? then use local buffer */
-			if(virt_to_bus(tp->Rpl[i].Skb->data) + tp->MaxPacketSize > ISA_MAX_ADDRESS)
-			{
-				tp->Rpl[i].SkbStat = SKB_DATA_COPY;
-				tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[i]));
-				tp->Rpl[i].MData = tp->LocalRxBuffers[i];
-			}
-			else	/* DMA directly in skb->data */
-			{
-				tp->Rpl[i].SkbStat = SKB_DMA_DIRECT;
-				tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->Rpl[i].Skb->data));
-				tp->Rpl[i].MData = tp->Rpl[i].Skb->data;
-			}
-		}
-
-		tp->Rpl[i].NextRPLPtr = &tp->Rpl[(i+1) % RPL_NUM];
-		tp->Rpl[i].RPLIndex = i;
-	}
-
-	tp->RplHead = &tp->Rpl[0];
-	tp->RplTail = &tp->Rpl[RPL_NUM-1];
-	tp->RplTail->Status = (RX_START_FRAME | RX_END_FRAME | RX_FRAME_IRQ);
-
-	return;
-}
-
-/*
- * Initializes the initialisation parameter block.
- */
-static void sktr_init_ipb(struct net_local *tp)
-{
-	tp->ipb.Init_Options	= BURST_MODE;
-	tp->ipb.CMD_Status_IV	= 0;
-	tp->ipb.TX_IV		= 0;
-	tp->ipb.RX_IV		= 0;
-	tp->ipb.Ring_Status_IV	= 0;
-	tp->ipb.SCB_Clear_IV	= 0;
-	tp->ipb.Adapter_CHK_IV	= 0;
-	tp->ipb.RX_Burst_Size	= BURST_SIZE;
-	tp->ipb.TX_Burst_Size	= BURST_SIZE;
-	tp->ipb.DMA_Abort_Thrhld = DMA_RETRIES;
-	tp->ipb.SCB_Addr	= 0;
-	tp->ipb.SSB_Addr	= 0;
-
-	return;
-}
-
-/*
- * Initializes the open parameter block.
- */
-static void sktr_init_opb(struct net_local *tp)
-{
-	unsigned long Addr;
-	unsigned short RplSize    = RPL_SIZE;
-	unsigned short TplSize    = TPL_SIZE;
-	unsigned short BufferSize = BUFFER_SIZE;
-
-	tp->ocpl.OPENOptions 	 = 0;
-	tp->ocpl.OPENOptions 	|= ENABLE_FULL_DUPLEX_SELECTION;
-	tp->ocpl.OPENOptions 	|= PAD_ROUTING_FIELD;
-	tp->ocpl.FullDuplex 	 = 0;
-	tp->ocpl.FullDuplex 	|= OPEN_FULL_DUPLEX_OFF;
-
-	/* Fixme: If mac address setable:
-	 * for (i=0; i<LENGTH_OF_ADDRESS; i++)
-	 *	mac->Vam->ocpl.NodeAddr[i] = mac->CurrentAddress[i];
-	 */
-
-	tp->ocpl.GroupAddr	 = 0;
-	tp->ocpl.FunctAddr	 = 0;
-	tp->ocpl.RxListSize	 = SWAPB(RplSize);
-	tp->ocpl.TxListSize	 = SWAPB(TplSize);
-	tp->ocpl.BufSize	 = SWAPB(BufferSize);
-	tp->ocpl.Reserved	 = 0;
-	tp->ocpl.TXBufMin	 = TX_BUF_MIN;
-	tp->ocpl.TXBufMax	 = TX_BUF_MAX;
-
-	Addr = htonl(virt_to_bus(tp->ProductID));
-
-	tp->ocpl.ProdIDAddr[0]	 = LOWORD(Addr);
-	tp->ocpl.ProdIDAddr[1]	 = HIWORD(Addr);
-
-	return;
-}
-
-/*
- * Send OPEN command to adapter
- */
-static void sktr_open_adapter(struct net_device *dev)
-{
-	struct net_local *tp = (struct net_local *)dev->priv;
-
-	if(tp->OpenCommandIssued)
-		return;
-
-	tp->OpenCommandIssued = 1;
-	sktr_exec_cmd(dev, OC_OPEN);
-
-	return;
-}
-
-/*
- * Clear the adapter's interrupt flag. Clear system interrupt enable
- * (SINTEN): disable adapter to system interrupts.
- */
-static void sktr_disable_interrupts(struct net_device *dev)
-{
-	outb(0, dev->base_addr + SIFACL);
-
-	return;
-}
-
-/*
- * Set the adapter's interrupt flag. Set system interrupt enable
- * (SINTEN): enable adapter to system interrupts.
- */
-static void sktr_enable_interrupts(struct net_device *dev)
-{
-	outb(ACL_SINTEN, dev->base_addr + SIFACL);
-
-	return;
-}
-
-/*
- * Put command in command queue, try to execute it.
- */
-static void sktr_exec_cmd(struct net_device *dev, unsigned short Command)
-{
-	struct net_local *tp = (struct net_local *)dev->priv;
-
-	tp->CMDqueue |= Command;
-	sktr_chk_outstanding_cmds(dev);
-
-	return;
-}
-
-/*
- * Linux always gives 18 byte of source routing information in the frame header.
- * But the length field can indicate shorter length. Then cut header
- * appropriate.
- */
-static unsigned char *sktr_fix_srouting(unsigned char *buf, short *FrameLen)
-{
-	struct trh_hdr *trh = (struct trh_hdr *)buf;
-	int len;
-        
-	if(buf[8] & TR_RII)
-	{
-		trh->rcf &= ~SWAPB((unsigned short) TR_RCF_LONGEST_FRAME_MASK);
-		trh->rcf |= SWAPB((unsigned short) TR_RCF_FRAME4K);
-		len = (SWAPB(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
-		if(len < 18)
-		{
-			memcpy(&buf[18-len],buf,sizeof(struct trh_hdr)-18+len);
-			*FrameLen -= (18 - len);
-		}
-		return (&buf[18-len]);
-	}
-
-	return (buf);
-}
-
-/*
- * Gets skb from system, queues it and checks if it can be sent
- */
-static int sktr_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-	struct net_local *tp = (struct net_local *)dev->priv;
-
-	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.
-		 *
-		 * Resetting the token ring adapter takes a long time so just
-		 * fake transmission time and go on trying. Our own timeout
-		 * routine is in sktr_timer_chk()
-		 */
-		dev->tbusy 	 = 0;
-		dev->trans_start = jiffies;
-		return (1);
-	}
-
-	/*
-	 * If some higher layer thinks we've missed an tx-done interrupt we
-	 * are passed NULL.
-	 */
-	if(skb == NULL)
-		return (0);
-
-	/*
-	 * Block a timer-based transmit from overlapping. This could better be
-	 * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
-	 */
-	if(test_and_set_bit(0, (void*)&dev->tbusy) != 0)
-	{
-		printk("%s: Transmitter access conflict.\n", dev->name);
-		return (1);
-	}
-
-	if(tp->QueueSkb == 0)
-		return (1);	/* Return with tbusy set: queue full */
-
-	tp->QueueSkb--;
-	skb_queue_tail(&tp->SendSkbQueue, skb);
-	sktr_hardware_send_packet(dev, tp);
-	if(tp->QueueSkb > 0)
-		dev->tbusy = 0;
-
-	return (0);
-}
-
-/*
- * Move frames from internal skb queue into adapter tx queue
- */
-static void sktr_hardware_send_packet(struct net_device *dev, struct net_local* tp)
-{
-	TPL *tpl;
-	short length;
-	unsigned char *buf, *newbuf;
-	struct sk_buff *skb;
-	int i;
-    
-	for(;;)
-	{
-		/* Try to get a free TPL from the chain.
-		 *
-		 * NOTE: We *must* always leave one unused TPL in the chain, 
-		 * because otherwise the adapter might send frames twice.
-		 */
-		if(tp->TplFree->NextTPLPtr->BusyFlag)	/* No free TPL */
-		{
-			printk(KERN_INFO "%s: No free TPL\n", dev->name);
-			return;
-		}
-
-		/* Send first buffer from queue */
-		skb = skb_dequeue(&tp->SendSkbQueue);
-		if(skb == NULL)
-			return;
-
-		tp->QueueSkb++;
-		/* Is buffer reachable for Busmaster-DMA? */
-		if(virt_to_bus((void*)(((long) skb->data) + skb->len))
-			> ISA_MAX_ADDRESS)
-		{
-			/* Copy frame to local buffer */
-			i 	= tp->TplFree->TPLIndex;
-			length 	= skb->len;
-			buf 	= tp->LocalTxBuffers[i];
-			memcpy(buf, skb->data, length);
-			newbuf 	= sktr_fix_srouting(buf, &length);
-		}
-		else
-		{
-			/* Send direct from skb->data */
-			length = skb->len;
-			newbuf = sktr_fix_srouting(skb->data, &length);
-		}
-
-		/* Source address in packet? */
-		sktr_chk_src_addr(newbuf, dev->dev_addr);
-
-		tp->LastSendTime	= jiffies;
-		tpl 			= tp->TplFree;	/* Get the "free" TPL */
-		tpl->BusyFlag 		= 1;		/* Mark TPL as busy */
-		tp->TplFree 		= tpl->NextTPLPtr;
-    
-		/* Save the skb for delayed return of skb to system */
-		tpl->Skb = skb;
-		tpl->FragList[0].DataCount = (unsigned short) SWAPB(length);
-		tpl->FragList[0].DataAddr  = htonl(virt_to_bus(newbuf));
-
-		/* Write the data length in the transmit list. */
-		tpl->FrameSize 	= (unsigned short) SWAPB(length);
-		tpl->MData 	= newbuf;
-
-		/* Transmit the frame and set the status values. */
-		sktr_write_tpl_status(tpl, TX_VALID | TX_START_FRAME
-					| TX_END_FRAME | TX_PASS_SRC_ADDR
-					| TX_FRAME_IRQ);
-
-		/* Let adapter send the frame. */
-		sktr_exec_sifcmd(dev, CMD_TX_VALID);
-	}
-
-	return;
-}
-
-/*
- * Write the given value to the 'Status' field of the specified TPL.
- * NOTE: This function should be used whenever the status of any TPL must be
- * modified by the driver, because the compiler may otherwise change the
- * order of instructions such that writing the TPL status may be executed at
- * an undesireable time. When this function is used, the status is always
- * written when the function is called.
- */
-static void sktr_write_tpl_status(TPL *tpl, unsigned int Status)
-{
-	tpl->Status = Status;
-}
-
-static void sktr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr)
-{
-	unsigned char SRBit;
-
-	if((((unsigned long)frame[8]) & ~0x80) != 0)	/* Compare 4 bytes */
-		return;
-	if((unsigned short)frame[12] != 0)		/* Compare 2 bytes */
-		return;
-
-	SRBit = frame[8] & 0x80;
-	memcpy(&frame[8], hw_addr, 6);
-	frame[8] |= SRBit;
-
-	return;
-}
-
-/*
- * The timer routine: Check if adapter still open and working, reopen if not. 
- */
-static void sktr_timer_chk(unsigned long data)
-{
-	struct net_device *dev = (struct net_device*)data;
-	struct net_local *tp = (struct net_local*)dev->priv;
-
-	if(tp->HaltInProgress)
-		return;
-
-	sktr_chk_outstanding_cmds(dev);
-	if(time_before(tp->LastSendTime + SEND_TIMEOUT, jiffies)
-		&& (tp->QueueSkb < MAX_TX_QUEUE || tp->TplFree != tp->TplBusy))
-	{
-		/* Anything to send, but stalled to long */
-		tp->LastSendTime = jiffies;
-		sktr_exec_cmd(dev, OC_CLOSE);	/* Does reopen automatically */
-	}
-
-	tp->timer.expires = jiffies + 2*HZ;
-	add_timer(&tp->timer);
-
-	if(tp->AdapterOpenFlag || tp->ReOpenInProgress)
-		return;
-	tp->ReOpenInProgress = 1;
-	sktr_open_adapter(dev);
-
-	return;
-}
-
-/*
- * The typical workload of the driver: Handle the network interface interrupts.
- */
-static void sktr_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct net_device *dev = dev_id;
-	struct net_local *tp;
-	int ioaddr;
-	unsigned short irq_type;
-
-	if(dev == NULL)
-	{
-		printk("%s: irq %d for unknown device.\n", dev->name, irq);
-		return;
-	}
-
-	dev->interrupt = 1;
-
-	ioaddr = dev->base_addr;
-	tp = (struct net_local *)dev->priv;
-
-	irq_type = inw(ioaddr + SIFSTS);
-
-	while(irq_type & STS_SYSTEM_IRQ)
-	{
-		irq_type &= STS_IRQ_MASK;
-
-		if(!sktr_chk_ssb(tp, irq_type))
-		{
-			printk(KERN_INFO "%s: DATA LATE occurred\n", dev->name);
-			break;
-		}
-
-		switch(irq_type)
-		{
-			case STS_IRQ_RECEIVE_STATUS:
-				sktr_reset_interrupt(dev);
-				sktr_rcv_status_irq(dev);
-				break;
-
-			case STS_IRQ_TRANSMIT_STATUS:
-				/* Check if TRANSMIT.HALT command is complete */
-				if(tp->ssb.Parm[0] & COMMAND_COMPLETE)
-				{
-					tp->TransmitCommandActive = 0;
-					tp->TransmitHaltScheduled = 0;
-
-					/* Issue a new transmit command. */
-					sktr_exec_cmd(dev, OC_TRANSMIT);
-				}
-
-				sktr_reset_interrupt(dev);
-				sktr_tx_status_irq(dev);
-				break;
-
-			case STS_IRQ_COMMAND_STATUS:
-				/* The SSB contains status of last command
-				 * other than receive/transmit.
-				 */
-				sktr_cmd_status_irq(dev);
-				break;
-
-			case STS_IRQ_SCB_CLEAR:
-				/* The SCB is free for another command. */
-				tp->ScbInUse = 0;
-				sktr_chk_outstanding_cmds(dev);
-				break;
-
-			case STS_IRQ_RING_STATUS:
-				sktr_ring_status_irq(dev);
-				break;
-
-			case STS_IRQ_ADAPTER_CHECK:
-				sktr_chk_irq(dev);
-				break;
-
-			default:
-				printk(KERN_INFO "Unknown Token Ring IRQ\n");
-				break;
-		}
-
-		/* Reset system interrupt if not already done. */
-		if(irq_type != STS_IRQ_TRANSMIT_STATUS
-			&& irq_type != STS_IRQ_RECEIVE_STATUS)
-		{
-			sktr_reset_interrupt(dev);
-		}
-
-		irq_type = inw(ioaddr + SIFSTS);
-	}
-
-	dev->interrupt = 0;
-
-	return;
-}
-
-/*
- *  Reset the INTERRUPT SYSTEM bit and issue SSB CLEAR command.
- */
-static void sktr_reset_interrupt(struct net_device *dev)
-{
-	struct net_local *tp = (struct net_local *)dev->priv;
-	SSB *ssb = &tp->ssb;
-
-	/*
-	 * [Workaround for "Data Late"]
-	 * Set all fields of the SSB to well-defined values so we can
-	 * check if the adapter has written the SSB.
-	 */
-
-	ssb->STS	= (unsigned short) -1;
-	ssb->Parm[0] 	= (unsigned short) -1;
-	ssb->Parm[1] 	= (unsigned short) -1;
-	ssb->Parm[2] 	= (unsigned short) -1;
-
-	/* Free SSB by issuing SSB_CLEAR command after reading IRQ code
-	 * and clear STS_SYSTEM_IRQ bit: enable adapter for further interrupts.
-	 */
-	sktr_exec_sifcmd(dev, CMD_SSB_CLEAR | CMD_CLEAR_SYSTEM_IRQ);
-
-	return;
-}
-
-/*
- * Check if the SSB has actually been written by the adapter.
- */
-static unsigned char sktr_chk_ssb(struct net_local *tp, unsigned short IrqType)
-{
-	SSB *ssb = &tp->ssb;	/* The address of the SSB. */
-
-	/* C 0 1 2 INTERRUPT CODE
-	 * - - - - --------------
-	 * 1 1 1 1 TRANSMIT STATUS
-	 * 1 1 1 1 RECEIVE STATUS
-	 * 1 ? ? 0 COMMAND STATUS
-	 * 0 0 0 0 SCB CLEAR
-	 * 1 1 0 0 RING STATUS
-	 * 0 0 0 0 ADAPTER CHECK
-	 *
-	 * 0 = SSB field not affected by interrupt
-	 * 1 = SSB field is affected by interrupt
-	 *
-	 * C = SSB ADDRESS +0: COMMAND
-	 * 0 = SSB ADDRESS +2: STATUS 0
-	 * 1 = SSB ADDRESS +4: STATUS 1
-	 * 2 = SSB ADDRESS +6: STATUS 2
-	 */
-
-	/* Check if this interrupt does use the SSB. */
-
-	if(IrqType != STS_IRQ_TRANSMIT_STATUS
-		&& IrqType != STS_IRQ_RECEIVE_STATUS
-		&& IrqType != STS_IRQ_COMMAND_STATUS
-		&& IrqType != STS_IRQ_RING_STATUS)
-	{
-		return (1);	/* SSB not involved. */
-	}
-
-	/* Note: All fields of the SSB have been set to all ones (-1) after it
-	 * has last been used by the software (see DriverIsr()).
-	 *
-	 * Check if the affected SSB fields are still unchanged.
-	 */
-
-	if(ssb->STS == (unsigned short) -1)
-		return (0);	/* Command field not yet available. */
-	if(IrqType == STS_IRQ_COMMAND_STATUS)
-		return (1);	/* Status fields not always affected. */
-	if(ssb->Parm[0] == (unsigned short) -1)
-		return (0);	/* Status 1 field not yet available. */
-	if(IrqType == STS_IRQ_RING_STATUS)
-		return (1);	/* Status 2 & 3 fields not affected. */
-
-	/* Note: At this point, the interrupt is either TRANSMIT or RECEIVE. */
-	if(ssb->Parm[1] == (unsigned short) -1)
-		return (0);	/* Status 2 field not yet available. */
-	if(ssb->Parm[2] == (unsigned short) -1)
-		return (0);	/* Status 3 field not yet available. */
-
-	return (1);	/* All SSB fields have been written by the adapter. */
-}
-
-/*
- * Evaluates the command results status in the SSB status field.
- */
-static void sktr_cmd_status_irq(struct net_device *dev)
-{
-	struct net_local *tp = (struct net_local *)dev->priv;
-	unsigned short ssb_cmd, ssb_parm_0;
-	unsigned short ssb_parm_1;
-	char *open_err = "Open error -";
-	char *code_err = "Open code -";
-
-	/* Copy the ssb values to local variables */
-	ssb_cmd    = tp->ssb.STS;
-	ssb_parm_0 = tp->ssb.Parm[0];
-	ssb_parm_1 = tp->ssb.Parm[1];
-
-	if(ssb_cmd == OPEN)
-	{
-		tp->Sleeping = 0;
-		if(!tp->ReOpenInProgress)
-	    		wake_up_interruptible(&tp->wait_for_tok_int);
-
-		tp->OpenCommandIssued = 0;
-		tp->ScbInUse = 0;
-
-		if((ssb_parm_0 & 0x00FF) == GOOD_COMPLETION)
-		{
-			/* Success, the adapter is open. */
-			tp->LobeWireFaultLogged	= 0;
-			tp->AdapterOpenFlag 	= 1;
-			tp->AdapterVirtOpenFlag = 1;
-			tp->TransmitCommandActive = 0;
-			sktr_exec_cmd(dev, OC_TRANSMIT);
-			sktr_exec_cmd(dev, OC_RECEIVE);
-
-			if(tp->ReOpenInProgress)
-				tp->ReOpenInProgress = 0;
-
-			return;
-		}
-		else 	/* The adapter did not open. */
-		{
-	    		if(ssb_parm_0 & NODE_ADDR_ERROR)
-				printk(KERN_INFO "%s: Node address error\n",
-					dev->name);
-	    		if(ssb_parm_0 & LIST_SIZE_ERROR)
-				printk(KERN_INFO "%s: List size error\n",
-					dev->name);
-	    		if(ssb_parm_0 & BUF_SIZE_ERROR)
-				printk(KERN_INFO "%s: Buffer size error\n",
-					dev->name);
-	    		if(ssb_parm_0 & TX_BUF_COUNT_ERROR)
-				printk(KERN_INFO "%s: Tx buffer count error\n",
-					dev->name);
-	    		if(ssb_parm_0 & INVALID_OPEN_OPTION)
-				printk(KERN_INFO "%s: Invalid open option\n",
-					dev->name);
-	    		if(ssb_parm_0 & OPEN_ERROR)
-			{
-				/* Show the open phase. */
-				switch(ssb_parm_0 & OPEN_PHASES_MASK)
-				{
-					case LOBE_MEDIA_TEST:
-						if(!tp->LobeWireFaultLogged)
-						{
-							tp->LobeWireFaultLogged = 1;
-							printk(KERN_INFO "%s: %s Lobe wire fault (check cable !).\n", dev->name, open_err);
-		    				}
-						tp->ReOpenInProgress	= 1;
-						tp->AdapterOpenFlag 	= 0;
-						tp->AdapterVirtOpenFlag = 1;
-						sktr_open_adapter(dev);
-						return;
-
-					case PHYSICAL_INSERTION:
-						printk(KERN_INFO "%s: %s Physical insertion.\n", dev->name, open_err);
-						break;
-
-					case ADDRESS_VERIFICATION:
-						printk(KERN_INFO "%s: %s Address verification.\n", dev->name, open_err);
-						break;
-
-					case PARTICIPATION_IN_RING_POLL:
-						printk(KERN_INFO "%s: %s Participation in ring poll.\n", dev->name, open_err);
-						break;
-
-					case REQUEST_INITIALISATION:
-						printk(KERN_INFO "%s: %s Request initialisation.\n", dev->name, open_err);
-						break;
-
-					case FULLDUPLEX_CHECK:
-						printk(KERN_INFO "%s: %s Full duplex check.\n", dev->name, open_err);
-						break;
-
-					default:
-						printk(KERN_INFO "%s: %s Unknown open phase\n", dev->name, open_err);
-						break;
-				}
-
-				/* Show the open errors. */
-				switch(ssb_parm_0 & OPEN_ERROR_CODES_MASK)
-				{
-					case OPEN_FUNCTION_FAILURE:
-						printk(KERN_INFO "%s: %s OPEN_FUNCTION_FAILURE", dev->name, code_err);
-						tp->LastOpenStatus =
-							OPEN_FUNCTION_FAILURE;
-						break;
-
-					case OPEN_SIGNAL_LOSS:
-						printk(KERN_INFO "%s: %s OPEN_SIGNAL_LOSS\n", dev->name, code_err);
-						tp->LastOpenStatus =
-							OPEN_SIGNAL_LOSS;
-						break;
-
-					case OPEN_TIMEOUT:
-						printk(KERN_INFO "%s: %s OPEN_TIMEOUT\n", dev->name, code_err);
-						tp->LastOpenStatus =
-							OPEN_TIMEOUT;
-						break;
-
-					case OPEN_RING_FAILURE:
-						printk(KERN_INFO "%s: %s OPEN_RING_FAILURE\n", dev->name, code_err);
-						tp->LastOpenStatus =
-							OPEN_RING_FAILURE;
-						break;
-
-					case OPEN_RING_BEACONING:
-						printk(KERN_INFO "%s: %s OPEN_RING_BEACONING\n", dev->name, code_err);
-						tp->LastOpenStatus =
-							OPEN_RING_BEACONING;
-						break;
-
-					case OPEN_DUPLICATE_NODEADDR:
-						printk(KERN_INFO "%s: %s OPEN_DUPLICATE_NODEADDR\n", dev->name, code_err);
-						tp->LastOpenStatus =
-							OPEN_DUPLICATE_NODEADDR;
-						break;
-
-					case OPEN_REQUEST_INIT:
-						printk(KERN_INFO "%s: %s OPEN_REQUEST_INIT\n", dev->name, code_err);
-						tp->LastOpenStatus =
-							OPEN_REQUEST_INIT;
-						break;
-
-					case OPEN_REMOVE_RECEIVED:
-						printk(KERN_INFO "%s: %s OPEN_REMOVE_RECEIVED", dev->name, code_err);
-						tp->LastOpenStatus =
-							OPEN_REMOVE_RECEIVED;
-						break;
-
-					case OPEN_FULLDUPLEX_SET:
-						printk(KERN_INFO "%s: %s OPEN_FULLDUPLEX_SET\n", dev->name, code_err);
-						tp->LastOpenStatus =
-							OPEN_FULLDUPLEX_SET;
-						break;
-
-					default:
-						printk(KERN_INFO "%s: %s Unknown open err code", dev->name, code_err);
-						tp->LastOpenStatus =
-							OPEN_FUNCTION_FAILURE;
-						break;
-				}
-			}
-
-			tp->AdapterOpenFlag 	= 0;
-			tp->AdapterVirtOpenFlag = 0;
-
-			return;
-		}
-	}
-	else
-	{
-		if(ssb_cmd != READ_ERROR_LOG)
-			return;
-
-		/* Add values from the error log table to the MAC
-		 * statistics counters and update the errorlogtable
-		 * memory.
-		 */
-		tp->MacStat.line_errors += tp->errorlogtable.Line_Error;
-		tp->MacStat.burst_errors += tp->errorlogtable.Burst_Error;
-		tp->MacStat.A_C_errors += tp->errorlogtable.ARI_FCI_Error;
-		tp->MacStat.lost_frames += tp->errorlogtable.Lost_Frame_Error;
-		tp->MacStat.recv_congest_count += tp->errorlogtable.Rx_Congest_Error;
-		tp->MacStat.rx_errors += tp->errorlogtable.Rx_Congest_Error;
-		tp->MacStat.frame_copied_errors += tp->errorlogtable.Frame_Copied_Error;
-		tp->MacStat.token_errors += tp->errorlogtable.Token_Error;
-		tp->MacStat.dummy1 += tp->errorlogtable.DMA_Bus_Error;
-		tp->MacStat.dummy1 += tp->errorlogtable.DMA_Parity_Error;
-		tp->MacStat.abort_delimiters += tp->errorlogtable.AbortDelimeters;
-		tp->MacStat.frequency_errors += tp->errorlogtable.Frequency_Error;
-		tp->MacStat.internal_errors += tp->errorlogtable.Internal_Error;
-	}
-
-	return;
-}
-
-/*
- * The inverse routine to sktr_open().
- */
-static int sktr_close(struct net_device *dev)
-{
-	struct net_local *tp = (struct net_local *)dev->priv;
-
-	dev->tbusy = 1;
-	dev->start = 0;
-
-	del_timer(&tp->timer);
-
-	/* Flush the Tx and disable Rx here. */
-
-	tp->HaltInProgress 	= 1;
-	sktr_exec_cmd(dev, OC_CLOSE);
-	tp->timer.expires	= jiffies + 1*HZ;
-	tp->timer.function 	= sktr_timer_end_wait;
-	tp->timer.data 		= (unsigned long)dev;
-	add_timer(&tp->timer);
-
-	sktr_enable_interrupts(dev);
-
-	tp->Sleeping = 1;
-	interruptible_sleep_on(&tp->wait_for_tok_int);
-	tp->TransmitCommandActive = 0;
-    
-	del_timer(&tp->timer);
-	sktr_disable_interrupts(dev);
-   
-	if(dev->dma > 0) 
-	{
-		unsigned long flags=claim_dma_lock();
-		disable_dma(dev->dma);
-		release_dma_lock(flags);
-	}
-	
-	outw(0xFF00, dev->base_addr + SIFCMD);
-	if(dev->dma > 0)
-		outb(0xff, dev->base_addr + POSREG);
-
-#ifdef MODULE
-	MOD_DEC_USE_COUNT;
-#endif
-
-	sktr_cancel_tx_queue(tp);
-
-	return (0);
-}
-
-/*
- * Get the current statistics. This may be called with the card open
- * or closed.
- */
-static struct enet_statistics *sktr_get_stats(struct net_device *dev)
-{
-	struct net_local *tp = (struct net_local *)dev->priv;
-
-	return ((struct enet_statistics *)&tp->MacStat);
-}
-
-/*
- * Set or clear the multicast filter for this adapter.
- */
-static void sktr_set_multicast_list(struct net_device *dev)
-{
-	struct net_local *tp = (struct net_local *)dev->priv;
-	unsigned int OpenOptions;
-
-	OpenOptions = tp->ocpl.OPENOptions &
-		~(PASS_ADAPTER_MAC_FRAMES
-		| PASS_ATTENTION_FRAMES
-		| PASS_BEACON_MAC_FRAMES
-		| COPY_ALL_MAC_FRAMES
-		| COPY_ALL_NON_MAC_FRAMES);
-
-	if(dev->flags & IFF_PROMISC)
-		/* Enable promiscuous mode */
-		OpenOptions |= COPY_ALL_NON_MAC_FRAMES | COPY_ALL_MAC_FRAMES;
-	else
-	{
-		if(dev->flags & IFF_ALLMULTI)
-			/* || dev->mc_count > HW_MAX_ADDRS) */
-		{
-			/* Disable promiscuous mode, use normal mode. */
-		}
-		else
-		{
-			if(dev->mc_count)
-			{
-				/* Walk the address list, and load the filter */
-			}
-		}
-	}
-
-	tp->ocpl.OPENOptions = OpenOptions;
-	sktr_exec_cmd(dev, OC_MODIFY_OPEN_PARMS);
-
-	return;
-}
-
-/*
- * Wait for some time (microseconds)
- */
-static void sktr_wait(unsigned long time)
-{
-	long tmp;
-
-	tmp = jiffies + time/(1000000/HZ);
-	do {
-  		current->state 		= TASK_INTERRUPTIBLE;
-		tmp = schedule_timeout(tmp);
-	} while(time_after(tmp, jiffies));
-
-	return;
-}
-
-/*
- * Write a command value to the SIFCMD register
- */
-static void sktr_exec_sifcmd(struct net_device *dev, unsigned int WriteValue)
-{
-	int ioaddr = dev->base_addr;
-	unsigned short cmd;
-	unsigned short SifStsValue;
-	unsigned long loop_counter;
-
-	WriteValue = ((WriteValue ^ CMD_SYSTEM_IRQ) | CMD_INTERRUPT_ADAPTER);
-	cmd = (unsigned short)WriteValue;
-	loop_counter = 0,5 * 800000;
-	do {
-		SifStsValue = inw(ioaddr + SIFSTS);
-	} while((SifStsValue & CMD_INTERRUPT_ADAPTER) && loop_counter--);
-	outw(cmd, ioaddr + SIFCMD);
-
-	return;
-}
-
-/*
- * Processes adapter hardware reset, halts adapter and downloads firmware,
- * clears the halt bit.
- */
-static int sktr_reset_adapter(struct net_device *dev)
-{
-	struct net_local *tp = (struct net_local *)dev->priv;
-	unsigned short *fw_ptr = (unsigned short *)&sktr_code;
-	unsigned short count, c;
-	int ioaddr = dev->base_addr;
-
-	/* Hardware adapter reset */
-	outw(ACL_ARESET, ioaddr + SIFACL);
-	sktr_wait(40);
-
-	c = inw(ioaddr + SIFACL);
-	sktr_wait(20);
-
-	if(dev->dma == 0)	/* For PCI adapters */
-	{
-		c &= ~(ACL_SPEED4 | ACL_SPEED16);	/* Clear bits */
-		if(tp->DataRate == SPEED_4)
-			c |= ACL_SPEED4;		/* Set 4Mbps */
-		else
-			c |= ACL_SPEED16;		/* Set 16Mbps */
-	}
-
-	/* In case a command is pending - forget it */
-	tp->ScbInUse = 0;
-
-	c &= ~ACL_ARESET;		/* Clear adapter reset bit */
-	c |=  ACL_CPHALT;		/* Halt adapter CPU, allow download */
-	c &= ~ACL_PSDMAEN;		/* Clear pseudo dma bit */
-	outw(c, ioaddr + SIFACL);
-	sktr_wait(40);
-
-	/* Download firmware via DIO interface: */
-	do {
-		/* Download first address part */
-		outw(*fw_ptr, ioaddr + SIFADX);
-		fw_ptr++;
-
-		/* Download second address part */
-		outw(*fw_ptr, ioaddr + SIFADD);
-		fw_ptr++;
-
-		if((count = *fw_ptr) != 0)	/* Load loop counter */
-		{
-			fw_ptr++;	/* Download block data */
-			for(; count > 0; count--)
-			{
-				outw(*fw_ptr, ioaddr + SIFINC);
-				fw_ptr++;
-			}
-		}
-		else	/* Stop, if last block downloaded */
-		{
-			c = inw(ioaddr + SIFACL);
-			c &= (~ACL_CPHALT | ACL_SINTEN);
-
-			/* Clear CPHALT and start BUD */
-			outw(c, ioaddr + SIFACL);
-			return (1);
-		}
-	} while(count == 0);
-
-	return (-1);
-}
-
-/*
- * Starts bring up diagnostics of token ring adapter and evaluates
- * diagnostic results.
- */
-static int sktr_bringup_diags(struct net_device *dev)
-{
-	int loop_cnt, retry_cnt;
-	unsigned short Status;
-	int ioaddr = dev->base_addr;
-
-	sktr_wait(HALF_SECOND);
-	sktr_exec_sifcmd(dev, EXEC_SOFT_RESET);
-	sktr_wait(HALF_SECOND);
-
-	retry_cnt = BUD_MAX_RETRIES;	/* maximal number of retrys */
-
-	do {
-		retry_cnt--;
-		if(sktr_debug > 3)
-			printk(KERN_INFO "BUD-Status: \n");
-		loop_cnt = BUD_MAX_LOOPCNT;	/* maximum: three seconds*/
-		do {			/* Inspect BUD results */
-			loop_cnt--;
-			sktr_wait(HALF_SECOND);
-			Status = inw(ioaddr + SIFSTS);
-			Status &= STS_MASK;
-
-			if(sktr_debug > 3)
-				printk(KERN_INFO " %04X \n", Status);
-			/* BUD successfully completed */
-			if(Status == STS_INITIALIZE)
-				return (1);
-		/* Unrecoverable hardware error, BUD not completed? */
-		} while((loop_cnt > 0) && ((Status & (STS_ERROR | STS_TEST))
-			!= (STS_ERROR | STS_TEST)));
-
-		/* Error preventing completion of BUD */
-		if(retry_cnt > 0)
-		{
-			printk(KERN_INFO "%s: Adapter Software Reset.\n", 
-				dev->name);
-			sktr_exec_sifcmd(dev, EXEC_SOFT_RESET);
-			sktr_wait(HALF_SECOND);
-		}
-	} while(retry_cnt > 0);
-
-	Status = inw(ioaddr + SIFSTS);
-	Status &= STS_ERROR_MASK;	/* Hardware error occurred! */
-
-	printk(KERN_INFO "%s: Bring Up Diagnostics Error (%04X) occurred\n",
-		dev->name, Status);
-
-	return (-1);
-}
-
-/*
- * Copy initialisation data to adapter memory, beginning at address
- * 1:0A00; Starting DMA test and evaluating result bits.
- */
-static int sktr_init_adapter(struct net_device *dev)
-{
-	struct net_local *tp = (struct net_local *)dev->priv;
-
-	const unsigned char SCB_Test[6] = {0x00, 0x00, 0xC1, 0xE2, 0xD4, 0x8B};
-	const unsigned char SSB_Test[8] = {0xFF, 0xFF, 0xD1, 0xD7,
-						0xC5, 0xD9, 0xC3, 0xD4};
-	void *ptr = (void *)&tp->ipb;
-	unsigned short *ipb_ptr = (unsigned short *)ptr;
-	unsigned char *cb_ptr = (unsigned char *) &tp->scb;
-	unsigned char *sb_ptr = (unsigned char *) &tp->ssb;
-	unsigned short Status;
-	int i, loop_cnt, retry_cnt;
-	int ioaddr = dev->base_addr;
-
-	/* Normalize: byte order low/high, word order high/low! (only IPB!) */
-	tp->ipb.SCB_Addr = SWAPW(virt_to_bus(&tp->scb));
-	tp->ipb.SSB_Addr = SWAPW(virt_to_bus(&tp->ssb));
-
-	/* Maximum: three initialization retries */
-	retry_cnt = INIT_MAX_RETRIES;
-
-	do {
-		retry_cnt--;
-
-		/* Transfer initialization block */
-		outw(0x0001, ioaddr + SIFADX);
-
-		/* To address 0001:0A00 of adapter RAM */
-		outw(0x0A00, ioaddr + SIFADD);
-
-		/* Write 11 words to adapter RAM */
-		for(i = 0; i < 11; i++)
-			outw(ipb_ptr[i], ioaddr + SIFINC);
-
-		/* Execute SCB adapter command */
-		sktr_exec_sifcmd(dev, CMD_EXECUTE);
-
-		loop_cnt = INIT_MAX_LOOPCNT;	/* Maximum: 11 seconds */
-
-		/* While remaining retries, no error and not completed */
-		do {
-			Status = 0;
-			loop_cnt--;
-			sktr_wait(HALF_SECOND);
-
-			/* Mask interesting status bits */
-			Status = inw(ioaddr + SIFSTS);
-			Status &= STS_MASK;
-		} while(((Status &(STS_INITIALIZE | STS_ERROR | STS_TEST)) != 0)
-			&& ((Status & STS_ERROR) == 0) && (loop_cnt != 0));
-
-		if((Status & (STS_INITIALIZE | STS_ERROR | STS_TEST)) == 0)
-		{
-			/* Initialization completed without error */
-			i = 0;
-			do {	/* Test if contents of SCB is valid */
-				if(SCB_Test[i] != *(cb_ptr + i))
-					/* DMA data error: wrong data in SCB */
-					return (-1);
-				i++;
-			} while(i < 6);
-
-			i = 0;
-			do {	/* Test if contents of SSB is valid */
-				if(SSB_Test[i] != *(sb_ptr + i))
-					/* DMA data error: wrong data in SSB */
-					return (-1);
-				i++;
-			} while (i < 8);
-
-			return (1);	/* Adapter successfully initialized */
-		}
-		else
-		{
-			if((Status & STS_ERROR) != 0)
-			{
-				/* Initialization error occurred */
-				Status = inw(ioaddr + SIFSTS);
-				Status &= STS_ERROR_MASK;
-				/* ShowInitialisationErrorCode(Status); */
-				return (-1); /* Unrecoverable error */
-			}
-			else
-			{
-				if(retry_cnt > 0)
-				{
-					/* Reset adapter and try init again */
-					sktr_exec_sifcmd(dev, EXEC_SOFT_RESET);
-					sktr_wait(HALF_SECOND);
-				}
-			}
-		}
-	} while(retry_cnt > 0);
-
-	return (-1);
-}
-
-/*
- * Check for outstanding commands in command queue and tries to execute
- * command immediately. Corresponding command flag in command queue is cleared.
- */
-static void sktr_chk_outstanding_cmds(struct net_device *dev)
-{
-	struct net_local *tp = (struct net_local *)dev->priv;
-	unsigned long Addr = 0;
-	unsigned char i = 0;
-
-	if(tp->CMDqueue == 0)
-		return;		/* No command execution */
-
-	/* If SCB in use: no command */
-	if(tp->ScbInUse == 1)
-		return;
-
-	/* Check if adapter is opened, avoiding COMMAND_REJECT
-	 * interrupt by the adapter!
-	 */
-	if(tp->AdapterOpenFlag == 0)
-	{
-		if(tp->CMDqueue & OC_OPEN)
-		{
-			/* Execute OPEN command	*/
-			tp->CMDqueue ^= OC_OPEN;
-
-			/* Copy the 18 bytes of the product ID */
-			while((AdapterName[i] != '\0') && (i < PROD_ID_SIZE))
-			{
-				tp->ProductID[i] = AdapterName[i];
-				i++;
-			}
-
-			Addr = htonl(virt_to_bus(&tp->ocpl));
-			tp->scb.Parm[0] = LOWORD(Addr);
-			tp->scb.Parm[1] = HIWORD(Addr);
-			tp->scb.CMD = OPEN;
-		}
-		else
-			/* No OPEN command queued, but adapter closed. Note:
-			 * We'll try to re-open the adapter in DriverPoll()
-			 */
-			return;		/* No adapter command issued */
-	}
-	else
-	{
-		/* Adapter is open; evaluate command queue: try to execute
-		 * outstanding commands (depending on priority!) CLOSE
-		 * command queued
-		 */
-		if(tp->CMDqueue & OC_CLOSE)
-		{
-			tp->CMDqueue ^= OC_CLOSE;
-			tp->AdapterOpenFlag = 0;
-			tp->scb.Parm[0] = 0; /* Parm[0], Parm[1] are ignored */
-			tp->scb.Parm[1] = 0; /* but should be set to zero! */
-			tp->scb.CMD = CLOSE;
-			if(!tp->HaltInProgress)
-				tp->CMDqueue |= OC_OPEN; /* re-open adapter */
-			else
-				tp->CMDqueue = 0;	/* no more commands */
-		}
-		else
-		{
-			if(tp->CMDqueue & OC_RECEIVE)
-			{
-				tp->CMDqueue ^= OC_RECEIVE;
-				Addr = htonl(virt_to_bus(tp->RplHead));
-				tp->scb.Parm[0] = LOWORD(Addr);
-				tp->scb.Parm[1] = HIWORD(Addr);
-				tp->scb.CMD = RECEIVE;
-			}
-			else
-			{
-				if(tp->CMDqueue & OC_TRANSMIT_HALT)
-				{
-					/* NOTE: TRANSMIT.HALT must be checked 
-					 * before TRANSMIT.
-					 */
-					tp->CMDqueue ^= OC_TRANSMIT_HALT;
-					tp->scb.CMD = TRANSMIT_HALT;
-
-					/* Parm[0] and Parm[1] are ignored
-					 * but should be set to zero!
-					 */
-					tp->scb.Parm[0] = 0;
-					tp->scb.Parm[1] = 0;
-				}
-				else
-				{
-					if(tp->CMDqueue & OC_TRANSMIT)
-					{
-						/* NOTE: TRANSMIT must be 
-						 * checked after TRANSMIT.HALT
-						 */
-						if(tp->TransmitCommandActive)
-						{
-							if(!tp->TransmitHaltScheduled)
-							{
-								tp->TransmitHaltScheduled = 1;
-								sktr_exec_cmd(dev, OC_TRANSMIT_HALT) ;
-							}
-							tp->TransmitCommandActive = 0;
-							return;
-						}
-
-						tp->CMDqueue ^= OC_TRANSMIT;
-						sktr_cancel_tx_queue(tp);
-						Addr = htonl(virt_to_bus(tp->TplBusy));
-						tp->scb.Parm[0] = LOWORD(Addr);
-						tp->scb.Parm[1] = HIWORD(Addr);
-						tp->scb.CMD = TRANSMIT;
-						tp->TransmitCommandActive = 1;
-					}
-					else
-					{
-						if(tp->CMDqueue & OC_MODIFY_OPEN_PARMS)
-						{
-							tp->CMDqueue ^= OC_MODIFY_OPEN_PARMS;
-							tp->scb.Parm[0] = tp->ocpl.OPENOptions; /* new OPEN options*/
-							tp->scb.Parm[0] |= ENABLE_FULL_DUPLEX_SELECTION;
-							tp->scb.Parm[1] = 0; /* is ignored but should be zero */
-							tp->scb.CMD = MODIFY_OPEN_PARMS;
-						}
-						else
-						{
-							if(tp->CMDqueue & OC_SET_FUNCT_ADDR)
-							{
-								tp->CMDqueue ^= OC_SET_FUNCT_ADDR;
-								tp->scb.Parm[0] = LOWORD(tp->ocpl.FunctAddr);
-								tp->scb.Parm[1] = HIWORD(tp->ocpl.FunctAddr);
-								tp->scb.CMD = SET_FUNCT_ADDR;
-							}
-							else
-							{
-								if(tp->CMDqueue & OC_SET_GROUP_ADDR)
-								{
-									tp->CMDqueue ^= OC_SET_GROUP_ADDR;
-									tp->scb.Parm[0] = LOWORD(tp->ocpl.GroupAddr);
-									tp->scb.Parm[1] = HIWORD(tp->ocpl.GroupAddr);
-									tp->scb.CMD = SET_GROUP_ADDR;
-								}
-								else
-								{
-									if(tp->CMDqueue & OC_READ_ERROR_LOG)
-									{
-										tp->CMDqueue ^= OC_READ_ERROR_LOG;
-										Addr = htonl(virt_to_bus(&tp->errorlogtable));
-										tp->scb.Parm[0] = LOWORD(Addr);
-										tp->scb.Parm[1] = HIWORD(Addr);
-										tp->scb.CMD = READ_ERROR_LOG;
-									}
-									else
-									{
-										printk(KERN_WARNING "CheckForOutstandingCommand: unknown Command\n");
-										tp->CMDqueue = 0;
-										return;
-									}
-								}
-							}
-						}
-					}
-				}
-			}
-		}
-	}
-
-	tp->ScbInUse = 1;	/* Set semaphore: SCB in use. */
-
-	/* Execute SCB and generate IRQ when done. */
-	sktr_exec_sifcmd(dev, CMD_EXECUTE | CMD_SCB_REQUEST);
-
-	return;
-}
-
-/*
- * IRQ conditions: signal loss on the ring, transmit or receive of beacon
- * frames (disabled if bit 1 of OPEN option is set); report error MAC
- * frame transmit (disabled if bit 2 of OPEN option is set); open or short
- * cirquit fault on the lobe is detected; remove MAC frame received;
- * error counter overflow (255); opened adapter is the only station in ring.
- * After some of the IRQs the adapter is closed!
- */
-static void sktr_ring_status_irq(struct net_device *dev)
-{
-	struct net_local *tp = (struct net_local *)dev->priv;
-
-	tp->CurrentRingStatus = SWAPB(tp->ssb.Parm[0]);
-
-	/* First: fill up statistics */
-	if(tp->ssb.Parm[0] & SIGNAL_LOSS)
-	{
-		printk(KERN_INFO "%s: Signal Loss\n", dev->name);
-		tp->MacStat.line_errors++;
-	}
-
-	/* Adapter is closed, but initialized */
-	if(tp->ssb.Parm[0] & LOBE_WIRE_FAULT)
-	{
-		printk(KERN_INFO "%s: Lobe Wire Fault, Reopen Adapter\n", 
-			dev->name);
-		tp->MacStat.line_errors++;
-	}
-
-	if(tp->ssb.Parm[0] & RING_RECOVERY)
-		printk(KERN_INFO "%s: Ring Recovery\n", dev->name);
-
-	/* Counter overflow: read error log */
-	if(tp->ssb.Parm[0] & COUNTER_OVERFLOW)
-	{
-		printk(KERN_INFO "%s: Counter Overflow\n", dev->name);
-		sktr_exec_cmd(dev, OC_READ_ERROR_LOG);
-	}
-
-	/* Adapter is closed, but initialized */
-	if(tp->ssb.Parm[0] & REMOVE_RECEIVED)
-		printk(KERN_INFO "%s: Remove Received, Reopen Adapter\n", 
-			dev->name);
-
-	/* Adapter is closed, but initialized */
-	if(tp->ssb.Parm[0] & AUTO_REMOVAL_ERROR)
-		printk(KERN_INFO "%s: Auto Removal Error, Reopen Adapter\n", 
-			dev->name);
-
-	if(tp->ssb.Parm[0] & HARD_ERROR)
-		printk(KERN_INFO "%s: Hard Error\n", dev->name);
-
-	if(tp->ssb.Parm[0] & SOFT_ERROR)
-		printk(KERN_INFO "%s: Soft Error\n", dev->name);
-
-	if(tp->ssb.Parm[0] & TRANSMIT_BEACON)
-		printk(KERN_INFO "%s: Transmit Beacon\n", dev->name);
-
-	if(tp->ssb.Parm[0] & SINGLE_STATION)
-		printk(KERN_INFO "%s: Single Station\n", dev->name);
-
-	/* Check if adapter has been closed */
-	if(tp->ssb.Parm[0] & ADAPTER_CLOSED)
-	{
-		printk(KERN_INFO "%s: Adapter closed (Reopening)," 
-			"QueueSkb %d, CurrentRingStat %x\n",
-			dev->name, tp->QueueSkb, tp->CurrentRingStatus);
-		tp->AdapterOpenFlag = 0;
-		sktr_open_adapter(dev);
-	}
-
-	return;
-}
-
-/*
- * Issued if adapter has encountered an unrecoverable hardware
- * or software error.
- */
-static void sktr_chk_irq(struct net_device *dev)
-{
-	int i;
-	unsigned short AdapterCheckBlock[4];
-	unsigned short ioaddr = dev->base_addr;
-	struct net_local *tp = (struct net_local *)dev->priv;
-
-	tp->AdapterOpenFlag = 0;	/* Adapter closed now */
-
-	/* Page number of adapter memory */
-	outw(0x0001, ioaddr + SIFADX);
-	/* Address offset */
-	outw(CHECKADDR, ioaddr + SIFADR);
-
-	/* Reading 8 byte adapter check block. */
-	for(i = 0; i < 4; i++)
-		AdapterCheckBlock[i] = inw(ioaddr + SIFINC);
-
-	if(sktr_debug > 3)
-	{
-		printk("%s: AdapterCheckBlock: ", dev->name);
-		for (i = 0; i < 4; i++)
-			printk("%04X", AdapterCheckBlock[i]);
-		printk("\n");
-	}
-
-	switch(AdapterCheckBlock[0])
-	{
-		case DIO_PARITY:
-			printk(KERN_INFO "%s: DIO parity error\n", dev->name);
-			break;
-
-		case DMA_READ_ABORT:
-			printk(KERN_INFO "%s DMA read operation aborted:\n",
-				dev->name);
-			switch (AdapterCheckBlock[1])
-			{
-				case 0:
-					printk(KERN_INFO "Timeout\n");
-					printk(KERN_INFO "Address: %04X %04X\n",
-						AdapterCheckBlock[2],
-						AdapterCheckBlock[3]);
-					break;
-
-				case 1:
-					printk(KERN_INFO "Parity error\n");
-					printk(KERN_INFO "Address: %04X %04X\n",
-						AdapterCheckBlock[2], 
-						AdapterCheckBlock[3]);
-					break;
-
-				case 2: 
-					printk(KERN_INFO "Bus error\n");
-					printk(KERN_INFO "Address: %04X %04X\n",
-						AdapterCheckBlock[2], 
-						AdapterCheckBlock[3]);
-					break;
-
-				default:
-					printk(KERN_INFO "Unknown error.\n");
-					break;
-			}
-			break;
-
-		case DMA_WRITE_ABORT:
-			printk(KERN_INFO "%s: DMA write operation aborted: \n",
-				dev->name);
-			switch (AdapterCheckBlock[1])
-			{
-				case 0: 
-					printk(KERN_INFO "Timeout\n");
-					printk(KERN_INFO "Address: %04X %04X\n",
-						AdapterCheckBlock[2], 
-						AdapterCheckBlock[3]);
-					break;
-
-				case 1: 
-					printk(KERN_INFO "Parity error\n");
-					printk(KERN_INFO "Address: %04X %04X\n",
-						AdapterCheckBlock[2], 
-						AdapterCheckBlock[3]);
-					break;
-
-				case 2: 
-					printk(KERN_INFO "Bus error\n");
-					printk(KERN_INFO "Address: %04X %04X\n",
-						AdapterCheckBlock[2], 
-						AdapterCheckBlock[3]);
-					break;
-
-				default:
-					printk(KERN_INFO "Unknown error.\n");
-					break;
-			}
-			break;
-
-		case ILLEGAL_OP_CODE:
-			printk("%s: Illegal operation code in firmware\n",
-				dev->name);
-			/* Parm[0-3]: adapter internal register R13-R15 */
-			break;
-
-		case PARITY_ERRORS:
-			printk("%s: Adapter internal bus parity error\n",
-				dev->name);
-			/* Parm[0-3]: adapter internal register R13-R15 */
-			break;
-
-		case RAM_DATA_ERROR:
-			printk("%s: RAM data error\n", dev->name);
-			/* Parm[0-1]: MSW/LSW address of RAM location. */
-			break;
-
-		case RAM_PARITY_ERROR:
-			printk("%s: RAM parity error\n", dev->name);
-			/* Parm[0-1]: MSW/LSW address of RAM location. */
-			break;
-
-		case RING_UNDERRUN:
-			printk("%s: Internal DMA underrun detected\n",
-				dev->name);
-			break;
-
-		case INVALID_IRQ:
-			printk("%s: Unrecognized interrupt detected\n",
-				dev->name);
-			/* Parm[0-3]: adapter internal register R13-R15 */
-			break;
-
-		case INVALID_ERROR_IRQ:
-			printk("%s: Unrecognized error interrupt detected\n",
-				dev->name);
-			/* Parm[0-3]: adapter internal register R13-R15 */
-			break;
-
-		case INVALID_XOP:
-			printk("%s: Unrecognized XOP request detected\n",
-				dev->name);
-			/* Parm[0-3]: adapter internal register R13-R15 */
-			break;
-
-		default:
-			printk("%s: Unknown status", dev->name);
-			break;
-	}
-
-	if(sktr_chipset_init(dev) == 1)
-	{
-		/* Restart of firmware successful */
-		tp->AdapterOpenFlag = 1;
-	}
-
-	return;
-}
-
-/*
- * Internal adapter pointer to RAM data are copied from adapter into
- * host system.
- */
-static void sktr_read_ptr(struct net_device *dev)
-{
-	struct net_local *tp = (struct net_local *)dev->priv;
-	unsigned short adapterram;
-
-	sktr_read_ram(dev, (unsigned char *)&tp->intptrs.BurnedInAddrPtr,
-			ADAPTER_INT_PTRS, 16);
-	sktr_read_ram(dev, (unsigned char *)&adapterram,
-			(unsigned short)SWAPB(tp->intptrs.AdapterRAMPtr), 2);
-
-	printk(KERN_INFO "%s: Adapter RAM size: %d K\n", 
-		dev->name, SWAPB(adapterram));
-
-	return;
-}
-
-/*
- * Reads a number of bytes from adapter to system memory.
- */
-static void sktr_read_ram(struct net_device *dev, unsigned char *Data,
-				unsigned short Address, int Length)
-{
-	int i;
-	unsigned short old_sifadx, old_sifadr, InWord;
-	unsigned short ioaddr = dev->base_addr;
-
-	/* Save the current values */
-	old_sifadx = inw(ioaddr + SIFADX);
-	old_sifadr = inw(ioaddr + SIFADR);
-
-	/* Page number of adapter memory */
-	outw(0x0001, ioaddr + SIFADX);
-	/* Address offset in adapter RAM */
-	outw(Address, ioaddr + SIFADR);
-
-	/* Copy len byte from adapter memory to system data area. */
-	i = 0;
-	for(;;)
-	{
-		InWord = inw(ioaddr + SIFINC);
-
-		*(Data + i) = HIBYTE(InWord);	/* Write first byte */
-		if(++i == Length)		/* All is done break */
-			break;
-
-		*(Data + i) = LOBYTE(InWord);	/* Write second byte */
-		if (++i == Length)		/* All is done break */
-			break;
-	}
-
-	/* Restore original values */
-	outw(old_sifadx, ioaddr + SIFADX);
-	outw(old_sifadr, ioaddr + SIFADR);
-
-	return;
-}
-
-/*
- * Reads MAC address from adapter ROM.
- */
-static void sktr_read_addr(struct net_device *dev, unsigned char *Address)
-{
-	int i, In;
-	unsigned short ioaddr = dev->base_addr;
-
-	/* Address: 0000:0000 */
-	outw(0, ioaddr + SIFADX);
-	outw(0, ioaddr + SIFADR);
-
-	/* Read six byte MAC address data */
-	for(i = 0; i < 6; i++)
-	{
-		In = inw(ioaddr + SIFINC);
-		*(Address + i) = (unsigned char)(In >> 8);
-	}
-
-	return;
-}
-
-/*
- * Cancel all queued packets in the transmission queue.
- */
-static void sktr_cancel_tx_queue(struct net_local* tp)
-{
-	TPL *tpl;
-	struct sk_buff *skb;
-
-	/*
-	 * NOTE: There must not be an active TRANSMIT command pending, when
-	 * this function is called.
-	 */
-	if(tp->TransmitCommandActive)
-		return;
-
-	for(;;)
-	{
-		tpl = tp->TplBusy;
-		if(!tpl->BusyFlag)
-			break;
-		/* "Remove" TPL from busy list. */
-		tp->TplBusy = tpl->NextTPLPtr;
-		sktr_write_tpl_status(tpl, 0);	/* Clear VALID bit */
-		tpl->BusyFlag = 0;		/* "free" TPL */
-
-		printk(KERN_INFO "Cancel tx (%08lXh).\n", (unsigned long)tpl);
-
-		dev_kfree_skb(tpl->Skb);
-	}
-
-	for(;;)
-	{
-		skb = skb_dequeue(&tp->SendSkbQueue);
-		if(skb == NULL)
-			break;
-		tp->QueueSkb++;
-		dev_kfree_skb(skb);
-	}
-
-	return;
-}
-
-/*
- * This function is called whenever a transmit interrupt is generated by the
- * adapter. For a command complete interrupt, it is checked if we have to
- * issue a new transmit command or not.
- */
-static void sktr_tx_status_irq(struct net_device *dev)
-{
-	struct net_local *tp = (struct net_local *)dev->priv;
-	unsigned char HighByte, HighAc, LowAc;
-	TPL *tpl;
-
-	/* NOTE: At this point the SSB from TRANSMIT STATUS is no longer
-	 * available, because the CLEAR SSB command has already been issued.
-	 *
-	 * Process all complete transmissions.
-	 */
-
-	for(;;)
-	{
-		tpl = tp->TplBusy;
-		if(!tpl->BusyFlag || (tpl->Status
-			& (TX_VALID | TX_FRAME_COMPLETE))
-			!= TX_FRAME_COMPLETE)
-		{
-			break;
-		}
-
-		/* "Remove" TPL from busy list. */
-		tp->TplBusy = tpl->NextTPLPtr ;
-
-		if(sktr_debug > 3)
-			sktr_dump(tpl->MData, SWAPB(tpl->FrameSize));
-
-		/* Check the transmit status field only for directed frames*/
-		if(DIRECTED_FRAME(tpl) && (tpl->Status & TX_ERROR) == 0)
-		{
-			HighByte = GET_TRANSMIT_STATUS_HIGH_BYTE(tpl->Status);
-			HighAc   = GET_FRAME_STATUS_HIGH_AC(HighByte);
-			LowAc    = GET_FRAME_STATUS_LOW_AC(HighByte);
-
-			if((HighAc != LowAc) || (HighAc == AC_NOT_RECOGNIZED))
-			{
-				printk(KERN_INFO "%s: (DA=%08lX not recognized)",
-					dev->name,
-					*(unsigned long *)&tpl->MData[2+2]);
-			}
-			else
-			{
-				if(sktr_debug > 3)
-					printk("%s: Directed frame tx'd\n", 
-						dev->name);
-			}
-		}
-		else
-		{
-			if(!DIRECTED_FRAME(tpl))
-			{
-				if(sktr_debug > 3)
-					printk("%s: Broadcast frame tx'd\n",
-						dev->name);
-			}
-		}
-
-                tp->MacStat.tx_packets++;
-		dev_kfree_skb(tpl->Skb);
-		tpl->BusyFlag = 0;	/* "free" TPL */
-	}
-
-	dev->tbusy = 0;
-	if(tp->QueueSkb < MAX_TX_QUEUE)
-		sktr_hardware_send_packet(dev, tp);
-
-	return;
-}
-
-/*
- * Called if a frame receive interrupt is generated by the adapter.
- * Check if the frame is valid and indicate it to system.
- */
-static void sktr_rcv_status_irq(struct net_device *dev)
-{
-	struct net_local *tp = (struct net_local *)dev->priv;
-	unsigned char *ReceiveDataPtr;
-	struct sk_buff *skb;
-	unsigned int Length, Length2;
-	RPL *rpl;
-	RPL *SaveHead;
-
-	/* NOTE: At this point the SSB from RECEIVE STATUS is no longer
-	 * available, because the CLEAR SSB command has already been issued.
-	 *
-	 * Process all complete receives.
-	 */
-
-	for(;;)
-	{
-		rpl = tp->RplHead;
-		if(rpl->Status & RX_VALID)
-			break;		/* RPL still in use by adapter */
-
-		/* Forward RPLHead pointer to next list. */
-		SaveHead = tp->RplHead;
-		tp->RplHead = rpl->NextRPLPtr;
-
-		/* Get the frame size (Byte swap for Intel).
-		 * Do this early (see workaround comment below)
-		 */
-		Length = (unsigned short)SWAPB(rpl->FrameSize);
-
-		/* Check if the Frame_Start, Frame_End and
-		 * Frame_Complete bits are set.
-		 */
-		if((rpl->Status & VALID_SINGLE_BUFFER_FRAME)
-			== VALID_SINGLE_BUFFER_FRAME)
-		{
-			ReceiveDataPtr = rpl->MData;
-
-			/* Workaround for delayed write of FrameSize on ISA
-			 * (FrameSize is false but valid-bit is reset)
-			 * Frame size is set to zero when the RPL is freed.
-			 * Length2 is there because there have also been
-			 * cases where the FrameSize was partially written
-			 */
-			Length2 = (unsigned short)SWAPB(rpl->FrameSize);
-
-			if(Length == 0 || Length != Length2)
-			{
-				tp->RplHead = SaveHead;
-				break;	/* Return to sktr_interrupt */
-			}
-
-			/* Drop frames sent by myself */
-			if(sktr_chk_frame(dev, rpl->MData))
-			{
-				printk(KERN_INFO "%s: Received my own frame\n",
-					dev->name);
-				if(rpl->Skb != NULL)
-					dev_kfree_skb(rpl->Skb);
-			}
-			else
-			{
-				sktr_update_rcv_stats(tp,ReceiveDataPtr,Length);
-
-				if(sktr_debug > 3)
-					printk("%s: Packet Length %04X (%d)\n",
-						dev->name, Length, Length);
-
-				/* Indicate the received frame to system the
-				 * adapter does the Source-Routing padding for 
-				 * us. See: OpenOptions in sktr_init_opb()
-				 */
-				skb = rpl->Skb;
-				if(rpl->SkbStat == SKB_UNAVAILABLE)
-				{
-					/* Try again to allocate skb */
-					skb = dev_alloc_skb(tp->MaxPacketSize);
-					if(skb == NULL)
-					{
-						/* Update Stats ?? */
-					}
-					else
-					{
-						skb->dev	= dev;
-						skb_put(skb, tp->MaxPacketSize);
-						rpl->SkbStat 	= SKB_DATA_COPY;
-						ReceiveDataPtr 	= rpl->MData;
-					}
-				}
-
-				if(rpl->SkbStat == SKB_DATA_COPY
-					|| rpl->SkbStat == SKB_DMA_DIRECT)
-				{
-					if(rpl->SkbStat == SKB_DATA_COPY)
-					{
-						memmove(skb->data, ReceiveDataPtr, Length);
-					}
-
-					/* Deliver frame to system */
-					rpl->Skb = NULL;
-					skb_trim(skb,Length);
-					skb->protocol = tr_type_trans(skb,dev);
-					netif_rx(skb);
-				}
-			}
-		}
-		else	/* Invalid frame */
-		{
-			if(rpl->Skb != NULL)
-				dev_kfree_skb(rpl->Skb);
-
-			/* Skip list. */
-			if(rpl->Status & RX_START_FRAME)
-				/* Frame start bit is set -> overflow. */
-				tp->MacStat.rx_errors++;
-		}
-
-		/* Allocate new skb for rpl */
-		rpl->Skb = dev_alloc_skb(tp->MaxPacketSize);
-
-		/* skb == NULL ? then use local buffer */
-		if(rpl->Skb == NULL)
-		{
-			rpl->SkbStat = SKB_UNAVAILABLE;
-			rpl->FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[rpl->RPLIndex]));
-			rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex];
-		}
-		else	/* skb != NULL */
-		{
-			rpl->Skb->dev = dev;
-			skb_put(rpl->Skb, tp->MaxPacketSize);
-
-			/* Data unreachable for DMA ? then use local buffer */
-			if(virt_to_bus(rpl->Skb->data) + tp->MaxPacketSize
-				> ISA_MAX_ADDRESS)
-			{
-				rpl->SkbStat = SKB_DATA_COPY;
-				rpl->FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[rpl->RPLIndex]));
-				rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex];
-			}
-			else
-			{
-				/* DMA directly in skb->data */
-				rpl->SkbStat = SKB_DMA_DIRECT;
-				rpl->FragList[0].DataAddr = htonl(virt_to_bus(rpl->Skb->data));
-				rpl->MData = rpl->Skb->data;
-			}
-		}
-
-		rpl->FragList[0].DataCount = SWAPB(tp->MaxPacketSize);
-		rpl->FrameSize = 0;
-
-		/* Pass the last RPL back to the adapter */
-		tp->RplTail->FrameSize = 0;
-
-		/* Reset the CSTAT field in the list. */
-		sktr_write_rpl_status(tp->RplTail, RX_VALID | RX_FRAME_IRQ);
-
-		/* Current RPL becomes last one in list. */
-		tp->RplTail = tp->RplTail->NextRPLPtr;
-
-		/* Inform adapter about RPL valid. */
-		sktr_exec_sifcmd(dev, CMD_RX_VALID);
-	}
-
-	return;
-}
-
-/*
- * This function should be used whenever the status of any RPL must be
- * modified by the driver, because the compiler may otherwise change the
- * order of instructions such that writing the RPL status may be executed
- * at an undesireable time. When this function is used, the status is
- * always written when the function is called.
- */
-static void sktr_write_rpl_status(RPL *rpl, unsigned int Status)
-{
-	rpl->Status = Status;
-
-	return;
-}
-
-/*
- * The function updates the statistic counters in mac->MacStat.
- * It differtiates between directed and broadcast/multicast ( ==functional)
- * frames.
- */
-static void sktr_update_rcv_stats(struct net_local *tp, unsigned char DataPtr[],
-					unsigned int Length)
-{
-	tp->MacStat.rx_packets++;
-
-	/* Test functional bit */
-	if(DataPtr[2] & GROUP_BIT)
-		tp->MacStat.multicast++;
-
-	return;
-}
-
-/*
- * Check if it is a frame of myself. Compare source address with my current
- * address in reverse direction, and mask out the TR_RII.
- */
-static unsigned char sktr_chk_frame(struct net_device *dev, unsigned char *Addr)
-{
-	int i;
-
-	for(i = 5; i > 0; i--)
-	{
-		if(Addr[8 + i] != dev->dev_addr[i])
-			return (0);
-	}
-
-	/* Mask out RIF bit. */
-	if((Addr[8] & ~TR_RII) != (unsigned char)(dev->dev_addr[0]))
-		return (0);
-
-	return (1);  /* It is my frame. */
-}
-
-/*
- * Dump Packet (data)
- */
-static void sktr_dump(unsigned char *Data, int length)
-{
-        int i, j;
-
-        for (i = 0, j = 0; i < length / 8; i++, j += 8)
-        {
-		printk(KERN_DEBUG "%02x %02x %02x %02x %02x %02x %02x %02x\n",
-			Data[j+0],Data[j+1],Data[j+2],Data[j+3],
-                        Data[j+4],Data[j+5],Data[j+6],Data[j+7]);
-        }
-
-        return;
-}
-
-#ifdef MODULE
-
-static struct net_device* dev_sktr[SKTR_MAX_ADAPTERS];
-static int io[SKTR_MAX_ADAPTERS]	= { 0, 0 };
-static int irq[SKTR_MAX_ADAPTERS] 	= { 0, 0 };
-static int mem[SKTR_MAX_ADAPTERS] 	= { 0, 0 };
-
-MODULE_PARM(io,  "1-" __MODULE_STRING(SKTR_MAX_ADAPTERS) "i");
-MODULE_PARM(irq, "1-" __MODULE_STRING(SKTR_MAX_ADAPTERS) "i");
-MODULE_PARM(mem, "1-" __MODULE_STRING(SKTR_MAX_ADAPTERS) "i");
-
-int init_module(void)
-{
-	int i;
-
-	for(i = 0; i < SKTR_MAX_ADAPTERS; i++)
-	{
-                irq[i] = 0;
-                mem[i] = 0;
-                dev_sktr[i] = NULL;
-                dev_sktr[i] = init_trdev(dev_sktr[i], 0);
-                if(dev_sktr[i] == NULL)
-                        return (-ENOMEM);
-
-		dev_sktr[i]->base_addr = io[i];
-                dev_sktr[i]->irq       = irq[i];
-                dev_sktr[i]->mem_start = mem[i];
-                dev_sktr[i]->init      = &sktr_probe;
-
-                if(register_trdev(dev_sktr[i]) != 0)
-		{
-                        kfree_s(dev_sktr[i], sizeof(struct net_device));
-                        dev_sktr[i] = NULL;
-                        if(i == 0)
-			{
-                                printk("sktr: register_trdev() returned non-zero.\n");
-                                return (-EIO);
-                        }
-			else
-                                return (0);
-                }
-        }
-
-        return (0);
-}
-
-void cleanup_module(void)
-{
-	int i;
-
-        for(i = 0; i < SKTR_MAX_ADAPTERS; i++)
-	{
-		if(dev_sktr[i])
-		{
-			unregister_trdev(dev_sktr[i]);
-			release_region(dev_sktr[i]->base_addr, SKTR_IO_EXTENT);
-			if(dev_sktr[i]->irq)
-				free_irq(dev_sktr[i]->irq, dev_sktr[i]);
-			if(dev_sktr[i]->dma > 0)
-				free_dma(dev_sktr[i]->dma);
-			if(dev_sktr[i]->priv)
-				kfree_s(dev_sktr[i]->priv, sizeof(struct net_local));
-			kfree_s(dev_sktr[i], sizeof(struct net_device));
-			dev_sktr[i] = NULL;
-                }
-	}
-}
-#endif /* MODULE */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/sktr.h linux/drivers/net/sktr.h
--- v2.3.20/linux/drivers/net/sktr.h	Wed May 12 13:27:37 1999
+++ linux/drivers/net/sktr.h	Wed Dec 31 16:00:00 1969
@@ -1,1098 +0,0 @@
-/* sktr.h: SysKonnect TokenRing driver for Linux
- *
- * Authors:
- * - Christoph Goos <cgoos@syskonnect.de>
- */
-
-#ifndef __LINUX_SKTR_H
-#define __LINUX_SKTR_H
-
-#ifdef __KERNEL__
-
-#define SKTR_MAX_ADAPTERS 7
-
-#define SEND_TIMEOUT 10*HZ
-
-#define TR_RCF_LONGEST_FRAME_MASK 0x0070
-#define TR_RCF_FRAME4K 0x0030
-
-/*------------------------------------------------------------------*/
-/*  Bit order for adapter communication with DMA		    */
-/*  --------------------------------------------------------------  */
-/*  Bit  8 | 9| 10| 11|| 12| 13| 14| 15|| 0| 1| 2| 3|| 4| 5| 6| 7|  */
-/*  --------------------------------------------------------------  */
-/*  The bytes in a word must be byte swapped. Also, if a double	    */
-/*  word is used for storage, then the words, as well as the bytes, */
-/*  must be swapped. 						    */
-/*  Bit order for adapter communication with DIO 		    */
-/*  --------------------------------------------------------------  */
-/*  Bit  0 | 1| 2| 3|| 4| 5| 6| 7|| 8| 9| 10| 11|| 12| 13| 14| 15|  */
-/*  --------------------------------------------------------------  */
-/*------------------------------------------------------------------*/
-
-/* Swap bytes of a word.                        */
-#define SWAPB(x) (((unsigned short)((x) << 8)) | ((unsigned short)((x) >> 8)))
-
-/* Swap words of a long.                        */
-#define SWAPW(x) (((x) << 16) | ((x) >> 16))
-
-/* Get the low byte of a word.                      */
-#define LOBYTE(w)       ((unsigned char)(w))
-
-/* Get the high byte of a word.                     */
-#define HIBYTE(w)       ((unsigned char)((unsigned short)(w) >> 8))
-
-/* Get the low word of a long.                      */
-#define LOWORD(l)       ((unsigned short)(l))
-
-/* Get the high word of a long.                     */
-#define HIWORD(l)       ((unsigned short)((unsigned long)(l) >> 16))
-
-
-
-/* Token ring adapter I/O addresses for normal mode. */
-#define SIFDAT      		0L	/* SIF/DMA data. */
-#define SIFINC      		2L  	/* IO Word data with auto increment. */
-#define SIFINH      		3L  	/* IO Byte data with auto increment. */
-#define SIFADR      		4L  	/* SIF/DMA Address. */
-#define SIFCMD      		6L  	/* SIF Command. */
-#define SIFSTS      		6L  	/* SIF Status. */
-#define SIFACL      		8L  	/* SIF Adapter Control Register. */
-#define SIFADD      		10L 	/* SIF/DMA Address. */
-#define SIFADX      		12L
-#define DMALEN      		14L 	/* SIF DMA length. */
-#define POSREG      		16L 	/* Adapter Program Option Select (POS)
-			 		 * Register: base IO address + 16 byte.
-			 		 */
-#define POSREG_2    		24L 	/* only for TR4/16+ adapter
-			 		 * base IO address + 24 byte.
-			 		 */
-
-
-/* SIFCMD command codes (high-low) */
-#define CMD_INTERRUPT_ADAPTER   0x8000  /* Cause internal adapter interrupt */
-#define CMD_ADAPTER_RESET   	0x4000  /* Hardware reset of adapter */
-#define CMD_SSB_CLEAR		0x2000  /* Acknowledge to adapter to
-					 * system interrupts.
-					 */
-#define CMD_EXECUTE		0x1000	/* Execute SCB command */
-#define CMD_SCB_REQUEST		0x0800  /* Request adapter to interrupt
-					 * system when SCB is available for
-					 * another command.
-					 */
-#define CMD_RX_CONTINUE		0x0400  /* Continue receive after odd pointer
-					 * stop. (odd pointer receive method)
-					 */
-#define CMD_RX_VALID		0x0200  /* Now actual RPL is valid. */
-#define CMD_TX_VALID		0x0100  /* Now actual TPL is valid. (valid
-					 * bit receive/transmit method)
-					 */
-#define CMD_SYSTEM_IRQ		0x0080  /* Adapter-to-attached-system
-					 * interrupt is reset.
-					 */
-#define CMD_CLEAR_SYSTEM_IRQ	0x0080	/* Clear SYSTEM_INTERRUPT bit.
-					 * (write: 1=ignore, 0=reset)
-					 */
-#define EXEC_SOFT_RESET		0xFF00  /* adapter soft reset. (restart
-					 * adapter after hardware reset)
-					 */
-
-
-/* ACL commands (high-low) */
-#define ACL_SWHLDA		0x0800  /* Software hold acknowledge. */
-#define ACL_SWDDIR		0x0400  /* Data transfer direction. */
-#define ACL_SWHRQ		0x0200  /* Pseudo DMA operation. */
-#define ACL_PSDMAEN		0x0100  /* Enable pseudo system DMA. */
-#define ACL_ARESET		0x0080  /* Adapter hardware reset command.
-					 * (held in reset condition as
-					 * long as bit is set)
-					 */
-#define ACL_CPHALT		0x0040  /* Communication processor halt.
-					 * (can only be set while ACL_ARESET
-					 * bit is set; prevents adapter
-					 * processor from executing code while
-					 * downloading firmware)
-					 */
-#define ACL_BOOT		0x0020
-#define ACL_SINTEN		0x0008  /* System interrupt enable/disable
-					 * (1/0): can be written if ACL_ARESET
-					 * is zero.
-					 */
-#define ACL_SPEED4		0x0003
-#define ACL_SPEED16		0x0001
-#define PS_DMA_MASK		(ACL_SWHRQ | ACL_PSDMAEN)
-
-
-/* SIFSTS register return codes (high-low) */
-#define STS_SYSTEM_IRQ		0x0080	/* Adapter-to-attached-system
-					 * interrupt is valid.
-					 */
-#define STS_INITIALIZE		0x0040  /* INITIALIZE status. (ready to
-					 * initialize)
-					 */
-#define STS_TEST		0x0020  /* TEST status. (BUD not completed) */
-#define STS_ERROR		0x0010  /* ERROR status. (unrecoverable
-					 * HW error occurred)
-					 */
-#define STS_MASK		0x00F0  /* Mask interesting status bits. */
-#define STS_ERROR_MASK		0x000F  /* Get Error Code by masking the
-					 * interrupt code bits.
-					 */
-#define ADAPTER_INT_PTRS	0x0A00  /* Address offset of adapter internal
-					 * pointers 01:0a00 (high-low) have to
-					 * be read after init and before open.
-					 */
-
-
-/* Interrupt Codes (only MAC IRQs) */
-#define STS_IRQ_ADAPTER_CHECK   0x0000  /* unrecoverable hardware or
-					 * software error.
-					 */ 
-#define STS_IRQ_RING_STATUS     0x0004  /* SSB is updated with ring status. */
-#define STS_IRQ_SCB_CLEAR       0x0006  /* SCB clear, following an
-					 * SCB_REQUEST IRQ.
-					 */
-#define STS_IRQ_COMMAND_STATUS  0x0008  /* SSB is updated with command 
-					 * status.
-					 */ 
-#define STS_IRQ_RECEIVE_STATUS  0x000A  /* SSB is updated with receive
-					 * status.
-					 */
-#define STS_IRQ_TRANSMIT_STATUS 0x000C  /* SSB is updated with transmit
-                                         * status
-					 */
-#define STS_IRQ_MASK            0x000F  /* = STS_ERROR_MASK. */
-
-
-/* TRANSMIT_STATUS completion code: (SSB.Parm[0]) */
-#define COMMAND_COMPLETE        0x0080  /* TRANSMIT command completed
-                                         * (avoid this!) issue another transmit
-					 * to send additional frames.
-					 */
-#define FRAME_COMPLETE          0x0040  /* Frame has been transmitted;
-					 * INTERRUPT_FRAME bit was set in the
-					 * CSTAT request; indication of possibly
-					 * more than one frame transmissions!
-					 * SSB.Parm[0-1]: 32 bit pointer to
-					 * TPL of last frame.
-					 */
-#define LIST_ERROR              0x0020  /* Error in one of the TPLs that
-					 * compose the frame; TRANSMIT
-					 * terminated; Parm[1-2]: 32 bit pointer
-					 * to TPL which starts the error
-					 * frame; error details in bits 8-13.
-					 * (14?)
-					 */
-#define FRAME_SIZE_ERROR        0x8000  /* FRAME_SIZE does not equal the sum of
-					 * the valid DATA_COUNT fields;
-					 * FRAME_SIZE less than header plus
-					 * information field. (15 bytes +
-					 * routing field) Or if FRAME_SIZE
-					 * was specified as zero in one list.
-					 */
-#define TX_THRESHOLD            0x4000  /* FRAME_SIZE greater than (BUFFER_SIZE
-					 * - 9) * TX_BUF_MAX.
-					 */
-#define ODD_ADDRESS             0x2000  /* Odd forward pointer value is
-					 * read on a list without END_FRAME
-					 * indication.
-					 */
-#define FRAME_ERROR             0x1000  /* START_FRAME bit is (not) anticipated,
-					 * but (not) set.
-					 */
-#define ACCESS_PRIORITY_ERROR   0x0800  /* Access priority requested has not
-					 * been allowed.
-					 */
-#define UNENABLED_MAC_FRAME     0x0400  /* MAC frame has source class of zero
-					 * or MAC frame PCF ATTN field is
-					 * greater than one.
-					 */
-#define ILLEGAL_FRAME_FORMAT    0x0200  /* Bit 0 or FC field was set to one. */
-
-
-/*
- * Since we need to support some functions even if the adapter is in a
- * CLOSED state, we have a (pseudo-) command queue which holds commands
- * that are outstandig to be executed.
- *
- * Each time a command completes, an interrupt occurs and the next
- * command is executed. The command queue is actually a simple word with 
- * a bit for each outstandig command. Therefore the commands will not be
- * executed in the order they have been queued.
- *
- * The following defines the command code bits and the command queue:
- */
-#define OC_OPEN                 0x0001	/* OPEN command */
-#define OC_TRANSMIT             0x0002  /* TRANSMIT command */
-#define OC_TRANSMIT_HALT        0x0004  /* TRANSMIT_HALT command */
-#define OC_RECEIVE              0x0008  /* RECEIVE command */
-#define OC_CLOSE                0x0010  /* CLOSE command */
-#define OC_SET_GROUP_ADDR       0x0020  /* SET_GROUP_ADDR command */
-#define OC_SET_FUNCT_ADDR       0x0040  /* SET_FUNCT_ADDR command */
-#define OC_READ_ERROR_LOG       0x0080  /* READ_ERROR_LOG command */
-#define OC_READ_ADAPTER         0x0100  /* READ_ADAPTER command */
-#define OC_MODIFY_OPEN_PARMS    0x0400  /* MODIFY_OPEN_PARMS command */
-#define OC_RESTORE_OPEN_PARMS   0x0800  /* RESTORE_OPEN_PARMS command */
-#define OC_SET_FIRST_16_GROUP   0x1000  /* SET_FIRST_16_GROUP command */
-#define OC_SET_BRIDGE_PARMS     0x2000  /* SET_BRIDGE_PARMS command */
-#define OC_CONFIG_BRIDGE_PARMS  0x4000  /* CONFIG_BRIDGE_PARMS command */
-
-#define OPEN			0x0300  /* C: open command. S: completion. */
-#define TRANSMIT		0x0400  /* C: transmit command. S: completion
-					 * status. (reject: COMMAND_REJECT if
-					 * adapter not opened, TRANSMIT already
-					 * issued or address passed in the SCB
-					 * not word aligned)
-					 */
-#define TRANSMIT_HALT		0x0500  /* C: interrupt TX TPL chain; if no
-					 * TRANSMIT command issued, the command
-					 * is ignored. (completion with TRANSMIT
-					 * status (0x0400)!)
-					 */
-#define RECEIVE			0x0600  /* C: receive command. S: completion
-					 * status. (reject: COMMAND_REJECT if
-					 * adapter not opened, RECEIVE already
-					 * issued or address passed in the SCB 
-					 * not word aligned)
-					 */
-#define CLOSE			0x0700  /* C: close adapter. S: completion.
-					 * (COMMAND_REJECT if adapter not open)
-					 */
-#define SET_GROUP_ADDR		0x0800  /* C: alter adapter group address after
-					 * OPEN.  S: completion. (COMMAND_REJECT
-					 * if adapter not open)
-					 */
-#define SET_FUNCT_ADDR		0x0900  /* C: alter adapter functional address
-					 * after OPEN. S: completion.
-					 * (COMMAND_REJECT if adapter not open)
-					 */
-#define READ_ERROR_LOG		0x0A00  /* C: read adapter error counters.
-					 * S: completion. (command ignored
-					 * if adapter not open!)
-					 */
-#define READ_ADAPTER		0x0B00  /* C: read data from adapter memory.
-					 * (important: after init and before
-					 * open!) S: completion. (ADAPTER_CHECK
-					 * interrupt if undefined storage area
-					 * read)
-					 */
-#define MODIFY_OPEN_PARMS	0x0D00  /* C: modify some adapter operational
-					 * parameters. (bit correspondend to
-					 * WRAP_INTERFACE is ignored)
-					 * S: completion. (reject: 
-					 * COMMAND_REJECT)
-					 */
-#define RESTORE_OPEN_PARMS	0x0E00  /* C: modify some adapter operational
-					 * parameters. (bit correspondend
-					 * to WRAP_INTERFACE is ignored)
-					 * S: completion. (reject:
-					 * COMMAND_REJECT)
-					 */
-#define SET_FIRST_16_GROUP	0x0F00  /* C: alter the first two bytes in
-					 * adapter group address.
-					 * S: completion. (reject:
-					 * COMMAND_REJECT)
-					 */
-#define SET_BRIDGE_PARMS	0x1000  /* C: values and conditions for the
-					 * adapter hardware to use when frames
-					 * are copied for forwarding.
-					 * S: completion. (reject:
-					 * COMMAND_REJECT)
-					 */
-#define CONFIG_BRIDGE_PARMS 0x1100	/* C: ..
-					 * S: completion. (reject:
-					 * COMMAND_REJECT)
-					 */
-
-#define SPEED_4         4
-#define SPEED_16        16	/* Default transmission speed  */
-
-
-/* Initialization Parameter Block (IPB); word alignment necessary! */
-#define BURST_SIZE      0x0018  /* Default burst size */
-#define BURST_MODE      0x9F00  /* Burst mode enable */
-#define DMA_RETRIES     0x0505  /* Magic DMA retry number... */
-
-#define CYCLE_TIME      3	/* Default AT-bus cycle time: 500 ns
-				 * (later adapter version: fix  cycle time!)
-				 */
-#define LINE_SPEED_BIT	0x80
-
-/* Macro definition for the wait function. */
-#define ONE_SECOND_TICKS	1000000
-#define HALF_SECOND		(ONE_SECOND_TICKS / 2)
-#define ONE_SECOND		(ONE_SECOND_TICKS)
-#define TWO_SECONDS		(ONE_SECOND_TICKS * 2)
-#define THREE_SECONDS		(ONE_SECOND_TICKS * 3)
-#define FOUR_SECONDS		(ONE_SECOND_TICKS * 4)
-#define FIVE_SECONDS		(ONE_SECOND_TICKS * 5)
-
-#define BUFFER_SIZE 2048	/* Buffers on Adapter */
-
-#pragma pack(1)
-typedef struct {
-	unsigned short Init_Options;	/* Initialize with burst mode;
-					 * LLC disabled. (MAC only)
-					 */
-
-	/* Interrupt vectors the adapter places on attached system bus. */
-	unsigned char CMD_Status_IV;	/* Interrupt vector: command status. */
-	unsigned char TX_IV;     	/* Interrupt vector: transmit. */
-	unsigned char RX_IV;     	/* Interrupt vector: receive. */
-	unsigned char Ring_Status_IV;	/* Interrupt vector: ring status. */
-	unsigned char SCB_Clear_IV;  	/* Interrupt vector: SCB clear. */
-	unsigned char Adapter_CHK_IV;	/* Interrupt vector: adapter check. */
-
-	unsigned short RX_Burst_Size;	/* Max. number of transfer cycles. */
-	unsigned short TX_Burst_Size;	/* During DMA burst; even value! */
-	unsigned short DMA_Abort_Thrhld; /* Number of DMA retries. */
-
-	unsigned long SCB_Addr;	/* SCB address: even, word aligned, high-low. */
-	unsigned long SSB_Addr;	/* SSB address: even, word aligned, high-low. */
-} IPB, *IPB_Ptr;
-#pragma pack()
-
-/*
- * OPEN Command Parameter List (OCPL) (can be reused, if the adapter has to
- * be reopened)
- */
-#define BUFFER_SIZE	2048		/* Buffers on Adapter. */
-#define TPL_SIZE	8+6*TX_FRAG_NUM /* Depending on fragments per TPL. */
-#define RPL_SIZE	14		/* (with TI firmware v2.26 handling
-					 * up to nine fragments possible)
-					 */
-#define TX_BUF_MIN      20		/* ??? (Stephan: calculation with */
-#define TX_BUF_MAX      40		/* BUFFER_SIZE and MAX_FRAME_SIZE) ??? 
-					 */
-#define DISABLE_EARLY_TOKEN_RELEASE 0x1000
-
-/* OPEN Options (high-low) */
-#define WRAP_INTERFACE		0x0080	/* Inserting omitted for test
-					 * purposes; transmit data appears
-					 * as receive data. (usefull for
-					 * testing; change: CLOSE necessary)
-					 */
-#define DISABLE_HARD_ERROR	0x0040  /* On HARD_ERROR & TRANSMIT_BEACON
-					 * no RING.STATUS interrupt.
-					 */
-#define DISABLE_SOFT_ERROR	0x0020  /* On SOFT_ERROR, no RING.STATUS
-					 * interrupt.
-					 */
-#define PASS_ADAPTER_MAC_FRAMES 0x0010  /* Passing unsupported MAC frames
-					 * to system.
-					 */
-#define PASS_ATTENTION_FRAMES   0x0008  /* All changed attention MAC frames are
-					 * passed to the system.
-					 */
-#define PAD_ROUTING_FIELD	0x0004  /* Routing field is padded to 18
-					 * bytes.
-					 */
-#define FRAME_HOLD		0x0002  /* Adapter waits for entire frame before
-					 * initiating DMA transfer; otherwise:
-					 * DMA transfer initiation if internal
-					 * buffer filled.
-					 */
-#define CONTENDER		0x0001  /* Adapter participates in the monitor
-					 * contention process.
-					 */
-#define PASS_BEACON_MAC_FRAMES  0x8000  /* Adapter passes beacon MAC frames
-					 * to the system.
-					 */
-#define EARLY_TOKEN_RELEASE 	0x1000  /* Only valid in 16 Mbps operation;
-					 * 0 = ETR. (no effect in 4 Mbps
-					 * operation)
-					 */
-#define COPY_ALL_MAC_FRAMES	0x0400  /* All MAC frames are copied to
-					 * the system. (after OPEN: duplicate
-					 * address test (DAT) MAC frame is 
-					 * first received frame copied to the
-					 * system)
-					 */
-#define COPY_ALL_NON_MAC_FRAMES	0x0200  /* All non MAC frames are copied to
-					 * the system.
-					 */
-#define PASS_FIRST_BUF_ONLY	0x0100  /* Passes only first internal buffer
-					 * of each received frame; FrameSize
-					 * of RPLs must contain internal
-					 * BUFFER_SIZE bits for promiscous mode.
-					 */
-#define ENABLE_FULL_DUPLEX_SELECTION 0x2000 /* Enable the use of full-duplex
-					 * settings with bits in byte 22 in
-					 * ocpl. (new feature in firmware
-					 * version 3.09)
-					 */
-
-/* Full-duplex settings */
-#define OPEN_FULL_DUPLEX_OFF	0x0000
-#define OPEN_FULL_DUPLEX_ON	0x00c0
-#define OPEN_FULL_DUPLEX_AUTO	0x0080
-
-#define PROD_ID_SIZE	18	/* Length of product ID. */
-
-#define TX_FRAG_NUM	3	 /* Number of fragments used in one TPL. */
-#define TX_MORE_FRAGMENTS 0x8000 /* Bit set in DataCount to indicate more
-				  * fragments following.
-				  */
-
-#define ISA_MAX_ADDRESS 0x00ffffff
-
-#pragma pack(1)
-typedef struct {
-	unsigned short OPENOptions;
-	unsigned char NodeAddr[6];	/* Adapter node address; use ROM 
-					 * address
-					 */
-	unsigned long GroupAddr;	/* Multicast: high order
-					 * bytes = 0xC000
-					 */
-	unsigned long FunctAddr;	/* High order bytes = 0xC000 */
-	unsigned short RxListSize;	/* RPL size: 0 (=26), 14, 20 or
-					 * 26 bytes read by the adapter.
-					 * (Depending on the number of 
-					 * fragments/list)
-					 */
-	unsigned short TxListSize;	/* TPL size */
-	unsigned short BufSize;		/* Is automatically rounded up to the
-					 * nearest nK boundary.
-					 */
-	unsigned short FullDuplex;
-	unsigned short Reserved;
-	unsigned char TXBufMin;		/* Number of adapter buffers reserved
-					 * for transmission a minimum of 2
-					 * buffers must be allocated.
-					 */
-	unsigned char TXBufMax;		/* Maximum number of adapter buffers
-					 * for transmit; a minimum of 2 buffers
-					 * must be available for receive.
-					 * Default: 6
-					 */
-	unsigned short ProdIDAddr[2];	/* Pointer to product ID. */
-} OPB, *OPB_Ptr;
-#pragma pack()
-
-/*
- * SCB: adapter commands enabled by the host system started by writing
- * CMD_INTERRUPT_ADAPTER | CMD_EXECUTE (|SCB_REQUEST) to the SIFCMD IO
- * register. (special case: | CMD_SYSTEM_IRQ for initialization)
- */
-#pragma pack(1)
-typedef struct {
-	unsigned short CMD;	/* Command code */
-	unsigned short Parm[2];	/* Pointer to Command Parameter Block */
-} SCB;	/* System Command Block (32 bit physical address; big endian)*/
-#pragma pack()
-
-/*
- * SSB: adapter command return status can be evaluated after COMMAND_STATUS
- * adapter to system interrupt after reading SSB, the availability of the SSB
- * has to be told the adapter by writing CMD_INTERRUPT_ADAPTER | CMD_SSB_CLEAR
- * in the SIFCMD IO register.
- */
-#pragma pack(1)
-typedef struct {
-	unsigned short STS;	/* Status code */
-	unsigned short Parm[3];	/* Parameter or pointer to Status Parameter
-				 * Block.
-				 */
-} SSB;	/* System Status Block (big endian - physical address)  */
-#pragma pack()
-
-typedef struct {
-	unsigned short BurnedInAddrPtr;	/* Pointer to adapter burned in
-					 * address. (BIA)
-					 */
-	unsigned short SoftwareLevelPtr;/* Pointer to software level data. */
-	unsigned short AdapterAddrPtr;	/* Pointer to adapter addresses. */
-	unsigned short AdapterParmsPtr;	/* Pointer to adapter parameters. */
-	unsigned short MACBufferPtr;	/* Pointer to MAC buffer. (internal) */
-	unsigned short LLCCountersPtr;	/* Pointer to LLC counters.  */
-	unsigned short SpeedFlagPtr;	/* Pointer to data rate flag.
-					 * (4/16 Mbps)
-					 */
-	unsigned short AdapterRAMPtr;	/* Pointer to adapter RAM found. (KB) */
-} INTPTRS;	/* Adapter internal pointers */
-
-#pragma pack(1)
-typedef struct {
-	unsigned char Line_Error;	/* Line error: code violation in
-					 * frame or in a token, or FCS error.
-					 */
-	unsigned char Internal_Error;	/* IBM specific. (Reserved_1) */
-	unsigned char Burst_Error;
-	unsigned char ARI_FCI_Error;	/* ARI/FCI bit zero in AMP or
-					 * SMP MAC frame.
-					 */
-	unsigned char AbortDelimeters;	/* IBM specific. (Reserved_2) */
-	unsigned char Reserved_3;
-	unsigned char Lost_Frame_Error;	/* Receive of end of transmitted
-					 * frame failed.
-					 */
-	unsigned char Rx_Congest_Error;	/* Adapter in repeat mode has not
-					 * enough buffer space to copy incoming
-					 * frame.
-					 */
-	unsigned char Frame_Copied_Error;/* ARI bit not zero in frame
-					 * addressed to adapter.
-					 */
-	unsigned char Frequency_Error;	/* IBM specific. (Reserved_4) */
-	unsigned char Token_Error;	/* (active only in monitor station) */
-	unsigned char Reserved_5;
-	unsigned char DMA_Bus_Error;	/* DMA bus errors not exceeding the
-					 * abort thresholds.
-					 */
-	unsigned char DMA_Parity_Error;	/* DMA parity errors not exceeding
-					 * the abort thresholds.
-					 */
-} ERRORTAB;	/* Adapter error counters */
-#pragma pack()
-
-
-/*--------------------- Send and Receive definitions -------------------*/
-#pragma pack(1)
-typedef struct {
-	unsigned short DataCount;	/* Value 0, even and odd values are
-					 * permitted; value is unaltered most
-					 * significant bit set: following
-					 * fragments last fragment: most
-					 * significant bit is not evaluated.
-					 * (???)
-					 */
-	unsigned long DataAddr;		/* Pointer to frame data fragment;
-					 * even or odd.
-					 */
-} Fragment;
-#pragma pack()
-
-#define MAX_FRAG_NUMBERS    9	/* Maximal number of fragments possible to use
-				 * in one RPL/TPL. (depending on TI firmware 
-				 * version)
-				 */
-#define MAX_TX_QUEUE	    10	/* Maximal number of skb's queued in driver. */
-
-/*
- * AC (1), FC (1), Dst (6), Src (6), RIF (18), Data (4472) = 4504
- * The packet size can be one of the follows: 548, 1502, 2084, 4504, 8176,
- * 11439, 17832. Refer to TMS380 Second Generation Token Ring User's Guide
- * Page 2-27.
- */
-#define HEADER_SIZE		(1 + 1 + 6 + 6)
-#define SRC_SIZE		18
-#define MIN_DATA_SIZE		516
-#define DEFAULT_DATA_SIZE	4472
-#define MAX_DATA_SIZE		17800
-
-#define DEFAULT_PACKET_SIZE (HEADER_SIZE + SRC_SIZE + DEFAULT_DATA_SIZE)
-#define MIN_PACKET_SIZE     (HEADER_SIZE + SRC_SIZE + MIN_DATA_SIZE)
-#define MAX_PACKET_SIZE     (HEADER_SIZE + SRC_SIZE + MAX_DATA_SIZE)
-
-/*
- * Macros to deal with the frame status field.
- */
-#define AC_NOT_RECOGNIZED	0x00
-#define GROUP_BIT		0x80
-#define GET_TRANSMIT_STATUS_HIGH_BYTE(Ts) ((unsigned char)((Ts) >> 8))
-#define GET_FRAME_STATUS_HIGH_AC(Fs)	  ((unsigned char)(((Fs) & 0xC0) >> 6))
-#define GET_FRAME_STATUS_LOW_AC(Fs)       ((unsigned char)(((Fs) & 0x0C) >> 2))
-#define DIRECTED_FRAME(Context)           (!((Context)->MData[2] & GROUP_BIT))
-
-
-/*--------------------- Send Functions ---------------------------------*/
-/* define TX_CSTAT _REQUEST (R) and _COMPLETE (C) values (high-low) */
-
-#define TX_VALID		0x0080	/* R: set via TRANSMIT.VALID interrupt.
-					 * C: always reset to zero!
-					 */
-#define TX_FRAME_COMPLETE	0x0040	/* R: must be reset to zero.
-					 * C: set to one.
-					 */
-#define TX_START_FRAME		0x0020  /* R: start of a frame: 1 
-					 * C: unchanged.
-					 */
-#define TX_END_FRAME		0x0010  /* R: end of a frame: 1
-					 * C: unchanged.
-					 */
-#define TX_FRAME_IRQ		0x0008  /* R: request interrupt generation
-					 * after transmission.
-					 * C: unchanged.
-					 */
-#define TX_ERROR		0x0004  /* R: reserved.
-					 * C: set to one if Error occurred.
-					 */
-#define TX_INTERFRAME_WAIT	0x0004
-#define TX_PASS_CRC		0x0002  /* R: set if CRC value is already
-					 * calculated. (valid only in
-					 * FRAME_START TPL)
-					 * C: unchanged.
-					 */
-#define TX_PASS_SRC_ADDR	0x0001  /* R: adapter uses explicit frame
-					 * source address and does not overwrite
-					 * with the adapter node address.
-					 * (valid only in FRAME_START TPL)
-					 *
-					 * C: unchanged.
-					 */
-#define TX_STRIP_FS		0xFF00  /* R: reserved.
-					 * C: if no Transmission Error,
-					 * field contains copy of FS byte after
-					 * stripping of frame.
-					 */
-
-/*
- * Structure of Transmit Parameter Lists (TPLs) (only one frame every TPL,
- * but possibly multiple TPLs for one frame) the length of the TPLs has to be
- * initialized in the OPL. (OPEN parameter list)
- */
-#define TPL_NUM		3	/* Number of Transmit Parameter Lists.
-				 * !! MUST BE >= 3 !!
-				 */
-
-#pragma pack(1)
-typedef struct s_TPL TPL;
-
-struct s_TPL {	/* Transmit Parameter List (align on even word boundaries) */
-	unsigned long NextTPLAddr;	/* Pointer to next TPL in chain; if
-					 * pointer is odd: this is the last
-					 * TPL. Pointing to itself can cause
-					 * problems!
-					 */
-	volatile unsigned short Status;	/* Initialized by the adapter:
-					 * CSTAT_REQUEST important: update least
-					 * significant bit first! Set by the
-					 * adapter: CSTAT_COMPLETE status.
-					 */
-	unsigned short FrameSize;	/* Number of bytes to be transmitted
-					 * as a frame including AC/FC,
-					 * Destination, Source, Routing field
-					 * not including CRC, FS, End Delimiter
-					 * (valid only if START_FRAME bit in 
-					 * CSTAT nonzero) must not be zero in
-					 * any list; maximum value: (BUFFER_SIZE
-					 * - 8) * TX_BUF_MAX sum of DataCount
-					 * values in FragmentList must equal
-					 * Frame_Size value in START_FRAME TPL!
-					 * frame data fragment list.
-					 */
-
-	/* TPL/RPL size in OPEN parameter list depending on maximal
-	 * numbers of fragments used in one parameter list.
-	 */
-	Fragment FragList[TX_FRAG_NUM];	/* Maximum: nine frame fragments in one
-					 * TPL actual version of firmware: 9
-					 * fragments possible.
-					 */
-#pragma pack()
-
-	/* Special proprietary data and precalculations */
-
-	TPL *NextTPLPtr;		/* Pointer to next TPL in chain. */
-	unsigned char *MData;
-	struct sk_buff *Skb;
-	unsigned char TPLIndex;
-	volatile unsigned char BusyFlag;/* Flag: TPL busy? */
-};
-
-/* ---------------------Receive Functions-------------------------------*
- * define RECEIVE_CSTAT_REQUEST (R) and RECEIVE_CSTAT_COMPLETE (C) values.
- * (high-low)
- */
-#define RX_VALID		0x0080	/* R: set; tell adapter with
-					 * RECEIVE.VALID interrupt.
-					 * C: reset to zero.
-					 */
-#define RX_FRAME_COMPLETE	0x0040  /* R: must be reset to zero,
-					 * C: set to one.
-					 */
-#define RX_START_FRAME		0x0020  /* R: must be reset to zero.
-					 * C: set to one on the list.
-					 */
-#define RX_END_FRAME		0x0010  /* R: must be reset to zero.
-					 * C: set to one on the list
-					 * that ends the frame.
-					 */
-#define RX_FRAME_IRQ		0x0008  /* R: request interrupt generation
-					 * after receive.
-					 * C: unchanged.
-					 */
-#define RX_INTERFRAME_WAIT	0x0004  /* R: after receiving a frame:
-					 * interrupt and wait for a
-					 * RECEIVE.CONTINUE.
-					 * C: unchanged.
-					 */
-#define RX_PASS_CRC		0x0002  /* R: if set, the adapter includes
-					 * the CRC in data passed. (last four 
-					 * bytes; valid only if FRAME_START is
-					 * set)
-					 * C: set, if CRC is included in
-					 * received data.
-					 */
-#define RX_PASS_SRC_ADDR	0x0001  /* R: adapter uses explicit frame
-					 * source address and does not
-					 * overwrite with the adapter node
-					 * address. (valid only if FRAME_START
-					 * is set)
-					 * C: unchanged.
-					 */
-#define RX_RECEIVE_FS		0xFC00  /* R: reserved; must be reset to zero.
-					 * C: on lists with START_FRAME, field
-					 * contains frame status field from
-					 * received frame; otherwise cleared.
-					 */
-#define RX_ADDR_MATCH		0x0300  /* R: reserved; must be reset to zero.
-					 * C: address match code mask.
-					 */ 
-#define RX_STATUS_MASK		0x00FF  /* Mask for receive status bits. */
-
-#define RX_INTERN_ADDR_MATCH    0x0100  /* C: internally address match. */
-#define RX_EXTERN_ADDR_MATCH    0x0200  /* C: externally matched via
-					 * XMATCH/XFAIL interface.
-					 */
-#define RX_INTEXT_ADDR_MATCH    0x0300  /* C: internally and externally
-					 * matched.
-					 */
-#define RX_READY (RX_VALID | RX_FRAME_IRQ) /* Ready for receive. */
-
-/* Constants for Command Status Interrupt.
- * COMMAND_REJECT status field bit functions (SSB.Parm[0])
- */
-#define ILLEGAL_COMMAND		0x0080	/* Set if an unknown command
-					 * is issued to the adapter
-					 */
-#define ADDRESS_ERROR		0x0040  /* Set if any address field in
-					 * the SCB is odd. (not word aligned)
-					 */
-#define ADAPTER_OPEN		0x0020  /* Command issued illegal with
-					 * open adapter.
-					 */
-#define ADAPTER_CLOSE		0x0010  /* Command issued illegal with
-					 * closed adapter.
-					 */
-#define SAME_COMMAND		0x0008  /* Command issued with same command
-					 * already executing.
-					 */
-
-/* OPEN_COMPLETION values (SSB.Parm[0], MSB) */
-#define NODE_ADDR_ERROR		0x0040  /* Wrong address or BIA read
-					 * zero address.
-					 */
-#define LIST_SIZE_ERROR		0x0020  /* If List_Size value not in 0,
-					 * 14, 20, 26.
-					 */
-#define BUF_SIZE_ERROR		0x0010  /* Not enough available memory for
-					 * two buffers.
-					 */
-#define TX_BUF_COUNT_ERROR	0x0004  /* Remaining receive buffers less than
-					 * two.
-					 */
-#define OPEN_ERROR		0x0002	/* Error during ring insertion; more
-					 * information in bits 8-15.
-					 */
-
-/* Standard return codes */
-#define GOOD_COMPLETION		0x0080  /* =OPEN_SUCCESSFULL */
-#define INVALID_OPEN_OPTION	0x0001  /* OPEN options are not supported by
-					 * the adapter.
-					 */
-
-/* OPEN phases; details of OPEN_ERROR (SSB.Parm[0], LSB)            */
-#define OPEN_PHASES_MASK            0xF000  /* Check only the bits 8-11. */
-#define LOBE_MEDIA_TEST             0x1000
-#define PHYSICAL_INSERTION          0x2000
-#define ADDRESS_VERIFICATION        0x3000
-#define PARTICIPATION_IN_RING_POLL  0x4000
-#define REQUEST_INITIALISATION      0x5000
-#define FULLDUPLEX_CHECK            0x6000
-
-/* OPEN error codes; details of OPEN_ERROR (SSB.Parm[0], LSB) */
-#define OPEN_ERROR_CODES_MASK	0x0F00  /* Check only the bits 12-15. */
-#define OPEN_FUNCTION_FAILURE   0x0100  /* Unable to transmit to itself or
-					 * frames received before insertion.
-					 */
-#define OPEN_SIGNAL_LOSS	0x0200	/* Signal loss condition detected at
-					 * receiver.
-					 */
-#define OPEN_TIMEOUT		0x0500	/* Insertion timer expired before
-					 * logical insertion.
-					 */
-#define OPEN_RING_FAILURE	0x0600	/* Unable to receive own ring purge
-					 * MAC frames.
-					 */
-#define OPEN_RING_BEACONING	0x0700	/* Beacon MAC frame received after
-					 * ring insertion.
-					 */
-#define OPEN_DUPLICATE_NODEADDR	0x0800  /* Other station in ring found
-					 * with the same address.
-					 */
-#define OPEN_REQUEST_INIT	0x0900	/* RPS present but does not respond. */
-#define OPEN_REMOVE_RECEIVED    0x0A00  /* Adapter received a remove adapter
-					 * MAC frame.
-					 */
-#define OPEN_FULLDUPLEX_SET	0x0D00	/* Got this with full duplex on when
-					 * trying to connect to a normal ring.
-					 */
-
-/* SET_BRIDGE_PARMS return codes: */
-#define BRIDGE_INVALID_MAX_LEN  0x4000  /* MAX_ROUTING_FIELD_LENGTH odd,
-					 * less than 6 or > 30.
-					 */
-#define BRIDGE_INVALID_SRC_RING 0x2000  /* SOURCE_RING number zero, too large
-					 * or = TARGET_RING.
-					 */
-#define BRIDGE_INVALID_TRG_RING 0x1000  /* TARGET_RING number zero, too large
-					 * or = SOURCE_RING.
-					 */
-#define BRIDGE_INVALID_BRDGE_NO 0x0800  /* BRIDGE_NUMBER too large. */
-#define BRIDGE_INVALID_OPTIONS  0x0400  /* Invalid bridge options. */
-#define BRIDGE_DIAGS_FAILED     0x0200  /* Diagnostics of TMS380SRA failed. */
-#define BRIDGE_NO_SRA           0x0100  /* The TMS380SRA does not exist in HW
-					 * configuration.
-					 */
-
-/*
- * Bring Up Diagnostics error codes.
- */
-#define BUD_INITIAL_ERROR       0x0
-#define BUD_CHECKSUM_ERROR      0x1
-#define BUD_ADAPTER_RAM_ERROR   0x2
-#define BUD_INSTRUCTION_ERROR   0x3
-#define BUD_CONTEXT_ERROR       0x4
-#define BUD_PROTOCOL_ERROR      0x5
-#define BUD_INTERFACE_ERROR	0x6
-
-/* BUD constants */
-#define BUD_MAX_RETRIES         3
-#define BUD_MAX_LOOPCNT         6
-#define BUD_TIMEOUT             3000
-
-/* Initialization constants */
-#define INIT_MAX_RETRIES        3	/* Maximum three retries. */
-#define INIT_MAX_LOOPCNT        22      /* Maximum loop counts. */
-
-/* RING STATUS field values (high/low) */
-#define SIGNAL_LOSS             0x0080  /* Loss of signal on the ring
-					 * detected.
-					 */
-#define HARD_ERROR              0x0040  /* Transmitting or receiving beacon
-					 * frames.
-					 */
-#define SOFT_ERROR              0x0020  /* Report error MAC frame
-					 * transmitted.
-					 */
-#define TRANSMIT_BEACON         0x0010  /* Transmitting beacon frames on the
-					 * ring.
-					 */
-#define LOBE_WIRE_FAULT         0x0008  /* Open or short circuit in the
-					 * cable to concentrator; adapter
-					 * closed.
-					 */
-#define AUTO_REMOVAL_ERROR      0x0004  /* Lobe wrap test failed, deinserted;
-					 * adapter closed.
-					 */
-#define REMOVE_RECEIVED         0x0001  /* Received a remove ring station MAC
-					 * MAC frame request; adapter closed.
-					 */
-#define COUNTER_OVERFLOW        0x8000  /* Overflow of one of the adapters
-					 * error counters; READ.ERROR.LOG.
-					 */
-#define SINGLE_STATION          0x4000  /* Adapter is the only station on the
-					 * ring.
-					 */
-#define RING_RECOVERY           0x2000  /* Claim token MAC frames on the ring;
-					 * reset after ring purge frame.
-					 */
-
-#define ADAPTER_CLOSED (LOBE_WIRE_FAULT | AUTO_REMOVAL_ERROR |\
-                        REMOVE_RECEIVED)
-
-/* Adapter_check_block.Status field bit assignments: */
-#define DIO_PARITY              0x8000  /* Adapter detects bad parity
-					 * through direct I/O access.
-					 */
-#define DMA_READ_ABORT          0x4000  /* Aborting DMA read operation
-					 * from system Parm[0]: 0=timeout,
-					 * 1=parity error, 2=bus error;
-					 * Parm[1]: 32 bit pointer to host
-					 * system address at failure.
-					 */
-#define DMA_WRITE_ABORT         0x2000  /* Aborting DMA write operation
-					 * to system. (parameters analogous to
-					 * DMA_READ_ABORT)
-					 */
-#define ILLEGAL_OP_CODE         0x1000  /* Illegal operation code in the
-					 * the adapters firmware Parm[0]-2:
-					 * communications processor registers
-					 * R13-R15.
-					 */
-#define PARITY_ERRORS           0x0800  /* Adapter detects internal bus
-					 * parity error.
-					 */
-#define RAM_DATA_ERROR          0x0080  /* Valid only during RAM testing;
-					 * RAM data error Parm[0-1]: 32 bit
-					 * pointer to RAM location.
-					 */
-#define RAM_PARITY_ERROR        0x0040  /* Valid only during RAM testing;
-					 * RAM parity error Parm[0-1]: 32 bit
-					 * pointer to RAM location.
-					 */
-#define RING_UNDERRUN           0x0020  /* Internal DMA underrun when
-					 * transmitting onto ring.
-					 */
-#define INVALID_IRQ             0x0008  /* Unrecognized interrupt generated
-					 * internal to adapter Parm[0-2]:
-					 * adapter register R13-R15.
-					 */
-#define INVALID_ERROR_IRQ       0x0004  /* Unrecognized error interrupt
-					 * generated Parm[0-2]: adapter register
-					 * R13-R15.
-					 */
-#define INVALID_XOP             0x0002  /* Unrecognized XOP request in
-					 * communication processor Parm[0-2]:
-					 * adapter register R13-R15.
-					 */
-#define CHECKADDR               0x05E0  /* Adapter check status information
-					 * address offset.
-					 */
-#define ROM_PAGE_0              0x0000  /* Adapter ROM page 0. */
-
-/*
- * RECEIVE.STATUS interrupt result SSB values: (high-low)
- * (RECEIVE_COMPLETE field bit definitions in SSB.Parm[0])
- */
-#define RX_COMPLETE             0x0080  /* SSB.Parm[0]; SSB.Parm[1]: 32
-					 * bit pointer to last RPL.
-					 */
-#define RX_SUSPENDED            0x0040  /* SSB.Parm[0]; SSB.Parm[1]: 32
-					 * bit pointer to RPL with odd
-					 * forward pointer.
-					 */
-
-/* Valid receive CSTAT: */
-#define RX_FRAME_CONTROL_BITS (RX_VALID | RX_START_FRAME | RX_END_FRAME | \
-			       RX_FRAME_COMPLETE)
-#define VALID_SINGLE_BUFFER_FRAME (RX_START_FRAME | RX_END_FRAME | \
-				   RX_FRAME_COMPLETE)
-
-typedef enum SKB_STAT SKB_STAT;
-enum SKB_STAT {
-	SKB_UNAVAILABLE,
-	SKB_DMA_DIRECT,
-	SKB_DATA_COPY
-};
-
-/* Receive Parameter List (RPL) The length of the RPLs has to be initialized 
- * in the OPL. (OPEN parameter list)
- */
-#define RPL_NUM		3
-
-#define RX_FRAG_NUM     1	/* Maximal number of used fragments in one RPL.
-				 * (up to firmware v2.24: 3, now: up to 9)
-				 */
-
-#pragma pack(1)
-typedef struct s_RPL RPL;
-struct s_RPL {	/* Receive Parameter List */
-	unsigned long NextRPLAddr;	/* Pointer to next RPL in chain
-					 * (normalized = physical 32 bit
-					 * address) if pointer is odd: this
-					 * is last RPL. Pointing to itself can
-					 * cause problems!
-					 */
-	volatile unsigned short Status;	/* Set by creation of Receive Parameter
-					 * List RECEIVE_CSTAT_COMPLETE set by
-					 * adapter in lists that start or end
-					 * a frame.
-					 */
-	volatile unsigned short FrameSize; /* Number of bytes received as a
-					 * frame including AC/FC, Destination,
-					 * Source, Routing field not including 
-					 * CRC, FS (Frame Status), End Delimiter
-					 * (valid only if START_FRAME bit in 
-					 * CSTAT nonzero) must not be zero in
-					 * any list; maximum value: (BUFFER_SIZE
-					 * - 8) * TX_BUF_MAX sum of DataCount
-					 * values in FragmentList must equal
-					 * Frame_Size value in START_FRAME TPL!
-					 * frame data fragment list
-					 */
-
-	/* TPL/RPL size in OPEN parameter list depending on maximal numbers
-	 * of fragments used in one parameter list.
-	 */
-	Fragment FragList[RX_FRAG_NUM];	/* Maximum: nine frame fragments in
-					 * one TPL. Actual version of firmware:
-					 * 9 fragments possible.
-					 */
-#pragma pack()
-
-	/* Special proprietary data and precalculations. */
-	RPL *NextRPLPtr;	/* Logical pointer to next RPL in chain. */
-	unsigned char *MData;
-	struct sk_buff *Skb;
-	SKB_STAT SkbStat;
-	int RPLIndex;
-};
-
-/* Information that need to be kept for each board. */
-typedef struct net_local {
-#pragma pack(1)
-	IPB ipb;	/* Initialization Parameter Block. */
-	SCB scb;	/* System Command Block: system to adapter 
-			 * communication.
-			 */
-	SSB ssb;	/* System Status Block: adapter to system 
-			 * communication.
-			 */
-	OPB ocpl;	/* Open Options Parameter Block. */
-
-	ERRORTAB errorlogtable;	/* Adapter statistic error counters.
-				 * (read from adapter memory)
-				 */
-	unsigned char ProductID[PROD_ID_SIZE + 1]; /* Product ID */
-#pragma pack()
-
-	TPL Tpl[TPL_NUM];
-	TPL *TplFree;
-	TPL *TplBusy;
-	unsigned char LocalTxBuffers[TPL_NUM][DEFAULT_PACKET_SIZE];
-
-	RPL Rpl[RPL_NUM];
-	RPL *RplHead;
-	RPL *RplTail;
-	unsigned char LocalRxBuffers[RPL_NUM][DEFAULT_PACKET_SIZE];
-
-	int DataRate;
-	unsigned char ScbInUse;
-	unsigned short CMDqueue;
-
-	unsigned long AdapterOpenFlag:1;
-	unsigned long AdapterVirtOpenFlag:1;
-	unsigned long OpenCommandIssued:1;
-	unsigned long TransmitCommandActive:1;
-	unsigned long TransmitHaltScheduled:1;
-	unsigned long HaltInProgress:1;
-	unsigned long LobeWireFaultLogged:1;
-	unsigned long ReOpenInProgress:1;
-	unsigned long Sleeping:1;
-
-	unsigned long LastOpenStatus;
-	unsigned short CurrentRingStatus;
-	unsigned long MaxPacketSize;
-	
-	unsigned long StartTime;
-	unsigned long LastSendTime;
-
-	struct sk_buff_head SendSkbQueue;
-	unsigned short QueueSkb;
-
-	struct tr_statistics MacStat;	/* MAC statistics structure */
-
-	struct timer_list timer;
-
-	wait_queue_head_t  wait_for_tok_int;
-
-	INTPTRS intptrs;	/* Internal adapter pointer. Must be read
-				 * before OPEN command.
-				 */
-} NET_LOCAL;
-
-#endif	/* __KERNEL__ */
-#endif	/* __LINUX_SKTR_H */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/sktr_firmware.h linux/drivers/net/sktr_firmware.h
--- v2.3.20/linux/drivers/net/sktr_firmware.h	Thu Jan  7 08:46:59 1999
+++ linux/drivers/net/sktr_firmware.h	Wed Dec 31 16:00:00 1969
@@ -1,3616 +0,0 @@
-/*
- * The firmware this driver downloads into the tokenring card is a
- * separate program and is not GPL'd source code, even though the Linux
- * side driver and the routine that loads this data into the card are.
- *
- * This firmware is licensed to you strictly for use in conjunction
- * with the use of SysKonnect TokenRing adapters. There is no
- * waranty expressed or implied about its fitness for any purpose.
- */
-
-/* sktr_firmware.h: SysKonnect TokenRing driver firmware dump for Linux.
- *
- * Notes:
- *  - Loaded from sktr_reset_adapter upon adapter reset.
- *
- * Authors:
- * - Christoph Goos <cgoos@syskonnect.de>
- */
-
-#include <linux/config.h>
-
-#if defined(CONFIG_SKTR) || defined(CONFIG_SKTR_MODULE)
-
-unsigned char sktr_code[] = {
-	0x00, 0x00, 0x00, 0xA0, 0x00, 0x20, 0x68, 0x54,
-	0x73, 0x69, 0x63, 0x20, 0x64, 0x6F, 0x20, 0x65,
-	0x73, 0x69, 0x72, 0x20, 0x6C, 0x65, 0x61, 0x65,
-	0x65, 0x73, 0x20, 0x64, 0x6E, 0x75, 0x65, 0x64,
-	0x20, 0x72, 0x69, 0x6C, 0x65, 0x63, 0x63, 0x6E,
-	0x20, 0x65, 0x6E, 0x4F, 0x79, 0x6C, 0x20, 0x2C,
-	0x6C, 0x41, 0x20, 0x6C, 0x69, 0x72, 0x68, 0x67,
-	0x73, 0x74, 0x72, 0x20, 0x73, 0x65, 0x72, 0x65,
-	0x65, 0x76, 0x2E, 0x64, 0x60, 0x01, 0x42, 0x01,
-	0x00, 0x08, 0x08, 0x16, 0xB0, 0x03, 0xE0, 0x04,
-	0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0xFF, 0xFF,
-	0xFC, 0x13, 0x80, 0x03, 0xA0, 0x07, 0x42, 0x01,
-	0x00, 0x08, 0x20, 0x07, 0x00, 0x00, 0xE0, 0x04,
-	0x00, 0x01, 0x8B, 0x07, 0x00, 0x3D, 0x60, 0x01,
-	0x42, 0x01, 0x80, 0x00, 0x09, 0x13, 0x8B, 0x07,
-	0x00, 0x2D, 0x20, 0xC0, 0x4E, 0x01, 0x80, 0x02,
-	0x41, 0x0F, 0x02, 0x11, 0x8B, 0x07, 0x00, 0x3D,
-	0x0B, 0xC8, 0x4A, 0x01, 0x00, 0x02, 0x00, 0x90,
-	0xA0, 0x09, 0x00, 0xC8, 0x66, 0x01, 0xE0, 0x02,
-	0xA0, 0x00, 0xA0, 0x07, 0x04, 0x01, 0x20, 0x00,
-	0xA0, 0x01, 0x40, 0x01, 0x00, 0xFE, 0x20, 0x48,
-	0x2A, 0xE0, 0x42, 0x01, 0xE0, 0x04, 0x02, 0x01,
-	0xE0, 0x04, 0x60, 0x09, 0xE0, 0x04, 0x82, 0x01,
-	0x60, 0x01, 0x1C, 0x01, 0x04, 0x00, 0x03, 0x16,
-	0xE0, 0x01, 0x40, 0x01, 0x00, 0x0C, 0xA0, 0x06,
-	0xBC, 0xA1, 0xA0, 0x07, 0x04, 0x01, 0x2D, 0x00,
-	0x20, 0xC2, 0x00, 0xE0, 0x88, 0x02, 0x11, 0xE3,
-	0x14, 0x16, 0xA0, 0x07, 0x04, 0x01, 0x2E, 0x00,
-	0x60, 0x01, 0x42, 0x01, 0x00, 0x03, 0x0D, 0x16,
-	0xA0, 0x07, 0x04, 0x01, 0x21, 0x00, 0x88, 0x07,
-	0x00, 0xA0, 0x89, 0x07, 0xFE, 0xFF, 0xA8, 0x09,
-	0xA9, 0x09, 0x8A, 0x07, 0x02, 0xE0, 0xA0, 0x06,
-	0x84, 0xEC, 0x56, 0x10, 0x88, 0x07, 0x00, 0x90,
-	0x89, 0x07, 0xFE, 0x9F, 0xA8, 0x09, 0xA9, 0x09,
-	0x8A, 0x07, 0x78, 0xE0, 0xA0, 0x06, 0x84, 0xEC,
-	0x4B, 0x10, 0xA0, 0x05, 0x04, 0x01, 0x88, 0x07,
-	0x08, 0x00, 0x89, 0x07, 0x7A, 0x00, 0x00, 0x03,
-	0x01, 0x00, 0xA0, 0x06, 0xD2, 0xAC, 0x40, 0x10,
-	0xA0, 0x06, 0xBC, 0xA1, 0xE0, 0x02, 0xF4, 0x03,
-	0x88, 0x07, 0xA0, 0x00, 0x89, 0x07, 0xFE, 0x00,
-	0xA0, 0x06, 0xD2, 0xAC, 0x35, 0x10, 0xE0, 0x02,
-	0xA0, 0x00, 0xE0, 0x04, 0x7E, 0x01, 0xC8, 0x04,
-	0x09, 0x02, 0xF2, 0x03, 0x48, 0x62, 0xE0, 0xC1,
-	0x40, 0x01, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x04,
-	0x18, 0xCE, 0x09, 0x06, 0xFD, 0x16, 0xA0, 0x01,
-	0x40, 0x01, 0x00, 0x40, 0x07, 0xC8, 0x40, 0x01,
-	0x88, 0x07, 0xF4, 0x03, 0x89, 0x07, 0xFE, 0x3F,
-	0xA0, 0x06, 0xD2, 0xAC, 0x19, 0x10, 0xE0, 0x02,
-	0xA0, 0x00, 0xA0, 0x06, 0xFA, 0xAD, 0x14, 0x10,
-	0x08, 0xC8, 0x44, 0x04, 0x09, 0xC8, 0x46, 0x04,
-	0xA0, 0x06, 0x28, 0xAD, 0x0D, 0x10, 0x81, 0x07,
-	0x7C, 0xE0, 0xB1, 0xC0, 0x26, 0x13, 0x01, 0xC8,
-	0xE0, 0x00, 0xA0, 0x05, 0x04, 0x01, 0x92, 0x06,
-	0x03, 0x10, 0x60, 0xC0, 0xE0, 0x00, 0xF5, 0x10,
-	0xE0, 0x01, 0x04, 0x01, 0x10, 0x00, 0xB0, 0x03,
-	0xFF, 0x10, 0xA0, 0x01, 0x04, 0x01, 0x00, 0x80,
-	0x80, 0x03, 0x80, 0x07, 0xA0, 0x00, 0xC2, 0x04,
-	0x80, 0xCC, 0x81, 0x07, 0xAA, 0xA1, 0x82, 0x02,
-	0x1E, 0x00, 0x02, 0x16, 0x81, 0x07, 0xB4, 0xA1,
-	0x81, 0xC4, 0x81, 0x8C, 0xE9, 0x16, 0x82, 0x02,
-	0x7C, 0x00, 0xF2, 0x16, 0x00, 0x03, 0x0F, 0x00,
-	0x5B, 0x04, 0x81, 0x07, 0x08, 0xE1, 0x82, 0x07,
-	0x04, 0x00, 0xE0, 0x04, 0x80, 0x01, 0xE0, 0x04,
-	0x82, 0x01, 0x91, 0xC4, 0xB1, 0x8C, 0xD8, 0x16,
-	0x82, 0x02, 0x7C, 0x00, 0xFA, 0x16, 0x20, 0xC8,
-	0x04, 0xE0, 0x82, 0x01, 0x20, 0xE8, 0x0C, 0xE0,
-	0x82, 0x01, 0x20, 0xC8, 0x10, 0xE0, 0x80, 0x01,
-	0x81, 0x07, 0x86, 0xE0, 0xB1, 0xC0, 0x07, 0x13,
-	0xB1, 0xC4, 0xFC, 0x10, 0xA0, 0x07, 0x04, 0x01,
-	0x2E, 0x00, 0x60, 0x04, 0xAA, 0xA1, 0x81, 0x07,
-	0x34, 0xE0, 0x82, 0x07, 0xFC, 0x05, 0x83, 0x07,
-	0x0A, 0x00, 0xB1, 0xCC, 0x43, 0x06, 0xFD, 0x16,
-	0x02, 0x02, 0x00, 0x06, 0x60, 0xD0, 0x4E, 0x01,
-	0xED, 0x13, 0x21, 0x02, 0x00, 0xF7, 0x21, 0x02,
-	0x00, 0xC0, 0x81, 0xDC, 0x60, 0xD0, 0x4F, 0x01,
-	0xC1, 0xC0, 0x41, 0x09, 0x21, 0x02, 0x00, 0xF0,
-	0x81, 0xDC, 0x43, 0x02, 0x00, 0x0F, 0x23, 0x02,
-	0x00, 0xF0, 0x83, 0xDC, 0x01, 0x02, 0x32, 0x0C,
-	0xA0, 0xC0, 0x44, 0x04, 0xE0, 0xC0, 0x46, 0x04,
-	0x03, 0xC1, 0x02, 0x61, 0x84, 0x05, 0x04, 0xC8,
-	0x48, 0x04, 0x03, 0xC1, 0x84, 0x05, 0x04, 0xA1,
-	0x01, 0xA1, 0x04, 0xC8, 0x30, 0x0C, 0x03, 0xC1,
-	0x84, 0x05, 0xF1, 0x04, 0x04, 0x06, 0xFD, 0x16,
-	0x08, 0x02, 0x00, 0xA0, 0xA8, 0x09, 0x60, 0xC2,
-	0x30, 0x0C, 0x29, 0x02, 0xFF, 0x03, 0xA9, 0x09,
-	0x29, 0x02, 0x40, 0x00, 0x80, 0x07, 0x00, 0x90,
-	0xA0, 0x09, 0x8A, 0x07, 0xFE, 0x9F, 0x2A, 0x02,
-	0xFF, 0x03, 0xAA, 0x09, 0x01, 0x02, 0x32, 0x0C,
-	0x05, 0x02, 0x00, 0x00, 0x03, 0xC1, 0x84, 0x05,
-	0x11, 0x07, 0xC1, 0x05, 0x85, 0x05, 0x04, 0x06,
-	0x0B, 0x13, 0x85, 0x80, 0xF9, 0x1A, 0x05, 0x80,
-	0xF8, 0x1A, 0x85, 0x82, 0xF5, 0x1A, 0x05, 0x82,
-	0xF4, 0x1A, 0x45, 0x82, 0xF1, 0x1A, 0xF1, 0x10,
-	0x20, 0x2D, 0x02, 0x00, 0x60, 0x01, 0x40, 0x01,
-	0x00, 0x40, 0x06, 0x16, 0x8A, 0x07, 0x00, 0x08,
-	0xA0, 0x01, 0x40, 0x01, 0x00, 0x40, 0x48, 0x10,
-	0x60, 0x01, 0x42, 0x01, 0x00, 0x80, 0x06, 0x16,
-	0x8A, 0x07, 0x00, 0x10, 0xA0, 0x01, 0x42, 0x01,
-	0x00, 0x80, 0x3E, 0x10, 0x60, 0x01, 0x02, 0x01,
-	0x00, 0x10, 0x0A, 0x16, 0x60, 0x01, 0x00, 0x01,
-	0x00, 0x04, 0x06, 0x16, 0x8A, 0x07, 0x00, 0x80,
-	0xA0, 0x01, 0x02, 0x01, 0x00, 0x10, 0x30, 0x10,
-	0x60, 0x01, 0x02, 0x01, 0x00, 0x08, 0x0A, 0x16,
-	0x60, 0x01, 0x00, 0x01, 0x00, 0x04, 0x06, 0x16,
-	0xA0, 0x01, 0x02, 0x01, 0x00, 0x08, 0x0D, 0x02,
-	0x01, 0x00, 0x0D, 0x10, 0x60, 0x01, 0x02, 0x01,
-	0x00, 0x04, 0x16, 0x16, 0x60, 0x01, 0x00, 0x01,
-	0x00, 0x08, 0x12, 0x16, 0xA0, 0x01, 0x02, 0x01,
-	0x00, 0x04, 0x0D, 0x02, 0x02, 0x00, 0xA0, 0xC3,
-	0x0E, 0x01, 0xE0, 0xC3, 0x10, 0x01, 0x8A, 0x07,
-	0x00, 0x20, 0x60, 0x01, 0x00, 0x01, 0x00, 0x80,
-	0x0B, 0x13, 0x8A, 0x07, 0x00, 0x40, 0x08, 0x10,
-	0x8A, 0x07, 0x04, 0x00, 0x05, 0x10, 0x8A, 0x07,
-	0x02, 0x00, 0x02, 0x10, 0x8A, 0x07, 0x08, 0x00,
-	0x00, 0x03, 0x00, 0x00, 0xE0, 0x04, 0x82, 0x01,
-	0x8B, 0x07, 0xE0, 0x05, 0xCA, 0xCE, 0xCD, 0xCE,
-	0xCE, 0xCE, 0xCF, 0xC6, 0x20, 0xC3, 0x58, 0x07,
-	0x20, 0x23, 0x04, 0xE0, 0x12, 0x13, 0x8B, 0x07,
-	0x18, 0xFF, 0x8A, 0x02, 0x00, 0x80, 0x0A, 0x13,
-	0x8B, 0x05, 0xCD, 0xA2, 0x8A, 0x02, 0x00, 0x40,
-	0x05, 0x13, 0x8A, 0x02, 0x00, 0x20, 0x02, 0x13,
-	0x8B, 0x07, 0x1D, 0xFF, 0x0B, 0xC8, 0x04, 0x01,
-	0x0D, 0x10, 0x20, 0xD3, 0x05, 0x01, 0xFD, 0x11,
-	0x20, 0xD8, 0xDF, 0x07, 0x17, 0x01, 0x8B, 0x07,
-	0x80, 0xFF, 0x0B, 0xC8, 0x04, 0x01, 0x20, 0xE8,
-	0x0A, 0xE0, 0x00, 0x01, 0xE0, 0xC2, 0x04, 0x01,
-	0xE0, 0x22, 0x86, 0xE1, 0xFB, 0x16, 0xE0, 0x02,
-	0xA0, 0x00, 0xE0, 0x04, 0x82, 0x01, 0x20, 0xE8,
-	0x0A, 0xE0, 0x00, 0x01, 0xE0, 0xC2, 0x00, 0x01,
-	0xE0, 0x22, 0x06, 0xE0, 0xF8, 0x13, 0xA0, 0x01,
-	0x40, 0x01, 0x00, 0xF6, 0x60, 0x04, 0x90, 0xA0,
-	0x00, 0x03, 0x02, 0x00, 0xA0, 0x07, 0x02, 0x01,
-	0xFF, 0xDF, 0x90, 0x03, 0xFF, 0xFF, 0x80, 0x03,
-	0x00, 0x03, 0x02, 0x00, 0x09, 0x07, 0xA0, 0xC2,
-	0x04, 0x01, 0x8A, 0x01, 0x80, 0x00, 0x4A, 0x52,
-	0x89, 0xD2, 0x0A, 0xC8, 0x04, 0x01, 0xA0, 0xD2,
-	0x04, 0x01, 0xF9, 0x16, 0x49, 0x05, 0x89, 0x01,
-	0x00, 0x80, 0x49, 0x01, 0x00, 0x40, 0x0E, 0x13,
-	0x09, 0xF8, 0x3A, 0x07, 0x60, 0xC2, 0x36, 0x07,
-	0x03, 0x16, 0x90, 0x03, 0xFF, 0xFF, 0x80, 0x03,
-	0xE0, 0x04, 0x36, 0x07, 0x54, 0x04, 0x90, 0x03,
-	0xFF, 0xFF, 0x80, 0x03, 0x60, 0x22, 0x86, 0xE1,
-	0xC2, 0x13, 0xE0, 0x04, 0x82, 0x01, 0x60, 0x04,
-	0xE0, 0xA3, 0x00, 0x03, 0x02, 0x00, 0xA0, 0x07,
-	0x62, 0x09, 0xE8, 0x03, 0xC9, 0x04, 0xA0, 0xC1,
-	0x34, 0x06, 0x04, 0x16, 0xA0, 0x06, 0x50, 0xB5,
-	0xE0, 0x04, 0x20, 0x09, 0x86, 0x07, 0xE8, 0x05,
-	0xA0, 0x01, 0x40, 0x01, 0x00, 0x80, 0x20, 0xC2,
-	0x84, 0x01, 0x20, 0x48, 0x08, 0xE0, 0x84, 0x01,
-	0x20, 0x22, 0x08, 0xE0, 0x08, 0x13, 0x60, 0x01,
-	0xAE, 0x01, 0x01, 0x00, 0x04, 0x16, 0xE0, 0x01,
-	0x34, 0x06, 0x00, 0x80, 0x06, 0x10, 0x20, 0xC2,
-	0x32, 0x09, 0x06, 0x13, 0xE0, 0x01, 0x34, 0x06,
-	0x00, 0x08, 0xE0, 0x04, 0x30, 0x06, 0x09, 0x07,
-	0xA0, 0x05, 0xEE, 0x05, 0x20, 0x06, 0xEC, 0x05,
-	0x02, 0x16, 0x16, 0xC2, 0x03, 0x16, 0x49, 0xC2,
-	0x12, 0x16, 0x80, 0x03, 0x98, 0xC5, 0xE8, 0xC1,
-	0x02, 0x00, 0xE0, 0xE9, 0x14, 0xE0, 0x04, 0x00,
-	0xD7, 0x04, 0x27, 0x02, 0x08, 0x00, 0xA0, 0x06,
-	0xE6, 0xB4, 0x16, 0xC2, 0x04, 0x13, 0x28, 0xC8,
-	0x08, 0x00, 0xEC, 0x05, 0xEF, 0x13, 0x54, 0x04,
-	0x00, 0x03, 0x02, 0x00, 0xE0, 0xC1, 0x86, 0x01,
-	0x47, 0x02, 0x0E, 0x00, 0xA7, 0xC2, 0x90, 0xE1,
-	0x5A, 0x04, 0x8A, 0x07, 0x00, 0xA0, 0x0A, 0xC8,
-	0x86, 0x01, 0xC7, 0xA1, 0x27, 0x02, 0x98, 0xE1,
-	0x37, 0xE8, 0x34, 0x06, 0x17, 0xE8, 0xD2, 0x06,
-	0xE0, 0x04, 0x30, 0x06, 0x60, 0x04, 0xF2, 0xA9,
-	0x0A, 0xE8, 0xD2, 0x06, 0xE0, 0x01, 0x34, 0x06,
-	0x00, 0x08, 0xE0, 0x04, 0x30, 0x06, 0x20, 0xE0,
-	0x18, 0xE0, 0x5B, 0x04, 0xA0, 0x05, 0x20, 0x09,
-	0x20, 0x88, 0x20, 0x09, 0x16, 0xE0, 0xE5, 0x1A,
-	0xE0, 0x04, 0x20, 0x09, 0xA0, 0x06, 0xD0, 0xD5,
-	0x80, 0x03, 0xA0, 0x05, 0x32, 0x09, 0x80, 0x03,
-	0x01, 0xC3, 0xFB, 0x13, 0x60, 0x01, 0x6A, 0x09,
-	0x01, 0x00, 0x78, 0x13, 0xA0, 0x05, 0x32, 0x09,
-	0x75, 0x10, 0x41, 0xC0, 0x06, 0x13, 0x01, 0xC8,
-	0x6C, 0x01, 0xE0, 0xC2, 0x02, 0xFC, 0x01, 0x11,
-	0x7B, 0x10, 0x60, 0x01, 0x9C, 0x01, 0x40, 0x00,
-	0x79, 0x16, 0x20, 0xD8, 0x2F, 0x09, 0x83, 0x01,
-	0x41, 0xC0, 0x04, 0x13, 0x01, 0xC8, 0x8A, 0x01,
-	0x01, 0xC8, 0x18, 0x09, 0x86, 0x07, 0x43, 0x00,
-	0x06, 0xC8, 0x6C, 0x01, 0x07, 0x02, 0x02, 0xFC,    
-	0x17, 0xC2, 0x60, 0x04, 0xFA, 0xA6, 0xE0, 0x04, 
-	0x18, 0x09, 0xC7, 0x61, 0x08, 0x07, 0x60, 0x01, 
-	0x06, 0xFC, 0x40, 0x00, 0x02, 0x13, 0x08, 0x02, 
-	0x01, 0x00, 0x09, 0x10, 0x4C, 0xC2, 0x20, 0xC3, 
-	0x00, 0xFC, 0x2A, 0x13, 0x0C, 0xC8, 0x6C, 0x01, 
-	0xE0, 0xC2, 0x02, 0xFC, 0x1B, 0x11, 0x4B, 0x01, 
-	0x00, 0x01, 0xF4, 0x16, 0xC8, 0x22, 0x12, 0x13, 
-	0xCB, 0x01, 0x00, 0x40, 0x0B, 0xC8, 0x02, 0xFC, 
-	0x0D, 0x10, 0xE0, 0xC1, 0x18, 0x09, 0x01, 0xC3, 
-	0x21, 0x13, 0x4C, 0xC2, 0x15, 0x13, 0x0C, 0xC8, 
-	0x6C, 0x01, 0xE0, 0xC2, 0x02, 0xFC, 0x06, 0x11, 
-	0xCC, 0x81, 0xD5, 0x13, 0x4C, 0xC2, 0x20, 0xC3, 
-	0x00, 0xFC, 0xF4, 0x10, 0x09, 0xC8, 0x6C, 0x01, 
-	0xE0, 0xC2, 0x02, 0xFC, 0x1E, 0x16, 0xA0, 0x07, 
-	0x02, 0xFC, 0x00, 0x80, 0x09, 0xC3, 0x19, 0x10, 
-	0x09, 0xC8, 0x6C, 0x01, 0xE0, 0xC2, 0x02, 0xFC, 
-	0x05, 0x16, 0xA0, 0x07, 0x02, 0xFC, 0x00, 0x80, 
-	0x09, 0xC3, 0x0F, 0x10, 0xE0, 0xC2, 0x02, 0x0C, 
-	0x01, 0x11, 0x1E, 0x10, 0x20, 0xD8, 0x00, 0xE2, 
-	0x83, 0x01, 0x8B, 0x09, 0x8B, 0x09, 0x8B, 0x09,  
-	0x8B, 0x09, 0xA0, 0x07, 0x8A, 0x01, 0x43, 0x00,  
-	0x13, 0x10, 0x0C, 0xC8, 0x8A, 0x01, 0x0C, 0xC8,  
-	0x18, 0x09, 0x0E, 0x10, 0x00, 0x03, 0x02, 0x00, 
-	0xE0, 0xC0, 0x6C, 0x01, 0x20, 0xC3, 0x8A, 0x01,  
-	0x20, 0x98, 0x83, 0x01, 0x00, 0xE2, 0x81, 0x13,  
-	0x60, 0x01, 0x9C, 0x01, 0x40, 0x00, 0xB9, 0x13, 
-	0x01, 0x83, 0x31, 0x16, 0x03, 0xC8, 0x6C, 0x01, 
-	0x40, 0x01, 0x10, 0x00, 0x14, 0x16, 0xE0, 0xC2, 
-	0x2E, 0x06, 0x11, 0x13, 0xE0, 0xC2, 0xF8, 0x05, 
-	0x0E, 0x13, 0xE0, 0x01, 0x3A, 0x07, 0x00, 0x80, 
-	0x80, 0x01, 0x10, 0x00, 0xE0, 0xC2, 0x36, 0x07, 
-	0x06, 0x13, 0xE0, 0x04, 0x36, 0x07, 0x80, 0x01, 
-	0x20, 0x00, 0x60, 0x04, 0xF2, 0xA9, 0x40, 0x01, 
-	0x20, 0x00, 0xF9, 0x13, 0x90, 0x03, 0xFF, 0x11, 
-	0x80, 0x03, 0x08, 0x01, 0x00, 0x04, 0x19, 0x16,  
-	0x60, 0x01, 0x6A, 0x09, 0x01, 0x00, 0x15, 0x16,  
-	0x88, 0x01, 0x00, 0x1A, 0xC8, 0x01, 0x00, 0x01, 
-	0xC8, 0xC5, 0x0F, 0x10, 0xE0, 0x04, 0x18, 0x09, 
-	0xC0, 0x01, 0x04, 0x00, 0x15, 0x10, 0x81, 0xC1, 
-	0x01, 0xC8, 0x6C, 0x01, 0x07, 0x02, 0x00, 0xFC, 
-	0x77, 0xC0, 0x17, 0xC2, 0x48, 0x01, 0x00, 0x18, 
-	0xE4, 0x13, 0x40, 0x01, 0x40, 0x00, 0x15, 0x16, 
-	0x80, 0x01, 0x45, 0x00, 0x46, 0xC1, 0x20, 0xD0, 
-	0x07, 0xFC, 0x60, 0x81, 0x18, 0x09, 0xE6, 0x13, 
-	0xE0, 0xC2, 0x08, 0xFC, 0x08, 0x11, 0xE0, 0xC2, 
-	0x0E, 0xFC, 0x07, 0x15, 0x06, 0x13, 0xE0, 0xC2, 
-	0x14, 0xFC, 0x03, 0x15, 0x02, 0x13, 0xC0, 0x01, 
-	0x01, 0x00, 0x48, 0x01, 0x00, 0x01, 0x11, 0x13, 
-	0x40, 0x01, 0x80, 0x40, 0x69, 0x13, 0x60, 0x04, 
-	0x66, 0xA6, 0x48, 0x01, 0x01, 0x00, 0x03, 0x16, 
-	0x40, 0x01, 0x00, 0x40, 0x0B, 0x16, 0xC8, 0x01, 
-	0x00, 0x40, 0xA0, 0x05, 0x32, 0x09, 0xC8, 0xC5, 
-	0x05, 0x10, 0xC0, 0x01, 0x40, 0x00, 0x40, 0x01, 
-	0x04, 0x00, 0xEF, 0x13, 0xB7, 0x01, 0x20, 0x00, 
-	0xD7, 0xC2, 0xC4, 0x62, 0x0B, 0x05, 0x2B, 0x02, 
-	0xFC, 0xFF, 0xCB, 0xC5, 0x02, 0x15, 0x46, 0x81, 
-	0x6A, 0x13, 0x08, 0x01, 0x00, 0x5E, 0x67, 0x16, 
-	0x08, 0x01, 0x88, 0x00, 0x13, 0x16, 0x86, 0x02, 
-	0x43, 0x00, 0x25, 0x16, 0x40, 0x01, 0x00, 0x40, 
-	0x0B, 0x13, 0x08, 0x01, 0x03, 0x00, 0x08, 0x13, 
-	0x84, 0xC2, 0x2A, 0x02, 0xD8, 0xFF, 0x06, 0xC8, 
-	0x6C, 0x01, 0x0A, 0x68, 0x04, 0xFC, 0x73, 0x10, 
-	0x60, 0x04, 0xD2, 0xA8, 0x40, 0x01, 0x01, 0x00, 
-	0xEA, 0x13, 0x08, 0x01, 0x02, 0x00, 0xE7, 0x16, 
-	0x48, 0x01, 0x01, 0x00, 0xE4, 0x16, 0x40, 0x01, 
-	0x00, 0x40, 0x04, 0x16, 0x60, 0x01, 0xA8, 0x09, 
-	0x80, 0x00, 0xDD, 0x13, 0x8A, 0x07, 0x80, 0x00, 
-	0xA0, 0x06, 0x32, 0xA5, 0xD8, 0x10, 0x00, 0xC0, 
-	0xE7, 0x11, 0x60, 0xC2, 0x6A, 0x09, 0x40, 0x01, 
-	0x00, 0x40, 0x0A, 0x13, 0x48, 0x01, 0x01, 0x00, 
-	0x34, 0x13, 0x48, 0x01, 0x02, 0x00, 0x0A, 0x13, 
-	0x49, 0x01, 0x04, 0x00, 0xD9, 0x16, 0x06, 0x10, 
-	0x49, 0x01, 0x02, 0x00, 0x03, 0x13, 0x08, 0x01, 
-	0x03, 0x00, 0x6E, 0x13, 0x49, 0x01, 0x01, 0x00, 
-	0x12, 0x13, 0x40, 0x01, 0x80, 0x40, 0x01, 0x16, 
-	0x46, 0xC1, 0xE0, 0x04, 0x00, 0xFC, 0x87, 0x07, 
-	0xF8, 0x05, 0x17, 0xC2, 0x14, 0x13, 0xC7, 0x05, 
-	0x17, 0xC8, 0x6C, 0x01, 0x05, 0xC8, 0x00, 0xFC,  
-	0xC6, 0xC5, 0x60, 0x04, 0x66, 0xA6, 0x07, 0x02, 
-	0x02, 0xFC, 0xE0, 0xA1, 0x2C, 0x09, 0xE0, 0xCD,  
-	0xEE, 0x05, 0xE0, 0xC5, 0x04, 0xFC, 0x20, 0xC8, 
-	0x2C, 0x09, 0x04, 0xFC, 0xE2, 0x10, 0xC5, 0xCD, 
-	0xC6, 0xC5, 0x60, 0x04, 0x66, 0xA6, 0x60, 0x04, 
-	0xB6, 0xA8, 0x06, 0xC8, 0x6C, 0x01, 0x85, 0x81, 
-	0x1A, 0x13, 0xE0, 0xC2, 0x04, 0xFC, 0x17, 0x15, 
-	0x86, 0xC2, 0x8A, 0xA2, 0xAA, 0xC1, 0x32, 0x0C, 
-	0x06, 0xC8, 0x6C, 0x01, 0x0B, 0xA8, 0x04, 0xFC, 
-	0x1A, 0x09, 0x0A, 0xC8, 0x6C, 0x01, 0xE0, 0xC2, 
-	0x02, 0xFC, 0xE0, 0x04, 0x00, 0xFC, 0x06, 0xC8, 
-	0x6C, 0x01, 0x0B, 0xC8, 0x02, 0xFC, 0xA0, 0x06, 
-	0x3E, 0xB4, 0x06, 0xC8, 0x6C, 0x01, 0xE0, 0x04, 
-	0x00, 0xFC, 0xA0, 0x01, 0x02, 0xFC, 0x02, 0x00, 
-	0x87, 0x07, 0x30, 0x06, 0xE7, 0x01, 0x04, 0x00, 
-	0x40, 0x00, 0xD7, 0x04, 0x27, 0x02, 0x0C, 0x00, 
-	0x05, 0xC2, 0x60, 0x01, 0x6A, 0x09, 0x04, 0x00, 
-	0x03, 0x16, 0xE0, 0x01, 0x02, 0xFC, 0x20, 0x00, 
-	0xA0, 0x06, 0xFC, 0xB4, 0xC0, 0x01, 0x20, 0x00, 
-	0x60, 0x04, 0x66, 0xA6, 0x48, 0x01, 0x00, 0x18, 
-	0x03, 0x13, 0x48, 0x01, 0x00, 0x10, 0x02, 0x16, 
-	0xA0, 0x05, 0x32, 0x09, 0x86, 0x02, 0x43, 0x00, 
-	0x03, 0x13, 0x40, 0x01, 0x80, 0x40, 0x98, 0x13, 
-	0x06, 0xC8, 0x6C, 0x01, 0xE0, 0x04, 0x00, 0xFC,  
-	0x85, 0xC2, 0xA0, 0x06, 0x3E, 0xB4, 0x20, 0x06, 
-	0x62, 0x09, 0xE6, 0x16, 0xA0, 0x06, 0xD0, 0xD5, 
-	0xE3, 0x10, 0xA0, 0xC2, 0xF6, 0x05, 0x56, 0x16, 
-	0x19, 0xC8, 0xF0, 0x05, 0xA9, 0xC2, 0x0A, 0x00, 
-	0x0D, 0x11, 0xA0, 0xF2, 0x2E, 0x09, 0x0A, 0xD8, 
-	0x80, 0x01, 0x29, 0xC8, 0x06, 0x00, 0x8C, 0x01, 
-	0xA0, 0x07, 0x16, 0x09, 0x04, 0x00, 0x09, 0xC8, 
-	0xF4, 0x05, 0x46, 0x10, 0x29, 0xC8, 0x06, 0x00, 
-	0x6C, 0x01, 0x20, 0xC8, 0x0E, 0xFC, 0xBC, 0x01, 
-	0x20, 0xC8, 0x10, 0xFC, 0xB0, 0x01, 0x20, 0xC8, 
-	0x12, 0xFC, 0xB2, 0x01, 0xA0, 0xF2, 0x2E, 0x09, 
-	0x8A, 0x01, 0x00, 0x10, 0xA0, 0x01, 0x80, 0x01, 
-	0x00, 0xC4, 0xE1, 0x10, 0x47, 0x01, 0x08, 0x00, 
-	0x06, 0x16, 0xA8, 0xC2, 0x06, 0x00, 0xA0, 0x06, 
-	0x3E, 0xB4, 0xE8, 0x04, 0x06, 0x00, 0x07, 0x01, 
-	0x20, 0x00, 0x31, 0x13, 0xE8, 0x04, 0x02, 0x00, 
-	0x3B, 0x10, 0xE0, 0x04, 0x00, 0xFC, 0xA0, 0x06, 
-	0x3E, 0xB4, 0x29, 0x10, 0x00, 0x03, 0x02, 0x00, 
-	0x20, 0xC2, 0x8C, 0x01, 0xE0, 0xC0, 0x6C, 0x01, 
-	0x20, 0xC2, 0xF4, 0x05, 0x28, 0xC8, 0x08, 0x00, 
-	0x6C, 0x01, 0xE8, 0xC1, 0x0A, 0x00, 0x20, 0xC3, 
-	0x02, 0xFC, 0x8C, 0x01, 0x20, 0x00, 0x0C, 0xC8, 
-	0x02, 0xFC, 0x0C, 0x01, 0x00, 0xFE, 0x3B, 0x16, 
-	0x47, 0x01, 0x40, 0x00, 0x50, 0x13, 0x60, 0xC2, 
-	0xF0, 0x05, 0xA7, 0x16, 0xE0, 0x04, 0xF4, 0x05, 
-	0x0C, 0xCA, 0x08, 0x00, 0x47, 0x01, 0x80, 0x00, 
-	0xC9, 0x16, 0x28, 0xC8, 0x06, 0x00, 0x6C, 0x01, 
-	0xA0, 0xC2, 0x00, 0xFC, 0xD2, 0x16, 0xE8, 0xC1, 
-	0x02, 0x00, 0xD7, 0xC2, 0x0F, 0x16, 0x27, 0x02, 
-	0x10, 0x00, 0xD8, 0x04, 0x57, 0xC2, 0x0E, 0x13, 
-	0xC7, 0x05, 0x57, 0xC2, 0x48, 0xC6, 0xC8, 0xC5, 
-	0x03, 0xC8, 0x6C, 0x01, 0x0D, 0x11, 0x90, 0x03, 
-	0xFF, 0x11, 0x80, 0x03, 0xD7, 0x04, 0xC3, 0x01, 
-	0x00, 0x80, 0xED, 0x10, 0xE7, 0x01, 0xF4, 0xFF, 
-	0x20, 0x00, 0xC8, 0xCD, 0xC8, 0xC5, 0xF0, 0x10, 
-	0x90, 0x03, 0xF8, 0x11, 0xE0, 0x02, 0xC0, 0x00, 
-	0x60, 0xC3, 0xFA, 0x00, 0xA0, 0xC3, 0xFC, 0x00, 
-	0xE0, 0xC3, 0xFE, 0x00, 0x54, 0x04, 0xE8, 0xC2, 
-	0x08, 0x00, 0xA8, 0xC2, 0x06, 0x00, 0x0C, 0xC3, 
-	0x33, 0x11, 0x20, 0x23, 0x0A, 0xE0, 0x45, 0x13, 
-	0x20, 0x23, 0x10, 0xE0, 0x46, 0x13, 0x20, 0x23, 
-	0x0E, 0xE0, 0x13, 0x13, 0xE0, 0x21, 0x16, 0xE0, 
-	0xB6, 0x16, 0x20, 0x23, 0x06, 0xE0, 0x03, 0x16, 
-	0x20, 0x27, 0xA8, 0xE4, 0x0A, 0x13, 0xE8, 0xC2, 
-	0x08, 0x00, 0xA8, 0xC2, 0x06, 0x00, 0x4C, 0x01, 
-	0x88, 0x00, 0xA9, 0x16, 0x0C, 0x01, 0x44, 0x00, 
-	0xA6, 0x16, 0x20, 0x06, 0x16, 0x09, 0xA3, 0x13, 
-	0x0A, 0xC8, 0x6C, 0x01, 0x20, 0xC8, 0x04, 0xE0, 
-	0x02, 0xFC, 0x0B, 0xC8, 0x6C, 0x01, 0xA0, 0x07, 
-	0x02, 0xFC, 0x00, 0x81, 0x20, 0xC3, 0x80, 0x01, 
-	0xA0, 0x01, 0x80, 0x01, 0x00, 0xC4, 0x0C, 0xC8, 
-	0x80, 0x01, 0x0A, 0xC8, 0x8C, 0x01, 0xAC, 0x10, 
-	0x0A, 0xC2, 0x0F, 0x13, 0x08, 0xC8, 0x6C, 0x01, 
-	0xA0, 0xC2, 0x00, 0xFC, 0x20, 0xC3, 0x02, 0xFC, 
-	0x20, 0x23, 0x12, 0xE0, 0xF5, 0x16, 0x0B, 0xC8, 
-	0x6C, 0x01, 0x0C, 0xC8, 0x02, 0xFC, 0x60, 0x04, 
-	0x72, 0xA9, 0x8A, 0x07, 0x00, 0x04, 0x60, 0x04, 
-	0x8A, 0xA3, 0x8A, 0x07, 0x20, 0x00, 0x60, 0x04, 
-	0x8A, 0xA3, 0x8A, 0x07, 0x00, 0x02, 0x20, 0x27, 
-	0x0E, 0xE0, 0x04, 0x16, 0xA0, 0x06, 0x32, 0xA5, 
-	0xC3, 0x01, 0x00, 0x80, 0xA8, 0xC2, 0x06, 0x00, 
-	0x60, 0x04, 0x98, 0xA9, 0x00, 0x03, 0x02, 0x00, 
-	0xC0, 0x01, 0x10, 0x00, 0xE0, 0xC2, 0x2E, 0x06, 
-	0x08, 0x13, 0xE0, 0xC2, 0xF8, 0x05, 0x05, 0x13, 
-	0xE0, 0x01, 0x3A, 0x07, 0x00, 0x80, 0x80, 0x01, 
-	0x10, 0x00, 0x90, 0x03, 0xFF, 0x7F, 0x80, 0x03, 
-	0x00, 0x03, 0x02, 0x00, 0x20, 0xC2, 0xF6, 0x05, 
-	0x20, 0xE2, 0xF4, 0x05, 0x0E, 0x16, 0x20, 0xD8, 
-	0x2E, 0x09, 0x80, 0x01, 0x2B, 0xC8, 0x06, 0x00, 
-	0x8C, 0x01, 0xA0, 0x07, 0x16, 0x09, 0x04, 0x00, 
-	0x0B, 0xC8, 0xF4, 0x05, 0x90, 0x03, 0xFF, 0xFF, 
-	0x80, 0x03, 0x87, 0x07, 0xF0, 0x05, 0xDB, 0x04, 
-	0x57, 0xC2, 0x05, 0x16, 0xCB, 0xCD, 0xCB, 0xC5, 
-	0x90, 0x03, 0xFF, 0xFF, 0x80, 0x03, 0xC7, 0x05, 
-	0x57, 0xC2, 0x4B, 0xC6, 0xCB, 0xC5, 0x90, 0x03, 
-	0xFF, 0xFF, 0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 
-	0x0B, 0xC2, 0x20, 0xC3, 0xF4, 0x05, 0x0F, 0x13, 
-	0xA8, 0xC2, 0x0A, 0x00, 0x4A, 0x01, 0x10, 0x00, 
-	0x16, 0x16, 0xA0, 0x22, 0x04, 0xE0, 0x1A, 0x16, 
-	0x08, 0xC3, 0xA0, 0x06, 0x36, 0xAC, 0x0C, 0xC2, 
-	0x20, 0xC3, 0xF4, 0x05, 0x13, 0x16, 0x68, 0x01, 
-	0x0A, 0x00, 0x10, 0x00, 0x03, 0x13, 0xE0, 0xC2, 
-	0xF6, 0x05, 0x05, 0x16, 0xA0, 0x06, 0x78, 0xAC, 
-	0x90, 0x03, 0xFF, 0xFF, 0x80, 0x03, 0x87, 0x07, 
-	0xF0, 0x05, 0xA0, 0x06, 0xE6, 0xB4, 0x90, 0x03, 
-	0xFF, 0xFF, 0x80, 0x03, 0x87, 0x07, 0xF0, 0x05, 
-	0xA0, 0x06, 0x2C, 0xB5, 0x80, 0x03, 0x00, 0x03, 
-	0x02, 0x00, 0x87, 0x07, 0xF0, 0x05, 0xCB, 0xC2, 
-	0x08, 0x16, 0xA0, 0x06, 0x36, 0xAC, 0x20, 0x07, 
-	0xF6, 0x05, 0x60, 0xCB, 0xF4, 0x05, 0x02, 0x00, 
-	0x80, 0x03, 0xE0, 0x04, 0xF6, 0x05, 0x20, 0xC2, 
-	0xF4, 0x05, 0x05, 0x16, 0x17, 0xC2, 0x03, 0x13, 
-	0xD8, 0xC5, 0xA0, 0x06, 0x78, 0xAC, 0x80, 0x03, 
-	0x00, 0x03, 0x02, 0x00, 0x0B, 0xC3, 0xA0, 0x06, 
-	0x36, 0xAC, 0x8C, 0xC2, 0xCC, 0xC1, 0x27, 0x02, 
-	0x10, 0x00, 0x88, 0x07, 0xF0, 0x05, 0x88, 0xC1, 
-	0x18, 0xC2, 0x26, 0x13, 0xA8, 0x82, 0x02, 0x00, 
-	0xFA, 0x16, 0xE8, 0xC2, 0x0A, 0x00, 0xE0, 0x22, 
-	0x1E, 0xE0, 0xF5, 0x16, 0x98, 0xC5, 0xE0, 0x22, 
-	0x1C, 0xE0, 0x0B, 0x16, 0x28, 0xC8, 0x06, 0x00, 
-	0xF4, 0x00, 0xE0, 0x02, 0xE0, 0x00, 0xA0, 0x06, 
-	0x3E, 0xB4, 0xE0, 0x02, 0xC0, 0x00, 0xE8, 0x04, 
-	0x06, 0x00, 0xE0, 0x22, 0x18, 0xE0, 0xE4, 0x13, 
-	0x20, 0xEA, 0x22, 0xE0, 0x0A, 0x00, 0xA0, 0xEA, 
-	0x18, 0xE0, 0x04, 0x00, 0xDA, 0x04, 0xA0, 0x06, 
-	0xE6, 0xB4, 0x47, 0x06, 0x06, 0xC2, 0xD8, 0x10, 
-	0x06, 0xC8, 0xF2, 0x05, 0x60, 0xCB, 0xF4, 0x05, 
-	0x02, 0x00, 0x54, 0x04, 0x20, 0xC2, 0xF4, 0x05, 
-	0x13, 0x13, 0xE0, 0x01, 0x9C, 0x01, 0x00, 0x40, 
-	0x8B, 0x0B, 0x8B, 0x0B, 0x60, 0x01, 0x9C, 0x01, 
-	0x00, 0x40, 0x0A, 0x16, 0x60, 0xC2, 0x6C, 0x01, 
-	0x28, 0xC8, 0x06, 0x00, 0x6C, 0x01, 0xA0, 0xC2, 
-	0x02, 0xFC, 0x03, 0x11, 0x09, 0xC8, 0x6C, 0x01, 
-	0x5B, 0x04, 0x09, 0xC8, 0x6C, 0x01, 0x4B, 0xC2, 
-	0x87, 0x07, 0xF0, 0x05, 0xA0, 0x06, 0x2C, 0xB5, 
-	0xE0, 0x04, 0xF4, 0x05, 0x59, 0x04, 0xA8, 0xC2, 
-	0x0A, 0x00, 0x0D, 0x11, 0xA0, 0xF2, 0x2E, 0x09, 
-	0x0A, 0xD8, 0x80, 0x01, 0x28, 0xC8, 0x06, 0x00, 
-	0x8C, 0x01, 0xA0, 0x07, 0x16, 0x09, 0x04, 0x00, 
-	0x08, 0xC8, 0xF4, 0x05, 0x5B, 0x04, 0x20, 0xC3, 
-	0x6C, 0x01, 0x28, 0xC8, 0x06, 0x00, 0x6C, 0x01, 
-	0x20, 0xC8, 0x0E, 0xFC, 0xBC, 0x01, 0x20, 0xC8, 
-	0x10, 0xFC, 0xB0, 0x01, 0x20, 0xC8, 0x12, 0xFC, 
-	0xB2, 0x01, 0x0C, 0xC8, 0x6C, 0x01, 0xA0, 0xF2, 
-	0x2E, 0x09, 0x8A, 0x01, 0x00, 0x10, 0xA0, 0x01, 
-	0x80, 0x01, 0x00, 0xC4, 0xDD, 0x10, 0x48, 0xC0, 
-	0x89, 0xC0, 0x81, 0x60, 0xC2, 0x05, 0x5B, 0x04, 
-	0x0B, 0xC3, 0xA0, 0x06, 0xC8, 0xAC, 0x41, 0xCC, 
-	0x42, 0x06, 0xFD, 0x16, 0xA0, 0x06, 0xC8, 0xAC, 
-	0x01, 0xC1, 0x44, 0x8C, 0x12, 0x16, 0xC4, 0x05, 
-	0x42, 0x06, 0xFB, 0x16, 0x04, 0x02, 0x0E, 0xAD, 
-	0x03, 0x02, 0x01, 0x01, 0x94, 0x06, 0x03, 0x02, 
-	0x5A, 0x5A, 0x94, 0x06, 0x43, 0x05, 0x94, 0x06, 
-	0x03, 0x07, 0x94, 0x06, 0xC3, 0x04, 0x94, 0x06, 
-	0xCC, 0x05, 0x5C, 0x04, 0xCB, 0xC1, 0xA0, 0x06, 
-	0xC8, 0xAC, 0x43, 0xCC, 0x42, 0x06, 0xFD, 0x16, 
-	0xA0, 0x06, 0xC8, 0xAC, 0x43, 0x8C, 0xF5, 0x16, 
-	0x42, 0x06, 0xFC, 0x16, 0x57, 0x04, 0x8B, 0xC2, 
-	0x08, 0xC0, 0x49, 0xC1, 0x85, 0x05, 0x80, 0x02, 
-	0x40, 0x00, 0x03, 0x11, 0x80, 0x02, 0x4F, 0x00, 
-	0x45, 0x12, 0x01, 0x02, 0xC8, 0xAC, 0xA1, 0x09, 
-	0x01, 0x80, 0x40, 0x13, 0x01, 0x02, 0xF8, 0xAD, 
-	0xA1, 0x09, 0x01, 0x80, 0x3B, 0x13, 0x60, 0xC0, 
-	0x06, 0x00, 0xA1, 0x09, 0x01, 0x80, 0x36, 0x13, 
-	0x81, 0x05, 0x01, 0x80, 0x33, 0x13, 0x4A, 0xC0, 
-	0xA1, 0x09, 0x01, 0x80, 0x2F, 0x13, 0x00, 0xC8, 
-	0x6A, 0x01, 0x80, 0x02, 0x80, 0x00, 0x17, 0x14, 
-	0x01, 0x02, 0x00, 0xF8, 0xA0, 0xC1, 0x40, 0x01, 
-	0xA0, 0x01, 0x40, 0x01, 0x00, 0x04, 0x02, 0x02, 
-	0x00, 0x10, 0x03, 0x02, 0x00, 0x04, 0xB1, 0xCC, 
-	0x43, 0x06, 0xFD, 0x16, 0xA0, 0x01, 0x40, 0x01, 
-	0x00, 0x40, 0x08, 0x02, 0x10, 0xF8, 0x06, 0xC8, 
-	0x40, 0x01, 0x00, 0xC0, 0x02, 0x13, 0x08, 0x02, 
-	0x00, 0xF8, 0x09, 0x02, 0xFE, 0xFB, 0xA0, 0x06, 
-	0xD2, 0xAC, 0x25, 0x10, 0x80, 0x02, 0x80, 0x00, 
-	0x09, 0x14, 0x01, 0x02, 0x00, 0xF8, 0x02, 0x02, 
-	0x00, 0x10, 0x03, 0x02, 0x00, 0x04, 0x72, 0xCC, 
-	0x43, 0x06, 0xFD, 0x16, 0x80, 0x05, 0x80, 0x02, 
-	0x80, 0x00, 0x04, 0x12, 0x60, 0x01, 0x04, 0x01, 
-	0x20, 0x00, 0x05, 0x13, 0x40, 0x81, 0xAB, 0x16, 
-	0x80, 0x02, 0x80, 0x00, 0x0B, 0x14, 0xA0, 0x07, 
-	0x6A, 0x01, 0x7E, 0x00, 0x02, 0x02, 0x00, 0x10, 
-	0x03, 0x02, 0x00, 0x04, 0xC1, 0x04, 0x81, 0xCC, 
-	0x43, 0x06, 0xFD, 0x16, 0xCA, 0x05, 0x5A, 0x04, 
-	0x00, 0x02, 0xEA, 0xAD, 0x01, 0x02, 0x1A, 0xAF, 
-	0x40, 0x02, 0x00, 0xFC, 0x41, 0x02, 0x00, 0xFC, 
-	0x40, 0x80, 0x04, 0x13, 0xA0, 0x07, 0x04, 0x01, 
-	0x3C, 0x00, 0x5B, 0x04, 0xC0, 0x04, 0x01, 0x02, 
-	0x08, 0x00, 0x02, 0x02, 0x00, 0x12, 0xE0, 0xC1, 
-	0x40, 0x01, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x04, 
-	0x03, 0x02, 0x00, 0x01, 0x00, 0xC8, 0x6A, 0x01, 
-	0xA0, 0xCC, 0x10, 0xF8, 0x80, 0x05, 0x03, 0x06, 
-	0xF9, 0x16, 0x22, 0x02, 0x00, 0x02, 0x01, 0x06, 
-	0xF3, 0x16, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x40, 
-	0x07, 0xC8, 0x40, 0x01, 0x00, 0x02, 0x00, 0x08, 
-	0x40, 0xC0, 0x01, 0x06, 0x01, 0xC8, 0x6A, 0x01, 
-	0x61, 0x02, 0x00, 0x80, 0x01, 0xC8, 0x10, 0xF8, 
-	0x00, 0x06, 0xF6, 0x16, 0xC0, 0x04, 0xC8, 0x04, 
-	0xC9, 0x04, 0x03, 0x02, 0x00, 0x08, 0x00, 0xC8, 
-	0x6A, 0x01, 0x80, 0xC1, 0x66, 0x02, 0x00, 0x80, 
-	0x20, 0xC1, 0x10, 0xF8, 0x06, 0x81, 0x15, 0x16, 
-	0x08, 0xC2, 0x06, 0x13, 0x80, 0x05, 0x03, 0x06, 
-	0xF2, 0x16, 0x08, 0xC2, 0x0D, 0x13, 0x19, 0x10, 
-	0xA0, 0x07, 0x10, 0xF8, 0x55, 0x55, 0x20, 0xC1, 
-	0x10, 0xF8, 0x84, 0x02, 0x55, 0x55, 0x02, 0x16, 
-	0x06, 0xC2, 0xF0, 0x10, 0x06, 0x81, 0xEE, 0x13, 
-	0x5B, 0x04, 0xA0, 0x07, 0x10, 0xF8, 0x55, 0x55, 
-	0x60, 0xC1, 0x10, 0xF8, 0x05, 0x81, 0x03, 0x13, 
-	0x85, 0x02, 0x55, 0x55, 0xF5, 0x16, 0x08, 0xC2, 
-	0xE1, 0x13, 0x40, 0xC2, 0x09, 0x06, 0x48, 0x02, 
-	0xFF, 0x07, 0xC0, 0x04, 0x01, 0x02, 0x08, 0x00, 
-	0x02, 0x02, 0x00, 0x12, 0x03, 0x02, 0x00, 0x01, 
-	0x00, 0xC8, 0x6A, 0x01, 0x32, 0xC8, 0x10, 0xF8, 
-	0x80, 0x05, 0x03, 0x06, 0xF9, 0x16, 0x22, 0x02, 
-	0x00, 0x02, 0x01, 0x06, 0xF3, 0x16, 0x88, 0x02, 
-	0x40, 0x00, 0x13, 0x15, 0x89, 0x02, 0x4F, 0x00, 
-	0x10, 0x11, 0xC0, 0x04, 0x02, 0x02, 0x00, 0x12, 
-	0x01, 0x02, 0x08, 0x00, 0x03, 0x02, 0x00, 0x01, 
-	0x80, 0xCC, 0x03, 0x06, 0xFD, 0x16, 0x22, 0x02, 
-	0x00, 0x02, 0x01, 0x06, 0xF7, 0x16, 0xCB, 0x05, 
-	0x5B, 0x04, 0xA0, 0x07, 0x04, 0x01, 0x37, 0x00, 
-	0x5B, 0x04, 0x33, 0x07, 0x33, 0x07, 0x0C, 0x10, 
-	0x13, 0x07, 0x23, 0x07, 0x02, 0x00, 0xCB, 0xC8, 
-	0x06, 0x00, 0x23, 0x02, 0x18, 0x00, 0xE0, 0xCC, 
-	0x6C, 0x01, 0xCD, 0xCC, 0xCE, 0xCC, 0xCF, 0xCC, 
-	0x83, 0x07, 0x30, 0x06, 0xD3, 0xC1, 0x0A, 0x13, 
-	0x83, 0x07, 0x36, 0x07, 0xD3, 0xC1, 0x06, 0x13, 
-	0x83, 0x07, 0xA0, 0x00, 0x93, 0x00, 0x0C, 0xC8, 
-	0x6C, 0x01, 0x80, 0x03, 0x63, 0x07, 0x02, 0x00, 
-	0x2A, 0x15, 0x63, 0xC2, 0x04, 0x00, 0x63, 0x42, 
-	0x06, 0x00, 0xDB, 0x13, 0x63, 0xC3, 0x1A, 0x00, 
-	0x49, 0xD2, 0x0C, 0x13, 0xC9, 0x06, 0x49, 0x72, 
-	0x69, 0xD2, 0xC0, 0xE1, 0xC9, 0x06, 0x49, 0x72, 
-	0xE9, 0x48, 0x04, 0xE0, 0x04, 0x00, 0x49, 0xCB, 
-	0x02, 0x00, 0x52, 0x04, 0x69, 0xC2, 0xC0, 0xE1, 
-	0x49, 0x72, 0x29, 0x02, 0x10, 0x00, 0xC3, 0xC2, 
-	0xE9, 0xA2, 0xA8, 0xE1, 0x1B, 0xC3, 0x89, 0x02, 
-	0x12, 0x00, 0x0F, 0x13, 0xDC, 0xC6, 0x03, 0x16, 
-	0xE9, 0x48, 0x04, 0xE0, 0x04, 0x00, 0x49, 0xCB, 
-	0x02, 0x00, 0x4C, 0xCB, 0x04, 0x00, 0x90, 0x03, 
-	0xFF, 0x01, 0x93, 0x00, 0x0C, 0xC8, 0x6C, 0x01, 
-	0x80, 0x03, 0x0C, 0xC8, 0x6C, 0x01, 0xE0, 0xC6, 
-	0x00, 0xFC, 0xF1, 0x16, 0xE9, 0x48, 0x04, 0xE0, 
-	0x04, 0x00, 0x49, 0xCB, 0x02, 0x00, 0x4C, 0xCB, 
-	0x04, 0x00, 0xED, 0x10, 0x00, 0x03, 0x02, 0x00, 
-	0xDB, 0xC2, 0x63, 0xC2, 0x04, 0x00, 0x4B, 0x42, 
-	0x9F, 0x13, 0x49, 0xD2, 0x0E, 0x13, 0xC9, 0x06, 
-	0x49, 0x72, 0x69, 0xD2, 0xC0, 0xE1, 0xC9, 0x06, 
-	0x49, 0x72, 0xE9, 0x48, 0x04, 0xE0, 0x04, 0x00, 
-	0x49, 0xCB, 0x02, 0x00, 0x90, 0x03, 0xFF, 0xFF, 
-	0x80, 0x03, 0x69, 0xC2, 0xC0, 0xE1, 0x49, 0x72, 
-	0x29, 0x02, 0x10, 0x00, 0xC3, 0xC2, 0xE9, 0xA2, 
-	0xA8, 0xE1, 0x1B, 0xC3, 0x89, 0x02, 0x12, 0x00, 
-	0x0C, 0x13, 0xDC, 0xC6, 0x03, 0x16, 0xE9, 0x48, 
-	0x04, 0xE0, 0x04, 0x00, 0x49, 0xCB, 0x02, 0x00, 
-	0x4C, 0xCB, 0x04, 0x00, 0x90, 0x03, 0xFF, 0xFF, 
-	0x80, 0x03, 0x0C, 0xC8, 0x6C, 0x01, 0xE0, 0xC6, 
-	0x00, 0xFC, 0xF4, 0x16, 0xF0, 0x10, 0x00, 0x03, 
-	0x02, 0x00, 0xBB, 0xC2, 0xBB, 0xC1, 0x86, 0xD1, 
-	0x03, 0x13, 0x86, 0xEA, 0x04, 0x00, 0x13, 0x10, 
-	0xA6, 0xD1, 0xC0, 0xE1, 0xC6, 0x06, 0x86, 0x71, 
-	0xCA, 0xC1, 0xE6, 0xA1, 0xB8, 0xE1, 0xA6, 0xEA, 
-	0x14, 0xE0, 0x04, 0x00, 0x1B, 0xC2, 0x86, 0x02, 
-	0x02, 0x00, 0x03, 0x16, 0xA0, 0x06, 0x0C, 0xB5, 
-	0x02, 0x10, 0xA0, 0x06, 0xE6, 0xB4, 0xDA, 0x04, 
-	0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 0xAB, 0xC2, 
-	0x06, 0x00, 0x8C, 0x07, 0xE8, 0x05, 0x5C, 0xC2, 
-	0x16, 0x13, 0xA0, 0xC1, 0xEC, 0x05, 0x8A, 0x81, 
-	0x1A, 0x1A, 0xC6, 0xC1, 0x09, 0xC2, 0x59, 0xC2, 
-	0x20, 0x13, 0xE9, 0xA1, 0x08, 0x00, 0x87, 0x82, 
-	0xF9, 0x12, 0xA9, 0xA2, 0x08, 0x00, 0x87, 0x62, 
-	0xCA, 0xCA, 0x08, 0x00, 0x4A, 0x6A, 0x08, 0x00, 
-	0xC9, 0xC6, 0x0B, 0xC6, 0x80, 0x03, 0xCA, 0xCA, 
-	0x08, 0x00, 0x0A, 0xC8, 0xEC, 0x05, 0xDB, 0x04, 
-	0x0B, 0xCF, 0x0B, 0xC7, 0x80, 0x03, 0x8A, 0x61, 
-	0x46, 0xCA, 0x08, 0x00, 0xCA, 0xCA, 0x08, 0x00, 
-	0x0A, 0xC8, 0xEC, 0x05, 0xC9, 0xC6, 0x0B, 0xC7, 
-	0x80, 0x03, 0x87, 0x62, 0xCA, 0xCA, 0x08, 0x00, 
-	0xDB, 0x04, 0x0B, 0xC6, 0x0B, 0xCB, 0x02, 0x00, 
-	0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 0xBB, 0xC1, 
-	0xDB, 0xC2, 0x8C, 0x07, 0xE8, 0x05, 0x4C, 0xC2, 
-	0xED, 0x04, 0x02, 0x00, 0x09, 0xC2, 0x59, 0xC2, 
-	0x18, 0x13, 0xA9, 0x81, 0x02, 0x00, 0xFA, 0x16, 
-	0xE9, 0x82, 0x04, 0x00, 0xF7, 0x16, 0x49, 0xCB, 
-	0x04, 0x00, 0x99, 0xC2, 0x0A, 0xC6, 0x0A, 0x13, 
-	0x08, 0x83, 0x04, 0x13, 0xA9, 0xAA, 0x08, 0x00, 
-	0x08, 0x00, 0x80, 0x03, 0x2A, 0xA8, 0x08, 0x00, 
-	0xEC, 0x05, 0x80, 0x03, 0x08, 0xCB, 0x02, 0x00, 
-	0x80, 0x03, 0x2D, 0x07, 0x02, 0x00, 0x8C, 0x07, 
-	0x08, 0x00, 0x06, 0xA3, 0x4C, 0xC2, 0x09, 0xC2, 
-	0x59, 0xC2, 0x13, 0x13, 0xE9, 0x82, 0x04, 0x00, 
-	0xFA, 0x16, 0xAD, 0x07, 0x02, 0x00, 0x01, 0x00, 
-	0x49, 0xCB, 0x04, 0x00, 0x19, 0xC6, 0x01, 0x13, 
-	0x80, 0x03, 0x08, 0x83, 0x04, 0x16, 0xA0, 0x49, 
-	0x14, 0xE0, 0x04, 0x00, 0x80, 0x03, 0x08, 0xCB, 
-	0x02, 0x00, 0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 
-	0x0B, 0x06, 0x1F, 0x11, 0x4D, 0x13, 0x8B, 0x07, 
-	0x00, 0x4E, 0x60, 0x01, 0x42, 0x01, 0x80, 0x00, 
-	0x09, 0x13, 0x8B, 0x07, 0x00, 0x3A, 0x20, 0xC1, 
-	0x4E, 0x01, 0x84, 0x02, 0x41, 0x0F, 0x02, 0x11, 
-	0x8B, 0x07, 0x00, 0x4E, 0x0B, 0xC8, 0x44, 0x01, 
-	0xA0, 0x07, 0x62, 0x09, 0xE8, 0x03, 0xE0, 0x01, 
-	0x40, 0x01, 0x00, 0x02, 0xE0, 0x01, 0x40, 0x01, 
-	0x00, 0x20, 0x84, 0x07, 0x34, 0xAF, 0x60, 0x04, 
-	0x42, 0xAF, 0x20, 0xC8, 0x16, 0xE0, 0xE0, 0x00, 
-	0xE0, 0xC2, 0x6A, 0x09, 0xE0, 0x22, 0x10, 0xE0, 
-	0x03, 0x13, 0x20, 0xE8, 0x14, 0xE0, 0xE0, 0x00, 
-	0x20, 0xC8, 0x04, 0xE0, 0x82, 0x01, 0x20, 0xC8, 
-	0xE2, 0x00, 0x8A, 0x01, 0xE0, 0x04, 0x18, 0x09, 
-	0xE0, 0x04, 0xF4, 0x05, 0xE0, 0x04, 0xF8, 0x05, 
-	0xE0, 0x04, 0xF0, 0x05, 0xE0, 0x04, 0x42, 0x07, 
-	0xA0, 0x07, 0x88, 0x01, 0x20, 0x00, 0xE0, 0xC2, 
-	0x30, 0x09, 0x09, 0x13, 0xA0, 0x07, 0x88, 0x01, 
-	0x80, 0x00, 0x20, 0xE8, 0x16, 0xE0, 0x80, 0x01, 
-	0xE0, 0x01, 0x82, 0x01, 0x00, 0x03, 0x8B, 0x07, 
-	0x00, 0xA0, 0x0B, 0xE8, 0x86, 0x01, 0x80, 0x03, 
-	0xE0, 0x04, 0x86, 0x01, 0xE0, 0x01, 0x9C, 0x01, 
-	0x40, 0x00, 0xE0, 0x01, 0x9C, 0x01, 0x00, 0x40, 
-	0xCB, 0x04, 0xB0, 0x03, 0x0B, 0x06, 0x04, 0x13, 
-	0x60, 0x01, 0x9C, 0x01, 0x00, 0x40, 0xF9, 0x16, 
-	0xE0, 0x04, 0x82, 0x01, 0x20, 0xE8, 0x08, 0xE0, 
-	0x6A, 0x09, 0x8B, 0x07, 0x00, 0x80, 0x0B, 0xC8, 
-	0x98, 0x07, 0x0B, 0xC8, 0x78, 0x07, 0x20, 0xC8, 
-	0x04, 0xE0, 0x82, 0x01, 0x8B, 0x07, 0x6F, 0x87, 
-	0x0B, 0x48, 0x3A, 0x07, 0xE0, 0xC2, 0x50, 0x07, 
-	0x8B, 0x02, 0x58, 0x07, 0x10, 0x13, 0x20, 0xE8, 
-	0x0A, 0xE0, 0x00, 0x01, 0xE0, 0xC2, 0x00, 0x01, 
-	0xE0, 0x22, 0x06, 0xE0, 0xF8, 0x13, 0x8B, 0x07, 
-	0x58, 0x07, 0x0B, 0xC8, 0x50, 0x07, 0x8B, 0x07, 
-	0x0C, 0xB8, 0x0B, 0xC8, 0x52, 0x07, 0x80, 0x03, 
-	0x00, 0x03, 0x02, 0x00, 0xE0, 0xC2, 0x1A, 0x09, 
-	0x0C, 0x13, 0x20, 0x06, 0x1C, 0x09, 0x0B, 0xC8, 
-	0x6C, 0x01, 0x20, 0xC8, 0x00, 0xFC, 0x1A, 0x09, 
-	0x4B, 0xCB, 0x02, 0x00, 0x90, 0x03, 0xFF, 0xFF, 
-	0x80, 0x03, 0x41, 0xC0, 0x0F, 0x13, 0x81, 0x80, 
-	0x0D, 0x13, 0x82, 0xA0, 0xE2, 0xC2, 0x32, 0x0C, 
-	0x12, 0x09, 0x0B, 0xC8, 0x6C, 0x01, 0xE0, 0x04, 
-	0x00, 0xFC, 0x20, 0xC3, 0x02, 0xFC, 0x07, 0x11, 
-	0x02, 0xC8, 0x00, 0xFC, 0xED, 0x04, 0x02, 0x00, 
-	0xE0, 0x04, 0x6C, 0x01, 0x80, 0x03, 0x42, 0xCB, 
-	0x02, 0x00, 0x02, 0xC8, 0x6C, 0x01, 0x8B, 0xC0, 
-	0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 0x83, 0x07, 
-	0x00, 0x80, 0x60, 0xC2, 0x7E, 0x09, 0x09, 0xC1, 
-	0x24, 0x02, 0xF8, 0xFF, 0xA9, 0x08, 0x01, 0x02, 
-	0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x0B, 0x02, 
-	0x00, 0x00, 0x0C, 0x02, 0x00, 0x00, 0x07, 0x02, 
-	0x00, 0x00, 0x2C, 0xCB, 0x32, 0x0C, 0x32, 0x0C, 
-	0x06, 0x13, 0x8B, 0x05, 0xCC, 0x05, 0x0B, 0x88, 
-	0x46, 0x04, 0x27, 0x1B, 0xF6, 0x10, 0x09, 0xC2, 
-	0x8B, 0xC2, 0x08, 0x06, 0x0A, 0x13, 0x8B, 0x05, 
-	0xCC, 0x05, 0x0B, 0x88, 0x46, 0x04, 0x1D, 0x1B, 
-	0x2C, 0xCB, 0x32, 0x0C, 0x32, 0x0C, 0xED, 0x16, 
-	0xF4, 0x10, 0x82, 0xC0, 0x14, 0x13, 0x02, 0xC8, 
-	0x6C, 0x01, 0x0A, 0xC8, 0x00, 0xFC, 0x0A, 0xC8, 
-	0x6C, 0x01, 0xE0, 0x04, 0x00, 0xFC, 0xA0, 0x07, 
-	0x02, 0xFC, 0x00, 0x80, 0x04, 0xC8, 0x04, 0xFC, 
-	0x0A, 0xC2, 0x08, 0xA2, 0x02, 0xCA, 0x32, 0x0C, 
-	0x8A, 0xC0, 0x87, 0x05, 0xD6, 0x10, 0x4A, 0xC0, 
-	0xEE, 0x10, 0x47, 0xCB, 0x02, 0x00, 0xE0, 0x04, 
-	0x6C, 0x01, 0x8B, 0x07, 0x43, 0x00, 0xE0, 0x04, 
-	0x00, 0x0C, 0x00, 0x03, 0x02, 0x00, 0x0B, 0xC8, 
-	0x6C, 0x01, 0x8B, 0x02, 0x43, 0x00, 0x04, 0x13, 
-	0x60, 0x01, 0x02, 0xFC, 0x20, 0x00, 0x06, 0x13, 
-	0x8B, 0xC2, 0xA0, 0x06, 0x42, 0xB4, 0x90, 0x03, 
-	0x7F, 0x00, 0x80, 0x03, 0xA0, 0x01, 0x02, 0xFC, 
-	0x20, 0x00, 0x60, 0x01, 0x6A, 0x09, 0x01, 0x00, 
-	0x0B, 0x16, 0x0A, 0x02, 0x02, 0xFC, 0xA0, 0xA2, 
-	0x2C, 0x09, 0xA0, 0xCE, 0xEE, 0x05, 0xA0, 0xC6, 
-	0x04, 0xFC, 0x20, 0xC8, 0x2C, 0x09, 0x04, 0xFC, 
-	0x8A, 0x07, 0xF8, 0x05, 0x5A, 0xC2, 0x08, 0x13, 
-	0xCA, 0x05, 0x5A, 0xC2, 0x09, 0xC8, 0x6C, 0x01, 
-	0x0B, 0xC8, 0x00, 0xFC, 0x8B, 0xC6, 0x02, 0x10, 
-	0x8B, 0xCE, 0x8B, 0xC6, 0x20, 0x20, 0x1A, 0xE0, 
-	0x05, 0x16, 0x20, 0xE8, 0x04, 0xE0, 0x3A, 0x07, 
-	0xE0, 0x04, 0x36, 0x07, 0x90, 0x03, 0x7F, 0x00, 
-	0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 0x0B, 0xC8, 
-	0x6C, 0x01, 0xCC, 0x04, 0xE0, 0x04, 0x00, 0xFC, 
-	0x8B, 0xC2, 0xA0, 0x06, 0x50, 0xB4, 0x90, 0x03, 
-	0x7F, 0x00, 0x80, 0x03, 0xA0, 0x07, 0x02, 0xFC, 
-	0x00, 0x80, 0x20, 0xC8, 0x8C, 0xE1, 0x04, 0xFC, 
-	0x41, 0xC0, 0x0F, 0x16, 0x20, 0xD8, 0x00, 0xE2, 
-	0x83, 0x01, 0x8B, 0x0B, 0x8B, 0x0B, 0x8B, 0x0B, 
-	0x8B, 0x0B, 0x8B, 0x0B, 0x8B, 0x0B, 0x8B, 0x0B, 
-	0x8B, 0x0B, 0x8B, 0x0B, 0x8B, 0x0B, 0x0A, 0xC8, 
-	0x8A, 0x01, 0x5B, 0x04, 0x0A, 0xC8, 0x6C, 0x01, 
-	0x20, 0xC3, 0x00, 0xFC, 0xE0, 0x04, 0x00, 0xFC, 
-	0x8A, 0x02, 0x43, 0x00, 0xDF, 0x13, 0xA0, 0x07, 
-	0x02, 0xFC, 0x00, 0x80, 0x04, 0xC8, 0x04, 0xFC, 
-	0x20, 0x98, 0x84, 0x09, 0x1D, 0x09, 0x0A, 0x13, 
-	0x20, 0xC8, 0x1A, 0x09, 0x00, 0xFC, 0x0A, 0xC8, 
-	0x1A, 0x09, 0xA0, 0x05, 0x1C, 0x09, 0x8C, 0xC2, 
-	0xE5, 0x16, 0x5B, 0x04, 0x41, 0xC0, 0x10, 0x13, 
-	0x8A, 0xA2, 0x82, 0xCA, 0x32, 0x0C, 0x1A, 0x09, 
-	0x02, 0xC8, 0x6C, 0x01, 0x0A, 0xC8, 0x00, 0xFC, 
-	0x8A, 0xC0, 0x20, 0x98, 0x83, 0x01, 0x00, 0xE2, 
-	0x09, 0x13, 0x8C, 0xC2, 0xD3, 0x16, 0x5B, 0x04, 
-	0x4A, 0xC0, 0x8A, 0xC0, 0x20, 0x98, 0x83, 0x01, 
-	0x00, 0xE2, 0x1B, 0x16, 0xE0, 0x01, 0x9C, 0x01, 
-	0x40, 0x00, 0xA0, 0x07, 0x64, 0x09, 0x00, 0x70, 
-	0x60, 0x01, 0x9C, 0x01, 0x40, 0x00, 0x07, 0x13, 
-	0x20, 0x06, 0x64, 0x09, 0xF9, 0x16, 0x0A, 0x02, 
-	0x00, 0x01, 0x60, 0x04, 0x8A, 0xA3, 0x60, 0x01, 
-	0x02, 0x0C, 0x00, 0x01, 0xE2, 0x13, 0x20, 0xD8, 
-	0x2F, 0x09, 0x83, 0x01, 0xA0, 0x07, 0x02, 0x0C, 
-	0x00, 0x80, 0x0A, 0xC8, 0x8A, 0x01, 0x0A, 0xC8, 
-	0x18, 0x09, 0xD7, 0x10, 0xD8, 0x04, 0x57, 0xC2, 
-	0x03, 0x16, 0xC8, 0xCD, 0xC8, 0xC5, 0x5B, 0x04, 
-	0xC7, 0x05, 0x57, 0xC2, 0x48, 0xC6, 0xC8, 0xC5, 
-	0x5B, 0x04, 0x08, 0xC8, 0x6C, 0x01, 0x08, 0xA2, 
-	0x20, 0xCA, 0x00, 0xFC, 0x32, 0x0C, 0x18, 0x09, 
-	0x02, 0x10, 0x08, 0xC8, 0x6C, 0x01, 0xE0, 0x04, 
-	0x00, 0xFC, 0x57, 0xC2, 0x03, 0x16, 0xC8, 0xCD, 
-	0xC8, 0xC5, 0x5B, 0x04, 0xC7, 0x05, 0x17, 0xC8, 
-	0x6C, 0x01, 0x08, 0xC8, 0x00, 0xFC, 0xC8, 0xC5, 
-	0x5B, 0x04, 0x17, 0xC6, 0x02, 0x16, 0xC8, 0xC9, 
-	0x02, 0x00, 0xC8, 0xC5, 0x5B, 0x04, 0x17, 0xC2, 
-	0x08, 0xC8, 0x6C, 0x01, 0x07, 0x13, 0xE0, 0xC5, 
-	0x00, 0xFC, 0x08, 0xA2, 0x28, 0xC8, 0x32, 0x0C, 
-	0x00, 0xFC, 0x18, 0x09, 0x5B, 0x04, 0x60, 0x01, 
-	0x82, 0x01, 0x00, 0x20, 0x0A, 0x16, 0x60, 0xC2, 
-	0x84, 0x01, 0xA0, 0x01, 0x82, 0x01, 0x00, 0x20, 
-	0xE0, 0x01, 0x82, 0x01, 0x00, 0x20, 0x09, 0xC8, 
-	0x84, 0x01, 0xC9, 0x04, 0x5B, 0x04, 0xA0, 0x06, 
-	0xBE, 0xB7, 0xD3, 0x04, 0xE0, 0x04, 0x02, 0x01, 
-	0x20, 0xE8, 0x14, 0xE0, 0x00, 0x01, 0x20, 0xC8, 
-	0x16, 0xE0, 0x04, 0x01, 0x05, 0x2C, 0x20, 0x48, 
-	0x14, 0xE0, 0x00, 0x01, 0x8C, 0x07, 0x00, 0x0A, 
-	0x8D, 0x07, 0xD8, 0x07, 0x8E, 0x07, 0x18, 0x00, 
-	0x7C, 0xCF, 0x4E, 0x06, 0xFD, 0x16, 0xE0, 0x02, 
-	0xD8, 0x07, 0x8F, 0x07, 0x11, 0xFF, 0x8B, 0x02, 
-	0x3B, 0x59, 0x21, 0x16, 0x8A, 0x02, 0x3B, 0x59, 
-	0x1E, 0x13, 0x8F, 0x05, 0x20, 0x20, 0x16, 0xE0, 
-	0x01, 0x16, 0x19, 0x10, 0x20, 0x20, 0x04, 0xE0, 
-	0x16, 0x16, 0x00, 0x01, 0xBF, 0x00, 0x13, 0x16, 
-	0x8B, 0x07, 0xC0, 0x40, 0x00, 0x01, 0x00, 0x60, 
-	0x10, 0x13, 0x40, 0x01, 0x00, 0x60, 0x0B, 0x16, 
-	0x8B, 0x07, 0xC4, 0x44, 0xA0, 0xC3, 0x02, 0x01, 
-	0x0E, 0x48, 0x02, 0x01, 0x4E, 0x01, 0x00, 0x10, 
-	0x04, 0x16, 0x8F, 0x07, 0x18, 0xFF, 0x60, 0x04, 
-	0x94, 0xB7, 0x0B, 0xC3, 0x4B, 0xC3, 0x20, 0x20, 
-	0x0A, 0xE0, 0x02, 0x16, 0x6B, 0x02, 0x20, 0x20, 
-	0x20, 0x20, 0x0C, 0xE0, 0x02, 0x16, 0x6C, 0x02, 
-	0x00, 0x20, 0x20, 0x20, 0x0E, 0xE0, 0x02, 0x16, 
-	0x6C, 0x02, 0x20, 0x00, 0x8F, 0x05, 0x20, 0x20, 
-	0x10, 0xE0, 0x07, 0x16, 0x6D, 0x02, 0x20, 0x00, 
-	0x20, 0x21, 0x22, 0xE0, 0xE4, 0x13, 0x04, 0xC1, 
-	0x02, 0x16, 0x84, 0x07, 0xFE, 0x7F, 0x8F, 0x05, 
-	0x20, 0x20, 0x12, 0xE0, 0x02, 0x16, 0x6D, 0x02, 
-	0x00, 0x20, 0x60, 0x21, 0x22, 0xE0, 0xD7, 0x13, 
-	0x45, 0xC1, 0x02, 0x16, 0x85, 0x07, 0xFE, 0x7F, 
-	0x8F, 0x05, 0x86, 0xD1, 0x0B, 0x13, 0xA0, 0x25, 
-	0x26, 0xE0, 0x08, 0x13, 0x8F, 0x05, 0x20, 0x26, 
-	0x22, 0xE0, 0x04, 0x16, 0x8F, 0x05, 0xA0, 0x26, 
-	0x22, 0xE0, 0x02, 0x13, 0x60, 0x04, 0x94, 0xB7, 
-	0x01, 0xD8, 0xEC, 0x08, 0x20, 0xD8, 0xDB, 0x07, 
-	0x00, 0x09, 0x02, 0xD8, 0xF6, 0x08, 0x20, 0xD8, 
-	0xDD, 0x07, 0xE2, 0x08, 0xE0, 0x02, 0x58, 0x07, 
-	0x20, 0xD8, 0xEF, 0x07, 0xF4, 0x07, 0x20, 0xD8, 
-	0xF1, 0x07, 0xF6, 0x07, 0x20, 0xD8, 0xF3, 0x07, 
-	0xF8, 0x07, 0x09, 0x02, 0x06, 0x00, 0xCB, 0x04, 
-	0x0F, 0x02, 0xEE, 0x07, 0x8F, 0x05, 0xCB, 0xDF, 
-	0x09, 0x06, 0xFC, 0x16, 0xA0, 0x06, 0xBE, 0xB7, 
-	0x89, 0x07, 0x5C, 0xE3, 0xE0, 0x04, 0x1A, 0x01, 
-	0x20, 0xC8, 0xE4, 0x07, 0x18, 0x01, 0x19, 0xC8, 
-	0x0C, 0x01, 0x39, 0xC8, 0x0A, 0x01, 0x39, 0xC8, 
-	0x12, 0x01, 0x09, 0x16, 0x79, 0xC3, 0x0F, 0x02, 
-	0x00, 0xE0, 0x4F, 0x63, 0x2D, 0x02, 0x00, 0x90, 
-	0x0D, 0xC8, 0x14, 0x01, 0x02, 0x10, 0x39, 0xC8, 
-	0x14, 0x01, 0xF9, 0xC3, 0x3F, 0xC8, 0x0E, 0x01, 
-	0x1F, 0xC8, 0x10, 0x01, 0xE0, 0x04, 0x14, 0x09, 
-	0xB9, 0xC2, 0x1A, 0xC8, 0x00, 0x01, 0x96, 0x06, 
-	0x89, 0x02, 0x84, 0xE3, 0xE0, 0x16, 0x8F, 0x07, 
-	0x1C, 0xFF, 0x8C, 0x07, 0x00, 0x0A, 0x8D, 0x07, 
-	0x84, 0xE3, 0x8E, 0x07, 0x10, 0x00, 0x7C, 0x8F, 
-	0x44, 0x16, 0x4E, 0x06, 0xFC, 0x16, 0xA0, 0xC3, 
-	0xE2, 0x07, 0xE0, 0xC3, 0xE0, 0x07, 0xCE, 0x83, 
-	0x01, 0x14, 0xCE, 0xC3, 0x0F, 0xC8, 0x1A, 0x01, 
-	0x8C, 0x07, 0x94, 0xE3, 0x8D, 0x07, 0x00, 0x0A, 
-	0x8E, 0x07, 0xA4, 0xE3, 0x8C, 0x63, 0x7C, 0xCF, 
-	0x4E, 0x06, 0xFD, 0x16, 0xE0, 0x04, 0x30, 0x09, 
-	0x20, 0x01, 0x42, 0x01, 0x00, 0x04, 0x02, 0x16, 
-	0x20, 0x07, 0x30, 0x09, 0x60, 0xC2, 0x62, 0x01, 
-	0xE0, 0x04, 0x62, 0x01, 0x8E, 0x07, 0x00, 0x80, 
-	0x8C, 0x07, 0x34, 0x09, 0x8D, 0x07, 0x06, 0x00, 
-	0x3E, 0xDF, 0x8E, 0x05, 0x0D, 0x06, 0xFC, 0x16, 
-	0xFE, 0xD3, 0xCF, 0x06, 0x8E, 0x05, 0xFE, 0xD3, 
-	0xCF, 0x06, 0x8C, 0x07, 0x34, 0x09, 0x09, 0xC8, 
-	0x62, 0x01, 0xC9, 0x04, 0x5C, 0xA3, 0x7C, 0xE2, 
-	0x5C, 0xA3, 0x7C, 0xE2, 0x5C, 0xA3, 0x7C, 0xE2, 
-	0x02, 0x13, 0xCD, 0x83, 0x09, 0x13, 0x20, 0x07, 
-	0x34, 0x09, 0x06, 0x10, 0x8F, 0x07, 0x19, 0xFF, 
-	0xCD, 0xA3, 0x0F, 0xC8, 0x04, 0x01, 0xFF, 0x10, 
-	0xA0, 0x01, 0x02, 0x01, 0x00, 0x10, 0xE0, 0xC3, 
-	0xEE, 0x07, 0xE0, 0x43, 0x06, 0xE0, 0x0F, 0xC8, 
-	0x00, 0x01, 0x20, 0xC0, 0x04, 0xE0, 0xE0, 0x04, 
-	0xFE, 0x06, 0xD3, 0x04, 0xE0, 0x04, 0x04, 0x01, 
-	0x60, 0x04, 0x0C, 0xB8, 0x8C, 0x07, 0x00, 0x0A, 
-	0x8D, 0x07, 0x18, 0x00, 0x8E, 0x07, 0x3B, 0x59, 
-	0x0E, 0xCF, 0x4D, 0x06, 0xFD, 0x16, 0x5B, 0x04, 
-	0x93, 0x01, 0x00, 0x80, 0x20, 0x04, 0xC0, 0xE2, 
-	0x60, 0xD0, 0x98, 0x07, 0x1C, 0x13, 0x00, 0x03, 
-	0x02, 0x00, 0xA0, 0xC0, 0x46, 0x07, 0x12, 0xC8, 
-	0x46, 0x07, 0x02, 0x16, 0x93, 0x01, 0x20, 0x00, 
-	0x00, 0x03, 0x0F, 0x00, 0x20, 0x04, 0xE8, 0xE2, 
-	0x93, 0x01, 0x00, 0x20, 0x80, 0x01, 0x00, 0x40, 
-	0x00, 0x01, 0xFE, 0x00, 0x49, 0x16, 0xC4, 0xC3, 
-	0x25, 0x16, 0xD3, 0xC3, 0xC5, 0x43, 0x0C, 0x16, 
-	0xE0, 0xC3, 0x98, 0x07, 0x03, 0x11, 0xE0, 0x02, 
-	0x98, 0x07, 0x51, 0x04, 0xE0, 0xC3, 0x78, 0x07, 
-	0x0A, 0x11, 0xE0, 0x02, 0x78, 0x07, 0x51, 0x04, 
-	0xD3, 0x11, 0x4F, 0x01, 0x00, 0x20, 0xE4, 0x13, 
-	0x4F, 0x01, 0x20, 0x00, 0xD1, 0x13, 0x05, 0x2C, 
-	0x41, 0xA0, 0x21, 0x04, 0xC0, 0xE2, 0x8B, 0x07, 
-	0x0C, 0xB8, 0x00, 0x01, 0x00, 0x40, 0x0F, 0x13, 
-	0xDD, 0xC3, 0x4F, 0x02, 0x0F, 0x00, 0x2F, 0xE1, 
-	0x14, 0xE0, 0x5B, 0x04, 0xE4, 0xC3, 0xC0, 0xE1, 
-	0xCF, 0x73, 0x2F, 0x41, 0x14, 0xE0, 0x6F, 0xC3, 
-	0xEC, 0xEA, 0x8B, 0x07, 0x0C, 0xB8, 0x4B, 0xC2, 
-	0xA0, 0xC2, 0xF4, 0x07, 0x8C, 0x07, 0x08, 0x00, 
-	0xBD, 0xC0, 0xA0, 0xC3, 0xEA, 0x07, 0xE0, 0xC3, 
-	0xEC, 0x07, 0xA0, 0x06, 0x00, 0xBA, 0xC0, 0x01, 
-	0x00, 0x40, 0x02, 0xD8, 0x17, 0x01, 0x62, 0x02, 
-	0x80, 0xFF, 0xA0, 0x06, 0x54, 0xBA, 0x02, 0xC8, 
-	0x04, 0x01, 0x90, 0x03, 0x3F, 0x60, 0x59, 0x04, 
-	0xC0, 0xC3, 0xCF, 0x73, 0xEF, 0xC3, 0xC0, 0xE1, 
-	0xCF, 0x73, 0xAF, 0xC3, 0xDE, 0xEA, 0x9E, 0xC3, 
-	0x4E, 0x02, 0x0F, 0x00, 0x2E, 0x21, 0x14, 0xE0, 
-	0x08, 0x13, 0x2F, 0x40, 0x14, 0xE0, 0xCF, 0xA3, 
-	0x2F, 0x04, 0xF0, 0xE2, 0x40, 0x01, 0x00, 0x40, 
-	0xA4, 0x13, 0xC4, 0xC3, 0xC7, 0x16, 0x00, 0x01, 
-	0xFE, 0x00, 0xE6, 0x16, 0x9E, 0x10, 0x40, 0x01, 
-	0x00, 0x40, 0x05, 0x16, 0x20, 0xE0, 0x14, 0xE0, 
-	0x65, 0x02, 0x00, 0x58, 0x96, 0x10, 0x20, 0xD8, 
-	0xDE, 0x07, 0x17, 0x01, 0x8F, 0x07, 0x86, 0xFF, 
-	0x0F, 0xC8, 0x04, 0x01, 0xC0, 0x01, 0x00, 0x40, 
-	0x45, 0x02, 0xFF, 0xA7, 0x8A, 0x10, 0x20, 0xC3, 
-	0xFE, 0x06, 0x20, 0x27, 0x38, 0xE3, 0x07, 0x13, 
-	0x20, 0x23, 0x22, 0xE0, 0x1A, 0x13, 0x65, 0x02, 
-	0xFF, 0xDF, 0x20, 0x40, 0x14, 0xE0, 0x20, 0xE0, 
-	0x16, 0xE0, 0x0C, 0xC8, 0xE6, 0x08, 0x8D, 0x07, 
-	0xE2, 0x08, 0x58, 0x04, 0x20, 0x48, 0x08, 0xE0, 
-	0xFE, 0x06, 0x20, 0xC3, 0xE6, 0x08, 0x20, 0x27, 
-	0x38, 0xE3, 0x19, 0x16, 0x80, 0x03, 0x02, 0xC3,  
-	0x6C, 0xC2, 0x0A, 0x00, 0x99, 0x06, 0x60, 0x04,  
-	0x0C, 0xB8, 0xA0, 0xC2, 0xF4, 0x07, 0x8C, 0x07, 
-	0x01, 0x00, 0x8D, 0x07, 0x06, 0x06, 0xCE, 0x04, 
-	0xE0, 0xC3, 0x08, 0x06, 0x01, 0x13, 0x97, 0x06, 
-	0x20, 0xD8, 0x07, 0x06, 0x17, 0x01, 0x8B, 0x07, 
-	0x82, 0xFF, 0x0B, 0xC8, 0x04, 0x01, 0xA0, 0x06, 
-	0xB4, 0xBE, 0x60, 0x04, 0x0C, 0xB8, 0xA0, 0xC2, 
-	0xEE, 0x07, 0x8C, 0x07, 0x06, 0x00, 0x8D, 0x07, 
-	0xEE, 0x08, 0xA0, 0xC3, 0xE6, 0x07, 0xE0, 0xC3, 
-	0xE8, 0x07, 0x97, 0x06, 0xA0, 0xC2, 0xF4, 0x07, 
-	0x8D, 0x07, 0xF4, 0x08, 0xDD, 0x04, 0x8C, 0x07, 
-	0x02, 0x00, 0x97, 0x06, 0x8D, 0x07, 0x00, 0x80, 
-	0xA0, 0xC2, 0xEE, 0x08, 0x0A, 0x88, 0x0C, 0x06, 
-	0x14, 0x1B, 0x82, 0x07, 0xD0, 0xB9, 0xA0, 0xC3, 
-	0xF0, 0x08, 0xE0, 0xC3, 0xF2, 0x08, 0x8B, 0x07, 
-	0x0C, 0xE3, 0x8A, 0x02, 0x14, 0x00, 0x04, 0x1A, 
-	0x8B, 0x07, 0xBA, 0xEA, 0x2A, 0x02, 0xEC, 0xFF, 
-	0x8A, 0xA2, 0xCA, 0xA2, 0xDB, 0xC2, 0x01, 0x13, 
-	0x9B, 0x06, 0x20, 0xC8, 0xEE, 0x08, 0xF2, 0x08, 
-	0x20, 0xC8, 0x20, 0xE0, 0xEE, 0x08, 0x0D, 0xC8, 
-	0xF0, 0x08, 0x8D, 0x07, 0xEC, 0x08, 0x20, 0xE0, 
-	0x18, 0xE0, 0x65, 0x02, 0x00, 0x58, 0x58, 0x04, 
-	0x45, 0x02, 0xFF, 0xA7, 0x80, 0x03, 0x60, 0xC0, 
-	0xEE, 0x05, 0x21, 0x02, 0xE8, 0x03, 0x20, 0x01, 
-	0x02, 0x01, 0x06, 0x00, 0x07, 0x16, 0x01, 0x88, 
-	0xEE, 0x05, 0xF9, 0x16, 0x39, 0x10, 0x60, 0xD0, 
-	0x03, 0x01, 0xF1, 0x13, 0x01, 0x02, 0x0A, 0x01, 
-	0x4C, 0xCC, 0x4C, 0xCC, 0x4E, 0xCC, 0x4F, 0xCC, 
-	0xB1, 0x07, 0x40, 0x00, 0x4D, 0xCC, 0x0A, 0xC8, 
-	0x00, 0x01, 0x5B, 0x04, 0x60, 0xC0, 0xEE, 0x05, 
-	0x21, 0x02, 0xE8, 0x03, 0x20, 0x01, 0x02, 0x01, 
-	0x06, 0x00, 0x07, 0x16, 0x01, 0x88, 0xEE, 0x05, 
-	0xF9, 0x16, 0x1E, 0x10, 0x60, 0xD0, 0x03, 0x01, 
-	0xF1, 0x13, 0x01, 0x02, 0x0A, 0x01, 0x4C, 0xCC, 
-	0x4C, 0xCC, 0x4E, 0xCC, 0x4F, 0xCC, 0xB1, 0x07, 
-	0x40, 0x00, 0x4D, 0xCC, 0x0A, 0xC8, 0x00, 0x01, 
-	0xA0, 0x03, 0x60, 0xD0, 0x03, 0x01, 0x01, 0x13, 
-	0x5B, 0x04, 0x60, 0xC0, 0xEE, 0x05, 0x21, 0x02, 
-	0xE8, 0x03, 0x20, 0x01, 0x02, 0x01, 0x06, 0x00, 
-	0xF7, 0x16, 0x01, 0x88, 0xEE, 0x05, 0xF9, 0x16, 
-	0xCD, 0x04, 0x8A, 0x07, 0x00, 0x40, 0x20, 0xC3, 
-	0x00, 0x01, 0x0C, 0x01, 0x00, 0x80, 0x02, 0x13, 
-	0x8A, 0x07, 0x00, 0x20, 0xA0, 0xC3, 0x0E, 0x01, 
-	0xE0, 0xC3, 0x10, 0x01, 0xB0, 0x03, 0x20, 0xC3, 
-	0x58, 0x07, 0x20, 0x23, 0x04, 0xE0, 0x02, 0x13, 
-	0x60, 0x04, 0x8E, 0xB7, 0x60, 0x04, 0x8A, 0xA3, 
-	0x8D, 0x07, 0x00, 0x20, 0x20, 0x20, 0x0A, 0xE0, 
-	0x01, 0x16, 0x5B, 0x04, 0x0D, 0x02, 0x32, 0x0C, 
-	0x5D, 0xC2, 0x01, 0x11, 0xDD, 0x04, 0xCD, 0x05, 
-	0x0D, 0x88, 0x30, 0x0C, 0xF9, 0x16, 0x60, 0xC2, 
-	0x0A, 0x06, 0x8D, 0x07, 0x6A, 0x09, 0xA0, 0x06, 
-	0xF4, 0xBE, 0x09, 0x02, 0x48, 0x00, 0xE0, 0xC3, 
-	0x30, 0x09, 0x03, 0x16, 0xE0, 0x01, 0x6A, 0x09, 
-	0x10, 0x00, 0xE0, 0xC2, 0x6A, 0x09, 0x0F, 0x02, 
-	0x00, 0x01, 0xC9, 0x26, 0x02, 0x13, 0x60, 0x04, 
-	0x86, 0xBD, 0x09, 0x02, 0x00, 0x12, 0x4B, 0x01, 
-	0x10, 0x00, 0x02, 0x13, 0x09, 0x02, 0x00, 0x13, 
-	0x09, 0xD8, 0x2E, 0x09, 0x8F, 0x07, 0x00, 0x40, 
-	0x89, 0x07, 0x6C, 0x09, 0xCB, 0x04, 0xF9, 0xE2, 
-	0xF9, 0xE2, 0xF9, 0xE2, 0x07, 0x16, 0x8B, 0x07, 
-	0x34, 0x09, 0x8C, 0x07, 0x6C, 0x09, 0x3B, 0xCF, 
-	0x3B, 0xCF, 0x1B, 0xC7, 0x20, 0xC3, 0x6C, 0x09, 
-	0x19, 0x11, 0x8F, 0x07, 0x00, 0x20, 0x89, 0x07, 
-	0x7A, 0x09, 0xA0, 0x06, 0x3A, 0xBB, 0xA0, 0x06, 
-	0x3A, 0xBB, 0x12, 0x10, 0x4C, 0xCE, 0x5B, 0x04, 
-	0x19, 0xC3, 0x02, 0x16, 0x8C, 0x07, 0x1A, 0x00, 
-	0x4C, 0xC3, 0x2D, 0x02, 0xF8, 0xFF, 0x0A, 0x02, 
-	0x09, 0x00, 0x2D, 0x02, 0xFA, 0xFF, 0xF2, 0x13, 
-	0x0A, 0x06, 0xFB, 0x16, 0x60, 0x04, 0x86, 0xBD, 
-	0x8F, 0x07, 0x00, 0x10, 0xD9, 0xC2, 0xFA, 0x11, 
-	0x02, 0x16, 0x8B, 0x07, 0x00, 0x04, 0x4B, 0xC3, 
-	0x8D, 0x02, 0x20, 0x00, 0x02, 0x14, 0x0D, 0x02, 
-	0x20, 0x00, 0x8D, 0x02, 0x00, 0x04, 0x02, 0x12, 
-	0x0D, 0x02, 0x00, 0x04, 0x2D, 0x02, 0xF8, 0xFF, 
-	0x0D, 0xC8, 0x2C, 0x09, 0x2B, 0x02, 0xFF, 0x03, 
-	0x8B, 0x01, 0xFF, 0x03, 0x4B, 0xCE, 0x60, 0xC3, 
-	0x6A, 0x09, 0x60, 0x23, 0x18, 0xE0, 0x0C, 0x16, 
-	0x49, 0xC3, 0xDD, 0xC2, 0x0F, 0x02, 0x01, 0x01, 
-	0x8B, 0x01, 0x80, 0xC0, 0xD7, 0x16, 0x8F, 0x05, 
-	0xED, 0xC2, 0x02, 0x00, 0xD3, 0x16, 0x02, 0x10, 
-	0x8D, 0x07, 0xBA, 0xEA, 0x3D, 0xC8, 0xA8, 0x09, 
-	0x1D, 0xC8, 0xAA, 0x09, 0xCB, 0x04, 0xE0, 0x04, 
-	0xF8, 0x05, 0xE0, 0x04, 0x66, 0x09, 0x20, 0xC8, 
-	0x30, 0x0C, 0x80, 0x09, 0xA0, 0x07, 0x82, 0x09, 
-	0xFE, 0xDF, 0x8D, 0x07, 0xFE, 0xDF, 0xE0, 0xC3, 
-	0xD8, 0x07, 0xE0, 0x23, 0x16, 0xE0, 0x24, 0x16, 
-	0xE0, 0xC3, 0x30, 0x0C, 0x4F, 0x63, 0xFF, 0x04, 
-	0xFF, 0x04, 0x4D, 0x06, 0xFD, 0x16, 0x8D, 0x07, 
-	0xFE, 0xDF, 0x20, 0x04, 0xA2, 0xEA, 0xA0, 0xC3, 
-	0xA2, 0xEA, 0xEE, 0xC3, 0x12, 0x00, 0xAA, 0x16, 
-	0x6E, 0xC3, 0x18, 0x00, 0xAD, 0x09, 0x8C, 0x07, 
-	0x00, 0xE0, 0xAC, 0x09, 0x0D, 0x63, 0x0C, 0x13, 
-	0x6E, 0xC3, 0x18, 0x00, 0xAD, 0x09, 0x2D, 0x02, 
-	0x40, 0x00, 0x1D, 0x0A, 0x2D, 0x02, 0x32, 0x0C, 
-	0xBD, 0x07, 0xFF, 0x7F, 0x0C, 0x06, 0xFC, 0x16, 
-	0x20, 0xC3, 0x46, 0x04, 0x8C, 0x02, 0x80, 0x00, 
-	0x13, 0x1A, 0xAC, 0x02, 0x0C, 0xC8, 0x9A, 0x00, 
-	0xE0, 0x02, 0x80, 0x00, 0x88, 0x07, 0x80, 0x00, 
-	0x60, 0xC2, 0x46, 0x04, 0xA0, 0x06, 0x28, 0xAD, 
-	0x02, 0x10, 0x9D, 0x00, 0x05, 0x10, 0x9D, 0x00, 
-	0x8F, 0x07, 0x00, 0x08, 0x60, 0x04, 0x86, 0xBD, 
-	0x4B, 0x2D, 0x81, 0xC3, 0xC9, 0x05, 0x8F, 0x07, 
-	0x00, 0x10, 0x8E, 0x02, 0x02, 0x00, 0xF6, 0x11, 
-	0x8F, 0x07, 0x00, 0x04, 0xC9, 0x05, 0xD9, 0xC2, 
-	0xE0, 0x26, 0x26, 0xE0, 0x02, 0x16, 0x2B, 0x02, 
-	0x06, 0x00, 0x4B, 0xC6, 0x4B, 0xC3, 0xCB, 0x72, 
-	0x2E, 0x02, 0xFE, 0xFF, 0x8B, 0x83, 0xE6, 0x1B, 
-	0xCD, 0x06, 0x4D, 0x73, 0xCD, 0x82, 0xE2, 0x1B, 
-	0xE0, 0x04, 0x1A, 0x09, 0xE0, 0x04, 0x1C, 0x09, 
-	0x4D, 0xC3, 0x02, 0x13, 0x60, 0x66, 0x12, 0xE0, 
-	0xC9, 0x05, 0xCF, 0x04, 0x81, 0x2D, 0x01, 0xC8, 
-	0x6C, 0x01, 0xD4, 0x13, 0x0F, 0xC8, 0x00, 0xFC, 
-	0xC1, 0xC3, 0x0D, 0x06, 0xF7, 0x15, 0x0D, 0x02, 
-	0x36, 0x07, 0x0E, 0x02, 0x98, 0x08, 0x0C, 0x02, 
-	0x03, 0x00, 0x8D, 0xCB, 0x02, 0x00, 0x81, 0x2D, 
-	0x81, 0xCB, 0x06, 0x00, 0xC3, 0x13, 0xEE, 0x04, 
-	0x0C, 0x00, 0x2E, 0x02, 0x18, 0x00, 0x0C, 0x06, 
-	0xF4, 0x16, 0xE0, 0x04, 0x96, 0x08, 0x1F, 0x2E, 
-	0xB9, 0xC3, 0xD9, 0xC3, 0x89, 0x07, 0x12, 0x00, 
-	0x8D, 0x07, 0x3A, 0x09, 0xA0, 0x06, 0xF4, 0xBE, 
-	0x60, 0xC3, 0xD8, 0x07, 0x60, 0x23, 0x16, 0xE0, 
-	0x09, 0x16, 0x20, 0xE8, 0x10, 0xE0, 0x6A, 0x09, 
-	0x20, 0xE8, 0x18, 0xE0, 0x98, 0x07, 0x20, 0xE8, 
-	0x12, 0xE0, 0x78, 0x07, 0x60, 0xC3, 0x6A, 0x09, 
-	0x60, 0x23, 0x1E, 0xE0, 0x03, 0x16, 0x20, 0x48, 
-	0xA4, 0xE3, 0x6A, 0x09, 0x60, 0x23, 0x22, 0xE0, 
-	0x06, 0x13, 0x60, 0x27, 0xA6, 0xE3, 0x03, 0x13, 
-	0x20, 0xE8, 0x10, 0xE0, 0x6A, 0x09, 0x20, 0x2D, 
-	0x00, 0x00, 0x8E, 0x07, 0x00, 0x00, 0xA0, 0x06, 
-	0xD4, 0xBE, 0x4E, 0x05, 0x0E, 0x2C, 0xA0, 0xC0, 
-	0x04, 0x08, 0xEF, 0xC3, 0x06, 0x00, 0x1B, 0x16, 
-	0xA0, 0xC3, 0x72, 0x09, 0xE0, 0xC3, 0x74, 0x09, 
-	0xA0, 0x06, 0xC2, 0xBD, 0xA0, 0xC3, 0x76, 0x09, 
-	0xE0, 0xC3, 0x78, 0x09, 0xA0, 0x06, 0xE0, 0xBD, 
-	0x20, 0xE0, 0x0A, 0xE0, 0x60, 0xC3, 0xD8, 0x07, 
-	0x60, 0x23, 0x16, 0xE0, 0x05, 0x16, 0xE0, 0x04, 
-	0x2E, 0x06, 0x60, 0x41, 0x04, 0xE0, 0x4D, 0x2E, 
-	0x8D, 0x07, 0x00, 0x80, 0x52, 0x04, 0xCF, 0x73, 
-	0x2F, 0x02, 0x00, 0x02, 0x4F, 0xC3, 0x52, 0x04, 
-	0x20, 0x20, 0x0A, 0xE0, 0x03, 0x13, 0x8D, 0x07, 
-	0x00, 0x10, 0x5B, 0x04, 0x20, 0x40, 0x0A, 0xE0, 
-	0x40, 0x02, 0xFF, 0xF0, 0x8E, 0x07, 0x02, 0x00, 
-	0xA0, 0x06, 0xD4, 0xBE, 0x4E, 0x05, 0x0E, 0x2C, 
-	0xA0, 0xC0, 0x04, 0x08, 0xA0, 0x06, 0xB4, 0xBE, 
-	0x60, 0xC3, 0xD8, 0x07, 0x60, 0x23, 0x16, 0xE0, 
-	0x66, 0x16, 0x20, 0x04, 0xB6, 0xEA, 0x63, 0x10, 
-	0x6E, 0x02, 0x00, 0x80, 0x8D, 0x07, 0x00, 0xC0, 
-	0x0D, 0xC8, 0xA6, 0x01, 0x0E, 0xC8, 0x72, 0x09, 
-	0x0F, 0xC8, 0x74, 0x09, 0x0E, 0xC8, 0xA8, 0x01, 
-	0x0F, 0xC8, 0xAA, 0x01, 0x12, 0x10, 0x8F, 0x01, 
-	0x01, 0x00, 0x8A, 0x07, 0x76, 0x09, 0xA0, 0xE3, 
-	0x4E, 0x09, 0x8E, 0xCE, 0x9A, 0x01, 0xFE, 0xFF, 
-	0xE0, 0xE3, 0x50, 0x09, 0x8F, 0xE6, 0x8A, 0x07, 
-	0xAC, 0x01, 0x8E, 0xCE, 0x9A, 0x01, 0xFE, 0xFF, 
-	0x8F, 0xE6, 0x20, 0x20, 0x0A, 0xE0, 0x3F, 0x13, 
-	0x8D, 0x07, 0x00, 0x10, 0x5B, 0x04, 0x20, 0x20, 
-	0x0A, 0xE0, 0x03, 0x13, 0x0D, 0x02, 0x00, 0x10, 
-	0x5B, 0x04, 0x8E, 0xC3, 0x04, 0x13, 0xE0, 0x01, 
-	0x50, 0x09, 0x00, 0x01, 0x06, 0x10, 0xA0, 0x01, 
-	0x50, 0x09, 0x00, 0x01, 0xA0, 0x01, 0x78, 0x09, 
-	0x00, 0x01, 0xA0, 0xC3, 0x76, 0x09, 0xE0, 0xC3, 
-	0x78, 0x09, 0xA0, 0xE3, 0x4E, 0x09, 0xE0, 0xE3, 
-	0x50, 0x09, 0x0E, 0xC8, 0xAC, 0x01, 0x0F, 0xC8, 
-	0xAE, 0x01, 0x0E, 0xC8, 0x76, 0x09, 0x0F, 0xC8, 
-	0x78, 0x09, 0x19, 0x10, 0x6E, 0x02, 0x00, 0x80, 
-	0x0E, 0xC8, 0xA6, 0x01, 0x20, 0x20, 0x0A, 0xE0, 
-	0x12, 0x13, 0x0D, 0x02, 0x00, 0x10, 0x5B, 0x04, 
-	0x8D, 0x07, 0x28, 0x07, 0x89, 0x07, 0x0E, 0x00, 
-	0xA0, 0x06, 0xFA, 0xBE, 0x8D, 0x07, 0x28, 0x07, 
-	0xFD, 0x04, 0x8D, 0x02, 0x36, 0x07, 0xFC, 0x16, 
-	0x20, 0x48, 0x14, 0xE0, 0xFE, 0x06, 0x8D, 0x07, 
-	0x00, 0x80, 0x52, 0x04, 0xA0, 0xC2, 0xEE, 0x07, 
-	0x8C, 0x07, 0x04, 0x00, 0x8D, 0x07, 0xF0, 0x08, 
-	0x97, 0x06, 0x7D, 0xC2, 0x5D, 0xC3, 0x60, 0x43, 
-	0x22, 0xE0, 0xA0, 0x06, 0xFA, 0xBE, 0xEF, 0x10, 
-	0x0E, 0xC8, 0x06, 0x06, 0x0F, 0xC8, 0x08, 0x06, 
-	0xEA, 0x10, 0xB0, 0x03, 0xA0, 0x01, 0x60, 0x07, 
-	0x26, 0x00, 0x40, 0x02, 0x00, 0xC0, 0xE0, 0x04, 
-	0x06, 0x06, 0x8C, 0x07, 0x10, 0x40, 0xCC, 0x44, 
-	0xE0, 0x04, 0xFE, 0x06, 0x85, 0x07, 0x40, 0x80, 
-	0x5B, 0x04, 0x02, 0xC8, 0x04, 0x08, 0x8F, 0x07, 
-	0xFA, 0x07, 0xCE, 0xCB, 0x02, 0x00, 0x8E, 0x07, 
-	0x36, 0x07, 0xCE, 0xCB, 0x04, 0x00, 0x8D, 0x07, 
-	0x30, 0x06, 0x8E, 0x07, 0x10, 0x00, 0x4D, 0x2C, 
-	0x5B, 0x04, 0xA0, 0xC2, 0xF2, 0x07, 0x02, 0x10, 
-	0xA0, 0xC2, 0xF8, 0x07, 0x0B, 0xC8, 0xEA, 0x08, 
-	0x09, 0xC3, 0x0A, 0x13, 0xA0, 0x06, 0x36, 0xBA, 
-	0xA0, 0xC2, 0x00, 0x01, 0xA0, 0xE2, 0x06, 0xE0, 
-	0x4C, 0xA3, 0xCC, 0xA3, 0x01, 0x17, 0x8E, 0x05, 
-	0x4C, 0x62, 0xE0, 0xC2, 0xEA, 0x08, 0x5B, 0x04, 
-	0x8D, 0x07, 0x00, 0x10, 0x20, 0x20, 0x0A, 0xE0, 
-	0x01, 0x13, 0x5B, 0x04, 0x0D, 0x02, 0x48, 0x00, 
-	0xE0, 0xC3, 0x30, 0x09, 0x02, 0x16, 0xCE, 0x01, 
-	0x10, 0x00, 0x8D, 0x27, 0x03, 0x13, 0x0D, 0x02, 
-	0x00, 0x01, 0x52, 0x04, 0x00, 0x03, 0x02, 0x00, 
-	0x60, 0xC3, 0x6A, 0x09, 0x4D, 0x02, 0x08, 0x80, 
-	0x4E, 0x02, 0xF7, 0x7F, 0x8D, 0xE3, 0xE0, 0xC3, 
-	0xD8, 0x07, 0xE0, 0x23, 0x16, 0xE0, 0x04, 0x13, 
-	0x8D, 0x07, 0x06, 0x00, 0x8D, 0x27, 0x02, 0x13, 
-	0xA0, 0xE3, 0x10, 0xE0, 0x0E, 0xC8, 0x6A, 0x09, 
-	0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, 0x09, 0x13, 
-	0x0D, 0x02, 0x00, 0x12, 0x4E, 0x01, 0x10, 0x00, 
-	0x02, 0x13, 0x0D, 0x02, 0x00, 0x13, 0x0D, 0xD8, 
-	0x2E, 0x09, 0x60, 0xC3, 0x80, 0x01, 0x4E, 0x02, 
-	0x01, 0x00, 0x4D, 0x02, 0xFE, 0xFF, 0x4E, 0xE3, 
-	0x0D, 0xC8, 0x80, 0x01, 0x20, 0xD8, 0x40, 0xE2, 
-	0x2F, 0x09, 0x20, 0x01, 0x6A, 0x09, 0x06, 0x00, 
-	0x03, 0x13, 0x20, 0xD8, 0xD0, 0xE1, 0x2F, 0x09, 
-	0x20, 0x98, 0x83, 0x01, 0x00, 0xE2, 0x03, 0x13, 
-	0x20, 0xD8, 0x2F, 0x09, 0x83, 0x01, 0x00, 0x03, 
-	0x0F, 0x00, 0x60, 0x04, 0x88, 0xBE, 0x20, 0x20, 
-	0x0A, 0xE0, 0x03, 0x13, 0x0D, 0x02, 0x00, 0x10, 
-	0x5B, 0x04, 0x09, 0x02, 0x08, 0x00, 0x0D, 0x02, 
-	0x58, 0x09, 0xA0, 0x06, 0xF4, 0xBE, 0xA0, 0x07, 
-	0x02, 0x02, 0x00, 0x00, 0x0D, 0x02, 0x00, 0x04, 
-	0xE0, 0xC3, 0x58, 0x09, 0x0F, 0x01, 0x00, 0x7C, 
-	0x01, 0x13, 0x52, 0x04, 0x8F, 0xC3, 0x4E, 0x02, 
-	0x0F, 0x00, 0xFB, 0x13, 0x8E, 0x02, 0x0F, 0x00, 
-	0xF8, 0x13, 0x0D, 0x02, 0x00, 0x40, 0x4F, 0xC2, 
-	0x49, 0x09, 0x49, 0x02, 0x3F, 0x00, 0x09, 0x01, 
-	0x01, 0x00, 0xEF, 0x16, 0x89, 0x02, 0x06, 0x00, 
-	0xEC, 0x1A, 0x89, 0x02, 0x20, 0x00, 0xE9, 0x14, 
-	0xC9, 0x06, 0x1F, 0x09, 0x4F, 0x02, 0x00, 0x40, 
-	0x4F, 0xE2, 0x69, 0x02, 0x00, 0x80, 0x09, 0xC8, 
-	0x58, 0x09, 0x0F, 0x02, 0xFF, 0xFF, 0x4E, 0xC2, 
-	0x1F, 0x09, 0x09, 0x06, 0xFD, 0x16, 0x4F, 0x05, 
-	0x0D, 0x02, 0x00, 0x20, 0x60, 0xC2, 0x5A, 0x09, 
-	0xD4, 0x13, 0x4F, 0x26, 0xD2, 0x16, 0x0D, 0x02, 
-	0x00, 0x10, 0x60, 0xC2, 0x5C, 0x09, 0xCD, 0x13, 
-	0x4F, 0x26, 0xCB, 0x16, 0x0D, 0x02, 0x00, 0x30, 
-	0x20, 0x88, 0x5A, 0x09, 0x5C, 0x09, 0xC5, 0x13, 
-	0xE0, 0xC3, 0x5A, 0x09, 0x4E, 0xC2, 0x1F, 0x0A, 
-	0x09, 0x06, 0xFD, 0x16, 0xE0, 0xE3, 0x5E, 0x09, 
-	0x0F, 0xC8, 0x5A, 0x09, 0xE0, 0xC3, 0x5C, 0x09, 
-	0x4E, 0xC2, 0x1F, 0x0A, 0x09, 0x06, 0xFD, 0x16, 
-	0xE0, 0xE3, 0x5E, 0x09, 0x0F, 0xC8, 0x5C, 0x09, 
-	0x0F, 0x02, 0xFF, 0xFF, 0x4E, 0xC2, 0x1F, 0x0A, 
-	0x09, 0x06, 0xFD, 0x16, 0x0D, 0x02, 0x00, 0x08, 
-	0x60, 0xC2, 0x5E, 0x09, 0x4F, 0x26, 0xA5, 0x16, 
-	0x4F, 0x05, 0x0F, 0xC8, 0x5E, 0x09, 0x0F, 0x02, 
-	0x02, 0x02, 0x0E, 0x02, 0x03, 0x00, 0x60, 0xC3, 
-	0x40, 0x01, 0x0C, 0x02, 0xFE, 0xC0, 0xA0, 0x01, 
-	0x40, 0x01, 0x00, 0x04, 0xCF, 0x05, 0x09, 0x02, 
-	0x55, 0x55, 0x9C, 0x06, 0x49, 0x05, 0x9C, 0x06, 
-	0x09, 0x07, 0x9C, 0x06, 0x49, 0x05, 0x9C, 0x06, 
-	0x0E, 0x06, 0xF4, 0x16, 0xA0, 0x01, 0x40, 0x01, 
-	0x00, 0x40, 0x0D, 0xC8, 0x40, 0x01, 0x09, 0x02, 
-	0x08, 0x00, 0x0E, 0x02, 0x58, 0x09, 0x0F, 0x02, 
-	0x02, 0x02, 0xFE, 0xCF, 0x49, 0x06, 0xFD, 0x16, 
-	0x60, 0x04, 0x88, 0xBE, 0xC9, 0xC7, 0x5F, 0x82, 
-	0x01, 0x16, 0x5B, 0x04, 0xA0, 0x01, 0x40, 0x01, 
-	0x00, 0x40, 0x0D, 0xC8, 0x40, 0x01, 0x0D, 0x02, 
-	0x00, 0x01, 0x52, 0x04, 0x8D, 0x07, 0x00, 0x10, 
-	0x20, 0x20, 0x0A, 0xE0, 0x0A, 0x16, 0x8D, 0x07, 
-	0x00, 0x08, 0x20, 0x20, 0x10, 0xE0, 0x05, 0x13, 
-	0x8D, 0x07, 0x00, 0x40, 0x4F, 0x01, 0x01, 0x00, 
-	0x01, 0x16, 0x5B, 0x04, 0x20, 0xE0, 0x10, 0xE0, 
-	0x20, 0x07, 0x9C, 0x08, 0x20, 0x07, 0xB4, 0x08, 
-	0x20, 0x07, 0xCC, 0x08, 0xA0, 0x07, 0xA2, 0x08, 
-	0x84, 0x02, 0xA0, 0x07, 0xBA, 0x08, 0x84, 0x02, 
-	0xA0, 0x07, 0xD2, 0x08, 0x84, 0x02, 0xA0, 0x07, 
-	0x04, 0x09, 0x00, 0x40, 0xE0, 0x04, 0x06, 0x09, 
-	0xE0, 0x04, 0x08, 0x09, 0x0E, 0xC8, 0x4C, 0x08, 
-	0x0F, 0xC8, 0x4E, 0x08, 0x0E, 0xC8, 0x8E, 0x08, 
-	0x0F, 0xC8, 0x90, 0x08, 0xE0, 0x04, 0x5A, 0x08, 
-	0xE0, 0x04, 0x60, 0x08, 0xE0, 0x02, 0x78, 0x07, 
-	0xE0, 0x04, 0x94, 0x08, 0x20, 0x40, 0x40, 0xE3, 
-	0x20, 0xE0, 0x0C, 0xE0, 0x60, 0x04, 0xBC, 0xC6, 
-	0x80, 0x01, 0x00, 0xF0, 0xC0, 0x01, 0x00, 0x40, 
-	0x10, 0x10, 0x80, 0x01, 0x00, 0xF0, 0x0D, 0x10, 
-	0xC0, 0x01, 0x00, 0xF0, 0x20, 0x40, 0x06, 0xE0, 
-	0x08, 0x10, 0xC0, 0x01, 0x00, 0xF0, 0x80, 0x01, 
-	0x00, 0x20, 0xE0, 0xC3, 0x94, 0x08, 0x01, 0x16, 
-	0x5B, 0x04, 0x4B, 0xC0, 0x20, 0x04, 0xDA, 0xEA, 
-	0x40, 0x01, 0x00, 0x20, 0xFB, 0x16, 0x51, 0x04, 
-	0xA0, 0xC2, 0xD8, 0x07, 0x4A, 0x01, 0x40, 0x00, 
-	0x01, 0x16, 0x5B, 0x04, 0xE0, 0x02, 0x78, 0x07, 
-	0x20, 0x20, 0x0C, 0xE0, 0xEF, 0x16, 0x43, 0xC2, 
-	0x02, 0x13, 0xA0, 0x06, 0x1A, 0xC3, 0x20, 0x2F, 
-	0x36, 0x07, 0x20, 0x40, 0x0C, 0xE0, 0xA0, 0x06, 
-	0xAC, 0xC1, 0xA0, 0xC3, 0x94, 0x08, 0xFB, 0x16, 
-	0xA0, 0x06, 0x3A, 0xC2, 0x8E, 0x07, 0x04, 0x09, 
-	0x9E, 0x07, 0x00, 0x80, 0x20, 0x20, 0x10, 0xE0, 
-	0x05, 0x16, 0x8F, 0x07, 0x4C, 0x08, 0xBF, 0xCF, 
-	0xBF, 0xCF, 0x9F, 0xC7, 0xA0, 0x06, 0x5A, 0xC2, 
-	0x20, 0xE8, 0x3C, 0xE3, 0x62, 0x07, 0xA0, 0x06, 
-	0x3A, 0xC2, 0x20, 0x48, 0x3C, 0xE3, 0x62, 0x07, 
-	0x20, 0x40, 0x40, 0xE3, 0x20, 0xE0, 0x04, 0xE0, 
-	0x20, 0x48, 0x10, 0xE0, 0x58, 0x07, 0x5B, 0x04, 
-	0x80, 0x01, 0x00, 0xF0, 0x20, 0xE0, 0x04, 0xE0, 
-	0x60, 0x01, 0x60, 0x07, 0x02, 0x00, 0x02, 0x13, 
-	0x9B, 0x06, 0xB8, 0x10, 0x20, 0xE8, 0x1E, 0xE0, 
-	0x58, 0x07, 0xB4, 0x10, 0x9B, 0x06, 0x80, 0x03, 
-	0xE0, 0x02, 0x58, 0x07, 0x00, 0x01, 0x00, 0x40, 
-	0x07, 0x16, 0x8D, 0x07, 0x00, 0x09, 0xA0, 0x06, 
-	0x68, 0xB8, 0xE0, 0x02, 0x78, 0x07, 0x5B, 0x04, 
-	0xC4, 0x01, 0x02, 0x00, 0xE0, 0x02, 0x78, 0x07, 
-	0x5B, 0x04, 0x0E, 0x68, 0x96, 0x08, 0xE9, 0x04, 
-	0x0C, 0x00, 0x11, 0x10, 0x0E, 0x02, 0x00, 0x23, 
-	0x4E, 0xDB, 0x01, 0x00, 0xCC, 0x01, 0x00, 0x04, 
-	0x4C, 0xD7, 0x1C, 0x10, 0x60, 0xC2, 0x5C, 0x07, 
-	0x20, 0x06, 0x94, 0x08, 0xA9, 0xC2, 0x08, 0x00, 
-	0xA9, 0xC3, 0x0C, 0x00, 0xEA, 0x16, 0x29, 0x07, 
-	0x04, 0x00, 0x69, 0x01, 0x0A, 0x00, 0x01, 0x00, 
-	0x2D, 0x13, 0x49, 0xC3, 0x2D, 0x02, 0x0E, 0x00, 
-	0x0A, 0xC3, 0x1D, 0xD3, 0x8C, 0x01, 0x00, 0x84, 
-	0xCC, 0x01, 0x00, 0x40, 0x0A, 0x01, 0x00, 0x5E, 
-	0xDD, 0x16, 0x4C, 0xC7, 0xA9, 0xC3, 0x10, 0x00, 
-	0xE9, 0xC3, 0x12, 0x00, 0x41, 0xCA, 0x10, 0x00, 
-	0x2F, 0x02, 0x04, 0x00, 0x01, 0x17, 0x8E, 0x05, 
-	0x8C, 0x07, 0x02, 0x00, 0xA0, 0xC2, 0xF6, 0x07, 
-	0xA0, 0x06, 0x00, 0xBA, 0x69, 0xC0, 0x10, 0x00, 
-	0x29, 0xC8, 0x14, 0x00, 0x06, 0x09, 0x29, 0xC8, 
-	0x16, 0x00, 0x08, 0x09, 0x69, 0x01, 0x0E, 0x00, 
-	0x00, 0x08, 0x04, 0x16, 0x90, 0x03, 0x7F, 0x00, 
-	0xA0, 0x06, 0x5A, 0xC2, 0x40, 0x01, 0x00, 0x40, 
-	0x01, 0x16, 0x51, 0x04, 0x60, 0x04, 0xBE, 0xC1, 
-	0xA9, 0xC3, 0x0C, 0x00, 0x0B, 0x13, 0x0E, 0x68, 
-	0x96, 0x08, 0xE9, 0x04, 0x0C, 0x00, 0x29, 0xC8, 
-	0x06, 0x00, 0x6C, 0x01, 0xA0, 0xC3, 0x00, 0xFC, 
-	0x01, 0x13, 0x1E, 0x2E, 0x29, 0x07, 0x04, 0x00, 
-	0x5B, 0x04, 0x81, 0x07, 0x20, 0x20, 0x89, 0x07, 
-	0x4C, 0x08, 0x41, 0xCE, 0x63, 0xCE, 0x10, 0x00, 
-	0x63, 0xC6, 0x12, 0x00, 0xA0, 0x06, 0x54, 0xBA, 
-	0x43, 0xC2, 0x02, 0x13, 0xA0, 0x06, 0x1A, 0xC3, 
-	0x20, 0xE0, 0x10, 0xE0, 0x60, 0x04, 0xEC, 0xC1, 
-	0x40, 0x01, 0x00, 0x04, 0xEA, 0x16, 0xA0, 0x06, 
-	0xAC, 0xC1, 0xA0, 0xC2, 0xF0, 0x07, 0x8C, 0x07, 
-	0x04, 0x00, 0x8D, 0x07, 0x4C, 0x08, 0xA0, 0xC3, 
-	0x8E, 0x08, 0xE0, 0xC3, 0x90, 0x08, 0xA0, 0x06, 
-	0x36, 0xBA, 0xE0, 0xC3, 0x4E, 0x08, 0x4F, 0x01, 
-	0x01, 0x00, 0x13, 0x16, 0xE0, 0xC2, 0x94, 0x08, 
-	0xEA, 0x16, 0x60, 0x04, 0xEC, 0xC1, 0xE0, 0xC3, 
-	0x4E, 0x08, 0x4F, 0x01, 0x01, 0x00, 0x09, 0x16, 
-	0x60, 0x04, 0xEC, 0xC1, 0xA0, 0x06, 0x54, 0xBA, 
-	0xE0, 0xC3, 0x4E, 0x08, 0x4F, 0x01, 0x01, 0x00, 
-	0xD7, 0x13, 0xA0, 0xC2, 0xF0, 0x07, 0x20, 0xC3, 
-	0x7C, 0x09, 0x8D, 0x07, 0x4C, 0x08, 0x9D, 0xC3, 
-	0xA0, 0x06, 0x36, 0xBA, 0xC0, 0x06, 0x20, 0xD0, 
-	0x50, 0x08, 0xC0, 0x06, 0x40, 0x01, 0x00, 0x04, 
-	0x0A, 0x16, 0x40, 0x01, 0x80, 0x00, 0x07, 0x13, 
-	0x0E, 0xC8, 0x4C, 0x08, 0x0F, 0xC8, 0x4E, 0x08, 
-	0xA0, 0x06, 0xA2, 0xC1, 0xD8, 0x10, 0x0E, 0xC8, 
-	0x8E, 0x08, 0x0F, 0xC8, 0x90, 0x08, 0x40, 0x01, 
-	0x00, 0x04, 0x0C, 0x13, 0x40, 0x01, 0x20, 0x00, 
-	0x58, 0x16, 0x81, 0x07, 0x10, 0x20, 0x9F, 0x10, 
-	0xA0, 0x06, 0xAC, 0xC1, 0xA0, 0xC3, 0x8E, 0x08, 
-	0xE0, 0xC3, 0x90, 0x08, 0x83, 0x07, 0x98, 0x08, 
-	0x63, 0x07, 0x04, 0x00, 0x2D, 0x11, 0x83, 0x07, 
-	0xB0, 0x08, 0x63, 0x07, 0x04, 0x00, 0x28, 0x11, 
-	0x83, 0x07, 0xC8, 0x08, 0x63, 0x07, 0x04, 0x00, 
-	0x23, 0x11, 0xC3, 0x60, 0x60, 0xC2, 0x46, 0x07, 
-	0xE7, 0x13, 0x69, 0x01, 0x0E, 0x00, 0x00, 0x08, 
-	0xE3, 0x13, 0x00, 0x03, 0x02, 0x00, 0x19, 0xC8, 
-	0x46, 0x07, 0x03, 0x16, 0xA0, 0x01, 0x3A, 0x07, 
-	0x20, 0x00, 0x00, 0x03, 0x0F, 0x00, 0xC0, 0x01, 
-	0x00, 0xF0, 0x80, 0x01, 0x00, 0x20, 0x01, 0x02, 
-	0x06, 0xC4, 0x60, 0x04, 0x9A, 0xC2, 0x81, 0x07, 
-	0x80, 0x20, 0xE0, 0xC8, 0x8E, 0x08, 0x14, 0x00, 
-	0xE0, 0xC8, 0x90, 0x08, 0x16, 0x00, 0xC7, 0x10, 
-	0xE0, 0xC8, 0x50, 0x08, 0x0E, 0x00, 0xCE, 0xC8, 
-	0x10, 0x00, 0xCF, 0xC8, 0x12, 0x00, 0x40, 0x01, 
-	0x20, 0x00, 0xBB, 0x16, 0xE3, 0xC1, 0x06, 0x00, 
-	0xC7, 0xC8, 0x08, 0x00, 0x07, 0xC8, 0x6C, 0x01, 
-	0x07, 0xC8, 0xE0, 0x08, 0x08, 0x02, 0x02, 0xFC, 
-	0xB8, 0x07, 0x00, 0x81, 0xE0, 0xC1, 0xE8, 0x00, 
-	0x07, 0xCE, 0x20, 0xC8, 0x52, 0x08, 0x92, 0x08, 
-	0xDA, 0x13, 0xCE, 0xC8, 0x14, 0x00, 0xCF, 0xC8, 
-	0x16, 0x00, 0x80, 0x01, 0x00, 0x04, 0x82, 0x07, 
-	0x54, 0x08, 0x32, 0xC1, 0x08, 0x11, 0x72, 0xC1, 
-	0x92, 0xC1, 0x82, 0x07, 0x8A, 0x08, 0x04, 0xC1, 
-	0x07, 0x16, 0x60, 0x04, 0x8E, 0xC5, 0x72, 0xC1, 
-	0xB2, 0xC1, 0x84, 0x01, 0x00, 0x80, 0xF9, 0x13, 
-	0x04, 0x68, 0x92, 0x08, 0xC7, 0xC1, 0x37, 0x16, 
-	0x20, 0x98, 0x97, 0x08, 0x85, 0x09, 0x16, 0x16, 
-	0x81, 0x07, 0x40, 0x20, 0xE0, 0xC1, 0x94, 0x08, 
-	0x57, 0x13, 0xA0, 0x06, 0xAC, 0xC1, 0xF4, 0x10, 
-	0xE0, 0xC2, 0x3A, 0x07, 0xE0, 0x42, 0x62, 0x07, 
-	0xE0, 0x26, 0x3A, 0xE3, 0x02, 0x13, 0xA0, 0x06, 
-	0x92, 0xC1, 0xA0, 0x06, 0x54, 0xBA, 0x22, 0x10, 
-	0xA0, 0x06, 0x9C, 0xC1, 0x81, 0x2D, 0x01, 0xC2, 
-	0xFB, 0x13, 0xA0, 0x05, 0x96, 0x08, 0x23, 0xC8, 
-	0x08, 0x00, 0x6C, 0x01, 0xA0, 0x07, 0x02, 0xFC, 
-	0x00, 0x80, 0xC3, 0xC1, 0x27, 0x02, 0x06, 0x00, 
-	0xA0, 0x06, 0x0C, 0xB5, 0xA3, 0x05, 0x0C, 0x00, 
-	0x08, 0xC8, 0x6C, 0x01, 0x08, 0xC8, 0xE0, 0x08, 
-	0x08, 0x02, 0x02, 0xFC, 0xB8, 0x07, 0x00, 0x81, 
-	0xF8, 0xC1, 0x04, 0xC1, 0x37, 0x13, 0xE0, 0xD2, 
-	0x03, 0x01, 0xD2, 0x13, 0x0B, 0x02, 0x0A, 0x01, 
-	0xC4, 0xCE, 0xC7, 0xCE, 0xC5, 0xCE, 0xC6, 0xCE, 
-	0xFB, 0x04, 0x09, 0x02, 0x00, 0x04, 0x48, 0xA2, 
-	0xC9, 0xC6, 0x20, 0xA8, 0xE0, 0x08, 0x12, 0x01, 
-	0x20, 0xC8, 0xF2, 0x07, 0x00, 0x01, 0x47, 0xC2, 
-	0xC4, 0x81, 0x01, 0x14, 0x44, 0xC2, 0xC9, 0x61, 
-	0x09, 0xA2, 0x89, 0xA1, 0x01, 0x17, 0x85, 0x05, 
-	0x09, 0x61, 0xA8, 0x16, 0x82, 0x02, 0x8A, 0x08, 
-	0x05, 0x16, 0x40, 0x01, 0x10, 0x00, 0x12, 0x13, 
-	0x60, 0x04, 0xA6, 0xC3, 0x60, 0x04, 0xBC, 0xC4, 
-	0x60, 0x04, 0x40, 0xC3, 0x81, 0x07, 0x80, 0x20, 
-	0xFB, 0x10, 0x81, 0x07, 0x80, 0x20, 0xF8, 0x10, 
-	0x81, 0x07, 0x02, 0x20, 0xF5, 0x10, 0x81, 0x07, 
-	0x04, 0x20, 0xF2, 0x10, 0x23, 0xC8, 0x08, 0x00, 
-	0x6C, 0x01, 0x07, 0x05, 0xE0, 0xA1, 0xE8, 0x00, 
-	0x0C, 0x02, 0x04, 0xFC, 0x07, 0xCF, 0xE0, 0xC2, 
-	0x92, 0x08, 0xE8, 0x16, 0xE0, 0xD2, 0x03, 0x01, 
-	0x10, 0x16, 0xE0, 0xC2, 0x3A, 0x07, 0xE0, 0x42, 
-	0x62, 0x07, 0xE0, 0x26, 0x3A, 0xE3, 0x07, 0x13, 
-	0x90, 0x03, 0xC8, 0x2F, 0xA0, 0x06, 0x92, 0xC1, 
-	0xE0, 0xD2, 0x03, 0x01, 0x02, 0x16, 0xA0, 0x06, 
-	0x54, 0xBA, 0x23, 0xC8, 0x06, 0x00, 0x6C, 0x01, 
-	0xA3, 0xC2, 0x0E, 0x00, 0x4A, 0x01, 0x00, 0x01, 
-	0x0B, 0x13, 0x0C, 0x02, 0x0E, 0xFC, 0x5C, 0xC2, 
-	0x49, 0x02, 0x00, 0x80, 0x0D, 0x02, 0x6C, 0x09, 
-	0x7D, 0xE2, 0x09, 0xCF, 0x3D, 0xCF, 0x3D, 0xCF, 
-	0x0C, 0x02, 0x00, 0xFC, 0x6C, 0xC3, 0x06, 0x00, 
-	0x4D, 0x02, 0xFF, 0xE0, 0x4A, 0x02, 0x00, 0x02, 
-	0x8A, 0xA2, 0x8A, 0xA2, 0x4A, 0xE3, 0x60, 0xE3,  
-	0x9E, 0x09, 0x0D, 0xCB, 0x06, 0x00, 0xCD, 0x06, 
-	0x0B, 0x02, 0x0F, 0x00, 0xEC, 0x82, 0x04, 0x00, 
-	0xAD, 0x11, 0xEC, 0xC3, 0x0E, 0x00, 0x11, 0x15, 
-	0x10, 0x13, 0x6C, 0xC2, 0x14, 0x00, 0x49, 0x02, 
-	0x00, 0x1F, 0xA7, 0x13, 0xC9, 0x06, 0x89, 0x02, 
-	0x12, 0x00, 0xA3, 0x1B, 0x49, 0x01, 0x01, 0x00, 
-	0xA0, 0x13, 0xC9, 0xA2, 0xEC, 0x82, 0x04, 0x00, 
-	0x9C, 0x11, 0x4D, 0xA3, 0x9D, 0x18, 0x14, 0x11, 
-	0x60, 0x01, 0x6A, 0x09, 0x00, 0x80, 0x18, 0x13, 
-	0x1D, 0x09, 0xCC, 0xA2, 0xEB, 0xC2, 0x08, 0x00, 
-	0x7B, 0x09, 0x4B, 0x02, 0x1E, 0x00, 0xA0, 0xC3, 
-	0xF0, 0x06, 0xAB, 0x23, 0x04, 0xE0, 0x8F, 0x16, 
-	0x60, 0x27, 0x3E, 0xE3, 0x8C, 0x16, 0x4D, 0xA3, 
-	0x4D, 0xA3, 0x4D, 0xA3, 0xCD, 0x06, 0x4D, 0x02, 
-	0x07, 0x00, 0x0D, 0x88, 0xEE, 0x06, 0x0A, 0x15, 
-	0x90, 0x03, 0xFF, 0x6F, 0x53, 0x2F, 0xA0, 0x05, 
-	0x94, 0x08, 0xC3, 0x04, 0xC0, 0x01, 0x00, 0x04, 
-	0x60, 0x04, 0xAA, 0xC3, 0x60, 0x01, 0x6A, 0x09, 
-	0x00, 0x80, 0xF2, 0x13, 0x01, 0x02, 0x08, 0x20, 
-	0x60, 0x04, 0xA2, 0xC5, 0x8D, 0x07, 0x00, 0x10, 
-	0x20, 0x20, 0x0A, 0xE0, 0x0A, 0x16, 0x8D, 0x07, 
-	0x00, 0x08, 0x20, 0x20, 0x0E, 0xE0, 0x05, 0x13, 
-	0x8D, 0x07, 0x00, 0x40, 0x4F, 0x01, 0x01, 0x00, 
-	0x01, 0x16, 0x5B, 0x04, 0x20, 0xE0, 0x0E, 0xE0, 
-	0xA0, 0x07, 0xFA, 0x08, 0x00, 0x80, 0x0E, 0xC8,  
-	0xFA, 0x07, 0x0F, 0xC8, 0xFC, 0x07, 0x0E, 0xC8,  
-	0x3C, 0x08, 0x0F, 0xC8, 0x3E, 0x08, 0xE0, 0x04,  
-	0x08, 0x08, 0xE0, 0x04, 0x0E, 0x08, 0xE0, 0x02,  
-	0x98, 0x07, 0x20, 0x40, 0x4C, 0xE3, 0x20, 0x07, 
-	0x2E, 0x06, 0x60, 0x04, 0x12, 0xCA, 0x00, 0x70, 
-	0x4B, 0xC0, 0xE0, 0x04, 0x2E, 0x06, 0x0B, 0x10, 
-	0x20, 0xF0, 0x4B, 0xE3, 0x02, 0x10, 0x20, 0xF0, 
-	0x4A, 0xE3, 0x4B, 0xC0, 0xE0, 0x04, 0x2E, 0x06, 
-	0xE0, 0x01, 0x62, 0x07, 0x40, 0x00, 0x20, 0xE8, 
-	0x46, 0xE3, 0x62, 0x07, 0x20, 0x04, 0xDA, 0xEA,  
-	0x40, 0x01, 0x00, 0x20, 0x04, 0x13, 0xFA, 0x10,  
-	0x40, 0x01, 0x00, 0x40, 0xF7, 0x16, 0x20, 0x07,  
-	0x2E, 0x06, 0x20, 0x50, 0x50, 0xE3, 0x51, 0x04, 
-	0xF1, 0x10, 0xE0, 0x02, 0x58, 0x07, 0x00, 0x01, 
-	0x00, 0x40, 0x07, 0x16, 0x8D, 0x07, 0xF6, 0x08, 
-	0xA0, 0x06, 0x68, 0xB8, 0xE0, 0x02, 0x98, 0x07, 
-	0x5B, 0x04, 0xC4, 0x01, 0x04, 0x00, 0xE0, 0x02, 
-	0x98, 0x07, 0x5B, 0x04, 0x60, 0x01, 0x60, 0x07, 
-	0x04, 0x00, 0x06, 0x16, 0x20, 0xE8, 0x1C, 0xE0, 
-	0x58, 0x07, 0x80, 0x03, 0xE0, 0x02, 0x98, 0x07, 
-	0x20, 0xD8, 0xDC, 0x07, 0x17, 0x01, 0x8F, 0x07, 
-	0x8E, 0xFF, 0x0F, 0xC8, 0x04, 0x01, 0x20, 0xE8, 
-	0x06, 0xE0, 0x58, 0x07, 0x80, 0x01, 0x00, 0x80, 
-	0x5B, 0x04, 0xE0, 0xC2, 0x4A, 0x08, 0xC3, 0x82, 
-	0x03, 0x13, 0xDB, 0x2D, 0x03, 0xC8, 0x4A, 0x08, 
-	0x49, 0x01, 0x00, 0x01, 0x02, 0x16, 0x60, 0x04, 
-	0x52, 0xC9, 0xE0, 0xC0, 0xF8, 0x05, 0xFD, 0x13, 
-	0x03, 0xC8, 0x6C, 0x01, 0x20, 0xC8, 0x00, 0xFC, 
-	0xF8, 0x05, 0x88, 0x07, 0x02, 0xFC, 0x78, 0xC2, 
-	0xF8, 0xC1, 0x28, 0x02, 0x00, 0x04, 0x49, 0x01, 
-	0x00, 0x01, 0x4D, 0x16, 0x09, 0x01, 0x00, 0x5E, 
-	0x29, 0x16, 0x49, 0x01, 0x02, 0x00, 0x0B, 0x16, 
-	0x60, 0x01, 0x46, 0x08, 0x00, 0x02, 0x0A, 0x16, 
-	0x27, 0x02, 0x04, 0x00, 0x07, 0x88, 0x7E, 0x09, 
-	0x05, 0x12, 0x27, 0x02, 0xFC, 0xFF, 0xA0, 0x01, 
-	0x46, 0x08, 0x00, 0x02, 0xC7, 0xC1, 0x37, 0x15, 
-	0xD3, 0x2D, 0xE0, 0xC0, 0x4A, 0x08, 0x07, 0xA8, 
-	0x48, 0x08, 0x07, 0xA8, 0x44, 0x08, 0x0C, 0x15, 
-	0x20, 0xC8, 0x3C, 0x08, 0xFA, 0x07, 0x20, 0xC8, 
-	0x3E, 0x08, 0xFC, 0x07, 0x20, 0xC8, 0x40, 0x08, 
-	0x3C, 0x08, 0x20, 0xC8, 0x42, 0x08, 0x3E, 0x08, 
-	0x60, 0x04, 0x52, 0xC9, 0xA0, 0x06, 0x54, 0xBA, 
-	0xD3, 0x2D, 0xE0, 0xC2, 0x4A, 0x08, 0xC3, 0x82, 
-	0x01, 0x13, 0xDB, 0x2D, 0x20, 0x88, 0x3E, 0x08, 
-	0x3A, 0x08, 0x0D, 0x16, 0x20, 0x88, 0x3C, 0x08, 
-	0x38, 0x08, 0x09, 0x16, 0xE0, 0x04, 0x44, 0x08, 
-	0x82, 0x07, 0x02, 0x08, 0x04, 0x61, 0xE0, 0x04, 
-	0x48, 0x08, 0x60, 0x04, 0x1E, 0xCA, 0x20, 0xC8, 
-	0x38, 0x08, 0xFA, 0x07, 0x20, 0xC8, 0x3A, 0x08, 
-	0xFC, 0x07, 0x60, 0x04, 0x12, 0xCA, 0x07, 0xA8, 
-	0x48, 0x08, 0x04, 0xC1, 0x1B, 0x16, 0x82, 0x02, 
-	0x38, 0x08, 0x0A, 0x16, 0x60, 0x01, 0xFC, 0x07, 
-	0x01, 0x00, 0x02, 0x16, 0xA0, 0x06, 0x6E, 0xCB, 
-	0xA0, 0x06, 0xFC, 0xCA, 0x80, 0x01, 0x10, 0x00, 
-	0x32, 0xC1, 0x07, 0x11, 0x72, 0xC1, 0x92, 0xC1, 
-	0x82, 0x07, 0x38, 0x08, 0x04, 0xC1, 0x06, 0x16, 
-	0xEA, 0x10, 0x72, 0xC1, 0xB2, 0xC1, 0x84, 0x01, 
-	0x00, 0x80, 0xE5, 0x13, 0xE0, 0xD2, 0x03, 0x01, 
-	0x34, 0x13, 0x0B, 0x02, 0x0A, 0x01, 0xC4, 0xCE, 
-	0xC7, 0xCE, 0xC5, 0xCE, 0xC6, 0xCE, 0xFB, 0x04, 
-	0xC8, 0xC6, 0x03, 0xA8, 0x12, 0x01, 0x20, 0xC8, 
-	0xF8, 0x07, 0x00, 0x01, 0xC7, 0xC2, 0xC4, 0x81, 
-	0x01, 0x14, 0xC4, 0xC2, 0x0B, 0xA8, 0x44, 0x08, 
-	0x0B, 0x61, 0x0B, 0xA2, 0x8B, 0xA1, 0x01, 0x17, 
-	0x85, 0x05, 0xCB, 0x61, 0xC6, 0x16, 0x40, 0x01, 
-	0x40, 0x00, 0x15, 0x16, 0x87, 0x07, 0x20, 0x00, 
-	0xE0, 0x61, 0x44, 0x08, 0xC4, 0x81, 0x08, 0x1A, 
-	0x07, 0xA8, 0x48, 0x08, 0x07, 0xA8, 0x44, 0x08, 
-	0x07, 0x61, 0x87, 0xA1, 0x01, 0x17, 0x85, 0x05, 
-	0x80, 0x01, 0x40, 0x00, 0x03, 0xC8, 0x6C, 0x01, 
-	0xE0, 0xC1, 0x04, 0xFC, 0xAC, 0x10, 0x60, 0x04, 
-	0xBC, 0xC7, 0x20, 0x01, 0x3A, 0x07, 0x00, 0x70, 
-	0x04, 0x13, 0xA0, 0x06, 0x28, 0xC7, 0x20, 0x07, 
-	0x2E, 0x06, 0xA0, 0x06, 0x54, 0xBA, 0xC1, 0x10, 
-	0xE0, 0xD2, 0x03, 0x01, 0x0A, 0x16, 0x20, 0x01, 
-	0x3A, 0x07, 0x00, 0x70, 0x04, 0x13, 0xA0, 0x06, 
-	0x28, 0xC7, 0x20, 0x07, 0x2E, 0x06, 0xA0, 0x06, 
-	0x54, 0xBA, 0x90, 0x03, 0xBF, 0x4F, 0xD3, 0x2D, 
-	0x60, 0x01, 0xFC, 0x07, 0x01, 0x00, 0x02, 0x16, 
-	0xA0, 0x06, 0x6E, 0xCB, 0x60, 0xD2, 0x46, 0x08, 
-	0x89, 0x01, 0x00, 0xF1, 0xC9, 0x01, 0x00, 0x70, 
-	0x40, 0x01, 0x10, 0x00, 0x1C, 0x13, 0x20, 0x88, 
-	0x3E, 0x08, 0x3A, 0x08, 0x04, 0x16, 0x20, 0x88, 
-	0x3C, 0x08, 0x38, 0x08, 0x14, 0x13, 0x89, 0x01, 
-	0x00, 0x10, 0x8D, 0x07, 0x44, 0x08, 0x9D, 0x07, 
-	0x00, 0x50, 0xA0, 0xC2, 0xF6, 0x07, 0x8C, 0x07, 
-	0x02, 0x00, 0xA0, 0xC3, 0x3C, 0x08, 0xE0, 0xC3, 
-	0x3E, 0x08, 0x2F, 0x02, 0x04, 0x00, 0x01, 0x17, 
-	0x8E, 0x05, 0xA0, 0x06, 0x00, 0xBA, 0x8D, 0x07, 
-	0x46, 0x08, 0x49, 0xC7, 0xA0, 0xC2, 0xF6, 0x07, 
-	0x8C, 0x07, 0x04, 0x00, 0xA0, 0xC3, 0x38, 0x08, 
-	0xE0, 0xC3, 0x3A, 0x08, 0xCC, 0xA3, 0x01, 0x17, 
-	0x8E, 0x05, 0xA0, 0x06, 0x00, 0xBA, 0x20, 0xC8, 
-	0x3C, 0x08, 0xFC, 0x08, 0x20, 0xC8, 0x3E, 0x08, 
-	0xFE, 0x08, 0x09, 0x01, 0x00, 0x0C, 0x0C, 0x13, 
-	0x49, 0x01, 0x00, 0x04, 0x05, 0x16, 0xA0, 0x06, 
-	0x6C, 0xC7, 0xA0, 0x06, 0x38, 0xC7, 0x04, 0x10, 
-	0x90, 0x03, 0x7F, 0x40, 0xA0, 0x06, 0x6C, 0xC7, 
-	0xC0, 0x01, 0x90, 0x00, 0xA0, 0x06, 0xFC, 0xCA, 
-	0x0B, 0xC8, 0x46, 0x08, 0xE0, 0xC2, 0x42, 0x07, 
-	0x2D, 0x13, 0xE0, 0xC2, 0x2E, 0x06, 0x2A, 0x13, 
-	0xE0, 0x02, 0x58, 0x07, 0x8F, 0x07, 0xBF, 0xFF, 
-	0x0F, 0x2C, 0xE0, 0x02, 0x98, 0x07, 0xE0, 0xC0, 
-	0x5C, 0x07, 0x03, 0xC8, 0x4A, 0x08, 0x03, 0xC8, 
-	0x6C, 0x01, 0xC3, 0xC2, 0xCB, 0xA2, 0xEB, 0xC2, 
-	0x32, 0x0C, 0x32, 0x13, 0x0B, 0xC8, 0x00, 0xFC, 
-	0x0B, 0xC3, 0x4B, 0xC3, 0x0B, 0xC8, 0x6C, 0x01, 
-	0xE0, 0xC2, 0x00, 0xFC, 0xFA, 0x16, 0x00, 0x03, 
-	0x02, 0x00, 0x20, 0xC8, 0xF8, 0x05, 0x00, 0xFC, 
-	0x02, 0x16, 0x0D, 0xC8, 0xFA, 0x05, 0x0C, 0xC8, 
-	0xF8, 0x05, 0x00, 0x03, 0x0F, 0x00, 0x03, 0xC8, 
-	0x6C, 0x01, 0x1A, 0x10, 0xA0, 0xC3, 0x2E, 0x06, 
-	0x03, 0x13, 0xE0, 0xC0, 0xF8, 0x05, 0x0D, 0x16, 
-	0x4F, 0x2E, 0xC0, 0x01, 0x00, 0x80, 0xA0, 0x01, 
-	0x62, 0x07, 0x00, 0x80, 0x8E, 0xC3, 0x03, 0x13, 
-	0xA0, 0x01, 0x62, 0x07, 0x40, 0x00, 0x60, 0x04, 
-	0x4E, 0xC7, 0x03, 0xC8, 0x6C, 0x01, 0x20, 0xC8, 
-	0x00, 0xFC, 0xF8, 0x05, 0x03, 0xC8, 0x4A, 0x08, 
-	0x60, 0x01, 0x6A, 0x09, 0x00, 0x04, 0x02, 0x13, 
-	0x60, 0x04, 0xE4, 0xC7, 0x8C, 0x07, 0x0E, 0x00, 
-	0x20, 0xC2, 0x0E, 0xFC, 0x0A, 0x15, 0x09, 0x13, 
-	0x20, 0xC2, 0x14, 0xFC, 0x48, 0x02, 0x00, 0x1F, 
-	0xC8, 0x06, 0x88, 0x02, 0x12, 0x00, 0xF0, 0x1B, 
-	0x08, 0xA3, 0x88, 0x07, 0x02, 0xFC, 0x78, 0xC2, 
-	0xF8, 0xC1, 0x28, 0x02, 0x00, 0x04, 0x07, 0x83, 
-	0xE7, 0x1A, 0xCC, 0x61, 0x07, 0xC8, 0x04, 0xFC, 
-	0xCC, 0xC1, 0xC0, 0x01, 0x40, 0x00, 0x60, 0x04, 
-	0xF0, 0xC7, 0x4B, 0xC1, 0xA0, 0xC2, 0xF0, 0x07, 
-	0x20, 0xC3, 0x7A, 0x09, 0x8D, 0x07, 0xFA, 0x07, 
-	0x9D, 0xC3, 0xE0, 0xC3, 0xFC, 0x07, 0xA0, 0x06, 
-	0x00, 0xBA, 0x20, 0xC8, 0x3C, 0x08, 0x40, 0x08, 
-	0x20, 0xC8, 0x3E, 0x08, 0x42, 0x08, 0x0E, 0xC8, 
-	0x3C, 0x08, 0x0F, 0xC8, 0x3E, 0x08, 0xC4, 0x04, 
-	0x82, 0x07, 0x02, 0x08, 0xE0, 0x04, 0x44, 0x08, 
-	0x40, 0x01, 0x80, 0x00, 0x06, 0x16, 0x0E, 0xC8, 
-	0x38, 0x08, 0x0F, 0xC8, 0x3A, 0x08, 0xE0, 0x04, 
-	0x48, 0x08, 0xA0, 0x06, 0x54, 0xBA, 0xE0, 0xC2, 
-	0xFE, 0x07, 0x0D, 0x11, 0x0E, 0xC8, 0xFA, 0x07, 
-	0x0F, 0xC8, 0xFC, 0x07, 0x20, 0xC8, 0x40, 0x08, 
-	0x3C, 0x08, 0x20, 0xC8, 0x42, 0x08, 0x3E, 0x08, 
-	0xA0, 0x06, 0x32, 0xC7, 0xCB, 0x10, 0x80, 0x01, 
-	0x80, 0x00, 0x55, 0x04, 0x8B, 0xC0, 0xA0, 0xC2, 
-	0xF0, 0x07, 0x8C, 0x07, 0x04, 0x00, 0x8D, 0x07, 
-	0xFA, 0x07, 0xA0, 0xC3, 0x3C, 0x08, 0xE0, 0xC3, 
-	0x3E, 0x08, 0xA0, 0x06, 0x36, 0xBA, 0x60, 0x01, 
-	0xFC, 0x07, 0x01, 0x00, 0x04, 0x13, 0xA0, 0x07, 
-	0xFA, 0x08, 0x00, 0x80, 0x52, 0x04, 0x60, 0x01, 
-	0x60, 0x07, 0x04, 0x00, 0x07, 0x16, 0x20, 0xD0, 
-	0x04, 0xE0, 0x20, 0xE8, 0x1A, 0xE0, 0x58, 0x07, 
-	0x60, 0x04, 0x3E, 0xC7, 0xA0, 0x07, 0xFA, 0x08, 
-	0x00, 0x40, 0x20, 0xC8, 0x3C, 0x08, 0xFC, 0x08, 
-	0x20, 0xC8, 0x3E, 0x08, 0xFE, 0x08, 0xA0, 0x06, 
-	0x6C, 0xC7, 0xA0, 0x06, 0x38, 0xC7, 0xD3, 0x10, 
-	0xAD, 0xC2, 0x02, 0x00, 0x6D, 0xC2, 0x00, 0x00, 
-	0x05, 0x16, 0xAA, 0x07, 0x02, 0x00, 0x36, 0x07, 
-	0x9A, 0x2C, 0x80, 0x03, 0xEA, 0x2C, 0x02, 0x00, 
-	0x41, 0xCB, 0x00, 0x00, 0x80, 0x03, 0x2D, 0xC3, 
-	0x18, 0x00, 0xAC, 0x07, 0x02, 0x00, 0x36, 0x07, 
-	0x20, 0x4B, 0x06, 0xEB, 0x0A, 0x00, 0x20, 0xEB, 
-	0x00, 0xEB, 0x0A, 0x00, 0x9C, 0x2E, 0x80, 0x03, 
-	0xA0, 0xC2, 0x22, 0xE0, 0x60, 0x04, 0x8A, 0xA3, 
-	0xED, 0xC0, 0x18, 0x00, 0xA0, 0x06, 0x3A, 0xCC, 
-	0x80, 0x03, 0x44, 0xC2, 0xC3, 0xC0, 0x02, 0x13, 
-	0xA0, 0x06, 0x3A, 0xCC, 0x19, 0xC3, 0x09, 0xCB, 
-	0x18, 0x00, 0xC9, 0x05, 0x19, 0xCB, 0x16, 0x00, 
-	0x4C, 0xC2, 0x2C, 0x02, 0x1A, 0x00, 0x0D, 0xCF, 
-	0x0E, 0xCF, 0x0F, 0xC7, 0x99, 0x00, 0x5B, 0x04, 
-	0x8C, 0x07, 0x0A, 0x09, 0x9C, 0xC2, 0xA0, 0x22, 
-	0x14, 0xE0, 0x06, 0x13, 0xA0, 0xC2, 0x58, 0x07, 
-	0xA0, 0x22, 0x20, 0xE0, 0x01, 0x16, 0x80, 0x03, 
-	0x03, 0xC1, 0xC3, 0x04, 0x8A, 0x07, 0x04, 0x00, 
-	0x84, 0xA2, 0x3A, 0xCF, 0x3A, 0xCF, 0x3A, 0xCF, 
-	0x3A, 0xCF, 0x3A, 0xCF, 0xE0, 0x02, 0x58, 0x07, 
-	0x8D, 0x07, 0x0A, 0x09, 0x0B, 0xC8, 0xC2, 0x07, 
-	0xA0, 0x06, 0x44, 0xB8, 0xE0, 0xC2, 0xC2, 0x07, 
-	0x20, 0xE0, 0x20, 0xE0, 0xE0, 0x02, 0xB8, 0x07, 
-	0x5B, 0x04, 0x2D, 0xC3, 0x18, 0x00, 0x8C, 0xC2, 
-	0x60, 0xC2, 0x6C, 0x01, 0x0A, 0xC8, 0x6C, 0x01, 
-	0xE0, 0xC2, 0x00, 0xFC, 0x02, 0x13, 0x8B, 0xC2, 
-	0xF9, 0x10, 0x09, 0xC8, 0x6C, 0x01, 0x8B, 0x07, 
-	0xF8, 0x05, 0x5B, 0xC2, 0x0C, 0x13, 0xCB, 0x05, 
-	0x5B, 0xC2, 0xCA, 0xC6, 0xE0, 0xC2, 0x6C, 0x01, 
-	0x09, 0xC8, 0x6C, 0x01, 0x0C, 0xC8, 0x00, 0xFC, 
-	0x0B, 0xC8, 0x6C, 0x01, 0x02, 0x10, 0xCC, 0xCE, 
-	0xCA, 0xC6, 0xA0, 0xC2, 0xE0, 0x00, 0xA0, 0x22, 
-	0x1A, 0xE0, 0x06, 0x16, 0x20, 0xE8, 0x04, 0xE0, 
-	0x3A, 0x07, 0x20, 0x48, 0x1A, 0xE0, 0xE0, 0x00, 
-	0x80, 0x03, 0xE0, 0xD3, 0xAB, 0xE3, 0xE0, 0x04, 
-	0x8E, 0x09, 0xE0, 0xC1, 0xA8, 0x06, 0x05, 0x16, 
-	0x07, 0x02, 0xA2, 0x06, 0xA0, 0x06, 0x38, 0xB5, 
-	0x0B, 0x16, 0xE0, 0xC1, 0xBA, 0x06, 0x23, 0x16, 
-	0x07, 0x02, 0xB4, 0x06, 0xA0, 0x06, 0x38, 0xB5, 
-	0x1E, 0x13, 0x07, 0x02, 0xB8, 0x06, 0x02, 0x10, 
-	0x07, 0x02, 0xA6, 0x06, 0x60, 0xC1, 0x02, 0xFC, 
-	0x25, 0xC8, 0x0C, 0x00, 0x02, 0xFC, 0xC5, 0xC9, 
-	0x0C, 0x00, 0xF5, 0xCD, 0xF5, 0xCD, 0xF5, 0xCD, 
-	0xF5, 0xCD, 0xF5, 0xCD, 0xF5, 0xC5, 0xB7, 0x01, 
-	0x28, 0x00, 0x27, 0x02, 0xF4, 0xFF, 0xA7, 0x07, 
-	0x04, 0x00, 0x52, 0xCE, 0x20, 0xE8, 0x9E, 0x09, 
-	0x06, 0xFC, 0x97, 0x2E, 0xD2, 0x10, 0x00, 0x03, 
-	0x02, 0x00, 0xA0, 0x06, 0x50, 0xB5, 0x00, 0x03, 
-	0x0F, 0x00, 0x20, 0x2C, 0xF0, 0xED, 0xE0, 0x93, 
-	0xAB, 0xE3, 0x03, 0x16, 0x81, 0x02, 0x16, 0x00, 
-	0xC4, 0x16, 0x21, 0xC1, 0x10, 0xEB, 0x54, 0x04, 
-	0xE0, 0x93, 0x10, 0xE0, 0x03, 0x16, 0xA0, 0xD2, 
-	0xA8, 0xE3, 0x0B, 0x10, 0xCF, 0xD3, 0x09, 0x16, 
-	0xA0, 0x23, 0x08, 0xE0, 0x06, 0x16, 0x84, 0x07, 
-	0x20, 0x00, 0x04, 0xE8, 0xD2, 0x06, 0xA0, 0xD2, 
-	0x0C, 0xE0, 0x60, 0x04, 0xD2, 0xCE, 0x60, 0x04, 
-	0x70, 0xD1, 0x22, 0xC1, 0x04, 0x00, 0xE2, 0x04, 
-	0x02, 0x00, 0x54, 0x04, 0x02, 0xC8, 0x6C, 0x01, 
-	0x82, 0xA0, 0x22, 0xC8, 0x32, 0x0C, 0x00, 0xFC, 
-	0x02, 0x02, 0x00, 0xFC, 0xE0, 0x93, 0xAA, 0xE3, 
-	0x13, 0x16, 0xB0, 0x03, 0x20, 0x98, 0xAA, 0xE3, 
-	0x65, 0x06, 0x0D, 0x16, 0x8B, 0x07, 0x17, 0xFC, 
-	0xDB, 0xD2, 0x8B, 0x09, 0x8B, 0x02, 0x15, 0x00, 
-	0x7B, 0x1B, 0xEB, 0xD2, 0xC4, 0xEA, 0x06, 0x13, 
-	0x77, 0x15, 0x20, 0x07, 0xA0, 0x09, 0x74, 0x10, 
-	0xA0, 0x06, 0x02, 0xD0, 0xA0, 0x48, 0x04, 0xE0, 
-	0x0E, 0x00, 0x85, 0x02, 0x07, 0x00, 0x0E, 0x13, 
-	0x0E, 0x01, 0x03, 0x00, 0x0B, 0x13, 0xA0, 0x23, 
-	0x22, 0xE0, 0x03, 0x16, 0xA0, 0xD2, 0x0E, 0xE0, 
-	0x02, 0x10, 0xA0, 0xD2, 0xA8, 0xE3, 0x8E, 0x01, 
-	0x03, 0x00, 0x5E, 0x10, 0x05, 0xC8, 0xFC, 0x06, 
-	0xC3, 0xC0, 0x57, 0x16, 0xA0, 0x43, 0x10, 0xE0, 
-	0x22, 0x88, 0x0E, 0x00, 0x6C, 0x09, 0x0A, 0x16, 
-	0x22, 0x88, 0x10, 0x00, 0x6E, 0x09, 0x06, 0x16, 
-	0x22, 0x88, 0x12, 0x00, 0x70, 0x09, 0x02, 0x16, 
-	0xA0, 0xE3, 0x10, 0xE0, 0x85, 0x02, 0x09, 0x00, 
-	0x02, 0x13, 0xA0, 0x06, 0xB8, 0xD7, 0x45, 0xA1, 
-	0x65, 0xC1, 0xAC, 0xE3, 0x55, 0x04, 0x62, 0xC0, 
-	0x04, 0x00, 0x22, 0xC8, 0x06, 0x00, 0x6C, 0x01, 
-	0x82, 0x02, 0x48, 0x04, 0x02, 0x1B, 0xA0, 0x43, 
-	0x0C, 0xE0, 0x22, 0xC1, 0x0E, 0x00, 0x51, 0x04, 
-	0x42, 0xC0, 0xE1, 0x04, 0x02, 0x00, 0xA2, 0xC0, 
-	0x0C, 0x00, 0x22, 0xC1, 0x0A, 0x00, 0x20, 0x21, 
-	0x18, 0xE0, 0x07, 0x13, 0xA1, 0xC8, 0x0A, 0x00, 
-	0x0A, 0x00, 0xA1, 0xC8, 0x08, 0x00, 0x08, 0x00, 
-	0xE2, 0x10, 0x22, 0xC8, 0x06, 0x00, 0x6C, 0x01, 
-	0xA0, 0x06, 0x66, 0xD6, 0x60, 0x04, 0xB0, 0xCE, 
-	0x02, 0xC8, 0xD4, 0x06, 0x62, 0xC1, 0x02, 0x00, 
-	0x65, 0xC1, 0xD8, 0xE3, 0x55, 0x04, 0x0F, 0x10, 
-	0x0E, 0x10, 0x85, 0x07, 0xF4, 0x03, 0xF5, 0x04, 
-	0x60, 0xCD, 0xCE, 0xED, 0xA0, 0x06, 0xA2, 0xD8, 
-	0xA0, 0xE3, 0x0C, 0xE0, 0x20, 0xE8, 0x9E, 0x09, 
-	0x06, 0x04, 0xA0, 0x2E, 0xF4, 0x03, 0x60, 0x04, 
-	0xE4, 0xCC, 0xA0, 0x06, 0x26, 0xD5, 0x0C, 0x10, 
-	0xA0, 0x06, 0x66, 0xD6, 0x09, 0x10, 0xA0, 0x06, 
-	0x2A, 0xD8, 0x06, 0x10, 0xA0, 0x06, 0x66, 0xD6, 
-	0x03, 0xC8, 0x2A, 0x09, 0xA0, 0xD2, 0xAA, 0xE3, 
-	0xA0, 0x06, 0x6E, 0xCF, 0xA0, 0x92, 0x26, 0xE0, 
-	0x0C, 0x16, 0xE0, 0xD3, 0x26, 0xE0, 0xE0, 0x23, 
-	0x14, 0xE0, 0x0A, 0x13, 0x0A, 0xC1, 0xC4, 0x83, 
-	0x07, 0x13, 0xC4, 0xC3, 0x24, 0xC1, 0xDC, 0xE3, 
-	0x54, 0x04, 0xCA, 0x93, 0xDC, 0x13, 0xCA, 0xD3, 
-	0xB0, 0x03, 0x0F, 0xD8, 0x59, 0x06, 0x04, 0x71, 
-	0x24, 0xC1, 0xEC, 0xE3, 0x54, 0x04, 0xA0, 0x23, 
-	0x0C, 0xE0, 0xD1, 0x13, 0x4D, 0xC3, 0xCF, 0x13, 
-	0x4D, 0x01, 0x00, 0x04, 0x0B, 0x13, 0x86, 0x07, 
-	0x02, 0x00, 0x84, 0x07, 0x26, 0x00, 0x46, 0x23, 
-	0x03, 0x13, 0x44, 0x06, 0x86, 0xA1, 0xFB, 0x10, 
-	0x46, 0x43, 0xB3, 0x10, 0x84, 0x07, 0x18, 0x00, 
-	0x8D, 0x01, 0x00, 0x04, 0x85, 0x07, 0xF4, 0x03, 
-	0xF5, 0x04, 0x60, 0xCD, 0xCE, 0xED, 0xA0, 0x06, 
-	0xA2, 0xD8, 0x20, 0xE8, 0x9C, 0x09, 0xFE, 0x03, 
-	0x20, 0xE8, 0x9E, 0x09, 0x06, 0x04, 0xA8, 0x10, 
-	0x85, 0x07, 0x1C, 0x07, 0x86, 0x07, 0x1A, 0x04, 
-	0x76, 0x6D, 0x76, 0x6D, 0x76, 0x6D, 0xC6, 0x05, 
-	0x76, 0x6D, 0x76, 0x6D, 0x76, 0x6D, 0x83, 0x07, 
-	0x00, 0x90, 0xA9, 0x10, 0x0B, 0xC3, 0x86, 0x07, 
-	0x00, 0x01, 0x85, 0x07, 0x00, 0x80, 0x20, 0xC1, 
-	0xD2, 0x06, 0x37, 0x13, 0xC4, 0x04, 0x60, 0xC0, 
-	0xD2, 0x06, 0x45, 0x20, 0x04, 0x13, 0x84, 0x05, 
-	0x15, 0x09, 0xF9, 0x16, 0x2E, 0x10, 0xCF, 0xD3, 
-	0x06, 0x16, 0xE0, 0x23, 0x14, 0xE0, 0x03, 0x16, 
-	0x0E, 0x01, 0x03, 0x00, 0x03, 0x13, 0xE0, 0x04, 
-	0xD2, 0x06, 0x23, 0x10, 0x64, 0xD0, 0x1C, 0x07, 
-	0x46, 0xB0, 0x10, 0x18, 0x01, 0xD9, 0x1C, 0x07, 
-	0x60, 0x23, 0x20, 0xE0, 0x0B, 0x13, 0x81, 0x07, 
-	0x18, 0x00, 0x61, 0xC0, 0xFC, 0xE3, 0x11, 0x88, 
-	0xCE, 0xED, 0x04, 0x13, 0x08, 0x02, 0x18, 0x80, 
-	0xA0, 0x06, 0xDA, 0xD4, 0x64, 0xD0, 0x28, 0x07, 
-	0x46, 0xB0, 0x08, 0x18, 0x01, 0xD9, 0x28, 0x07, 
-	0x46, 0xB0, 0x04, 0x17, 0x83, 0x07, 0x40, 0x80, 
-	0xA0, 0x06, 0x2A, 0xD8, 0x05, 0x48, 0xD2, 0x06, 
-	0xCA, 0x16, 0x20, 0xC1, 0x32, 0x09, 0x01, 0x16, 
-	0x5C, 0x04, 0x04, 0x02, 0x07, 0x00, 0x20, 0x06, 
-	0x32, 0x09, 0x05, 0x02, 0x00, 0x01, 0xC7, 0x10, 
-	0x0B, 0xC3, 0xC5, 0x04, 0x42, 0xC0, 0xC7, 0x04, 
-	0x20, 0xC2, 0x6C, 0x01, 0xE1, 0xA1, 0x04, 0x00, 
-	0x11, 0xC8, 0x6C, 0x01, 0xFB, 0x16, 0x08, 0xC8, 
-	0x6C, 0x01, 0xC8, 0x04, 0xA0, 0x43, 0x1A, 0xE0, 
-	0x22, 0xC1, 0x0E, 0x00, 0x0D, 0x15, 0x0C, 0x13, 
-	0xA0, 0xE3, 0x1A, 0xE0, 0xA0, 0x06, 0x14, 0xD8, 
-	0x08, 0xC2, 0x48, 0x13, 0x88, 0x02, 0x12, 0x00, 
-	0x45, 0x1B, 0x20, 0x22, 0x22, 0xE0, 0x42, 0x13, 
-	0x02, 0xC1, 0x08, 0xA1, 0x08, 0x05, 0x28, 0x02, 
-	0xF2, 0xFF, 0x07, 0xA2, 0x83, 0x07, 0x01, 0x80, 
-	0x88, 0x02, 0x04, 0x00, 0x6E, 0x11, 0x64, 0xC2, 
-	0x16, 0x00, 0x49, 0xD2, 0x02, 0x16, 0x02, 0x81, 
-	0x31, 0x16, 0x09, 0x01, 0x00, 0xF0, 0x28, 0x16, 
-	0x49, 0xC1, 0x45, 0x71, 0xC3, 0x04, 0x85, 0x02, 
-	0x09, 0x00, 0x7C, 0x13, 0x83, 0x07, 0x02, 0x80, 
-	0xA4, 0xC1, 0x14, 0x00, 0x88, 0x81, 0x76, 0x16, 
-	0x83, 0x05, 0x85, 0x02, 0x15, 0x00, 0x13, 0x1B, 
-	0x83, 0x05, 0x49, 0x99, 0x30, 0xEB, 0x0A, 0x13, 
-	0x09, 0x98, 0x0E, 0xE0, 0x6B, 0x16, 0x25, 0x98, 
-	0x30, 0xEB, 0x0C, 0xE0, 0x67, 0x16, 0xE0, 0xC1, 
-	0xEC, 0x06, 0x64, 0x16, 0xC3, 0x04, 0x52, 0xC2, 
-	0x0F, 0x13, 0x83, 0x07, 0x09, 0x80, 0xE0, 0xC1, 
-	0x6A, 0x09, 0x47, 0x01, 0x00, 0x10, 0x5A, 0x16, 
-	0xA0, 0xC0, 0x6C, 0x01, 0xA0, 0x06, 0xBE, 0xD6, 
-	0x60, 0x04, 0xB0, 0xCE, 0x60, 0x04, 0xBA, 0xCE, 
-	0x89, 0x07, 0x0E, 0x07, 0xC7, 0x04, 0xE5, 0xD1, 
-	0x46, 0xEB, 0x05, 0x13, 0xC7, 0x06, 0x27, 0x02, 
-	0x5C, 0xEB, 0x77, 0xCE, 0xFE, 0x15, 0x44, 0xC0, 
-	0x21, 0x02, 0x18, 0x00, 0x28, 0x02, 0xFC, 0xFF, 
-	0x36, 0x13, 0x91, 0xC1, 0x86, 0xD1, 0x1F, 0x13, 
-	0xC6, 0x06, 0x87, 0x07, 0x0E, 0x07, 0xF7, 0xC0, 
-	0x46, 0x02, 0xFF, 0xBF, 0x43, 0x02, 0xFF, 0x3F, 
-	0xA0, 0x91, 0xF5, 0xED, 0x09, 0x16, 0xB0, 0x03, 
-	0x20, 0x98, 0x0E, 0xE0, 0x5D, 0x06, 0x0F, 0x16, 
-	0x21, 0xC8, 0x02, 0x00, 0x0C, 0x07, 0x17, 0x10, 
-	0x47, 0x82, 0x0C, 0x1B, 0xC6, 0x90, 0xEB, 0x16, 
-	0x47, 0x06, 0xF7, 0x04, 0xB0, 0x03, 0x20, 0x98, 
-	0x5D, 0x06, 0x57, 0x06, 0x0C, 0x13, 0x83, 0x07, 
-	0x05, 0x80, 0x1C, 0x10, 0xD1, 0xC0, 0xE0, 0x20, 
-	0x16, 0xE0, 0x03, 0x16, 0x83, 0x07, 0x08, 0x80, 
-	0x15, 0x10, 0x60, 0x44, 0x26, 0xE0, 0x86, 0x71, 
-	0x46, 0xA0, 0x06, 0x62, 0x83, 0x07, 0x05, 0x80, 
-	0x08, 0xC2, 0xCB, 0x15, 0x0B, 0x16, 0xC3, 0x04, 
-	0x87, 0x07, 0x0E, 0x07, 0x77, 0xC0, 0x47, 0x82, 
-	0x05, 0x1B, 0x60, 0x20, 0x06, 0xE0, 0xFA, 0x16, 
-	0x83, 0x07, 0x07, 0x80, 0x5C, 0x04, 0xA0, 0x92, 
-	0x0E, 0xE0, 0x11, 0x16, 0x20, 0xC8, 0x20, 0xE0, 
-	0x08, 0x07, 0xE0, 0x04, 0x84, 0x01, 0x60, 0x05, 
-	0x02, 0x07, 0x4B, 0x13, 0x20, 0x48, 0x06, 0xE0, 
-	0x82, 0x01, 0xA0, 0x06, 0xD0, 0xD4, 0x83, 0x07, 
-	0x00, 0xC0, 0xA0, 0x06, 0x2A, 0xD8, 0x20, 0xC8, 
-	0x1E, 0xE0, 0x02, 0x07, 0xA0, 0xE3, 0x04, 0xE0, 
-	0x08, 0x02, 0x24, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 
-	0x42, 0x10, 0x20, 0xC1, 0x84, 0x01, 0x44, 0x02, 
-	0x00, 0x88, 0x2A, 0x13, 0x04, 0x48, 0x84, 0x01, 
-	0x20, 0x06, 0x02, 0x07, 0xF1, 0x16, 0x60, 0x01, 
-	0x8E, 0x09, 0x00, 0x80, 0x15, 0x13, 0xA0, 0x23, 
-	0x22, 0xE0, 0x05, 0x16, 0xA0, 0x43, 0x22, 0xE0, 
-	0xA0, 0xD2, 0x0E, 0xE0, 0xCF, 0x10, 0xE0, 0x23, 
-	0x14, 0xE0, 0x04, 0x13, 0x20, 0x98, 0xA9, 0xE3, 
-	0x65, 0x06, 0x0C, 0x16, 0xA0, 0x92, 0x0E, 0xE0, 
-	0xC5, 0x13, 0xA0, 0xD2, 0xA8, 0xE3, 0xD3, 0x10, 
-	0x20, 0xC8, 0x20, 0xE0, 0x08, 0x07, 0x83, 0x07, 
-	0x00, 0xC0, 0x04, 0x10, 0x83, 0x07, 0x02, 0x00, 
-	0x60, 0x04, 0xCA, 0xCE, 0x60, 0x04, 0xC0, 0xCE, 
-	0x20, 0xE8, 0x06, 0xE0, 0x82, 0x01, 0xA0, 0x06, 
-	0xD0, 0xD4, 0x20, 0x07, 0x02, 0x07, 0xA0, 0x43, 
-	0x04, 0xE0, 0x20, 0xC8, 0xAE, 0xE4, 0x86, 0x01, 
-	0x20, 0x88, 0x20, 0xE0, 0x08, 0x07, 0x03, 0x16, 
-	0x20, 0xC8, 0x78, 0xEB, 0x08, 0x07, 0x60, 0x04, 
-	0xD2, 0xCE, 0x0E, 0x01, 0x03, 0x00, 0x16, 0x13, 
-	0xCF, 0xD3, 0x08, 0x16, 0xA0, 0x23, 0x20, 0xE0, 
-	0x03, 0x16, 0xA0, 0xD2, 0xA8, 0xE3, 0x02, 0x10, 
-	0xA0, 0xD2, 0x0E, 0xE0, 0x8E, 0x01, 0x03, 0x00, 
-	0x09, 0x10, 0x60, 0xC1, 0x84, 0x01, 0x60, 0x21, 
-	0x0A, 0xE0, 0x04, 0x16, 0x83, 0x07, 0x00, 0x84, 
-	0x60, 0x04, 0xCA, 0xCE, 0x20, 0xC8, 0x2E, 0xE0, 
-	0x84, 0x01, 0x08, 0x02, 0x06, 0x80, 0xA0, 0x06, 
-	0xDA, 0xD4, 0x60, 0x04, 0xD2, 0xCE, 0x60, 0xE3, 
-	0x20, 0xE0, 0x60, 0x04, 0xD2, 0xCE, 0xE0, 0x93, 
-	0x26, 0xE0, 0x10, 0x16, 0xA0, 0x23, 0x08, 0xE0, 
-	0x0D, 0x16, 0xA0, 0x23, 0x06, 0xE0, 0x02, 0x13, 
-	0x60, 0xE3, 0x1C, 0xE0, 0x60, 0xE3, 0x18, 0xE0, 
-	0xA0, 0x43, 0x06, 0xE0, 0x08, 0x02, 0x3C, 0x80, 
-	0xA0, 0x06, 0xDA, 0xD4, 0x60, 0x04, 0xD2, 0xCE, 
-	0xA0, 0x92, 0xA8, 0xE3, 0x03, 0x13, 0xA0, 0x92, 
-	0xA9, 0xE3, 0x1E, 0x16, 0xE0, 0x23, 0x14, 0xE0, 
-	0x08, 0x13, 0x20, 0x98, 0xA9, 0xE3, 0x65, 0x06, 
-	0x04, 0x13, 0x83, 0x07, 0x07, 0x00, 0x60, 0x04, 
-	0xCA, 0xCE, 0xA0, 0xD2, 0x0E, 0xE0, 0x20, 0xC8, 
-	0x20, 0xE0, 0x08, 0x07, 0xA0, 0x27, 0x04, 0xE0, 
-	0x0B, 0x16, 0x20, 0xC8, 0x1E, 0xE0, 0x08, 0x07, 
-	0xE0, 0x93, 0xA8, 0xE3, 0x05, 0x16, 0xA0, 0x23, 
-	0x12, 0xE0, 0x02, 0x13, 0x20, 0x06, 0x08, 0x07, 
-	0x60, 0x04, 0xD2, 0xCE, 0xE0, 0x23, 0x14, 0xE0, 
-	0x3E, 0x13, 0xB0, 0x03, 0x20, 0x98, 0x0E, 0xE0, 
-	0x6F, 0x06, 0x0F, 0x16, 0xCF, 0xD3, 0x37, 0x16, 
-	0xA0, 0xD2, 0xA8, 0xE3, 0x60, 0x04, 0xD2, 0xCE, 
-	0xA0, 0x92, 0x0C, 0xE0, 0x30, 0x16, 0xE0, 0x23, 
-	0x14, 0xE0, 0xF6, 0x13, 0x83, 0x07, 0x06, 0x00, 
-	0x07, 0x10, 0x83, 0x07, 0x05, 0x00, 0xE0, 0x93, 
-	0x0E, 0xE0, 0x02, 0x16, 0x83, 0x07, 0x07, 0x00, 
-	0x60, 0x04, 0xCA, 0xCE, 0x60, 0xE3, 0x12, 0xE0, 
-	0xE0, 0x23, 0x14, 0xE0, 0x11, 0x13, 0x20, 0x98, 
-	0x0C, 0xE0, 0x65, 0x06, 0x03, 0x16, 0x20, 0xD8, 
-	0xA9, 0xE3, 0x65, 0x06, 0x14, 0x10, 0x60, 0x01, 
-	0x8E, 0x09, 0x00, 0x80, 0x10, 0x13, 0x20, 0xC1, 
-	0x84, 0x01, 0x20, 0x21, 0x06, 0xE0, 0xD2, 0x16, 
-	0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, 0x07, 0x13, 
-	0x20, 0x48, 0x06, 0xE0, 0x84, 0x01, 0x08, 0x02, 
-	0x30, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x60, 0x04, 
-	0xD2, 0xCE, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x20, 
-	0xFA, 0x16, 0x08, 0x02, 0x78, 0x80, 0xA0, 0x06, 
-	0xDA, 0xD4, 0x20, 0xC2, 0xA2, 0x09, 0x03, 0x13, 
-	0x20, 0x06, 0xA2, 0x09, 0x21, 0x13, 0x20, 0xC2, 
-	0xA4, 0x09, 0xED, 0x13, 0x20, 0x06, 0xA4, 0x09, 
-	0xEA, 0x16, 0xA0, 0x07, 0xA4, 0x09, 0x05, 0x00, 
-	0xCD, 0x01, 0x00, 0x04, 0xE4, 0x10, 0x60, 0x01, 
-	0x8E, 0x09, 0x80, 0x00, 0x3E, 0x13, 0x60, 0x01, 
-	0x8E, 0x09, 0x00, 0x10, 0x02, 0x16, 0xA0, 0x06, 
-	0xE6, 0xD5, 0xA0, 0x01, 0x8E, 0x09, 0x00, 0x10, 
-	0xE0, 0x01, 0x8E, 0x09, 0x80, 0x00, 0x83, 0x07, 
-	0x00, 0xA8, 0xA0, 0x06, 0x2A, 0xD8, 0x16, 0x10, 
-	0x60, 0x01, 0x8E, 0x09, 0x00, 0x04, 0x21, 0x13, 
-	0xE0, 0x01, 0x8E, 0x09, 0x00, 0x10, 0xA0, 0x07, 
-	0x08, 0x07, 0x05, 0x00, 0x83, 0x07, 0x08, 0xA8, 
-	0xA0, 0x23, 0x04, 0xE0, 0x05, 0x16, 0x20, 0xC8,  
-	0x20, 0xE0, 0x08, 0x07, 0x83, 0x07, 0x08, 0xE8,  
-	0xA0, 0x06, 0x2A, 0xD8, 0xA0, 0x01, 0x8E, 0x09, 
-	0x00, 0x20, 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x01, 
-	0xE0, 0x01, 0x82, 0x01, 0x00, 0x08, 0xA0, 0xD2, 
-	0x0E, 0xE0, 0x83, 0x07, 0x10, 0x80, 0x60, 0x04, 
-	0xC0, 0xCE, 0x08, 0x02, 0x78, 0x00, 0xA0, 0x06, 
-	0xDA, 0xD4, 0x83, 0x07, 0x00, 0x82, 0x60, 0x04, 
-	0xCA, 0xCE, 0x60, 0x04, 0xD2, 0xCE, 0x20, 0x06, 
-	0x90, 0x09, 0x07, 0x15, 0xA0, 0xD2, 0x10, 0xE0, 
-	0xCA, 0x06, 0xA0, 0xD2, 0x26, 0xE0, 0xCF, 0x04, 
-	0xF4, 0x10, 0x08, 0x02, 0x7E, 0x80, 0xA0, 0x06, 
-	0xDA, 0xD4, 0x20, 0xC2, 0x90, 0x09, 0x88, 0x02,  
-	0x96, 0x00, 0x0D, 0x1B, 0xEA, 0x16, 0x20, 0x48,  
-	0x08, 0xE0, 0x82, 0x01, 0xA0, 0x01, 0x8E, 0x09, 
-	0x00, 0x10, 0xA0, 0x06, 0xE6, 0xD5, 0x83, 0x07, 
-	0x00, 0x28, 0x60, 0x04, 0xC0, 0xCE, 0x60, 0x01, 
-	0x8E, 0x09, 0x00, 0x10, 0xDA, 0x16, 0x84, 0x07, 
-	0x04, 0x00, 0x85, 0x07, 0xF4, 0x03, 0xF5, 0x04, 
-	0xB5, 0x07, 0x30, 0x06, 0xA0, 0x06, 0xA2, 0xD8, 
-	0xA0, 0x07, 0xF8, 0x03, 0x34, 0xD4, 0x60, 0x04, 
-	0xC0, 0xDB, 0xA0, 0x07, 0x90, 0x09, 0xF4, 0x01, 
-	0x08, 0x02, 0x7E, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 
-	0x08, 0x02, 0x36, 0x00, 0xA0, 0x06, 0xDA, 0xD4, 
-	0x20, 0xE8, 0x0C, 0xE0, 0x82, 0x01, 0xA0, 0x23, 
-	0x18, 0xE0, 0x06, 0x13, 0xA0, 0xE3, 0x18, 0xE0, 
-	0xE0, 0x2E, 0x00, 0x00, 0x41, 0xC0, 0xFA, 0x16, 
-	0xA0, 0x06, 0xE6, 0xD5, 0xB2, 0x10, 0x04, 0x02, 
-	0x64, 0x00, 0x04, 0x06, 0xFE, 0x16, 0x5B, 0x04, 
-	0xA0, 0xE3, 0x0A, 0xE0, 0x08, 0xC2, 0x02, 0x11, 
-	0xA0, 0x43, 0x0A, 0xE0, 0x20, 0x42, 0x04, 0xE0, 
-	0x28, 0x02, 0xFC, 0xE3, 0x58, 0xC0, 0x02, 0xC0, 
-	0x11, 0x88, 0xCE, 0xED, 0x03, 0x16, 0xD1, 0x2C, 
-	0x58, 0xC0, 0xD1, 0x04, 0x80, 0xC0, 0x0E, 0x01, 
-	0x00, 0x10, 0x0F, 0x13, 0x60, 0xCC, 0xCE, 0xED, 
-	0xC8, 0x05, 0x78, 0xCC, 0x03, 0x16, 0x41, 0x06, 
-	0x60, 0xCC, 0xD6, 0x06, 0x58, 0xC4, 0x02, 0x16, 
-	0x60, 0xC4, 0x00, 0x07, 0x21, 0x02, 0xFA, 0xFF, 
-	0x91, 0x2C, 0x5B, 0x04, 0x0B, 0xC3, 0xA0, 0x06, 
-	0xC2, 0xD5, 0xA0, 0x06, 0x9C, 0xD5, 0x08, 0xC2, 
-	0x05, 0x16, 0x62, 0xC2, 0x02, 0x00, 0x60, 0x26, 
-	0xA8, 0xE4, 0x0D, 0x16, 0x42, 0xC2, 0xC9, 0x05, 
-	0x60, 0xCE, 0xF2, 0xED, 0x60, 0xC6, 0x7C, 0xEB, 
-	0xA0, 0x06, 0x10, 0xD6, 0x18, 0xCA, 0x0A, 0x00, 
-	0x20, 0x46, 0x26, 0xE0, 0x04, 0x16, 0xA0, 0xC0, 
-	0x6C, 0x01, 0x12, 0x2E, 0x1D, 0x10, 0x12, 0xC1, 
-	0x05, 0x13, 0x60, 0xC1, 0x6C, 0x01, 0x14, 0x2E, 
-	0x05, 0xC8, 0x6C, 0x01, 0xD2, 0x04, 0x48, 0x06, 
-	0x84, 0x07, 0x02, 0x00, 0x48, 0xC1, 0xA0, 0xC0, 
-	0x6C, 0x01, 0x02, 0xC0, 0xA0, 0x06, 0xA2, 0xD8, 
-	0x60, 0xC5, 0x02, 0xFC, 0x07, 0x02, 0xA2, 0x06, 
-	0x25, 0x02, 0xF4, 0xFF, 0x05, 0xC8, 0x02, 0xFC, 
-	0x20, 0xC2, 0x6C, 0x01, 0xA0, 0x06, 0xFC, 0xB4, 
-	0x5C, 0x04, 0x42, 0xC2, 0x29, 0x02, 0x08, 0x00, 
-	0x39, 0xC2, 0x48, 0x02, 0x00, 0xC0, 0x88, 0x02, 
-	0x00, 0xC0, 0x08, 0x16, 0x60, 0x8E, 0x2E, 0xE0, 
-	0x05, 0x16, 0x60, 0x86, 0x2E, 0xE0, 0x02, 0x16, 
-	0xC8, 0x04, 0x5B, 0x04, 0x08, 0x07, 0x5B, 0x04, 
-	0x20, 0x88, 0x8E, 0xE1, 0x6C, 0x01, 0x02, 0x16,  
-	0x60, 0x04, 0xBA, 0xCE, 0x5B, 0x04, 0x88, 0x07,  
-	0xAE, 0x01, 0x20, 0xE8, 0x0E, 0xE0, 0x80, 0x01, 
-	0x08, 0x06, 0xFE, 0x16, 0x20, 0x48, 0x0E, 0xE0, 
-	0x80, 0x01, 0x5B, 0x04, 0xC2, 0x04, 0xA0, 0x23, 
-	0x0C, 0xE0, 0x10, 0x16, 0x20, 0x2F, 0x30, 0x06, 
-	0x82, 0x07, 0xDF, 0xFF, 0x02, 0x2C, 0x82, 0x02, 
-	0xF4, 0x03, 0x06, 0x13, 0xE2, 0x04, 0x02, 0x00, 
-	0xA2, 0xC0, 0x06, 0x00, 0x12, 0x2E, 0xF4, 0x10, 
-	0xA0, 0x43, 0x0C, 0xE0, 0x5B, 0x04, 0x42, 0xC2, 
-	0x88, 0x07, 0x0E, 0x00, 0x09, 0xA2, 0x29, 0x02, 
-	0x08, 0x00, 0x78, 0xCE, 0x78, 0xCE, 0x78, 0xCE, 
-	0x60, 0xCE, 0x6C, 0x09, 0x60, 0xCE, 0x6E, 0x09, 
-	0x60, 0xCE, 0x70, 0x09, 0xA0, 0x23, 0x1A, 0xE0, 
-	0x0F, 0x16, 0x58, 0xC2, 0x49, 0x02, 0x80, 0x1F, 
-	0x60, 0x2A, 0x14, 0xE0, 0xA0, 0xE8, 0x04, 0xE0, 
-	0x0E, 0x00, 0x09, 0xC6, 0x49, 0x02, 0x00, 0x1F, 
-	0xC9, 0x06, 0x09, 0xA2, 0x89, 0xA8, 0x04, 0x00, 
-	0x28, 0x02, 0x02, 0x00, 0x58, 0xC2, 0x49, 0x0A, 
-	0x49, 0x02, 0x00, 0xF0, 0x09, 0xD6, 0xE2, 0x04, 
-	0x06, 0x00, 0x5B, 0x04, 0x00, 0x07, 0x82, 0xC0, 
-	0x53, 0x13, 0xA0, 0xC0, 0x6C, 0x01, 0xA0, 0xC1, 
-	0x06, 0xFC, 0x46, 0x02, 0x0F, 0x00, 0x86, 0x02, 
-	0x01, 0x00, 0x3D, 0x12, 0x06, 0x88, 0xF2, 0x06, 
-	0x12, 0x16, 0x01, 0x02, 0x0E, 0xFC, 0x31, 0x88, 
-	0xF4, 0x06, 0x0D, 0x16, 0x31, 0x88, 0xF6, 0x06, 
-	0x0A, 0x16, 0x31, 0x88, 0xF8, 0x06, 0x07, 0x16, 
-	0x86, 0x02, 0x02, 0x00, 0x2C, 0x16, 0x20, 0x88, 
-	0x0A, 0x07, 0xFA, 0x06, 0x28, 0x13, 0x20, 0xC1, 
-	0x6A, 0x09, 0x44, 0x01, 0x00, 0x08, 0x06, 0x13, 
-	0x86, 0x02, 0x02, 0x00, 0x20, 0x16, 0x44, 0x01, 
-	0x80, 0x00, 0x1D, 0x16, 0x00, 0x07, 0xE0, 0x23, 
-	0x14, 0xE0, 0x19, 0x16, 0x82, 0x02, 0x43, 0x00, 
-	0x16, 0x13, 0x00, 0x02, 0x02, 0xFC, 0x40, 0xC0, 
-	0xB0, 0x01, 0x20, 0x00, 0x60, 0x01, 0x6A, 0x09, 
-	0x01, 0x00, 0x07, 0x16, 0x60, 0xA0, 0x2C, 0x09, 
-	0x60, 0xCC, 0xEE, 0x05, 0x50, 0xC4, 0x20, 0xC4, 
-	0x2C, 0x09, 0x80, 0x07, 0x36, 0x07, 0x81, 0x07, 
-	0x40, 0x00, 0x40, 0x2C, 0xC0, 0x04, 0x84, 0x07, 
-	0xF2, 0x06, 0x06, 0xCD, 0x01, 0x02, 0x0E, 0xFC, 
-	0x31, 0xCD, 0x31, 0xCD, 0x31, 0xCD, 0x20, 0xC5, 
-	0x0A, 0x07, 0x00, 0xC0, 0x01, 0x13, 0x12, 0x2E, 
-	0xE0, 0x04, 0x6C, 0x01, 0x5B, 0x04, 0x60, 0x01, 
-	0x8A, 0x09, 0x00, 0x80, 0x12, 0x13, 0x0B, 0xC8, 
-	0x22, 0x09, 0xA0, 0x06, 0x3E, 0xD7, 0x08, 0x02, 
-	0x42, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x08, 0x02, 
-	0x30, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0xE0, 0xC2, 
-	0x22, 0x09, 0x5B, 0x04, 0x20, 0x48, 0xAC, 0xE4, 
-	0x80, 0x01, 0x20, 0x48, 0x7E, 0xEB, 0x82, 0x01, 
-	0x20, 0x48, 0x22, 0xE0, 0xAE, 0x01, 0x20, 0x48, 
-	0x22, 0xE0, 0x78, 0x09, 0x60, 0x43, 0x18, 0xE0, 
-	0xA0, 0x43, 0x08, 0xE0, 0x60, 0x01, 0x8A, 0x09, 
-	0x00, 0x80, 0xEB, 0x13, 0x0B, 0xC3, 0x08, 0x02, 
-	0x42, 0x00, 0xA0, 0x06, 0xDA, 0xD4, 0x5C, 0x04, 
-	0x0B, 0xC3, 0x20, 0xE8, 0x0E, 0xE0, 0x82, 0x01, 
-	0x20, 0xE8, 0x22, 0xE0, 0xAE, 0x01, 0x20, 0xE8, 
-	0x22, 0xE0, 0x78, 0x09, 0xA0, 0xE3, 0x08, 0xE0, 
-	0x60, 0xE3, 0x18, 0xE0, 0xA0, 0x43, 0x06, 0xE0, 
-	0x08, 0x02, 0x3C, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 
-	0x08, 0x02, 0x42, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 
-	0x5C, 0x04, 0x0B, 0xC3, 0x83, 0x07, 0x00, 0x68, 
-	0xA0, 0x06, 0x2A, 0xD8, 0x83, 0x07, 0x10, 0x80, 
-	0xA0, 0x06, 0x2A, 0xD8, 0x5C, 0x04, 0x0B, 0xC3, 
-	0xA0, 0x06, 0x14, 0xD8, 0x02, 0xA2, 0x68, 0xC2, 
-	0x14, 0x00, 0x29, 0x02, 0xFC, 0xFF, 0x24, 0x13, 
-	0x28, 0x02, 0x18, 0x00, 0x87, 0x07, 0x0E, 0x00, 
-	0x81, 0x07, 0x0E, 0x07, 0xF1, 0x04, 0x47, 0x06, 
-	0xFD, 0x15, 0x58, 0xC0, 0xB0, 0x03, 0x01, 0x78, 
-	0x63, 0x06, 0x41, 0x02, 0x3F, 0x00, 0x0E, 0x13, 
-	0x81, 0x02, 0x1F, 0x00, 0x0B, 0x1B, 0x41, 0xA0, 
-	0x61, 0xC0, 0x86, 0xE4, 0xF8, 0xC1, 0xC7, 0x06, 
-	0xC7, 0x71, 0x47, 0x06, 0x78, 0xCC, 0x47, 0x06, 
-	0xFD, 0x15, 0x04, 0x10, 0x58, 0xC0, 0xC1, 0x06, 
-	0x41, 0x70, 0x01, 0xA2, 0x49, 0xC2, 0xE5, 0x15, 
-	0x5C, 0x04, 0xA0, 0x23, 0x1A, 0xE0, 0x02, 0x13, 
-	0xC8, 0x04, 0x5B, 0x04, 0x22, 0xC2, 0x14, 0x00, 
-	0x48, 0x02, 0x00, 0x1F, 0xC8, 0x06, 0x5B, 0x04, 
-	0x83, 0x02, 0x0F, 0x00, 0x17, 0x1B, 0xA0, 0xC1, 
-	0xD4, 0x06, 0x35, 0x13, 0x26, 0x02, 0x04, 0x00, 
-	0xA0, 0xCD, 0xCE, 0xED, 0x83, 0xC5, 0x04, 0x13, 
-	0x4A, 0xC2, 0x39, 0x0A, 0xC9, 0xE0, 0x83, 0xC5, 
-	0x86, 0x07, 0x36, 0x07, 0x87, 0x07, 0x10, 0x00, 
-	0x20, 0xC2, 0xD4, 0x06, 0xE0, 0x04, 0xD4, 0x06, 
-	0x46, 0x2C, 0x5B, 0x04, 0x60, 0xC0, 0xFE, 0x06, 
-	0x20, 0xC2, 0x6A, 0x09, 0x48, 0x02, 0x00, 0x60, 
-	0x20, 0x22, 0x06, 0xE0, 0x04, 0x16, 0x20, 0xE2, 
-	0x0A, 0xE0, 0x20, 0xE2, 0x18, 0xE0, 0x13, 0x0A, 
-	0x04, 0x18, 0x41, 0x05, 0x03, 0x48, 0xFE, 0x06, 
-	0x06, 0x10, 0x83, 0x02, 0x02, 0x00, 0x01, 0x16, 
-	0x13, 0x09, 0x03, 0xE8, 0xFE, 0x06, 0xC8, 0x40, 
-	0xC1, 0x40, 0x05, 0x13, 0x88, 0x07, 0x36, 0x07, 
-	0x89, 0x07, 0x00, 0x40, 0x48, 0x2C, 0x5B, 0x04, 
-	0xC9, 0x04, 0x24, 0xC1, 0x94, 0xEB, 0x84, 0xC1, 
-	0x86, 0x71, 0x86, 0xA1, 0x26, 0x02, 0x56, 0xEC, 
-	0xC4, 0x06, 0x04, 0x71, 0x24, 0x02, 0xC2, 0xEB, 
-	0x14, 0xD2, 0xC8, 0x09, 0x08, 0xA2, 0xB0, 0x03, 
-	0x34, 0xD8, 0x5F, 0x06, 0x47, 0x02, 0x0F, 0x00, 
-	0xC7, 0xA1, 0x28, 0xC2, 0x82, 0xEB, 0x58, 0x04, 
-	0x76, 0xCD, 0x47, 0x06, 0xFD, 0x16, 0x32, 0x10, 
-	0x36, 0xC2, 0x26, 0x10, 0x17, 0x09, 0x47, 0xA1, 
-	0x2D, 0x10, 0x17, 0x09, 0x47, 0x61, 0x2A, 0x10, 
-	0xA0, 0x43, 0x16, 0xE0, 0x5B, 0x04, 0xA0, 0x43, 
-	0x16, 0xE0, 0x49, 0xC2, 0x03, 0x16, 0x44, 0xC2, 
-	0x06, 0xC8, 0x22, 0x09, 0x27, 0xC1, 0x8E, 0xED, 
-	0x84, 0xC1, 0x86, 0x71, 0x26, 0x02, 0xC4, 0xED, 
-	0xC4, 0x06, 0x04, 0x71, 0x24, 0x02, 0xAA, 0xED, 
-	0xD3, 0x10, 0x09, 0xC1, 0xA0, 0xC1, 0x22, 0x09, 
-	0xC9, 0x04, 0x10, 0x10, 0x36, 0xC2, 0x78, 0xD5,  
-	0x60, 0x41, 0x22, 0xE0, 0xC5, 0x05, 0x0A, 0x10, 
-	0x78, 0xCD, 0x47, 0x06, 0xFD, 0x15, 0x06, 0x10, 
-	0xA0, 0x23, 0x16, 0xE0, 0xCD, 0x16, 0x49, 0xC2, 
-	0xEC, 0x16, 0xD6, 0x10, 0xA0, 0xE3, 0x16, 0xE0, 
-	0xBB, 0x10, 0x08, 0x02, 0x5A, 0x80, 0xA0, 0x06, 
-	0xDA, 0xD4, 0x44, 0x10, 0xA0, 0x92, 0x0C, 0xE0, 
-	0x15, 0x16, 0x44, 0x02, 0x00, 0x5E, 0x14, 0x16, 
-	0x20, 0x48, 0xAC, 0xE4, 0x80, 0x01, 0xA0, 0x06, 
-	0x72, 0xD7, 0x20, 0xC8, 0x9E, 0x01, 0x9E, 0x01, 
-	0xE0, 0x2E, 0x01, 0x00, 0xA0, 0x43, 0x18, 0xE0, 
-	0xA0, 0xD2, 0x26, 0xE0, 0x83, 0x07, 0x10, 0x00, 
-	0xA0, 0x06, 0x2A, 0xD8, 0x60, 0x04, 0xD2, 0xCE, 
-	0x84, 0x07, 0x08, 0x00, 0x60, 0x04, 0x94, 0xCE, 
-	0x85, 0x07, 0x03, 0x02, 0x05, 0xC8, 0xCE, 0x06, 
-	0xA0, 0x43, 0x12, 0xE0, 0xE0, 0x04, 0xFA, 0x06, 
-	0xA0, 0x06, 0xA4, 0xD7, 0x08, 0x02, 0x48, 0x80, 
-	0xA0, 0x06, 0xDA, 0xD4, 0x17, 0x10, 0x60, 0x01, 
-	0x8E, 0x09, 0x00, 0x80, 0x02, 0x16, 0x60, 0x04, 
-	0x9C, 0xD4, 0xA0, 0x27, 0x2C, 0xE0, 0x04, 0x16, 
-	0x08, 0x02, 0x54, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 
-	0x83, 0x07, 0x00, 0xA8, 0x20, 0x88, 0x08, 0x07, 
-	0x20, 0xE0, 0x02, 0x16, 0x83, 0x07, 0x00, 0xE8, 
-	0xA0, 0x06, 0x2A, 0xD8, 0x08, 0x02, 0x36, 0x00, 
-	0xA0, 0x06, 0xDA, 0xD4, 0x20, 0xE8, 0x0C, 0xE0, 
-	0x82, 0x01, 0xA0, 0x23, 0x18, 0xE0, 0x06, 0x13, 
-	0xA0, 0xE3, 0x18, 0xE0, 0xE0, 0x2E, 0x00, 0x00, 
-	0x41, 0xC0, 0xFA, 0x16, 0xA0, 0x06, 0xE6, 0xD5, 
-	0x82, 0xC0, 0x02, 0x13, 0x4F, 0x02, 0x80, 0xFF, 
-	0xC4, 0x04, 0x0F, 0xD1, 0xC4, 0x06, 0x60, 0x04, 
-	0x94, 0xCE, 0xA0, 0x06, 0x32, 0xDA, 0x08, 0x02, 
-	0x36, 0x80, 0xA0, 0x07, 0xD6, 0x06, 0x20, 0xDA, 
-	0xA0, 0x06, 0xDA, 0xD4, 0x10, 0x10, 0xA0, 0x06, 
-	0x32, 0xDA, 0x20, 0xD1, 0xCE, 0x06, 0xE6, 0x13, 
-	0x20, 0x78, 0x12, 0xE0, 0xCE, 0x06, 0xE2, 0x10, 
-	0x20, 0xC1, 0x16, 0x04, 0x14, 0x0A, 0xC4, 0x06, 
-	0x0A, 0x91, 0x01, 0x16, 0x5B, 0x04, 0x60, 0x04, 
-	0xD2, 0xCE, 0xB0, 0x03, 0x20, 0x98, 0xAB, 0xE3, 
-	0x65, 0x06, 0x02, 0x13, 0x60, 0x04, 0xBA, 0xCE, 
-	0x60, 0xC1, 0x94, 0x09, 0x02, 0x13, 0x60, 0x04, 
-	0x22, 0xDE, 0x60, 0xD1, 0x0E, 0xE0, 0x3D, 0x10, 
-	0x85, 0x07, 0xBE, 0xEA, 0x35, 0xC8, 0x8A, 0x09, 
-	0x15, 0xC8, 0x8C, 0x09, 0x0B, 0x10, 0xE0, 0x04, 
-	0xA0, 0x09, 0x20, 0xD8, 0x2E, 0x09, 0xA6, 0x09, 
-	0x20, 0xC8, 0xA8, 0x09, 0x8A, 0x09, 0x20, 0xC8, 
-	0xAA, 0x09, 0x8C, 0x09, 0xE0, 0x04, 0x8E, 0x09, 
-	0xCA, 0x04, 0xCD, 0x04, 0xCE, 0x04, 0xCF, 0x04, 
-	0xE0, 0x04, 0xA8, 0x06, 0xE0, 0x04, 0xBA, 0x06, 
-	0x84, 0x07, 0xA0, 0x01, 0x85, 0x07, 0x10, 0x00, 
-	0xF4, 0x04, 0x45, 0x06, 0xFD, 0x15, 0x84, 0x07, 
-	0xD8, 0x06, 0x85, 0x07, 0x34, 0x07, 0x44, 0x61, 
-	0xF4, 0x04, 0x45, 0x06, 0xFD, 0x15, 0x84, 0x07, 
-	0xC8, 0x00, 0x04, 0xC8, 0x00, 0x07, 0x84, 0x07, 
-	0xFF, 0x7F, 0x04, 0xC8, 0xF0, 0x06, 0x84, 0x07, 
-	0x06, 0x00, 0x04, 0xC8, 0xEE, 0x06, 0x85, 0x07, 
-	0x02, 0x0C, 0x20, 0xC1, 0x8A, 0x09, 0x01, 0x11, 
-	0xC5, 0x06, 0xB0, 0x03, 0x05, 0xD8, 0x65, 0x06, 
-	0x60, 0x04, 0xD2, 0xCE, 0xB0, 0x03, 0x20, 0x98, 
-	0xAA, 0xE3, 0x65, 0x06, 0x79, 0x16, 0x60, 0xD1, 
-	0x10, 0xE0, 0xF3, 0x10, 0x60, 0xD1, 0xAB, 0xE3, 
-	0xA0, 0x01, 0x8E, 0x09, 0x00, 0x02, 0xE0, 0x01, 
-	0x80, 0x01, 0x00, 0x20, 0xC8, 0x04, 0x20, 0xD2, 
-	0x80, 0x01, 0x08, 0xC8, 0x9C, 0x09, 0x08, 0xD8, 
-	0x2E, 0x09, 0xE3, 0x10, 0x20, 0xF8, 0x19, 0xEE, 
-	0x82, 0x01, 0x20, 0xC8, 0x10, 0xE0, 0xC6, 0x06, 
-	0x20, 0xC8, 0x20, 0xE0, 0xC8, 0x06, 0x20, 0xC8, 
-	0xC2, 0xEA, 0x90, 0x09, 0xE0, 0x2E, 0x00, 0x00, 
-	0xA0, 0x06, 0xE6, 0xD5, 0x20, 0xC8, 0x6C, 0x09, 
-	0xA0, 0x01, 0x20, 0xC8, 0x6E, 0x09, 0xA2, 0x01, 
-	0x20, 0xC8, 0x70, 0x09, 0xA4, 0x01, 0x20, 0xC8, 
-	0x6E, 0x09, 0xB0, 0x01, 0x20, 0xC8, 0x70, 0x09, 
-	0xB2, 0x01, 0x20, 0xC8, 0x70, 0x09, 0xCC, 0x06, 
-	0x20, 0xF8, 0x18, 0xEE, 0x80, 0x01, 0xB0, 0x03, 
-	0xA0, 0x01, 0x8E, 0x09, 0x00, 0x02, 0x20, 0x98, 
-	0xAA, 0xE3, 0x65, 0x06, 0x3A, 0x13, 0xE0, 0x01, 
-	0x8E, 0x09, 0x00, 0x02, 0x88, 0x07, 0x56, 0xDF, 
-	0xE0, 0xC2, 0x8A, 0x09, 0x05, 0x11, 0xA0, 0x01, 
-	0x8E, 0x09, 0x00, 0x02, 0x88, 0x07, 0x9A, 0xDF, 
-	0x98, 0x06, 0x08, 0x02, 0x12, 0x80, 0xA0, 0x06, 
-	0xDA, 0xD4, 0x84, 0x07, 0x0A, 0x00, 0x85, 0x07, 
-	0xF4, 0x03, 0x20, 0x88, 0xC6, 0x06, 0x20, 0xE0, 
-	0x08, 0x1B, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, 
-	0xA5, 0x13, 0x84, 0x07, 0x1C, 0x00, 0x85, 0x07, 
-	0xF8, 0x03, 0xA0, 0x06, 0xA2, 0xD8, 0x85, 0x07, 
-	0x42, 0xDC, 0x05, 0xC8, 0xF8, 0x03, 0x20, 0xC8, 
-	0xA0, 0x09, 0xA0, 0x09, 0x6C, 0x16, 0x20, 0xE8, 
-	0x9C, 0x09, 0xFE, 0x03, 0x20, 0xE8, 0x9E, 0x09, 
-	0x06, 0x04, 0xA0, 0x23, 0x0C, 0xE0, 0x32, 0x13, 
-	0xA0, 0xE3, 0x0C, 0xE0, 0xA0, 0x2E, 0xF4, 0x03, 
-	0x2D, 0x10, 0xA0, 0x06, 0x56, 0xDF, 0x60, 0x01, 
-	0x8E, 0x09, 0x00, 0x40, 0x08, 0x13, 0x08, 0x02, 
-	0x6C, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x22, 0x10, 
-	0xE0, 0x01, 0x8E, 0x09, 0x00, 0x40, 0x08, 0x02, 
-	0x60, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x84, 0x07, 
-	0x2A, 0x00, 0x85, 0x07, 0xF4, 0x03, 0xA0, 0x06, 
-	0xA2, 0xD8, 0xD5, 0x10, 0xB0, 0x03, 0x20, 0x98, 
-	0xAA, 0xE3, 0x65, 0x06, 0x0F, 0x16, 0x20, 0x06, 
-	0x90, 0x09, 0x9A, 0x16, 0x60, 0x01, 0x8A, 0x09, 
-	0x00, 0x40, 0x39, 0x13, 0xE0, 0x04, 0x8A, 0x09, 
-	0xE0, 0x04, 0x8C, 0x09, 0xE0, 0x04, 0x8E, 0x09, 
-	0x60, 0x04, 0x62, 0xDA, 0x60, 0x04, 0xB0, 0xCE, 
-	0xB0, 0x03, 0x20, 0x98, 0x10, 0xE0, 0x65, 0x06, 
-	0xF9, 0x16, 0x44, 0x02, 0x00, 0x5E, 0x04, 0x16, 
-	0x20, 0x06, 0xC6, 0x06, 0x9A, 0x16, 0x0A, 0x10, 
-	0xB0, 0x03, 0x20, 0x98, 0x10, 0xE0, 0x65, 0x06, 
-	0xED, 0x16, 0x20, 0x06, 0xC8, 0x06, 0x02, 0x13, 
-	0x60, 0x04, 0x5A, 0xDB, 0x60, 0x01, 0x8E, 0x09, 
-	0x00, 0x01, 0x02, 0x16, 0xCE, 0x01, 0x03, 0x00, 
-	0x0E, 0x01, 0x03, 0x00, 0x03, 0x13, 0x83, 0x07, 
-	0x00, 0x82, 0x07, 0x10, 0x83, 0x07, 0x01, 0x00, 
-	0xE0, 0x04, 0x8E, 0x09, 0x20, 0xE8, 0x0C, 0xE0, 
-	0x82, 0x01, 0x60, 0x04, 0xCA, 0xCE, 0x60, 0x01, 
-	0x8A, 0x09, 0x00, 0x40, 0xC7, 0x16, 0x83, 0x07, 
-	0x0D, 0x00, 0xF2, 0x10, 0xB0, 0x03, 0x20, 0x98, 
-	0xAA, 0xE3, 0x65, 0x06, 0xC7, 0x16, 0x20, 0x88, 
-	0x98, 0x09, 0x20, 0xE0, 0xF0, 0x16, 0x22, 0xC8, 
-	0x0E, 0x00, 0xDC, 0x06, 0x22, 0xC8, 0x10, 0x00, 
-	0xDE, 0x06, 0x22, 0xC8, 0x12, 0x00, 0xE0, 0x06, 
-	0xE0, 0x01, 0x8E, 0x09, 0x00, 0x80, 0x08, 0x02, 
-	0x66, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0xB2, 0x10, 
-	0xA0, 0x07, 0x9A, 0x09, 0x5A, 0x00, 0xA0, 0x07, 
-	0xA2, 0x09, 0x19, 0x00, 0xA0, 0x07, 0xA4, 0x09, 
-	0x05, 0x00, 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x20, 
-	0xE0, 0x01, 0x8E, 0x09, 0x00, 0x04, 0x08, 0x02, 
-	0x78, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0xB0, 0x03, 
-	0x20, 0x98, 0xAB, 0xE3, 0x65, 0x06, 0x9A, 0x16, 
-	0x08, 0x02, 0x72, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 
-	0x20, 0xE8, 0x0C, 0xE0, 0x82, 0x01, 0xA0, 0x06, 
-	0xD0, 0xD5, 0x20, 0x06, 0x9A, 0x09, 0xBF, 0x13, 
-	0x84, 0x07, 0x2C, 0x00, 0x85, 0x07, 0xF4, 0x03, 
-	0xA0, 0x06, 0xA2, 0xD8, 0x60, 0x04, 0xC0, 0xDB, 
-	0x20, 0x48, 0x0C, 0xE0, 0x82, 0x01, 0x82, 0x10, 
-	0x0E, 0x01, 0x03, 0x00, 0x0A, 0x13, 0x08, 0x02, 
-	0x0C, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0xE0, 0xE3, 
-	0x14, 0xE0, 0x20, 0xC8, 0xAE, 0xE4, 0x86, 0x01, 
-	0x26, 0x10, 0x20, 0x48, 0x0C, 0xE0, 0x82, 0x01, 
-	0xE0, 0x2E, 0x01, 0x00, 0x60, 0xC1, 0x1E, 0x09, 
-	0x35, 0x0A, 0x05, 0xE8, 0x82, 0x01, 0x20, 0xC1, 
-	0x6A, 0x09, 0x04, 0x01, 0x06, 0x00, 0x06, 0x13, 
-	0x20, 0xD8, 0xD0, 0xE1, 0x2F, 0x09, 0x20, 0xD8, 
-	0xD0, 0xE1, 0x83, 0x01, 0x20, 0x21, 0x22, 0xE0, 
-	0x03, 0x16, 0x20, 0xE8, 0x22, 0xE0, 0x80, 0x01, 
-	0x20, 0x21, 0x04, 0xE0, 0x04, 0x16, 0xA0, 0xE3, 
-	0x14, 0xE0, 0x60, 0x04, 0x0A, 0xD3, 0x08, 0x02, 
-	0x00, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x20, 0xE8, 
-	0x08, 0xE0, 0x82, 0x01, 0xE0, 0xC2, 0x8A, 0x09, 
-	0x02, 0x11, 0x60, 0x04, 0xB0, 0xCE, 0xA0, 0x01, 
-	0x8E, 0x09, 0x00, 0x04, 0x6B, 0x10, 0x20, 0xC8, 
-	0xAE, 0xE4, 0x86, 0x01, 0x08, 0x02, 0x00, 0x80, 
-	0xA0, 0x06, 0xDA, 0xD4, 0x20, 0xC2, 0x1E, 0x09, 
-	0x08, 0xA2, 0x08, 0x05, 0x28, 0xC8, 0x22, 0xE0, 
-	0xCA, 0x06, 0x20, 0xC8, 0x20, 0xE0, 0xC6, 0x06, 
-	0x20, 0xC8, 0x20, 0xE0, 0xC8, 0x06, 0x60, 0xE3, 
-	0x16, 0xE0, 0x60, 0x04, 0xD2, 0xCE, 0x44, 0xC1, 
-	0x44, 0x02, 0x00, 0x5E, 0xF8, 0x16, 0x60, 0x25, 
-	0xA8, 0xE4, 0x0F, 0x16, 0x20, 0x06, 0xC6, 0x06, 
-	0xF2, 0x16, 0x20, 0x06, 0xCA, 0x06, 0x03, 0x13, 
-	0xA0, 0x05, 0xCC, 0x06, 0xE6, 0x10, 0xB0, 0x03, 
-	0x20, 0xD8, 0x0C, 0xE0, 0x65, 0x06, 0x60, 0x04, 
-	0xD2, 0xCE, 0x20, 0x06, 0xC8, 0x06, 0xE3, 0x16, 
-	0x20, 0x88, 0x70, 0x09, 0xCC, 0x06, 0x03, 0x16, 
-	0x83, 0x07, 0x08, 0x00, 0x02, 0x10, 0x83, 0x07, 
-	0x0C, 0x00, 0x60, 0x04, 0x8A, 0xDC, 0x60, 0x04, 
-	0xD2, 0xCE, 0xA0, 0x23, 0x08, 0xE0, 0x03, 0x13, 
-	0x60, 0x23, 0x12, 0xE0, 0x06, 0x16, 0xB0, 0x03, 
-	0x20, 0xD8, 0xA9, 0xE3, 0x65, 0x06, 0x60, 0x04, 
-	0xD2, 0xCE, 0x08, 0x02, 0x00, 0x80, 0xA0, 0x06, 
-	0xDA, 0xD4, 0x60, 0x04, 0xB0, 0xCE, 0x08, 0x02, 
-	0x00, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x20, 0xC8, 
-	0x1E, 0xE0, 0xC6, 0x06, 0x20, 0xC8, 0x1E, 0xE0, 
-	0xC8, 0x06, 0x60, 0xE3, 0x10, 0xE0, 0x60, 0x04, 
-	0xD2, 0xCE, 0xE0, 0x23, 0x14, 0xE0, 0x30, 0x13, 
-	0x44, 0xC1, 0x44, 0x02, 0x00, 0x1E, 0xF5, 0x16, 
-	0x60, 0x25, 0xA8, 0xE4, 0x1D, 0x16, 0x20, 0x06, 
-	0xC8, 0x06, 0xEF, 0x16, 0x60, 0x01, 0x8E, 0x09, 
-	0x00, 0x80, 0x13, 0x16, 0x60, 0x01, 0x8E, 0x09, 
-	0x00, 0x01, 0x0C, 0x16, 0xA0, 0x01, 0x8E, 0x09, 
-	0x00, 0x01, 0xA0, 0x01, 0x8E, 0x09, 0x80, 0x00, 
-	0xA0, 0x43, 0x04, 0xE0, 0x83, 0x07, 0x18, 0x68, 
-	0xA0, 0x06, 0x2A, 0xD8, 0x20, 0xC8, 0xAE, 0xE4, 
-	0x86, 0x01, 0xC2, 0x04, 0x60, 0x04, 0x2C, 0xE4, 
-	0x08, 0x02, 0x1E, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 
-	0x07, 0x10, 0x20, 0x06, 0xC6, 0x06, 0xCD, 0x16, 
-	0x83, 0x07, 0x09, 0x00, 0xA0, 0x06, 0x8A, 0xDC, 
-	0x60, 0x04, 0xB0, 0xCE, 0xCE, 0x04, 0xE0, 0x04, 
-	0x2A, 0x09, 0xE0, 0xD3, 0xAA, 0xE3, 0x8F, 0xC2, 
-	0x20, 0xC8, 0xB0, 0xE4, 0x86, 0x01, 0x20, 0x48, 
-	0x08, 0xE0, 0x82, 0x01, 0x86, 0x07, 0x05, 0x00, 
-	0x84, 0x07, 0x72, 0x06, 0x54, 0xC1, 0x01, 0x13, 
-	0xD4, 0x2C, 0x24, 0x02, 0x0A, 0x00, 0x06, 0x06, 
-	0xF9, 0x16, 0x08, 0x02, 0x2A, 0x80, 0xA0, 0x06, 
-	0xDA, 0xD4, 0x20, 0x2C, 0x1A, 0xE0, 0x60, 0x04, 
-	0x50, 0xCD, 0xA0, 0x06, 0x3E, 0xD7, 0xCD, 0x04, 
-	0xA0, 0x23, 0x1C, 0xE0, 0x0D, 0x13, 0x0E, 0x01, 
-	0x03, 0x00, 0x0A, 0x13, 0xA0, 0xE3, 0x1C, 0xE0, 
-	0xB0, 0x03, 0x20, 0xD8, 0x10, 0xE0, 0x65, 0x06, 
-	0xA0, 0xD2, 0x26, 0xE0, 0xCF, 0x04, 0x08, 0x10, 
-	0x20, 0x2D, 0x01, 0x00, 0xE0, 0xC0, 0x2A, 0x09, 
-	0xA0, 0x06, 0x2A, 0xD8, 0xA0, 0xD2, 0xAB, 0xE3, 
-	0x60, 0x04, 0xD2, 0xCE, 0xA0, 0x01, 0x80, 0x01, 
-	0x00, 0x01, 0xE0, 0x01, 0x80, 0x01, 0x00, 0xAC, 
-	0xA0, 0x01, 0x82, 0x01, 0x00, 0x03, 0xE0, 0x01, 
-	0x82, 0x01, 0x00, 0x08, 0x88, 0x07, 0xAE, 0x01, 
-	0x08, 0x06, 0xFE, 0x16, 0x60, 0x01, 0x8E, 0x09, 
-	0x00, 0x02, 0x03, 0x16, 0xA0, 0x01, 0x80, 0x01, 
-	0x00, 0x20, 0xC8, 0x04, 0x20, 0xD2, 0x80, 0x01, 
-	0x08, 0xC8, 0x9C, 0x09, 0x08, 0xD8, 0x2E, 0x09, 
-	0xA0, 0x07, 0x9E, 0x09, 0x00, 0x10, 0x5B, 0x04, 
-	0x20, 0xD8, 0xA6, 0x09, 0x2E, 0x09, 0xE0, 0x01, 
-	0x80, 0x01, 0x00, 0x04, 0xE0, 0x01, 0x82, 0x01, 
-	0x00, 0x08, 0xA0, 0x01, 0x82, 0x01, 0x00, 0x03, 
-	0x20, 0xC2, 0x30, 0x09, 0x03, 0x13, 0xE0, 0x01, 
-	0x82, 0x01, 0x00, 0x03, 0xA0, 0x01, 0x80, 0x01, 
-	0x00, 0xA1, 0x20, 0xF8, 0x2E, 0x09, 0x80, 0x01, 
-	0x88, 0x07, 0xAE, 0x01, 0x08, 0x06, 0xFE, 0x16, 
-	0xA0, 0x01, 0x80, 0x01, 0x00, 0x0C, 0xE0, 0x04, 
-	0x9E, 0x01, 0xE0, 0x04, 0x9C, 0x09, 0xE0, 0x04, 
-	0x9E, 0x09, 0x5B, 0x04, 0x20, 0x01, 0xA8, 0x09, 
-	0x00, 0x80, 0x11, 0x13, 0xE0, 0x93, 0x26, 0xE0, 
-	0x0E, 0x16, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, 
-	0x0A, 0x13, 0x08, 0x02, 0x84, 0x80, 0x00, 0x00, 
-	0x00, 0xE0, 0xDC, 0x0F, 0xA0, 0x06, 0xDA, 0xD4, 
-	0x20, 0x48, 0x08, 0xE0, 0x82, 0x01, 0x02, 0x10, 
-	0x60, 0x04, 0x70, 0xDA, 0x60, 0x04, 0xBA, 0xCE, 
-	0xA0, 0x06, 0x9C, 0xD5, 0x08, 0xC2, 0x19, 0x13, 
-	0x83, 0x07, 0x80, 0x80, 0xE0, 0x23, 0x14, 0xE0, 
-	0x02, 0x13, 0x83, 0x07, 0x0A, 0x00, 0x60, 0x04, 
-	0xC6, 0xCE, 0x20, 0xC1, 0x06, 0x06, 0x0D, 0x13, 
-	0xA0, 0x06, 0x9C, 0xD5, 0x08, 0xC2, 0x09, 0x13, 
-	0x83, 0x07, 0x0B, 0x00, 0xE0, 0x23, 0x14, 0xE0, 
-	0x02, 0x16, 0x83, 0x07, 0x01, 0x80, 0x60, 0x04, 
-	0xC6, 0xCE, 0x83, 0x07, 0x0A, 0x80, 0x60, 0x04, 
-	0xB4, 0xCE, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, 
-	0x06, 0x16, 0xA0, 0x06, 0xA8, 0xE5, 0x47, 0x10, 
-	0xD0, 0x03, 0x60, 0x04, 0xB0, 0xD3, 0xE0, 0x93, 
-	0x0E, 0xE0, 0x5E, 0x13, 0xE0, 0x93, 0x10, 0xE0, 
-	0x17, 0x13, 0xE0, 0x23, 0x14, 0xE0, 0x04, 0x13,  
-	0x83, 0x07, 0x07, 0x00, 0x60, 0x04, 0xC6, 0xCE, 
-	0x83, 0x07, 0x00, 0xA0, 0xA0, 0x06, 0x2A, 0xD8,  
-	0x83, 0x07, 0x00, 0x48, 0xA0, 0x06, 0x2A, 0xD8, 
-	0xA0, 0xD2, 0x10, 0xE0, 0x20, 0xC8, 0x1C, 0xE0, 
-	0xCA, 0x06, 0x20, 0xC8, 0x20, 0xE0, 0xCC, 0x06, 
-	0xA0, 0x06, 0x3E, 0xD7, 0x08, 0x02, 0x4E, 0x80, 
-	0xA0, 0x06, 0xDA, 0xD4, 0xA0, 0x23, 0x1C, 0xE0, 
-	0x20, 0x13, 0x20, 0x88, 0x6C, 0x09, 0x0E, 0x07, 
-	0x1C, 0x16, 0x20, 0x88, 0x6E, 0x09, 0x10, 0x07, 
-	0x18, 0x16, 0x20, 0x88, 0x70, 0x09, 0x12, 0x07, 
-	0x14, 0x16, 0x20, 0x88, 0x0A, 0x07, 0x22, 0xE0, 
-	0x10, 0x13, 0x20, 0x06, 0xCA, 0x06, 0x38, 0x16, 
-	0xA0, 0xE3, 0x20, 0xE0, 0x06, 0x10, 0xE0, 0x23, 
-	0x14, 0xE0, 0xCA, 0x16, 0xA0, 0xE3, 0x22, 0xE0, 
-	0xC2, 0x04, 0xA0, 0xD2, 0xAA, 0xE3, 0x60, 0x04, 
-	0xBA, 0xCE, 0x20, 0xC8, 0x1C, 0xE0, 0xCA, 0x06, 
-	0xA0, 0x88, 0xDC, 0x06, 0x0E, 0x00, 0x10, 0x16, 
-	0xA0, 0x88, 0xDE, 0x06, 0x10, 0x00, 0x0C, 0x16, 
-	0xA0, 0x88, 0xE0, 0x06, 0x12, 0x00, 0x08, 0x16, 
-	0x20, 0x06, 0xCC, 0x06, 0x19, 0x16, 0x20, 0xE8, 
-	0x0E, 0xE0, 0x82, 0x01, 0xA0, 0xE3, 0x1E, 0xE0, 
-	0x20, 0xC8, 0x20, 0xE0, 0xCC, 0x06, 0x10, 0x10, 
-	0xA0, 0x23, 0x10, 0xE0, 0x08, 0x16, 0x64, 0xC1, 
-	0x06, 0x00, 0x60, 0x21, 0x0C, 0xE0, 0x08, 0x13, 
-	0xA0, 0xD2, 0xA8, 0xE3, 0x05, 0x10, 0x20, 0x88, 
-	0x0A, 0x07, 0x08, 0x07, 0x96, 0x12, 0x00, 0x10, 
-	0x60, 0x04, 0xBA, 0xCE, 0x60, 0x01, 0x8E, 0x09, 
-	0x00, 0x80, 0x06, 0x16, 0x83, 0x07, 0x00, 0x82, 
-	0xA0, 0x06, 0x2A, 0xD8, 0x60, 0x04, 0xCA, 0xCE, 
-	0xE0, 0x93, 0x0E, 0xE0, 0x50, 0x13, 0xE0, 0x93, 
-	0xA9, 0xE3, 0x4D, 0x13, 0xE0, 0x93, 0xA8, 0xE3, 
-	0x1C, 0x13, 0xA0, 0x06, 0xA4, 0xD7, 0xA0, 0x23, 
-	0x10, 0xE0, 0x45, 0x13, 0xA0, 0x23, 0x08, 0xE0, 
-	0x06, 0x16, 0x60, 0xE3, 0x1E, 0xE0, 0x20, 0xC8, 
-	0x22, 0xE0, 0x06, 0x07, 0x34, 0x10, 0xE0, 0x23, 
-	0x14, 0xE0, 0x31, 0x16, 0x60, 0xC1, 0x6A, 0x09, 
-	0x60, 0x21, 0x12, 0xE0, 0x2C, 0x16, 0xA0, 0x06, 
-	0x0E, 0xE2, 0x31, 0x10, 0xA0, 0xD2, 0xA8, 0xE3, 
-	0x2E, 0x10, 0xA0, 0xE3, 0x12, 0xE0, 0xA0, 0x06, 
-	0x0E, 0xE2, 0x64, 0xC1, 0x06, 0x00, 0x60, 0x21, 
-	0x0C, 0xE0, 0x25, 0x13, 0x20, 0x88, 0x0E, 0x07, 
-	0xDC, 0x06, 0x14, 0x16, 0x20, 0x88, 0x10, 0x07, 
-	0xDE, 0x06, 0x10, 0x16, 0x20, 0x88, 0x12, 0x07, 
-	0xE0, 0x06, 0x0C, 0x16, 0x20, 0x98, 0xCE, 0x06, 
-	0xCF, 0x06, 0x15, 0x13, 0x20, 0x06, 0xCE, 0x06, 
-	0x12, 0x16, 0x60, 0xE3, 0x1A, 0xE0, 0xA0, 0xD2, 
-	0x0C, 0xE0, 0x0D, 0x10, 0x60, 0xE3, 0x1E, 0xE0,  
-	0x20, 0xC8, 0x32, 0xE0, 0x06, 0x07, 0xA0, 0x06, 
-	0x3E, 0xD7, 0x08, 0x02, 0x48, 0x80, 0xA0, 0x06, 
-	0xDA, 0xD4, 0xA0, 0xD2, 0xA9, 0xE3, 0x60, 0x04, 
-	0xBA, 0xCE, 0x22, 0x88, 0x0E, 0x00, 0x6C, 0x09, 
-	0xC9, 0x1A, 0x0B, 0x1B, 0x22, 0x88, 0x10, 0x00, 
-	0x6E, 0x09, 0xC4, 0x1A, 0x06, 0x1B, 0x22, 0x88, 
-	0x12, 0x00, 0x70, 0x09, 0xBF, 0x1A, 0x01, 0x1B, 
-	0x5B, 0x04, 0x60, 0xC1, 0x6C, 0x01, 0x85, 0x02, 
-	0x43, 0x00, 0xE1, 0x13, 0xE0, 0x93, 0xA8, 0xE3, 
-	0xDE, 0x16, 0xA0, 0xC8, 0x00, 0xEE, 0x02, 0x00, 
-	0x84, 0x07, 0x0E, 0x00, 0x42, 0xC1, 0xA0, 0xC0, 
-	0x6C, 0x01, 0x02, 0xC0, 0x25, 0x02, 0x48, 0x00, 
-	0x81, 0x07, 0x60, 0xE2, 0x83, 0x07, 0x14, 0xAE, 
-	0x60, 0x04, 0x9E, 0xE5, 0x02, 0x02, 0x00, 0xFC, 
-	0xCA, 0x10, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, 
-	0x06, 0x16, 0x83, 0x07, 0x00, 0x82, 0xA0, 0x06, 
-	0x2A, 0xD8, 0x60, 0x04, 0xCA, 0xCE, 0x20, 0x98, 
-	0x0E, 0xE0, 0x65, 0x06, 0x03, 0x16, 0x20, 0xD8, 
-	0xA8, 0xE3, 0x65, 0x06, 0xE0, 0x93, 0xA9, 0xE3, 
-	0x0D, 0x13, 0xA0, 0x23, 0x08, 0xE0, 0x19, 0x16, 
-	0xA0, 0x23, 0x10, 0xE0, 0x16, 0x13, 0x60, 0xE3, 
-	0x1E, 0xE0, 0x20, 0xC8, 0x20, 0xE0, 0x06, 0x07, 
-	0xA0, 0x06, 0x3E, 0xD7, 0xA0, 0x43, 0x18, 0xE0, 
-	0xE0, 0x2E, 0x01, 0x00, 0xA0, 0xD2, 0x26, 0xE0, 
-	0x83, 0x07, 0x10, 0x00, 0xA0, 0x06, 0x2A, 0xD8, 
-	0xE0, 0x23, 0x14, 0xE0, 0x02, 0x16, 0xA0, 0x06, 
-	0x18, 0xD7, 0xA0, 0x43, 0x2C, 0xE0, 0x20, 0xC8, 
-	0x20, 0xE0, 0x24, 0x09, 0x60, 0x04, 0xBA, 0xCE, 
-	0xA0, 0x06, 0xA8, 0xE5, 0x01, 0x10, 0x03, 0x10, 
-	0x20, 0x07, 0xA0, 0x09, 0x03, 0x10, 0xA0, 0x07, 
-	0xA2, 0x09, 0x19, 0x00, 0x60, 0x04, 0xBA, 0xCE, 
-	0xA0, 0x43, 0x0E, 0xE0, 0xA0, 0xC1, 0x24, 0x09, 
-	0x02, 0x13, 0x20, 0x06, 0x24, 0x09, 0xE0, 0x23, 
-	0x14, 0xE0, 0x03, 0x13, 0xA0, 0x23, 0x08, 0xE0, 
-	0x29, 0x16, 0x20, 0xC2, 0x8A, 0x09, 0xE4, 0x11, 
-	0x08, 0x02, 0x42, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 
-	0xA0, 0x23, 0x08, 0xE0, 0x1F, 0x16, 0xA0, 0x23, 
-	0x10, 0xE0, 0x0A, 0x16, 0x22, 0xC1, 0x02, 0x00, 
-	0x20, 0x25, 0xA8, 0xE4, 0x23, 0x16, 0x83, 0x07, 
-	0x20, 0x80, 0xA0, 0x06, 0x2A, 0xD8, 0x12, 0x10, 
-	0xA0, 0x06, 0x3E, 0xD7, 0xE0, 0x23, 0x14, 0xE0, 
-	0x02, 0x16, 0xA0, 0x06, 0x18, 0xD7, 0x60, 0xE3, 
-	0x1E, 0xE0, 0x20, 0xC8, 0x20, 0xE0, 0x06, 0x07, 
-	0xA0, 0x23, 0x08, 0xE0, 0x03, 0x16, 0xA0, 0x23, 
-	0x06, 0xE0, 0x51, 0x13, 0x20, 0x98, 0x0E, 0xE0, 
-	0x65, 0x06, 0x03, 0x16, 0x20, 0xD8, 0xA8, 0xE3, 
-	0x65, 0x06, 0x22, 0xC1, 0x02, 0x00, 0x20, 0x25, 
-	0xA8, 0xE4, 0x0E, 0x13, 0x83, 0x07, 0x20, 0x00, 
-	0xA0, 0x06, 0x2A, 0xD8, 0x22, 0xC8, 0x0E, 0x00, 
-	0xE6, 0x06, 0x22, 0xC8, 0x10, 0x00, 0xE8, 0x06, 
-	0x22, 0xC8, 0x12, 0x00, 0xEA, 0x06, 0x37, 0x10, 
-	0x22, 0x88, 0x0E, 0x00, 0xDC, 0x06, 0x08, 0x16, 
-	0x22, 0x88, 0x10, 0x00, 0xDE, 0x06, 0x04, 0x16, 
-	0x22, 0x88, 0x12, 0x00, 0xE0, 0x06, 0x0B, 0x13, 
-	0x22, 0xC8, 0x0E, 0x00, 0xDC, 0x06, 0x22, 0xC8, 
-	0x10, 0x00, 0xDE, 0x06, 0x22, 0xC8, 0x12, 0x00,  
-	0xE0, 0x06, 0x60, 0xE3, 0x14, 0xE0, 0xA0, 0x23, 
-	0x0E, 0xE0, 0x08, 0x16, 0xA0, 0xC1, 0x24, 0x09, 
-	0x1A, 0x16, 0x86, 0x07, 0x00, 0x10, 0x06, 0xE8, 
-	0xD2, 0x06, 0x15, 0x10, 0xA0, 0xE3, 0x0E, 0xE0, 
-	0xA0, 0x23, 0x08, 0xE0, 0x09, 0x16, 0xA0, 0xE3, 
-	0x06, 0xE0, 0xE0, 0x04, 0xE6, 0x06, 0xE0, 0x04, 
-	0xE8, 0x06, 0xE0, 0x04, 0xEA, 0x06, 0x07, 0x10, 
-	0x08, 0x02, 0x36, 0x80, 0xA0, 0x07, 0xD6, 0x06, 
-	0x36, 0xD3, 0xA0, 0x06, 0xDA, 0xD4, 0x60, 0x04, 
-	0xBA, 0xCE, 0x20, 0x98, 0x65, 0x06, 0x10, 0xE0, 
-	0x03, 0x16, 0x20, 0xD8, 0x0E, 0xE0, 0x65, 0x06, 
-	0x60, 0x04, 0xBA, 0xCE, 0xE0, 0x23, 0x14, 0xE0, 
-	0x02, 0x13, 0x60, 0x04, 0xBA, 0xCE, 0x2E, 0x10, 
-	0xB0, 0x03, 0x20, 0x98, 0xA9, 0xE3, 0x6F, 0x06, 
-	0x19, 0x16, 0x24, 0xC2, 0x08, 0x00, 0x16, 0x11, 
-	0xE0, 0xE3, 0x14, 0xE0, 0x83, 0x07, 0x00, 0x00, 
-	0xA0, 0x06, 0x2A, 0xD8, 0xA0, 0x23, 0x14, 0xE0, 
-	0x04, 0x13, 0x08, 0x02, 0x06, 0x80, 0xA0, 0x06, 
-	0xDA, 0xD4, 0x08, 0x02, 0x1E, 0x00, 0xA0, 0x06, 
-	0xDA, 0xD4, 0xA0, 0x23, 0x08, 0xE0, 0x02, 0x13, 
-	0xA0, 0x06, 0x18, 0xD7, 0x82, 0xC0, 0x02, 0x16, 
-	0x60, 0x04, 0xD2, 0xCE, 0x20, 0xE8, 0x1C, 0xEE, 
-	0xF0, 0x06, 0x20, 0x99, 0x0E, 0xE0, 0x16, 0x00, 
-	0x05, 0x16, 0xE0, 0x04, 0xEC, 0x06, 0x20, 0x48, 
-	0x14, 0xE0, 0xF0, 0x06, 0x83, 0x07, 0x01, 0x00, 
-	0x60, 0x04, 0xB4, 0xCE, 0x64, 0xC2, 0x14, 0x00, 
-	0x24, 0x02, 0x18, 0x00, 0xC4, 0xC1, 0xC2, 0x61, 
-	0x27, 0x02, 0xFC, 0xFF, 0x74, 0xC1, 0x85, 0xC1, 
-	0x45, 0x71, 0x85, 0x02, 0x27, 0x00, 0x46, 0x16, 
-	0x54, 0xC1, 0x45, 0x02, 0xCF, 0xFF, 0x42, 0x16, 
-	0xC8, 0x04, 0x64, 0xC1, 0x08, 0x00, 0x06, 0x15, 
-	0x05, 0x13, 0x24, 0xC2, 0x0E, 0x00, 0x48, 0x02, 
-	0x00, 0x1F, 0xC8, 0x06, 0x28, 0x02, 0x11, 0x00, 
-	0x04, 0xA2, 0x18, 0x98, 0x21, 0xEE, 0x32, 0x16, 
-	0x42, 0xC1, 0x25, 0x02, 0x04, 0x00, 0x47, 0x65, 
-	0x35, 0xC2, 0x74, 0xCD, 0x48, 0x06, 0xFD, 0x15, 
-	0xA0, 0xC0, 0x6C, 0x01, 0x02, 0xC1, 0x04, 0xC8, 
-	0x6C, 0x01, 0xA0, 0xC1, 0x00, 0xFC, 0x05, 0x13, 
-	0x20, 0xC8, 0x80, 0xEB, 0x02, 0xFC, 0x06, 0xC1, 
-	0xF6, 0x10, 0x20, 0xC8, 0x00, 0xEE, 0x02, 0xFC, 
-	0x02, 0xC8, 0x6C, 0x01, 0x81, 0x07, 0x08, 0xE5, 
-	0x04, 0xC0, 0x83, 0x07, 0x10, 0x02, 0x84, 0x07, 
-	0x0E, 0x00, 0x3B, 0x10, 0x84, 0x07, 0x0C, 0x00, 
-	0xE2, 0xC0, 0x08, 0x00, 0x05, 0x02, 0x00, 0xFC, 
-	0xA0, 0xC0, 0x6C, 0x01, 0x02, 0xC0, 0x95, 0xC1, 
-	0x30, 0x13, 0xD5, 0x04, 0x16, 0x2E, 0x02, 0xC8, 
-	0x6C, 0x01, 0x2B, 0x10, 0xA0, 0xC8, 0x22, 0xEE, 
-	0x0E, 0x00, 0xA0, 0xC8, 0x24, 0xEE, 0x10, 0x00, 
-	0xA0, 0xC8, 0x26, 0xEE, 0x12, 0x00, 0x83, 0x07, 
-	0x06, 0x80, 0x60, 0x04, 0xB4, 0xCE, 0x60, 0x04, 
-	0xD2, 0xCE, 0x84, 0x07, 0x10, 0x00, 0x85, 0x07, 
-	0x34, 0x00, 0x09, 0x10, 0x84, 0x07, 0x12, 0x00, 
-	0x85, 0x07, 0x32, 0x00, 0x04, 0x10, 0x84, 0x07, 
-	0x14, 0x00, 0x85, 0x07, 0x38, 0x00, 0xA0, 0x06, 
-	0xC2, 0xD5, 0x85, 0xC8, 0x04, 0x00, 0xA0, 0x06, 
-	0x10, 0xD6, 0xA0, 0xC8, 0x00, 0xEE, 0x02, 0x00, 
-	0xA0, 0xC0, 0x6C, 0x01, 0x02, 0xC0, 0x48, 0x06, 
-	0x48, 0xC1, 0xA0, 0x06, 0xA2, 0xD8, 0x07, 0x02, 
-	0xA2, 0x06, 0x60, 0xC5, 0x02, 0xFC, 0x25, 0x02, 
-	0xF4, 0xFF, 0x05, 0xC8, 0x02, 0xFC, 0x20, 0xC2, 
-	0x6C, 0x01, 0xA0, 0x06, 0xFC, 0xB4, 0x60, 0x04, 
-	0xB0, 0xCE, 0xA0, 0x06, 0xA2, 0xD8, 0x07, 0x02, 
-	0xB4, 0x06, 0xEF, 0x10, 0x22, 0x88, 0x12, 0x00, 
-	0x70, 0x09, 0x08, 0x16, 0x22, 0x88, 0x10, 0x00, 
-	0x6E, 0x09, 0x04, 0x16, 0x22, 0x88, 0x0E, 0x00, 
-	0x6C, 0x09, 0x0E, 0x13, 0x22, 0x88, 0x12, 0x00, 
-	0xE0, 0x06, 0x08, 0x16, 0x22, 0x88, 0x10, 0x00, 
-	0xDE, 0x06, 0x04, 0x16, 0x22, 0x88, 0x0E, 0x00, 
-	0xDC, 0x06, 0x01, 0x13, 0xCB, 0x05, 0xCB, 0x05, 
-	0x5B, 0x04, 0x0B, 0xC3, 0x00, 0x03, 0x02, 0x00, 
-	0x82, 0x07, 0xC0, 0x00, 0x20, 0xC8, 0x0C, 0x00, 
-	0xC0, 0x00, 0x20, 0xC8, 0x0E, 0x00, 0xC2, 0x00, 
-	0x20, 0xC8, 0x10, 0x00, 0xC4, 0x00, 0x20, 0xC8, 
-	0x12, 0x00, 0xC6, 0x00, 0x20, 0xC8, 0x14, 0x00, 
-	0xC8, 0x00, 0x20, 0xC8, 0x16, 0x00, 0xCA, 0x00, 
-	0x20, 0xC8, 0x04, 0x00, 0xCC, 0x00, 0x20, 0xC8, 
-	0x06, 0x00, 0xCE, 0x00, 0x02, 0xC8, 0x0C, 0x00, 
-	0xA0, 0x07, 0x0E, 0x00, 0x7E, 0xE6, 0x02, 0xC8, 
-	0x10, 0x00, 0xA0, 0x07, 0x12, 0x00, 0x88, 0xE6, 
-	0x02, 0xC8, 0x14, 0x00, 0xA0, 0x07, 0x16, 0x00, 
-	0xB8, 0xE6, 0x02, 0xC8, 0x04, 0x00, 0xA0, 0x07, 
-	0x06, 0x00, 0xCE, 0xE6, 0x60, 0x01, 0x1C, 0x01, 
-	0x04, 0x00, 0x09, 0x16, 0xE0, 0x01, 0x40, 0x01, 
-	0x00, 0x08, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x40, 
-	0xE0, 0x01, 0x40, 0x01, 0x00, 0x04, 0xA0, 0x06, 
-	0x8E, 0xE9, 0x05, 0x02, 0x00, 0x80, 0x05, 0xD8, 
-	0x80, 0x04, 0xC7, 0x04, 0x00, 0x03, 0x0F, 0x00, 
-	0x88, 0x07, 0x00, 0x10, 0x09, 0x02, 0x00, 0x20, 
-	0x8A, 0x07, 0xE6, 0xE6, 0x03, 0x02, 0x3E, 0xE6, 
-	0x5A, 0x04, 0x00, 0x03, 0x00, 0x00, 0x20, 0xD2, 
-	0x87, 0x01, 0x06, 0x10, 0x00, 0x03, 0x00, 0x00, 
-	0x20, 0xC2, 0x8A, 0x01, 0x08, 0x02, 0x00, 0x1A, 
-	0x60, 0xC2, 0xAE, 0x00, 0x48, 0xDA, 0x80, 0x04, 
-	0x89, 0x05, 0x89, 0x02, 0x06, 0x00, 0x07, 0x15, 
-	0x88, 0x07, 0x00, 0x80, 0x48, 0xDA, 0x80, 0x04, 
-	0x09, 0xC8, 0xAE, 0x00, 0x80, 0x03, 0xE0, 0x02, 
-	0xA0, 0x00, 0x5C, 0x04, 0x00, 0x03, 0x00, 0x00, 
-	0x60, 0x01, 0x9C, 0x01, 0x20, 0x00, 0xE2, 0x13, 
-	0x20, 0xC2, 0x8C, 0x01, 0x08, 0x02, 0x00, 0x1C, 
-	0xE3, 0x10, 0x00, 0x03, 0x00, 0x00, 0x60, 0x01,  
-	0x40, 0x01, 0x00, 0x40, 0xEC, 0x16, 0xA0, 0x01,  
-	0x40, 0x01, 0x00, 0x40, 0x08, 0x02, 0x00, 0x02, 
-	0xD7, 0x10, 0xB3, 0xC0, 0x92, 0x06, 0xFD, 0x10, 
-	0xB3, 0xC0, 0x48, 0xC0, 0x72, 0xCC, 0x72, 0xCC, 
-	0x32, 0xC1, 0x44, 0xCC, 0x72, 0xDC, 0x04, 0x06, 
-	0xFD, 0x16, 0x5B, 0x04, 0x48, 0xC0, 0x02, 0x02, 
-	0xD0, 0xE9, 0x84, 0x07, 0x06, 0x00, 0xF6, 0x10, 
-	0x02, 0x02, 0x1E, 0xE6, 0x49, 0xC0, 0x84, 0x07, 
-	0x06, 0x00, 0xF0, 0x10, 0xB3, 0xC0, 0x32, 0xC1, 
-	0x01, 0x02, 0x01, 0x00, 0x44, 0xD0, 0xC1, 0x06, 
-	0x44, 0x02, 0xFF, 0x00, 0xE7, 0x10, 0x33, 0xC1, 
-	0x73, 0xC0, 0x44, 0xD1, 0x44, 0x02, 0xFF, 0x00, 
-	0x45, 0xDC, 0x04, 0x06, 0xFD, 0x16, 0x5A, 0x04, 
-	0xA0, 0x06, 0x0E, 0xE9, 0x33, 0xC8, 0x9E, 0x01, 
-	0x5A, 0x04, 0xA0, 0x06, 0x0C, 0xE7, 0x89, 0xC1, 
-	0xA6, 0x09, 0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, 
-	0x8A, 0x01, 0x88, 0xC1, 0xA6, 0x09, 0x66, 0x02,  
-	0x40, 0x00, 0x06, 0xC8, 0x8C, 0x01, 0xC2, 0x04,  
-	0xC7, 0xC1, 0x03, 0x16, 0x02, 0x06, 0xFC, 0x16,  
-	0x4D, 0x10, 0x5A, 0x04, 0xA0, 0x06, 0x58, 0xE8, 
-	0x89, 0xC1, 0xA6, 0x09, 0x66, 0x02, 0x40, 0x00, 
-	0x06, 0xC8, 0x8A, 0x01, 0x88, 0xC1, 0xA6, 0x09, 
-	0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, 0x8C, 0x01, 
-	0x33, 0xC8, 0x9E, 0x01, 0xE8, 0x10, 0x33, 0x8A, 
-	0x02, 0x00, 0x38, 0x16, 0x73, 0x8A, 0x02, 0x00, 
-	0x35, 0x16, 0x5A, 0x04, 0x20, 0x8A, 0xCA, 0xE9, 
-	0x02, 0x00, 0x30, 0x16, 0x60, 0x8A, 0xCE, 0xE9, 
-	0x02, 0x00, 0x2C, 0x16, 0x82, 0x07, 0x74, 0xEA, 
-	0x01, 0x10, 0xB3, 0xC0, 0x04, 0x02, 0x80, 0x04, 
-	0x52, 0xD1, 0x03, 0x13, 0x32, 0x9D, 0x22, 0x16, 
-	0xFB, 0x10, 0x85, 0x07, 0x00, 0x80, 0x05, 0xD8, 
-	0x80, 0x04, 0xC7, 0x04, 0x5A, 0x04, 0x20, 0xC8, 
-	0xC0, 0x00, 0x0C, 0x00, 0x20, 0xC8, 0xC2, 0x00, 
-	0x0E, 0x00, 0x20, 0xC8, 0xC4, 0x00, 0x10, 0x00, 
-	0x20, 0xC8, 0xC6, 0x00, 0x12, 0x00, 0x20, 0xC8, 
-	0xC8, 0x00, 0x14, 0x00, 0x20, 0xC8, 0xCA, 0x00, 
-	0x16, 0x00, 0x20, 0xC8, 0xCC, 0x00, 0x04, 0x00, 
-	0x20, 0xC8, 0xCE, 0x00, 0x06, 0x00, 0x00, 0x03, 
-	0x0F, 0x00, 0xCC, 0x05, 0x5C, 0x04, 0xE0, 0x04, 
-	0x82, 0x01, 0x02, 0x02, 0x18, 0xE6, 0x32, 0xC8, 
-	0x82, 0x01, 0x32, 0xC8, 0x80, 0x01, 0xA0, 0x06, 
-	0x24, 0xE8, 0x12, 0xC8, 0x82, 0x01, 0xCA, 0xC2, 
-	0x84, 0x07, 0xD0, 0x07, 0xE0, 0x04, 0x84, 0x01, 
-	0x04, 0x06, 0xFC, 0x16, 0x20, 0xC1, 0x84, 0x01, 
-	0xE9, 0x16, 0x04, 0x02, 0x32, 0x00, 0x85, 0x07, 
-	0x00, 0x80, 0x05, 0xD8, 0x80, 0x04, 0xC7, 0x04, 
-	0x60, 0xC1, 0x86, 0x01, 0x04, 0x06, 0xFC, 0x16, 
-	0x20, 0xC1, 0x84, 0x01, 0x5B, 0x04, 0xB3, 0xC0, 
-	0xB3, 0xC4, 0x5B, 0x04, 0x48, 0xC0, 0xB3, 0xC0, 
-	0x73, 0xA0, 0x42, 0xC4, 0x5B, 0x04, 0x33, 0x88, 
-	0x84, 0x01, 0xE6, 0x16, 0x5A, 0x04, 0x89, 0xC1, 
-	0xA6, 0x09, 0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, 
-	0x8A, 0x01, 0x5B, 0x04, 0xC5, 0x04, 0xA0, 0x07, 
-	0x9C, 0x01, 0x40, 0x00, 0x60, 0x01, 0x9C, 0x01, 
-	0x40, 0x00, 0x03, 0x13, 0x05, 0x06, 0xF7, 0x16, 
-	0x5C, 0x04, 0x5B, 0x04, 0xA0, 0x06, 0xAC, 0xE8, 
-	0x60, 0xC0, 0x40, 0x01, 0x05, 0xC8, 0x40, 0x01, 
-	0x02, 0xC5, 0x01, 0xC8, 0x40, 0x01, 0x5A, 0x04, 
-	0xA0, 0x06, 0xAC, 0xE8, 0x08, 0xA1, 0xF4, 0x10, 
-	0xB3, 0xC0, 0x33, 0xC1, 0x60, 0xC1, 0x40, 0x01, 
-	0x85, 0x01, 0x00, 0x04, 0xC5, 0x01, 0x00, 0x10,  
-	0x5B, 0x04, 0x08, 0xC1, 0x09, 0xC2, 0x44, 0xC2, 
-	0x5B, 0x04, 0x05, 0x02, 0xC8, 0x00, 0x05, 0x06, 
-	0xFE, 0x16, 0x5B, 0x04, 0x33, 0xC1, 0x03, 0xC0, 
-	0xC4, 0xC0, 0x5B, 0x04, 0xC0, 0xC0, 0x5B, 0x04, 
-	0xE0, 0x94, 0x9E, 0x01, 0xC2, 0x16, 0xC3, 0x05, 
-	0x5B, 0x04, 0x73, 0xC0, 0xA0, 0x06, 0x26, 0xE9, 
-	0x2D, 0x02, 0x08, 0x00, 0x85, 0x07, 0x08, 0x00, 
-	0x71, 0x9F, 0xB7, 0x16, 0x05, 0x06, 0xFC, 0x16, 
-	0x5A, 0x04, 0x02, 0x02, 0x24, 0xE6, 0x60, 0x04, 
-	0x10, 0xE7, 0xE9, 0x8C, 0x04, 0x00, 0xAD, 0x16, 
-	0x5B, 0x04, 0x20, 0xC1, 0x80, 0x01, 0x85, 0x07, 
-	0xD0, 0x07, 0xE0, 0x01, 0x80, 0x01, 0x00, 0x04, 
-	0x45, 0x06, 0xFE, 0x16, 0x04, 0xC8, 0x80, 0x01, 
-	0x5B, 0x04, 0x33, 0xC1, 0x48, 0xC3, 0x04, 0xC1, 
-	0x04, 0x13, 0x2D, 0x02, 0x00, 0x04, 0x04, 0x06, 
-	0xFC, 0x16, 0x5B, 0x04, 0x8D, 0xC3, 0xA0, 0x06, 
-	0x26, 0xE9, 0x8D, 0xC1, 0xA6, 0x09, 0x66, 0x02, 
-	0x40, 0x00, 0x86, 0xC7, 0x5A, 0x04, 0x8D, 0xC1, 
-	0xA6, 0x09, 0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, 
-	0x8A, 0x01, 0x5B, 0x04, 0x8D, 0xC1, 0xA6, 0x09, 
-	0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, 0x8C, 0x01, 
-	0x5B, 0x04, 0x4D, 0xC0, 0x04, 0x02, 0x28, 0x00, 
-	0x85, 0x07, 0x00, 0x55, 0x60, 0x04, 0x34, 0xE7, 
-	0x4D, 0xC0, 0xB3, 0xC0, 0x32, 0xC1, 0x60, 0x04, 
-	0xF8, 0xE6, 0x33, 0xC1, 0x60, 0x01, 0x1C, 0x01, 
-	0x04, 0x00, 0x01, 0x16, 0x5B, 0x04, 0xC4, 0xC0, 
-	0x5B, 0x04, 0x89, 0x07, 0x66, 0xE5, 0x39, 0xC2, 
-	0x07, 0x13, 0x39, 0xC6, 0x39, 0x86, 0x25, 0x16, 
-	0x39, 0xC6, 0x39, 0x86, 0x22, 0x16, 0xF7, 0x10, 
-	0x02, 0x02, 0xAC, 0xE9, 0xC4, 0x04, 0xC5, 0x04, 
-	0x39, 0xC2, 0x02, 0x13, 0x60, 0x04, 0xE8, 0xE9, 
-	0x02, 0x02, 0xBA, 0xE9, 0xC4, 0x04, 0x39, 0xC2, 
-	0x03, 0x13, 0x79, 0xC1, 0x60, 0x04, 0xE8, 0xE9, 
-	0x02, 0x02, 0xCA, 0xE9, 0xC5, 0x04, 0x39, 0xC2, 
-	0x03, 0x13, 0x39, 0xC1, 0x60, 0x04, 0xE8, 0xE9, 
-	0x79, 0xC0, 0xB9, 0xC0, 0x81, 0x60, 0xC2, 0x05, 
-	0x12, 0x09, 0xF1, 0x04, 0x02, 0x06, 0xFD, 0x16, 
-	0x5B, 0x04, 0x5C, 0x04, 0x01, 0x02, 0xAA, 0xAA, 
-	0x01, 0xC6, 0x44, 0xE0, 0x45, 0x40, 0x58, 0x80, 
-	0xF8, 0x16, 0x01, 0x02, 0x14, 0x00, 0x01, 0x06, 
-	0xFE, 0x16, 0x01, 0x02, 0x55, 0x55, 0x01, 0xC6, 
-	0x44, 0xE0, 0x45, 0x40, 0x58, 0x80, 0xED, 0x16, 
-	0x52, 0x04, 0xE0, 0x02, 0xA0, 0x00, 0x88, 0x07, 
-	0xC0, 0x00, 0x09, 0x02, 0x62, 0xEA, 0x84, 0x07, 
-	0x2A, 0xE6, 0x05, 0x02, 0x01, 0x00, 0x8B, 0xC2, 
-	0xCC, 0x04, 0xA0, 0x06, 0x6C, 0xEA, 0x60, 0x2C, 
-	0x01, 0x00, 0x99, 0x06, 0xA0, 0x2C, 0x02, 0x00, 
-	0x99, 0x06, 0x20, 0x2D, 0x04, 0x00, 0x99, 0x06, 
-	0x20, 0x2E, 0x08, 0x00, 0x99, 0x06, 0xA0, 0x2F, 
-	0x10, 0x00, 0x8C, 0x05, 0x09, 0x16, 0x80, 0xCC, 
-	0x81, 0xC4, 0x83, 0x07, 0xB0, 0xEA, 0x88, 0xC0, 
-	0x02, 0x04, 0x8C, 0x05, 0x01, 0x16, 0x33, 0x10, 
-	0xE0, 0x02, 0xA0, 0x00, 0x5A, 0x04, 0x8C, 0x05, 
-	0xFB, 0x16, 0x80, 0xCC, 0x81, 0xC4, 0x15, 0x0A, 
-	0xB4, 0xC0, 0x12, 0xC0, 0x88, 0xCC, 0x52, 0xC0, 
-	0xB4, 0xC4, 0x42, 0x06, 0x5B, 0x04, 0x2D, 0x07, 
-	0x18, 0x00, 0x41, 0x8B, 0x0A, 0x00, 0xEC, 0x16, 
-	0xC1, 0x82, 0xEA, 0x16, 0xC2, 0x02, 0x42, 0x02, 
-	0x00, 0x02, 0xE6, 0x16, 0x80, 0x03, 0x81, 0x07, 
-	0x01, 0x00, 0xF1, 0x10, 0x01, 0x02, 0x02, 0x00, 
-	0xEE, 0x10, 0x01, 0x02, 0x04, 0x00, 0xEB, 0x10, 
-	0x01, 0x02, 0x08, 0x00, 0xE8, 0x10, 0x01, 0x02, 
-	0x10, 0x00, 0xE5, 0x10, 0xA1, 0x02, 0x41, 0x8B, 
-	0x10, 0x00, 0x02, 0x13, 0x60, 0x04, 0x5C, 0xEA, 
-	0x2D, 0x07, 0x18, 0x00, 0x80, 0x03, 0x09, 0x02, 
-	0x00, 0x08, 0x03, 0x02, 0x04, 0x00, 0xC7, 0x04, 
-	0xA0, 0x06, 0xDC, 0xEB, 0x60, 0x01, 0x1C, 0x01, 
-	0x04, 0x00, 0x1C, 0x16, 0xA0, 0x01, 0x40, 0x01, 
-	0x00, 0x08, 0xE0, 0x01, 0x40, 0x01, 0x00, 0x10, 
-	0x04, 0x02, 0x01, 0x00, 0x44, 0xCE, 0xC4, 0x06, 
-	0x44, 0xC6, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x10, 
-	0x49, 0x06, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x40, 
-	0xE0, 0x01, 0x40, 0x01, 0x00, 0x04, 0xE0, 0x01, 
-	0x40, 0x01, 0x00, 0x08, 0xA0, 0x06, 0x7A, 0xEC, 
-	0xA0, 0x06, 0x7A, 0xEC, 0xC7, 0x05, 0x04, 0x02, 
-	0xE4, 0xE4, 0xE0, 0x04, 0xD0, 0x03, 0x74, 0xC1, 
-	0xB4, 0xC1, 0x86, 0x05, 0x1C, 0x13, 0xE0, 0x02, 
-	0xC0, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, 0xC0, 
-	0x80, 0xC0, 0xC0, 0xC0, 0x00, 0xC1, 0x40, 0xC1, 
-	0x80, 0xC1, 0xC0, 0xC1, 0x00, 0xC2, 0x40, 0xC2, 
-	0x80, 0xC2, 0xC0, 0xC2, 0x00, 0xC3, 0x40, 0xC3, 
-	0x80, 0xC3, 0xC0, 0xC3, 0xA0, 0x04, 0xAA, 0x00, 
-	0xD0, 0x03, 0xD0, 0x03, 0x3F, 0x10, 0x85, 0x05, 
-	0x85, 0x81, 0xE1, 0x13, 0xE4, 0x10, 0xC7, 0x05, 
-	0x05, 0x02, 0xFF, 0x7F, 0x45, 0xA1, 0xD0, 0x03, 
-	0xD0, 0x03, 0x34, 0x10, 0xC0, 0xCC, 0xC1, 0xC4, 
-	0x03, 0x02, 0x28, 0x00, 0xA0, 0x06, 0xDC, 0xEB, 
-	0xE0, 0x01, 0x42, 0x01, 0x00, 0x10, 0xC7, 0x05, 
-	0xD0, 0x03, 0xD0, 0x03, 0x27, 0x10, 0xC7, 0x05, 
-	0xA0, 0xC1, 0x4A, 0x01, 0xA0, 0x07, 0x4A, 0x01, 
-	0x00, 0x0E, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x02, 
-	0x20, 0x07, 0x44, 0x01, 0x60, 0xC1, 0x44, 0x01, 
-	0x85, 0x02, 0x00, 0xFF, 0x17, 0x16, 0xE0, 0x01, 
-	0x40, 0x01, 0x00, 0x22, 0x05, 0x02, 0xC0, 0x00, 
-	0x05, 0x06, 0xD0, 0x03, 0xFD, 0x16, 0x60, 0xC1, 
-	0x46, 0x01, 0x85, 0x02, 0x00, 0xFF, 0x0A, 0x13, 
-	0x05, 0x02, 0x93, 0x33, 0x05, 0x06, 0x00, 0x10, 
-	0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 
-	0xD0, 0x03, 0xF8, 0x16, 0x51, 0x10, 0x06, 0xC8, 
-	0x4A, 0x01, 0xC0, 0xCC, 0xC1, 0xC4, 0x4B, 0x10, 
-	0x13, 0xC0, 0xC8, 0xCC, 0x53, 0xC0, 0x02, 0x02, 
-	0xEC, 0xEB, 0xC2, 0xC4, 0x43, 0x06, 0x5B, 0x04, 
-	0x60, 0xC0, 0xAE, 0x00, 0xC4, 0x02, 0x44, 0x02, 
-	0x0F, 0x00, 0x44, 0x88, 0xCA, 0xE4, 0x3C, 0x16, 
-	0x81, 0x02, 0x08, 0x00, 0x27, 0x13, 0x21, 0xC1, 
-	0xDC, 0xE4, 0x14, 0xC1, 0x21, 0x21, 0xBA, 0xE4, 
-	0x33, 0x16, 0x21, 0xC1, 0xC2, 0xE4, 0x81, 0x02, 
-	0x00, 0x00, 0x0B, 0x13, 0x0D, 0x02, 0xA0, 0x00, 
-	0x84, 0x83, 0x09, 0x13, 0xC4, 0x05, 0x84, 0x83, 
-	0x06, 0x13, 0xC4, 0x05, 0x84, 0x83, 0x03, 0x13, 
-	0x23, 0x10, 0x0E, 0x81, 0x21, 0x16, 0x21, 0xC1, 
-	0xDC, 0xE4, 0x21, 0x45, 0xBA, 0xE4, 0xE0, 0x01, 
-	0x42, 0x01, 0x00, 0x10, 0xA0, 0x01, 0x42, 0x01, 
-	0x00, 0x10, 0xA1, 0xC3, 0xD4, 0xE4, 0x0F, 0x02, 
-	0x2F, 0x00, 0x80, 0x03, 0xA0, 0x01, 0x40, 0x01, 
-	0x00, 0x02, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x80, 
-	0x6D, 0xC0, 0x0A, 0x00, 0x09, 0x13, 0x81, 0x02, 
-	0x5C, 0x12, 0x06, 0x1B, 0x0E, 0x02, 0xD2, 0xEB, 
-	0x0F, 0x02, 0x0F, 0x00, 0x80, 0x03, 0xCA, 0x05, 
-	0xE0, 0x02, 0xA0, 0x00, 0x5A, 0x04, 0x59, 0xCE, 
-	0x20, 0x88, 0xE4, 0xE4, 0xE4, 0xE4, 0xF8, 0x10, 
-	0xC1, 0x04, 0x48, 0x62, 0x89, 0x05, 0xA0, 0xC0, 
-	0x6C, 0x01, 0x08, 0xC8, 0x6C, 0x01, 0x03, 0x02, 
-	0x00, 0xFC, 0x04, 0x02, 0x00, 0x02, 0x73, 0xA0, 
-	0x04, 0x06, 0xFD, 0x16, 0x88, 0x05, 0x09, 0x06, 
-	0xF4, 0x16, 0x02, 0xC8, 0x6C, 0x01, 0x81, 0x86, 
-	0x02, 0x16, 0xD0, 0x03, 0xCB, 0x05, 0x5B, 0x04, 
-	0x43, 0x28, 0x31, 0x29, 0x38, 0x39, 0x2D, 0x33, 
-	0x38, 0x38, 0x42, 0x20, 0x20, 0x59, 0x49, 0x54, 
-	0x4B, 0xC2, 0xA8, 0x02, 0x98, 0x00, 0x83, 0x07, 
-	0x02, 0x00, 0x28, 0x02, 0x08, 0x00, 0x23, 0xC6, 
-	0x36, 0xE5, 0x48, 0x06, 0xC4, 0xC0, 0x73, 0x0A, 
-	0x65, 0x17, 0xA0, 0x06, 0xAA, 0xED, 0xC8, 0xC1, 
-	0xC7, 0x05, 0x03, 0x02, 0xA5, 0x00, 0xB0, 0x03, 
-	0xF8, 0xCD, 0xF8, 0xCD, 0xA6, 0x02, 0x06, 0x62, 
-	0x88, 0x02, 0x0A, 0x00, 0x57, 0x16, 0x03, 0x29, 
-	0x55, 0x16, 0x05, 0x29, 0xC4, 0x80, 0x52, 0x16, 
-	0x15, 0x09, 0x50, 0x17, 0x15, 0x09, 0x4E, 0x18, 
-	0x85, 0x02, 0x29, 0x00, 0x4B, 0x16, 0xC6, 0x05, 
-	0x96, 0x00, 0x03, 0x07, 0xC4, 0x04, 0x45, 0x06, 
-	0x95, 0x00, 0x44, 0x05, 0x43, 0x16, 0x44, 0x81, 
-	0x41, 0x16, 0x00, 0x03, 0x05, 0x00, 0xC4, 0x02, 
-	0x00, 0x03, 0x0A, 0x00, 0x44, 0x02, 0x0F, 0x00, 
-	0x84, 0x02, 0x05, 0x00, 0x37, 0x16, 0xC4, 0x02, 
-	0x00, 0x03, 0x0F, 0x00, 0x44, 0x02, 0x0F, 0x00, 
-	0x84, 0x02, 0x0A, 0x00, 0x2F, 0x16, 0x04, 0x02, 
-	0xFE, 0xFF, 0x2C, 0x13, 0x2B, 0x15, 0x2A, 0x1A, 
-	0x84, 0x05, 0x28, 0x12, 0x27, 0x15, 0x26, 0x1A, 
-	0x25, 0x18, 0x84, 0x05, 0x23, 0x16, 0x22, 0x1B, 
-	0x21, 0x17, 0x84, 0x05, 0x1F, 0x13, 0x1E, 0x1A, 
-	0x1D, 0x11, 0x04, 0x06, 0x1B, 0x16, 0xA5, 0x02, 
-	0xC5, 0xC1, 0x25, 0x02, 0x06, 0x00, 0x03, 0x02, 
-	0xA5, 0xA5, 0x83, 0xC1, 0x95, 0x00, 0x03, 0x38, 
-	0x94, 0x00, 0x83, 0x02, 0x2E, 0x6B, 0x0E, 0x16, 
-	0x84, 0x02, 0x59, 0x1C, 0x0B, 0x16, 0x24, 0x02, 
-	0x69, 0x00, 0x95, 0x00, 0x03, 0x3C, 0x94, 0x00, 
-	0x83, 0x81, 0x04, 0x16, 0x84, 0x02, 0x69, 0x00, 
-	0x01, 0x16, 0xC9, 0x05, 0x59, 0x04, 0xC3, 0xD0, 
-	0xFD, 0x13, 0x01, 0x1C, 0xFB, 0x10, 0xE0, 0x90, 
-	0x3D, 0xE5, 0xF8, 0x16, 0xC3, 0x06, 0xC3, 0xD0, 
-	0xF5, 0x1C, 0xF4, 0x16, 0xE0, 0x90, 0x3A, 0xE5, 
-	0xF1, 0x16, 0x5B, 0x04, 0x0B, 0xC3, 0x09, 0x02, 
-	0x3E, 0xE5, 0xA0, 0x06, 0x92, 0xE9, 0xCC, 0x05, 
-	0x5C, 0x04, 0x88, 0x07, 0x00, 0xA0, 0x89, 0x07, 
-	0xFE, 0xFF, 0xA8, 0x09, 0xA9, 0x09, 0x8A, 0x07, 
-	0x02, 0xE0, 0xA0, 0x06, 0x84, 0xEC, 0x00, 0x00, 
-	0x88, 0x07, 0x00, 0x90, 0x89, 0x07, 0xFE, 0x9F, 
-	0xA8, 0x09, 0xA9, 0x09, 0x8A, 0x07, 0x78, 0xE0, 
-	0xA0, 0x06, 0x84, 0xEC, 0x00, 0x00, 0xA0, 0x06, 
-	0xC4, 0xEC, 0x00, 0x00, 0xE6, 0x10, 0xE5, 0x10, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 
-	0x00, 0x08, 0x11, 0xE3, 0x6C, 0xCC, 0x00, 0x80, 
-	0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 
-	0x00, 0x04, 0x00, 0x02, 0x00, 0x01, 0x80, 0x00, 
-	0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 0x00, 
-	0x04, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0xFF, 
-	0xFF, 0x00, 0xF0, 0xFF, 0x00, 0xF0, 0x0F, 0x00,  
-	0xFF, 0xFF, 0xFF, 0x7F, 0x03, 0x00, 0x00, 0x00,  
-	0xC3, 0x00, 0xE7, 0xE7, 0xF3, 0xE7, 0xF1, 0xF1, 
-	0x43, 0x28, 0x20, 0x29, 0x4F, 0x43, 0x59, 0x50, 
-	0x49, 0x52, 0x48, 0x47, 0x20, 0x54, 0x42, 0x49, 
-	0x20, 0x4D, 0x39, 0x31, 0x33, 0x38, 0x34, 0x2C, 
-	0x35, 0x2C, 0x36, 0x2C, 0x43, 0x28, 0x20, 0x29, 
-	0x4F, 0x43, 0x59, 0x50, 0x49, 0x52, 0x48, 0x47, 
-	0x20, 0x54, 0x49, 0x54, 0x31, 0x20, 0x38, 0x39, 
-	0x2D, 0x33, 0x39, 0x38, 0x39, 0x2C, 0x2D, 0x30, 
-	0x38, 0x39, 0x00, 0x00, 0x61, 0x9B, 0xC4, 0xEC, 
-	0x0E, 0xEA, 0xDE, 0xE5, 0xC8, 0xED, 0x00, 0x00, 
-	0xC4, 0x00, 0xB8, 0xAF, 0x4A, 0x06, 0x50, 0x06, 
-	0x4C, 0x06, 0xDC, 0xCC, 0x4E, 0x06, 0x0F, 0x00, 
-	0x32, 0x06, 0x01, 0x00, 0x50, 0x07, 0x58, 0x07, 
-	0x52, 0x07, 0x70, 0xB5, 0x54, 0x07, 0x0F, 0x00, 
-	0x38, 0x07, 0x01, 0x00, 0xBA, 0x00, 0xA0, 0x00, 
-	0xBC, 0x00, 0xD6, 0xED, 0xBE, 0x00, 0x0F, 0x00, 
-	0x5E, 0x07, 0x3A, 0x07, 0x62, 0x07, 0x40, 0x80, 
-	0x64, 0x07, 0x54, 0xBA, 0x66, 0x07, 0x36, 0xBA, 
-	0x68, 0x07, 0x40, 0xB8, 0x98, 0x07, 0x00, 0x80, 
-	0x78, 0x07, 0x00, 0x80, 0xE2, 0x08, 0x04, 0x00, 
-	0xE4, 0x08, 0x01, 0x00, 0xEC, 0x08, 0x08, 0x00, 
-	0xF6, 0x08, 0x0A, 0x00, 0xF8, 0x08, 0x06, 0x00, 
-	0x00, 0x09, 0x0C, 0x00, 0x02, 0x09, 0x04, 0x00, 
-	0xAE, 0x01, 0x00, 0x00, 0x1E, 0x09, 0x00, 0x00, 
-	0x66, 0x09, 0x00, 0x00, 0x0C, 0x06, 0x13, 0x00, 
-	0x0A, 0x06, 0x20, 0x00, 0x00, 0x00, 0xE0, 0x00, 
-	0x86, 0xA3, 0xE0, 0x00, 0xE6, 0xA2, 0xE0, 0x00, 
-	0x86, 0xA3, 0xE0, 0x00, 0x02, 0xA5, 0xE0, 0x00, 
-	0x5E, 0xA6, 0xE0, 0x00, 0x66, 0xA9, 0xE0, 0x00, 
-	0x12, 0xA4, 0xC0, 0x00, 0x22, 0xA4, 0xE0, 0x00, 
-	0x86, 0xA3, 0xE0, 0x00, 0x86, 0xA3, 0xC0, 0x00, 
-	0x74, 0xA4, 0xE0, 0x00, 0x86, 0xA3, 0xE0, 0x00, 
-	0x86, 0xA3, 0xE0, 0x00, 0x86, 0xA3, 0xE0, 0x00, 
-	0x86, 0xA3, 0xE0, 0x00, 0x86, 0xA3, 0xC0, 0x00, 
-	0xDE, 0xAF, 0xC0, 0x00, 0x48, 0xB0, 0xC0, 0x00, 
-	0x84, 0xB0, 0xC0, 0x00, 0xF4, 0xB0, 0xC0, 0x00, 
-	0x76, 0xB1, 0xE0, 0x00, 0xE4, 0xB2, 0xE0, 0x00, 
-	0x8A, 0xB2, 0xE0, 0x00, 0xF4, 0xB3, 0xE0, 0x00, 
-	0x7C, 0xB3, 0xE0, 0x00, 0xC6, 0xAA, 0xC0, 0x00, 
-	0x36, 0xAB, 0xC0, 0x00, 0x90, 0xAB, 0xC0, 0x00, 
-	0xC2, 0xAB, 0xC0, 0x00, 0xEA, 0xAA, 0xC0, 0x00, 
-	0x80, 0xA3, 0xC0, 0x00, 0x80, 0xA3, 0x00, 0x3F, 
-	0x00, 0x7F, 0x00, 0x5E, 0x30, 0x00, 0x28, 0x00, 
-	0x43, 0x00, 0xB6, 0xA6, 0xB6, 0xA6, 0x1C, 0xA5, 
-	0x14, 0xA5, 0x46, 0xA5, 0x46, 0xA5, 0x62, 0xA5, 
-	0xB6, 0xA6, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, 
-	0x00, 0x00, 0x00, 0x08, 0x00, 0x20, 0x00, 0x08, 
-	0x00, 0x80, 0x00, 0x08, 0x00, 0x01, 0x00, 0x10, 
-	0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 
-	0x14, 0x00, 0x0E, 0x10, 0x0C, 0x0C, 0x0A, 0x0A, 
-	0x0A, 0x0A, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 
-	0x08, 0x08, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,  
-	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 
-	0x06, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,  
-	0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 
-	0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 
-	0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 
-	0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 
-	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 
-	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 
-	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 
-	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 
-	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 
-	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 
-	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 
-	0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x98, 0x07, 0x7E, 0xCA, 0x58, 0x07, 
-	0xF8, 0xB8, 0x58, 0x07, 0xFE, 0xB7, 0x58, 0x07, 
-	0x68, 0xB9, 0x58, 0x07, 0xD0, 0xB8, 0x98, 0x07, 
-	0x5A, 0xC7, 0x98, 0x07, 0x52, 0xC7, 0x78, 0x07, 
-	0xC2, 0xC1, 0x58, 0x07, 0x30, 0xB9, 0x98, 0x07, 
-	0x38, 0xCA, 0x78, 0x07, 0x96, 0xC2, 0x58, 0x07, 
-	0x6A, 0xC7, 0x58, 0x07, 0xE0, 0xB8, 0x58, 0x07, 
-	0x1E, 0xB9, 0x58, 0x07, 0xE2, 0xB9, 0x98, 0x07, 
-	0xAE, 0xCB, 0x98, 0x07, 0x8E, 0xC7, 0x78, 0x07, 
-	0x56, 0xC2, 0xB8, 0x07, 0x14, 0xCC, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0xA2, 0xBA, 0x16, 0xC1, 
-	0xCA, 0xC1, 0xD6, 0xC6, 0x8A, 0xBD, 0xC2, 0xBD, 
-	0xE0, 0xBD, 0x6A, 0xBE, 0x8E, 0xBE, 0xAA, 0xBE, 
-	0x22, 0xBF, 0x22, 0xBF, 0x56, 0xBE, 0xC8, 0xBF, 
-	0x10, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 
-	0x00, 0x0C, 0x01, 0x0F, 0xFF, 0xFE, 0x00, 0x58, 
-	0x00, 0x0E, 0xFF, 0xFE, 0x0E, 0x00, 0x00, 0x70, 
-	0x40, 0x80, 0x00, 0x5E, 0xA0, 0xC0, 0xDF, 0xFF, 
-	0x00, 0x18, 0x00, 0xE0, 0x00, 0x78, 0x00, 0x50, 
-	0x00, 0x60, 0x00, 0x70, 0x00, 0x0C, 0x06, 0x00, 
-	0x00, 0x00, 0x84, 0xE3, 0xE6, 0x07, 0xF4, 0x07, 
-	0x08, 0x00, 0x00, 0x00, 0x8A, 0xE3, 0xEA, 0x07, 
-	0xF4, 0x07, 0x06, 0x00, 0x40, 0x00, 0x00, 0x0A, 
-	0xE6, 0x07, 0xEE, 0x07, 0x08, 0x00, 0x40, 0x00, 
-	0x06, 0x0A, 0xEA, 0x07, 0xEE, 0x07, 0x00, 0x00, 
-	0xE2, 0xC1, 0x8B, 0xD4, 0xFF, 0xFF, 0xD7, 0xD1, 
-	0xD9, 0xC5, 0xD4, 0xC3, 0x3B, 0x59, 0x34, 0x09, 
-	0xFC, 0x05, 0x6C, 0x09, 0xD8, 0x06, 0x06, 0x04, 
-	0xBA, 0xEA, 0x30, 0x09, 0x48, 0x04, 0x80, 0x08, 
-	0x06, 0x00, 0x0A, 0x06, 0x0E, 0x0C, 0xBA, 0xCE, 
-	0x2E, 0xE0, 0x56, 0xE0, 0x50, 0xE1, 0x66, 0xE2, 
-	0xEC, 0xE2, 0x4C, 0xE3, 0xFE, 0xE3, 0xBA, 0xCE, 
-	0x80, 0xE4, 0x10, 0xE4, 0x14, 0xE0, 0x1C, 0xE4, 
-	0x1C, 0xE4, 0x46, 0xE5, 0x50, 0xE5, 0x5A, 0xE5, 
-	0xBA, 0xCE, 0xA6, 0xDC, 0xBA, 0xCE, 0x44, 0xDA, 
-	0xE6, 0xDF, 0x70, 0xDA, 0xDE, 0xDE, 0xB0, 0xCE, 
-	0x16, 0xDB, 0x3A, 0xDD, 0xB8, 0xDD, 0x34, 0xDE, 
-	0x58, 0xDE, 0x16, 0xDB, 0xDA, 0xDC, 0x08, 0xCF, 
-	0xB0, 0xCE, 0xA8, 0xD9, 0x8A, 0xD9, 0x44, 0xD9, 
-	0xB0, 0xCE, 0xEA, 0xDE, 0xB0, 0xCE, 0x72, 0x06, 
-	0xF6, 0xD2, 0x08, 0x07, 0x72, 0x06, 0x54, 0xD2, 
-	0xF4, 0x01, 0x72, 0x06, 0x34, 0xD2, 0x08, 0x07, 
-	0x7C, 0x06, 0x5A, 0xDC, 0x04, 0x00, 0x7C, 0x06, 
-	0x78, 0xD2, 0x00, 0x00, 0x7C, 0x06, 0xCC, 0xDE, 
-	0xFA, 0x00, 0x86, 0x06, 0xAC, 0xD1, 0x05, 0x00, 
-	0x90, 0x06, 0x1C, 0xDF, 0x28, 0x00, 0x90, 0x06, 
-	0x50, 0xD3, 0x04, 0x01, 0x90, 0x06, 0x00, 0x00, 
-	0x02, 0x00, 0x90, 0x06, 0x80, 0xD2, 0xBC, 0x02, 
-	0x9A, 0x06, 0x06, 0xD3, 0xDC, 0x05, 0x9A, 0x06, 
-	0xAA, 0xD2, 0x64, 0x00, 0x9A, 0x06, 0x0A, 0xD3, 
-	0x14, 0x00, 0x9A, 0x06, 0xE2, 0xE0, 0x40, 0x06, 
-	0x9A, 0x06, 0x12, 0xD3, 0x64, 0x00, 0x7C, 0x06, 
-	0x16, 0xDC, 0x04, 0x00, 0x7C, 0x06, 0xE6, 0xDA,  
-	0x16, 0x00, 0x7C, 0x06, 0xFA, 0xDB, 0x05, 0x00, 
-	0x7C, 0x06, 0x00, 0xDD, 0x14, 0x00, 0x9A, 0x06, 
-	0x7C, 0xD3, 0x14, 0x00, 0x9A, 0x06, 0x38, 0xD4, 
-	0x02, 0x00, 0x7C, 0x06, 0x0C, 0xE0, 0x19, 0x00, 
-	0x00, 0x00, 0x0A, 0x07, 0x0E, 0x07, 0x04, 0x07, 
-	0xD8, 0x06, 0x00, 0x07, 0xF0, 0x06, 0xEE, 0x06, 
-	0xEC, 0x06, 0x0C, 0x07, 0xE6, 0x06, 0x18, 0x07, 
-	0x92, 0x09, 0x94, 0x09, 0x96, 0x09, 0x98, 0x09, 
-	0x00, 0x50, 0xCC, 0x00, 0x03, 0x00, 0x00, 0x84, 
-	0x00, 0xA8, 0x00, 0xA0, 0x00, 0x20, 0x00, 0x80, 
-	0x00, 0x40, 0x00, 0x08, 0x00, 0x40, 0x00, 0x80, 
-	0x00, 0x40, 0x00, 0x10, 0x82, 0xEC, 0x48, 0xEB, 
-	0x62, 0xEB, 0x7C, 0xEB, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x09, 0x00, 0x09, 0x00, 0xEA, 0xEB, 
-	0x52, 0xEB, 0x68, 0xEB, 0x82, 0xEB, 0x40, 0x01, 
-	0x42, 0x01, 0x42, 0x01, 0x42, 0x01, 0x00, 0x00, 
-	0x7F, 0x00, 0xA0, 0x00, 0xFF, 0x00, 0x10, 0x02, 
-	0x1F, 0x02, 0x30, 0x02, 0x3F, 0x02, 0x50, 0x02, 
-	0x5F, 0x02, 0x70, 0x02, 0x7F, 0x02, 0x90, 0x02, 
-	0x9F, 0x02, 0xB0, 0x02, 0xBF, 0x02, 0xD0, 0x02, 
-	0xDF, 0x02, 0xE1, 0x02, 0xFF, 0x02, 0x01, 0x03, 
-	0x7F, 0x03, 0x81, 0x03, 0x8F, 0x03, 0x91, 0x03, 
-	0x9F, 0x03, 0xA1, 0x03, 0xAF, 0x03, 0xB1, 0x03, 
-	0xBF, 0x03, 0xC1, 0x03, 0xCF, 0x03, 0xE1, 0x03, 
-	0xFF, 0x03, 0xC0, 0x07, 0xFF, 0x07, 0x00, 0x0C, 
-	0xFF, 0x0F, 0x00, 0x30, 0xFF, 0x37, 0xFF, 0xFF, 
-	0xFF, 0xFF, 0xBC, 0xFE, 0x07, 0x00, 0x5E, 0x02, 
-	0x00, 0x01, 0xFF, 0xBA, 0x80, 0xBA, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x0C, 0x01, 0x0A, 0x01, 
-	0x0E, 0x01, 0x10, 0x01, 0x14, 0x01, 0x00, 0x00, 
-	0x12, 0x01, 0x00, 0xF8, 0x16, 0x01, 0x00, 0xFF, 
-	0x00, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x1C, 0x01, 
-	0x82, 0x01, 0x66, 0x96, 0x66, 0x96, 0x55, 0x55, 
-	0x00, 0x00, 0x82, 0x01, 0x2A, 0x8A, 0x2A, 0x8A, 
-	0x18, 0xC9, 0x18, 0xC9, 0x86, 0x01, 0xAA, 0xA2, 
-	0x1E, 0xA0, 0x55, 0x55, 0x1E, 0x54, 0x8A, 0x01, 
-	0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 
-	0x8C, 0x01, 0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, 
-	0x00, 0x00, 0x8E, 0x01, 0x00, 0x50, 0x00, 0x00, 
-	0x00, 0xA8, 0x00, 0x00, 0x90, 0x01, 0x00, 0x50, 
-	0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x92, 0x01, 
-	0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 
-	0x94, 0x01, 0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, 
-	0x00, 0x00, 0x96, 0x01, 0x00, 0x50, 0x00, 0x00, 
-	0x00, 0xA8, 0x00, 0x00, 0x98, 0x01, 0x00, 0x50, 
-	0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x9A, 0x01, 
-	0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 
-	0x9C, 0x01, 0x55, 0x55, 0xC0, 0x7F, 0xAA, 0xAA, 
-	0xC0, 0x7F, 0x00, 0x00, 0xA2, 0x01, 0xA4, 0x01, 
-	0xA8, 0x01, 0xAA, 0x01, 0xAE, 0x01, 0xB0, 0x01, 
-	0xB2, 0x01, 0x80, 0x01, 0x00, 0x00, 0x88, 0x01, 
-	0x00, 0xFF, 0x9E, 0x01, 0xFF, 0x00, 0xA0, 0x01, 
-	0x00, 0x80, 0xAC, 0x01, 0x00, 0x80, 0x00, 0x00, 
-	0xA6, 0x01, 0x00, 0x80, 0x00, 0x00, 0x80, 0x01, 
-	0xBC, 0x01, 0x00, 0x88, 0x00, 0x06, 0x00, 0xC8, 
-	0x00, 0x00, 0x00, 0x80, 0x30, 0x00, 0x00, 0x00, 
-	0x00, 0x80, 0x02, 0x00, 0x44, 0x00, 0x92, 0xEA, 
-	0x48, 0x00, 0x98, 0xEA, 0x50, 0x00, 0x9E, 0xEA, 
-	0x60, 0x00, 0xA4, 0xEA, 0x78, 0x00, 0xAA, 0xEA, 
-	0x0A, 0xE8, 0x18, 0xE7, 0x3C, 0xEA, 0x2A, 0xE7, 
-	0x14, 0x55, 0xA0, 0x01, 0xEC, 0xE6, 0xD0, 0xE9, 
-	0x46, 0xE7, 0xA0, 0xE7, 0x00, 0xE7, 0x58, 0xE8, 
-	0x00, 0x00, 0x1E, 0x00, 0x46, 0xE7, 0x92, 0xE7, 
-	0x00, 0x41, 0x01, 0x41, 0xB6, 0xE7, 0x73, 0xEA, 
-	0x18, 0xE7, 0x48, 0xEA, 0xEC, 0xE6, 0x04, 0xEA, 
-	0x56, 0xE7, 0x62, 0xE7, 0xB6, 0xE7, 0x6E, 0xEA, 
-	0x62, 0xE8, 0x00, 0x00, 0x36, 0xE8, 0xEC, 0xE6, 
-	0xFA, 0xE9, 0x56, 0xE7, 0x62, 0xE7, 0x36, 0xE8, 
-	0x62, 0xE8, 0x00, 0x00, 0xEC, 0xE6, 0xF0, 0xE9, 
-	0x0C, 0xE7, 0x4A, 0xE7, 0x62, 0xE7, 0x36, 0xE8, 
-	0xEC, 0xE6, 0xFA, 0xE9, 0x56, 0xE7, 0x62, 0xE7, 
-	0x36, 0xE8, 0x62, 0xE8, 0x00, 0x20, 0x2A, 0xE7, 
-	0x14, 0x55, 0xA0, 0x01, 0x18, 0xE7, 0x50, 0xEA, 
-	0xEC, 0xE6, 0xD0, 0xE9, 0x58, 0xE8, 0x50, 0x55, 
-	0x0C, 0x00, 0x46, 0xE7, 0x92, 0xE7, 0x00, 0x01, 
-	0x00, 0x00, 0xB6, 0xE7, 0x75, 0xEA, 0x00, 0xE7, 
-	0x58, 0xE8, 0x55, 0x55, 0x0C, 0x00, 0x56, 0xE7, 
-	0xA0, 0xE7, 0x00, 0xE7, 0x58, 0xE8, 0xFF, 0xFF, 
-	0x08, 0x00, 0x58, 0xE8, 0x02, 0x10, 0x06, 0x00, 
-	0x46, 0xE7, 0x92, 0xE7, 0x00, 0x01, 0x01, 0x01, 
-	0xB6, 0xE7, 0x80, 0xEA, 0x00, 0xE7, 0x58, 0xE8, 
-	0x00, 0xC0, 0x08, 0x00, 0x58, 0xE8, 0xFF, 0xFF, 
-	0x0A, 0x00, 0x58, 0xE8, 0xFF, 0xFF, 0x0C, 0x00, 
-	0x58, 0xE8, 0x0D, 0x10, 0x06, 0x00, 0x46, 0xE7, 
-	0x92, 0xE7, 0x00, 0x01, 0x01, 0x01, 0xB6, 0xE7, 
-	0x74, 0xEA, 0x62, 0xE8, 0x08, 0x20, 0x00, 0xE7, 
-	0x52, 0xE8, 0x82, 0x01, 0x02, 0xC9, 0x46, 0xE7, 
-	0xB6, 0xE7, 0x80, 0xEA, 0x62, 0xE8, 0x34, 0x20, 
-	0x00, 0xE7, 0x58, 0xE8, 0x00, 0x10, 0x06, 0x00, 
-	0x46, 0xE7, 0xC6, 0xE8, 0xB6, 0xE7, 0x78, 0xEA, 
-	0x52, 0xE8, 0x9C, 0x01, 0x40, 0x00, 0x18, 0xE7, 
-	0x50, 0xEA, 0x2A, 0xE7, 0xFF, 0x00, 0x80, 0x07, 
-	0x26, 0xE9, 0x03, 0x00, 0x66, 0xE9, 0x74, 0xE9, 
-	0x12, 0xEA, 0x38, 0xE9, 0x00, 0x00, 0x74, 0xE9, 
-	0x1C, 0xEA, 0x38, 0xE9, 0x04, 0x00, 0x74, 0xE9, 
-	0x24, 0xEA, 0x38, 0xE9, 0x07, 0x00, 0x74, 0xE9, 
-	0x2C, 0xEA, 0x26, 0xE9, 0x01, 0x00, 0x74, 0xE9, 
-	0x34, 0xEA, 0x38, 0xE9, 0x02, 0x00, 0x74, 0xE9, 
-	0x34, 0xEA, 0x38, 0xE9, 0x06, 0x00, 0x74, 0xE9, 
-	0x34, 0xEA, 0x38, 0xE9, 0x05, 0x00, 0x74, 0xE9, 
-	0x34, 0xEA, 0x26, 0xE9, 0x01, 0x00, 0x4A, 0xE9, 
-	0x26, 0xE9, 0x03, 0x00, 0x58, 0xE9, 0x62, 0xE7, 
-	0xE6, 0xE8, 0xD8, 0xE9, 0x01, 0x00, 0xE6, 0xE8, 
-	0x25, 0xEA, 0x02, 0x00, 0xE6, 0xE8, 0x2F, 0xEA, 
-	0x06, 0x00, 0xE6, 0xE8, 0x3A, 0xEA, 0x05, 0x00, 
-	0xB6, 0xE7, 0x74, 0xEA, 0x36, 0xE8, 0xEC, 0xE6, 
-	0xD0, 0xE9, 0x56, 0xE7, 0xC6, 0xE8, 0x0C, 0xE7, 
-	0x92, 0xE7, 0x00, 0x01, 0x00, 0x80, 0xB6, 0xE7, 
-	0x78, 0xEA, 0x00, 0xE7, 0xFE, 0xE8, 0x52, 0xE8, 
-	0x80, 0x01, 0x41, 0x8E, 0x4A, 0xE7, 0x92, 0xE7, 
-	0x00, 0x01, 0x01, 0x1B, 0x06, 0xE9, 0xE4, 0xFF, 
-	0xB6, 0xE7, 0x7C, 0xEA, 0xBE, 0xE8, 0x18, 0xE7, 
-	0x56, 0xEA, 0x0C, 0xE7, 0x6A, 0xE8, 0x3C, 0xE7, 
-	0x00, 0xE0, 0xC6, 0xE8, 0xB6, 0xE7, 0x86, 0xEA, 
-	0x3C, 0xE7, 0x00, 0xE8, 0x62, 0xE7, 0xB6, 0xE7, 
-	0x85, 0xEA, 0x3C, 0xE7, 0x00, 0x08, 0xC6, 0xE8, 
-	0xB6, 0xE7, 0x86, 0xEA, 0x3C, 0xE7, 0x00, 0xF8, 
-	0x62, 0xE7, 0xB6, 0xE7, 0x85, 0xEA, 0x52, 0xE8, 
-	0x80, 0x01, 0x00, 0x02, 0x3C, 0xE7, 0x00, 0xE0, 
-	0x62, 0xE7, 0xB6, 0xE7, 0x85, 0xEA, 0x52, 0xE8, 
-	0x84, 0x01, 0x00, 0x00, 0x62, 0xE8, 0x34, 0x00, 
-	0x3C, 0xE7, 0x00, 0x00, 0xC6, 0xE8, 0x62, 0xE8, 
-	0x34, 0x60, 0x0E, 0xE9, 0x52, 0xE8, 0x84, 0x01, 
-	0x00, 0x00, 0xB6, 0xE7, 0x86, 0xEA, 0x52, 0xE8, 
-	0x82, 0x01, 0x00, 0xC8, 0x3C, 0xE7, 0x00, 0xE0, 
-	0xC6, 0xE8, 0x3C, 0xE7, 0x00, 0x10, 0xC6, 0xE8, 
-	0x62, 0xE8, 0x34, 0x60, 0x52, 0xE8, 0x80, 0x01, 
-	0x00, 0x06, 0x3C, 0xE7, 0x10, 0x00, 0x78, 0xE8, 
-	0x36, 0xE8, 0x52, 0xE8, 0x84, 0x01, 0x00, 0x00, 
-	0x62, 0xE8, 0x34, 0x00, 0xEC, 0xE6, 0xD0, 0xE9, 
-	0x18, 0xE7, 0x5C, 0xEA, 0xD0, 0xE8, 0x92, 0xE9, 
-	0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0xF0, 
-	0x06, 0x00, 0x00, 0xC7, 0xA0, 0xE7, 0xDC, 0xE8, 
-	0x00, 0xE0, 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 
-	0x40, 0xD0, 0x06, 0x00, 0x00, 0xE0, 0xA0, 0xE7, 
-	0xDC, 0xE8, 0x00, 0xC0, 0x00, 0xE7, 0x0C, 0xE7, 
-	0x70, 0xE7, 0x40, 0x90, 0x06, 0x00, 0x00, 0xA0, 
-	0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x80, 0x00, 0xE7, 
-	0x0C, 0xE7, 0x70, 0xE7, 0x40, 0x50, 0x06, 0x00, 
-	0x00, 0x60, 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x40, 
-	0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0x10, 
-	0x06, 0x00, 0x00, 0x20, 0xA0, 0xE7, 0xDC, 0xE8,  
-	0x00, 0x00, 0xD0, 0xE8, 0x92, 0xE9, 0x00, 0xE7,  
-	0x0C, 0xE7, 0x70, 0xE7, 0x40, 0xD0, 0x06, 0x00, 
-	0x00, 0xA6, 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0xC0, 
-	0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0x90, 
-	0x06, 0x00, 0x00, 0xC0, 0xA0, 0xE7, 0xDC, 0xE8, 
-	0x00, 0x80, 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 
-	0x40, 0x50, 0x06, 0x00, 0x00, 0x40, 0xA0, 0xE7, 
-	0xDC, 0xE8, 0x00, 0x40, 0x00, 0xE7, 0x0C, 0xE7, 
-	0x70, 0xE7, 0x40, 0x70, 0x06, 0x00, 0x00, 0x60, 
-	0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x60, 0x7E, 0xE9, 
-	0x90, 0xE9, 0x18, 0xE7, 0x62, 0xEA, 0xEC, 0xE6, 
-	0xD0, 0xE9, 0xA4, 0xE8, 0x55, 0x55, 0x16, 0x00, 
-	0x46, 0xE7, 0x92, 0xE7, 0x00, 0x00, 0x00, 0x00, 
-	0xB6, 0xE7, 0x8B, 0xEA, 0x0A, 0xE8, 0x18, 0xE7, 
-	0x62, 0xEA, 0x58, 0xE8, 0x55, 0x55, 0x16, 0x00, 
-	0x00, 0xE7, 0x46, 0xE7, 0xA0, 0xE7, 0x2A, 0xE7, 
-	0xFF, 0x00, 0x00, 0x08, 0x2A, 0xE7, 0xFF, 0x00, 
-	0x00, 0x0C, 0x2A, 0xE7, 0xFF, 0x00, 0x00, 0x10,  
-	0x2A, 0xE7, 0xFF, 0x00, 0x00, 0x14, 0x2A, 0xE7, 
-	0xFF, 0x00, 0x00, 0x18, 0x2A, 0xE7, 0xFF, 0x00, 
-	0x00, 0x1C, 0x2A, 0xE7, 0xFF, 0x00, 0x00, 0x20, 
-	0x2A, 0xE7, 0xFF, 0x00, 0x00, 0x24, 0x2A, 0xE7, 
-	0xFF, 0x00, 0x00, 0x28, 0x2A, 0xE7, 0xFF, 0x00, 
-	0x00, 0x2C, 0xD2, 0xE7, 0x00, 0xE7, 0x0C, 0xE7, 
-	0x70, 0xE7, 0x40, 0x30, 0x06, 0x00, 0x00, 0x01, 
-	0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x20, 0x00, 0xE7, 
-	0x0C, 0xE7, 0x70, 0xE7, 0x40, 0x70, 0x06, 0x00, 
-	0x00, 0x43, 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x60, 
-	0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0xB0, 
-	0x06, 0x00, 0x00, 0x85, 0xA0, 0xE7, 0xDC, 0xE8, 
-	0x00, 0xA0, 0xD8, 0xE8, 0x00, 0x01, 0x03, 0x01, 
-	0x01, 0x01, 0x00, 0x00, 0x00, 0x81, 0x1A, 0x00, 
-	0x40, 0x10, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 
-	0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x72, 0x82, 
-	0x4A, 0xA9, 0xA5, 0x5A, 0xDA, 0xE7, 0x03, 0x09, 
-	0x11, 0x9D, 0x00, 0x00, 0x00, 0x81, 0x04, 0x00, 
-	0xD8, 0x90, 0x00, 0x10, 0x00, 0x00, 0x00, 0x81, 
-	0x04, 0x00, 0xD8, 0x90, 0xD8, 0xB4, 0x00, 0x00, 
-	0x00, 0x81, 0x08, 0x00, 0xD8, 0x90, 0x46, 0x16, 
-	0x00, 0x40, 0xD8, 0xB4, 0x08, 0x00, 0x00, 0x00, 
-	0x00, 0x80, 0x13, 0x00, 0x40, 0x10, 0x16, 0x00, 
-	0x00, 0x00, 0x00, 0x80, 0x10, 0x00, 0x15, 0x00, 
-	0x00, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x15, 0x00, 
-	0x00, 0x00, 0x00, 0x81, 0x0F, 0x00, 0x06, 0x00, 
-	0x00, 0x00, 0x00, 0x80, 0x12, 0x00, 0x0A, 0x80, 
-	0x40, 0x9E, 0x00, 0xC8, 0x00, 0x00, 0x5E, 0x80, 
-	0x0F, 0x00, 0x06, 0x80, 0x40, 0xFE, 0x00, 0xCC, 
-	0x00, 0x00, 0x04, 0x80, 0x40, 0x8E, 0x00, 0xC9, 
-	0x04, 0x80, 0x00, 0x06, 0x00, 0xCC, 0x04, 0x80, 
-	0x40, 0x0A, 0x00, 0xC8, 0x0A, 0x80, 0x40, 0x8A, 
-	0x00, 0xC8, 0x00, 0x00, 0x5E, 0x80, 0x0F, 0x00, 
-	0x0A, 0x08, 0x80, 0x1C, 0x0A, 0x00, 0x1C, 0x1A, 
-	0x00, 0x80, 0x1C, 0x0C, 0x00, 0x80, 0x1C, 0x1A, 
-	0x00, 0x80, 0x1A, 0x0E, 0x80, 0x1C, 0x04, 0x00, 
-	0x00, 0x80, 0x80, 0x02, 0x02, 0x00, 0x00, 0x80, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x80, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 
-	0x40, 0x00, 0x00, 0x00, 0x58, 0x07, 0x0C, 0xB8, 
-	0x16, 0xE0, 0xE2, 0x08, 0xEC, 0x08, 0xF6, 0x08, 
-	0x16, 0xE0, 0x00, 0x09, 0x0A, 0x09, 0x00, 0x00, 
-	0x00, 0x00, 0xE2, 0x08, 0x00, 0x00, 0xEC, 0x08, 
-	0xF6, 0x08, 0x00, 0x09, 0x00, 0x00, 0xB8, 0x07, 
-	0xCA, 0xCB, 0x80, 0x02, 0xB8, 0x07, 0xE8, 0xCB, 
-	0x84, 0xFF, 0xB8, 0x07, 0x0A, 0xCC, 0xB8, 0x07, 
-	0x84, 0xCC, 0x6E, 0xCD, 0x62, 0xCD, 0x88, 0xCD, 
-	0x90, 0xCE, 0x84, 0xCD, 0x92, 0xCE, 0x92, 0xCE, 
-	0x92, 0xCE, 0x8C, 0xCD, 0x96, 0xCD, 0x38, 0xCE, 
-	0x82, 0xCE, 0x92, 0xCE, 0x92, 0xCE, 0x92, 0xCE, 
-	0x92, 0xCE, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x08, 0x00, 0x08, 0x01, 0x05, 0x08, 
-	0x08, 0x08, 0x03, 0x08, 0x03, 0x03, 0x03, 0x03, 
-	0x00, 0x00, 0x04, 0x02, 0x04, 0x04, 0x00, 0x04, 
-	0x0A, 0x08, 0x00, 0x00, 0x10, 0x0C, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x18, 0x00, 0x1A, 0x00, 0x00, 
-	0x04, 0x41, 0x06, 0x0B, 0x08, 0xC2, 0x00, 0xE6, 
-	0x00, 0xE7, 0x04, 0x06, 0x04, 0x07, 0x04, 0x03, 
-	0x06, 0x04, 0x04, 0x05, 0x04, 0x88, 0x04, 0xCF, 
-	0x04, 0xCD, 0x03, 0x00, 0x05, 0x00, 0x1C, 0x00, 
-	0x00, 0x0C, 0x00, 0x80, 0xD2, 0xD8, 0xDA, 0xD8, 
-	0x1E, 0xD9, 0xDE, 0xD8, 0xEA, 0xD8, 0xF0, 0xD8, 
-	0x14, 0xD9, 0xE4, 0xD8, 0x32, 0xD9, 0x00, 0x06, 
-	0x00, 0x00, 0x03, 0x07, 0x0A, 0x0E, 0x0F, 0x14, 
-	0x26, 0x2A, 0x52, 0x42, 0x50, 0x48, 0x5D, 0x4D, 
-	0x62, 0x62, 0x6D, 0x57, 0x46, 0x39, 0x1A, 0x1D, 
-	0x7C, 0x76, 0x1F, 0x23, 0x15, 0x1D, 0x74, 0x6F, 
-	0x84, 0x7C, 0x8B, 0x82, 0x92, 0x89, 0x00, 0x00, 
-	0x32, 0x2F, 0x3F, 0x34, 0x32, 0x01, 0x01, 0x57, 
-	0x32, 0x11, 0x81, 0x51, 0x02, 0x56, 0x03, 0x55, 
-	0x54, 0x11, 0x56, 0x81, 0x55, 0x02, 0x54, 0x02, 
-	0x56, 0x81, 0x01, 0x76, 0x02, 0x34, 0x02, 0x55, 
-	0x81, 0x54, 0x02, 0x58, 0x02, 0x55, 0x81, 0x54, 
-	0x02, 0x58, 0x11, 0x12, 0x02, 0x52, 0x58, 0x83, 
-	0x52, 0x05, 0x83, 0x04, 0x02, 0x58, 0x08, 0x55, 
-	0x58, 0x83, 0x55, 0x02, 0x81, 0x02, 0x05, 0x58, 
-	0x03, 0x52, 0x5C, 0x15, 0x53, 0x5B, 0x52, 0x87, 
-	0x11, 0x03, 0x41, 0x51, 0x78, 0x51, 0x34, 0x11, 
-	0x81, 0x11, 0x20, 0x31, 0x54, 0x57, 0x01, 0x53, 
-	0x5A, 0x12, 0x81, 0x51, 0x20, 0x31, 0x5B, 0x57, 
-	0x01, 0x5A, 0x01, 0x11, 0x51, 0x11, 0x31, 0x81, 
-	0x57, 0x20, 0x15, 0x01, 0x13, 0x01, 0x11, 0x01, 
-	0x11, 0x11, 0x81, 0x51, 0x05, 0x58, 0x02, 0x52, 
-	0x5B, 0x54, 0x5D, 0x81, 0x52, 0x05, 0x54, 0x02, 
-	0x58, 0x81, 0x50, 0x02, 0x13, 0x03, 0x58, 0x81, 
-	0x50, 0x02, 0x11, 0x03, 0x81, 0x54, 0x72, 0x5D, 
-	0x50, 0x03, 0x13, 0x03, 0x13, 0x01, 0x40, 0x54, 
-	0x0E, 0x00, 0x20, 0x06, 0x56, 0x06, 0x0C, 0xDA, 
-	0x24, 0x00, 0x02, 0x10, 0x16, 0x00, 0x02, 0x00, 
-	0x01, 0x04, 0x08, 0x07, 0x0C, 0xDA, 0x20, 0x00, 
-	0x03, 0x10, 0x12, 0x00, 0x03, 0x00, 0x4E, 0xD9, 
-	0x14, 0x8E, 0x20, 0x00, 0x04, 0x10, 0x12, 0x00, 
-	0x04, 0x00, 0xD2, 0xCE, 0x20, 0x00, 0x05, 0xE0, 
-	0x12, 0x00, 0x05, 0x00, 0xD2, 0xCE, 0x20, 0x00, 
-	0x06, 0xE0, 0x12, 0x00, 0x06, 0x00, 0xE8, 0xDD, 
-	0x12, 0x00, 0x01, 0xE0, 0x6C, 0x09, 0xCC, 0x06, 
-	0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x30, 0x06, 
-	0x42, 0xDC, 0xF0, 0x05, 0x00, 0xE0, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0xE2, 0x05, 0x08, 0x00, 
-	0x26, 0xFF, 0xDC, 0x05, 0x00, 0x00, 0x30, 0x06, 
-	0xF8, 0xDB, 0x1E, 0x00, 0x01, 0xE0, 0x10, 0x00, 
-	0x11, 0x30, 0x0C, 0x04, 0x01, 0x00, 0x0E, 0x04, 
-	0x02, 0x00, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 
-	0x30, 0x06, 0x32, 0xDD, 0x12, 0x00, 0x01, 0xE0, 
-	0x04, 0x00, 0x13, 0x30, 0x74, 0xDE, 0x3E, 0x00, 
-	0x00, 0xE0, 0x00, 0xC0, 0x00, 0x00, 0x02, 0x00, 
-	0x30, 0x00, 0x20, 0x50, 0x23, 0x0C, 0xFC, 0x05, 
-	0x52, 0x06, 0x56, 0x06, 0x00, 0x00, 0x00, 0x81, 
-	0x16, 0x00, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0x00, 
-	0x10, 0x00, 0x08, 0x00, 0x2A, 0x40, 0x2A, 0x04, 
-	0x56, 0x06, 0x26, 0x00, 0x19, 0xED, 0x2B, 0x06, 
-	0x72, 0x09, 0x22, 0x00, 0x24, 0x00, 0x2F, 0xED, 
-	0x23, 0x0C, 0xFC, 0x05, 0x28, 0x08, 0x34, 0x09, 
-	0x29, 0x08, 0x58, 0x07, 0x78, 0x07, 0x98, 0x07, 
-	0x23, 0x00, 0x2A, 0x00, 0x3D, 0xED, 0x06, 0x04, 
-	0xF0, 0x06, 0x07, 0x04, 0xEE, 0x06, 0x24, 0x00, 
-	0xD2, 0xCE, 0x34, 0x00, 0x00, 0xE0, 0x00, 0xC0, 
-	0x00, 0x00, 0x10, 0x00, 0x26, 0x00, 0x25, 0x40, 
-	0xD2, 0xCE, 0x20, 0x00, 0x00, 0xE0, 0x00, 0xC0, 
-	0x00, 0x00, 0x10, 0x00, 0x12, 0x00, 0x26, 0x40, 
-	0xD2, 0xCE, 0x1A, 0x00, 0x00, 0xE0, 0x0C, 0x00, 
-	0x27, 0x60, 0x0A, 0x08, 0xE6, 0x06, 0xD2, 0xCE, 
-	0x24, 0x00, 0x00, 0xE0, 0x16, 0x00, 0x28, 0x60, 
-	0x30, 0x04, 0x06, 0x07, 0x52, 0xCF, 0x00, 0x81, 
-	0x30, 0x00, 0x00, 0xE0, 0x22, 0x00, 0x29, 0x60, 
-	0x2D, 0x08, 0x1C, 0x07, 0x2E, 0x08, 0x22, 0x07, 
-	0x00, 0x00, 0x08, 0x02, 0x06, 0x01, 0x14, 0x06, 
-	0x18, 0x08, 0x20, 0x0C, 0x26, 0x0E, 0x30, 0x0F, 
-	0x34, 0x11, 0x3E, 0x12, 0x42, 0x14, 0x46, 0x16, 
-	0x1C, 0x0A, 0x4A, 0x18, 0x13, 0x03, 0x11, 0x83, 
-	0x01, 0x11, 0x11, 0x81, 0x12, 0x81, 0x13, 0x01, 
-	0x52, 0x83, 0x81, 0x85, 0x85, 0x11, 0x12, 0x81, 
-	0x12, 0x81, 0x19, 0x81, 0x60, 0x85, 0x00, 0xC0, 
-	0x00, 0x00, 0x08, 0x00, 0x6C, 0x09, 0x00, 0x00, 
-	0x30, 0x06, 0x08, 0xE5, 0x54, 0x06, 0x50, 0x06, 
-	0x38, 0x02, 0x21, 0x04, 0x1E, 0x09, 0x0B, 0x06, 
-	0xD8, 0x06, 0x02, 0x08, 0xDC, 0x06, 0x00, 0xC0, 
-	0xFF, 0xFF, 0xFF, 0xFF, 0x41, 0x00, 0x41, 0x00, 
-	0x14, 0xAE, 0x00, 0x00, 0x00, 0x81, 0x09, 0x04, 
-	0x0C, 0x07, 0x41, 0x00, 0x41, 0x00, 0x14, 0x02, 
-	0x00, 0x00, 0x00, 0x81, 0x0B, 0x06, 0xD8, 0x06, 
-	0x2C, 0x06, 0x76, 0x09, 0x22, 0x14, 0x3A, 0x09, 
-	0x41, 0x00, 0x41, 0x00, 0x54, 0x02, 0x00, 0x00, 
-	0x00, 0x81, 0xD8, 0x06, 0x00, 0x84, 0x00, 0x48, 
-	0xFC, 0xFF, 0x09, 0x00, 0x00, 0xC0, 0x00, 0x00, 
-	0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0x00, 0x00, 0xB8, 0xFF, 0x20, 0x00, 
-	0x43, 0x28, 0x31, 0x29, 0x38, 0x39, 0x2D, 0x33, 
-	0x39, 0x38, 0x39, 0x2C, 0x2D, 0x30, 0x38, 0x39, 
-	0x54, 0x20, 0x78, 0x65, 0x73, 0x61, 0x49, 0x20, 
-	0x73, 0x6E, 0x72, 0x74, 0x6D, 0x75, 0x6E, 0x65, 
-	0x73, 0x74, 0x28, 0x0A, 0x29, 0x43, 0x39, 0x31, 
-	0x33, 0x38, 0x34, 0x2C, 0x35, 0x2C, 0x36, 0x2C, 
-	0x49, 0x20, 0x4D, 0x42, 0x43, 0x20, 0x72, 0x6F, 
-	0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-	0x00, 0x00, 0xF8, 0xFF, 0x01, 0x00, 0x34, 0x90, 
-	0x00, 0x00, 0xFA, 0xFF, 0x01, 0x00, 0xB8, 0xFF, 
-	0x00, 0x00, 0xFC, 0xFF, 0x02, 0x00, 0x80, 0x00, 
-	0x3E, 0xA0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00  
-};
-#endif /* CONFIG_SKTR */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/syncppp.c linux/drivers/net/syncppp.c
--- v2.3.20/linux/drivers/net/syncppp.c	Thu Aug 26 13:05:38 1999
+++ linux/drivers/net/syncppp.c	Wed Dec 31 16:00:00 1969
@@ -1,1315 +0,0 @@
-/*
- *	NET3:	A (fairly minimal) implementation of synchronous PPP for Linux
- *		as well as a CISCO HDLC implementation. See the copyright 
- *		message below for the original source.
- *
- *	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.
- *
- *	Note however. This code is also used in a different form by FreeBSD.
- *	Therefore when making any non OS specific change please consider
- *	contributing it back to the original author under the terms
- *	below in addition.
- *		-- Alan
- *
- *	Port for Linux-2.1 by Jan "Yenya" Kasprzak <kas@fi.muni.cz>
- */
-
-/*
- * Synchronous PPP/Cisco link level subroutines.
- * Keepalive protocol implemented in both Cisco and PPP modes.
- *
- * Copyright (C) 1994 Cronyx Ltd.
- * Author: Serge Vakulenko, <vak@zebub.msk.su>
- *
- * This software is distributed with NO WARRANTIES, not even the implied
- * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Authors grant any other persons or organisations permission to use
- * or modify this software as long as this message is kept with the software,
- * all derivative works or modified versions.
- *
- * Version 1.9, Wed Oct  4 18:58:15 MSK 1995
- *
- * $Id: if_spppsubr.c,v 1.12 1996/06/10 23:17:45 gpalmer Exp $
- */
-#undef DEBUG
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/if_arp.h>
-#include <linux/skbuff.h>
-#include <linux/route.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/random.h>
-#include <linux/pkt_sched.h>
-#include <asm/byteorder.h>
-#include "syncppp.h"
-
-#define MAXALIVECNT     6               /* max. alive packets */
-
-#define PPP_ALLSTATIONS 0xff            /* All-Stations broadcast address */
-#define PPP_UI          0x03            /* Unnumbered Information */
-#define PPP_IP          0x0021          /* Internet Protocol */
-#define PPP_ISO         0x0023          /* ISO OSI Protocol */
-#define PPP_XNS         0x0025          /* Xerox NS Protocol */
-#define PPP_IPX         0x002b          /* Novell IPX Protocol */
-#define PPP_LCP         0xc021          /* Link Control Protocol */
-#define PPP_IPCP        0x8021          /* Internet Protocol Control Protocol */
-
-#define LCP_CONF_REQ    1               /* PPP LCP configure request */
-#define LCP_CONF_ACK    2               /* PPP LCP configure acknowledge */
-#define LCP_CONF_NAK    3               /* PPP LCP configure negative ack */
-#define LCP_CONF_REJ    4               /* PPP LCP configure reject */
-#define LCP_TERM_REQ    5               /* PPP LCP terminate request */
-#define LCP_TERM_ACK    6               /* PPP LCP terminate acknowledge */
-#define LCP_CODE_REJ    7               /* PPP LCP code reject */
-#define LCP_PROTO_REJ   8               /* PPP LCP protocol reject */
-#define LCP_ECHO_REQ    9               /* PPP LCP echo request */
-#define LCP_ECHO_REPLY  10              /* PPP LCP echo reply */
-#define LCP_DISC_REQ    11              /* PPP LCP discard request */
-
-#define LCP_OPT_MRU             1       /* maximum receive unit */
-#define LCP_OPT_ASYNC_MAP       2       /* async control character map */
-#define LCP_OPT_AUTH_PROTO      3       /* authentication protocol */
-#define LCP_OPT_QUAL_PROTO      4       /* quality protocol */
-#define LCP_OPT_MAGIC           5       /* magic number */
-#define LCP_OPT_RESERVED        6       /* reserved */
-#define LCP_OPT_PROTO_COMP      7       /* protocol field compression */
-#define LCP_OPT_ADDR_COMP       8       /* address/control field compression */
-
-#define IPCP_CONF_REQ   LCP_CONF_REQ    /* PPP IPCP configure request */
-#define IPCP_CONF_ACK   LCP_CONF_ACK    /* PPP IPCP configure acknowledge */
-#define IPCP_CONF_NAK   LCP_CONF_NAK    /* PPP IPCP configure negative ack */
-#define IPCP_CONF_REJ   LCP_CONF_REJ    /* PPP IPCP configure reject */
-#define IPCP_TERM_REQ   LCP_TERM_REQ    /* PPP IPCP terminate request */
-#define IPCP_TERM_ACK   LCP_TERM_ACK    /* PPP IPCP terminate acknowledge */
-#define IPCP_CODE_REJ   LCP_CODE_REJ    /* PPP IPCP code reject */
-
-#define CISCO_MULTICAST         0x8f    /* Cisco multicast address */
-#define CISCO_UNICAST           0x0f    /* Cisco unicast address */
-#define CISCO_KEEPALIVE         0x8035  /* Cisco keepalive protocol */
-#define CISCO_ADDR_REQ          0       /* Cisco address request */
-#define CISCO_ADDR_REPLY        1       /* Cisco address reply */
-#define CISCO_KEEPALIVE_REQ     2       /* Cisco keepalive request */
-
-struct ppp_header {
-	u8 address;
-	u8 control;
-	u16 protocol;
-};
-#define PPP_HEADER_LEN          sizeof (struct ppp_header)
-
-struct lcp_header {
-	u8 type;
-	u8 ident;
-	u16 len;
-};
-#define LCP_HEADER_LEN          sizeof (struct lcp_header)
-
-struct cisco_packet {
-	u32 type;
-	u32 par1;
-	u32 par2;
-	u16 rel;
-	u16 time0;
-	u16 time1;
-};
-#define CISCO_PACKET_LEN 18
-#define CISCO_BIG_PACKET_LEN 20
-
-static struct sppp *spppq;
-static struct timer_list sppp_keepalive_timer;
-
-static void sppp_keepalive (unsigned long dummy);
-static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type,
-	u8 ident, u16 len, void *data);
-static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2);
-static void sppp_lcp_input (struct sppp *sp, struct sk_buff *m);
-static void sppp_cisco_input (struct sppp *sp, struct sk_buff *m);
-static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *m);
-static void sppp_lcp_open (struct sppp *sp);
-static void sppp_ipcp_open (struct sppp *sp);
-static int sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h,
-	int len, u32 *magic);
-static void sppp_cp_timeout (unsigned long arg);
-static char *sppp_lcp_type_name (u8 type);
-static char *sppp_ipcp_type_name (u8 type);
-static void sppp_print_bytes (u8 *p, u16 len);
-
-static int debug = 0;
-
-/*
- *	Interface down stub
- */	
-
-static void if_down(struct net_device *dev)
-{
-	;
-}
-
-/*
- * Timeout routine activations.
- */
-
-static void sppp_set_timeout(struct sppp *p,int s) 
-{
-	if (! (p->pp_flags & PP_TIMO)) 
-	{
-		init_timer(&p->pp_timer);
-		p->pp_timer.function=sppp_cp_timeout;
-		p->pp_timer.expires=jiffies+s*HZ;
-		p->pp_timer.data=(unsigned long)p;
-		p->pp_flags |= PP_TIMO;
-		add_timer(&p->pp_timer);
-	}
-}
-
-static void sppp_clear_timeout(struct sppp *p)
-{
-	if (p->pp_flags & PP_TIMO) 
-	{
-		del_timer(&p->pp_timer);
-		p->pp_flags &= ~PP_TIMO; 
-	}
-}
-
-/*
- * Process the received packet.
- */
- 
-void sppp_input (struct net_device *dev, struct sk_buff *skb)
-{
-	struct ppp_header *h;
-	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
-	
-	skb->dev=dev;
-	skb->mac.raw=skb->data;
-	
-	if (dev->flags & IFF_UP)
-	{
-		/* Count received bytes, add FCS and one flag */
-		sp->ibytes+= skb->len + 3;
-		sp->ipkts++;
-	}
-
-	if (skb->len <= PPP_HEADER_LEN) {
-		/* Too small packet, drop it. */
-		if (sp->pp_flags & PP_DEBUG)
-			printk (KERN_DEBUG "%s: input packet is too small, %d bytes\n",
-				dev->name, skb->len);
-drop:           kfree_skb(skb);
-		return;
-	}
-
-	/* Get PPP header. */
-	h = (struct ppp_header *)skb->data;
-	skb_pull(skb,sizeof(struct ppp_header));
-
-	switch (h->address) {
-	default:        /* Invalid PPP packet. */
-invalid:        if (sp->pp_flags & PP_DEBUG)
-			printk (KERN_WARNING "%s: invalid input packet <0x%x 0x%x 0x%x>\n",
-				dev->name,
-				h->address, h->control, ntohs (h->protocol));
-		goto drop;
-	case PPP_ALLSTATIONS:
-		if (h->control != PPP_UI)
-			goto invalid;
-		if (sp->pp_flags & PP_CISCO) {
-			if (sp->pp_flags & PP_DEBUG)
-				printk (KERN_WARNING "%s: PPP packet in Cisco mode <0x%x 0x%x 0x%x>\n",
-					dev->name,
-					h->address, h->control, ntohs (h->protocol));
-			goto drop;
-		}
-		switch (ntohs (h->protocol)) {
-		default:
-			if (sp->lcp.state == LCP_STATE_OPENED)
-				sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ,
-					++sp->pp_seq, skb->len + 2,
-					&h->protocol);
-			if (sp->pp_flags & PP_DEBUG)
-				printk (KERN_WARNING "%s: invalid input protocol <0x%x 0x%x 0x%x>\n",
-					dev->name,
-					h->address, h->control, ntohs (h->protocol));
-			goto drop;
-		case PPP_LCP:
-			sppp_lcp_input (sp, skb);
-			kfree_skb(skb);
-			return;
-		case PPP_IPCP:
-			if (sp->lcp.state == LCP_STATE_OPENED)
-				sppp_ipcp_input (sp, skb);
-			else
-				printk(KERN_DEBUG "IPCP when still waiting LCP finish.\n");
-			kfree_skb(skb);
-			return;
-		case PPP_IP:
-			if (sp->ipcp.state == IPCP_STATE_OPENED) {
-				if(sp->pp_flags&PP_DEBUG)
-					printk(KERN_DEBUG "Yow an IP frame.\n");
-				skb->protocol=htons(ETH_P_IP);
-				netif_rx(skb);
-				return;
-			}
-			break;
-#ifdef IPX
-		case PPP_IPX:
-			/* IPX IPXCP not implemented yet */
-			if (sp->lcp.state == LCP_STATE_OPENED) {
-				skb->protocol=htons(ETH_P_IPX);
-				netif_rx(skb);
-				return;
-			}
-			break;
-#endif
-		}
-		break;
-	case CISCO_MULTICAST:
-	case CISCO_UNICAST:
-		/* Don't check the control field here (RFC 1547). */
-		if (! (sp->pp_flags & PP_CISCO)) {
-			if (sp->pp_flags & PP_DEBUG)
-				printk (KERN_WARNING "%s: Cisco packet in PPP mode <0x%x 0x%x 0x%x>\n",
-					dev->name,
-					h->address, h->control, ntohs (h->protocol));
-			goto drop;
-		}
-		switch (ntohs (h->protocol)) {
-		default:
-			goto invalid;
-		case CISCO_KEEPALIVE:
-			sppp_cisco_input (sp, skb);
-			kfree_skb(skb);
-			return;
-#ifdef CONFIG_INET
-		case ETH_P_IP:
-			skb->protocol=htons(ETH_P_IP);
-			netif_rx(skb);
-			return;
-#endif
-#ifdef CONFIG_IPX
-		case ETH_P_IPX:
-			skb->protocol=htons(ETH_P_IPX);
-			netif_rx(skb);
-			return;
-#endif
-		}
-		break;
-	}
-	kfree_skb(skb);
-}
-
-EXPORT_SYMBOL(sppp_input);
-
-/*
- *	Handle transmit packets.
- */
- 
-static int sppp_hard_header(struct sk_buff *skb, struct net_device *dev, __u16 type,
-		void *daddr, void *saddr, unsigned int len)
-{
-	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
-	struct ppp_header *h;
-	skb_push(skb,sizeof(struct ppp_header));
-	h=(struct ppp_header *)skb->data;
-	if(sp->pp_flags&PP_CISCO)
-	{
-		h->address = CISCO_MULTICAST;
-		h->control = 0;
-	}
-	else
-	{
-		h->address = PPP_ALLSTATIONS;
-		h->control = PPP_UI;
-	}
-	if(sp->pp_flags & PP_CISCO)
-	{
-		h->protocol = htons(type);
-	}
-	else switch(type)
-	{
-		case ETH_P_IP:
-			h->protocol = htons(PPP_IP);
-			break;
-		case ETH_P_IPX:
-			h->protocol = htons(PPP_IPX);
-			break;
-	}
-	return sizeof(struct ppp_header);
-}
-
-static int sppp_rebuild_header(struct sk_buff *skb)
-{
-	return 0;
-}
-
-/*
- * Send keepalive packets, every 10 seconds.
- */
-
-static void sppp_keepalive (unsigned long dummy)
-{
-	struct sppp *sp;
-	unsigned long flags;
-	save_flags(flags);
-	cli();
-
-	for (sp=spppq; sp; sp=sp->pp_next) 
-	{
-		struct net_device *dev = sp->pp_if;
-
-		/* Keepalive mode disabled or channel down? */
-		if (! (sp->pp_flags & PP_KEEPALIVE) ||
-		    ! (dev->flags & IFF_RUNNING))
-			continue;
-
-		/* No keepalive in PPP mode if LCP not opened yet. */
-		if (! (sp->pp_flags & PP_CISCO) &&
-		    sp->lcp.state != LCP_STATE_OPENED)
-			continue;
-
-		if (sp->pp_alivecnt == MAXALIVECNT) {
-			/* No keepalive packets got.  Stop the interface. */
-			printk (KERN_WARNING "%s: down\n", dev->name);
-			if_down (dev);
-			if (! (sp->pp_flags & PP_CISCO)) {
-				/* Shut down the PPP link. */
-				sp->lcp.magic = jiffies;
-				sp->lcp.state = LCP_STATE_CLOSED;
-				sp->ipcp.state = IPCP_STATE_CLOSED;
-				sppp_clear_timeout (sp);
-				/* Initiate negotiation. */
-				sppp_lcp_open (sp);
-			}
-		}
-		if (sp->pp_alivecnt <= MAXALIVECNT)
-			++sp->pp_alivecnt;
-		if (sp->pp_flags & PP_CISCO)
-			sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq,
-				sp->pp_rseq);
-		else if (sp->lcp.state == LCP_STATE_OPENED) {
-			long nmagic = htonl (sp->lcp.magic);
-			sp->lcp.echoid = ++sp->pp_seq;
-			sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ,
-				sp->lcp.echoid, 4, &nmagic);
-		}
-	}
-	restore_flags(flags);
-	sppp_keepalive_timer.expires=jiffies+10*HZ;
-	add_timer(&sppp_keepalive_timer);
-}
-
-/*
- * Handle incoming PPP Link Control Protocol packets.
- */
- 
-static void sppp_lcp_input (struct sppp *sp, struct sk_buff *skb)
-{
-	struct lcp_header *h;
-	struct net_device *dev = sp->pp_if;
-	int len = skb->len;
-	u8 *p, opt[6];
-	u32 rmagic;
-
-	if (len < 4) {
-		if (sp->pp_flags & PP_DEBUG)
-			printk (KERN_WARNING "%s: invalid lcp packet length: %d bytes\n",
-				dev->name, len);
-		return;
-	}
-	h = (struct lcp_header *)skb->data;
-	skb_pull(skb,sizeof(struct lcp_header *));
-	
-	if (sp->pp_flags & PP_DEBUG) 
-	{
-		char state = '?';
-		switch (sp->lcp.state) {
-		case LCP_STATE_CLOSED:   state = 'C'; break;
-		case LCP_STATE_ACK_RCVD: state = 'R'; break;
-		case LCP_STATE_ACK_SENT: state = 'S'; break;
-		case LCP_STATE_OPENED:   state = 'O'; break;
-		}
-		printk (KERN_WARNING "%s: lcp input(%c): %d bytes <%s id=%xh len=%xh",
-			dev->name, state, len,
-			sppp_lcp_type_name (h->type), h->ident, ntohs (h->len));
-		if (len > 4)
-			sppp_print_bytes ((u8*) (h+1), len-4);
-		printk (">\n");
-	}
-	if (len > ntohs (h->len))
-		len = ntohs (h->len);
-	switch (h->type) {
-	default:
-		/* Unknown packet type -- send Code-Reject packet. */
-		sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq,
-			skb->len, h);
-		break;
-	case LCP_CONF_REQ:
-		if (len < 4) {
-			if (sp->pp_flags & PP_DEBUG)
-				printk (KERN_DEBUG"%s: invalid lcp configure request packet length: %d bytes\n",
-					dev->name, len);
-			break;
-		}
-		if (len>4 && !sppp_lcp_conf_parse_options (sp, h, len, &rmagic))
-			goto badreq;
-		if (rmagic == sp->lcp.magic) {
-			/* Local and remote magics equal -- loopback? */
-			if (sp->pp_loopcnt >= MAXALIVECNT*5) {
-				printk (KERN_WARNING "%s: loopback\n",
-					dev->name);
-				sp->pp_loopcnt = 0;
-				if (dev->flags & IFF_UP) {
-					if_down (dev);
-				}
-			} else if (sp->pp_flags & PP_DEBUG)
-				printk (KERN_DEBUG "%s: conf req: magic glitch\n",
-					dev->name);
-			++sp->pp_loopcnt;
-
-			/* MUST send Conf-Nack packet. */
-			rmagic = ~sp->lcp.magic;
-			opt[0] = LCP_OPT_MAGIC;
-			opt[1] = sizeof (opt);
-			opt[2] = rmagic >> 24;
-			opt[3] = rmagic >> 16;
-			opt[4] = rmagic >> 8;
-			opt[5] = rmagic;
-			sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK,
-				h->ident, sizeof (opt), &opt);
-badreq:
-			switch (sp->lcp.state) {
-			case LCP_STATE_OPENED:
-				/* Initiate renegotiation. */
-				sppp_lcp_open (sp);
-				/* fall through... */
-			case LCP_STATE_ACK_SENT:
-				/* Go to closed state. */
-				sp->lcp.state = LCP_STATE_CLOSED;
-				sp->ipcp.state = IPCP_STATE_CLOSED;
-			}
-			break;
-		}
-		/* Send Configure-Ack packet. */
-		sp->pp_loopcnt = 0;
-		sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK,
-				h->ident, len-4, h+1);
-		/* Change the state. */
-		switch (sp->lcp.state) {
-		case LCP_STATE_CLOSED:
-			sp->lcp.state = LCP_STATE_ACK_SENT;
-			break;
-		case LCP_STATE_ACK_RCVD:
-			sp->lcp.state = LCP_STATE_OPENED;
-			sppp_ipcp_open (sp);
-			break;
-		case LCP_STATE_OPENED:
-#if 0		
-			/* Remote magic changed -- close session. */
-			sp->lcp.state = LCP_STATE_CLOSED;
-			sp->ipcp.state = IPCP_STATE_CLOSED;
-			/* Initiate renegotiation. */
-			sppp_lcp_open (sp);
-			/* An ACK has already been sent. */
-			sp->lcp.state = LCP_STATE_ACK_SENT;
-#endif			
-			break;
-		}
-		break;
-	case LCP_CONF_ACK:
-		if (h->ident != sp->lcp.confid)
-			break;
-		sppp_clear_timeout (sp);
-		if (! (dev->flags & IFF_UP) &&
-		    (dev->flags & IFF_RUNNING)) {
-			/* Coming out of loopback mode. */
-			dev->flags |= IFF_UP;
-			printk (KERN_INFO "%s: up\n", dev->name);
-		}
-		switch (sp->lcp.state) {
-		case LCP_STATE_CLOSED:
-			sp->lcp.state = LCP_STATE_ACK_RCVD;
-			sppp_set_timeout (sp, 5);
-			break;
-		case LCP_STATE_ACK_SENT:
-			sp->lcp.state = LCP_STATE_OPENED;
-			sppp_ipcp_open (sp);
-			break;
-		}
-		break;
-	case LCP_CONF_NAK:
-		if (h->ident != sp->lcp.confid)
-			break;
-		p = (u8*) (h+1);
-		if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) {
-			rmagic = (u32)p[2] << 24 |
-				(u32)p[3] << 16 | p[4] << 8 | p[5];
-			if (rmagic == ~sp->lcp.magic) {
-				int newmagic;
-				if (sp->pp_flags & PP_DEBUG)
-					printk (KERN_DEBUG "%s: conf nak: magic glitch\n",
-						dev->name);
-				get_random_bytes(&newmagic, sizeof(newmagic));
-				sp->lcp.magic += newmagic;
-			} else
-				sp->lcp.magic = rmagic;
-			}
-		if (sp->lcp.state != LCP_STATE_ACK_SENT) {
-			/* Go to closed state. */
-			sp->lcp.state = LCP_STATE_CLOSED;
-			sp->ipcp.state = IPCP_STATE_CLOSED;
-		}
-		/* The link will be renegotiated after timeout,
-		 * to avoid endless req-nack loop. */
-		sppp_clear_timeout (sp);
-		sppp_set_timeout (sp, 2);
-		break;
-	case LCP_CONF_REJ:
-		if (h->ident != sp->lcp.confid)
-			break;
-		sppp_clear_timeout (sp);
-		/* Initiate renegotiation. */
-		sppp_lcp_open (sp);
-		if (sp->lcp.state != LCP_STATE_ACK_SENT) {
-			/* Go to closed state. */
-			sp->lcp.state = LCP_STATE_CLOSED;
-			sp->ipcp.state = IPCP_STATE_CLOSED;
-		}
-		break;
-	case LCP_TERM_REQ:
-		sppp_clear_timeout (sp);
-		/* Send Terminate-Ack packet. */
-		sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, 0);
-		/* Go to closed state. */
-		sp->lcp.state = LCP_STATE_CLOSED;
-		sp->ipcp.state = IPCP_STATE_CLOSED;
-		/* Initiate renegotiation. */
-		sppp_lcp_open (sp);
-		break;
-	case LCP_TERM_ACK:
-	case LCP_CODE_REJ:
-	case LCP_PROTO_REJ:
-		/* Ignore for now. */
-		break;
-	case LCP_DISC_REQ:
-		/* Discard the packet. */
-		break;
-	case LCP_ECHO_REQ:
-		if (sp->lcp.state != LCP_STATE_OPENED)
-			break;
-		if (len < 8) {
-			if (sp->pp_flags & PP_DEBUG)
-				printk (KERN_WARNING "%s: invalid lcp echo request packet length: %d bytes\n",
-					dev->name, len);
-			break;
-		}
-		if (ntohl (*(long*)(h+1)) == sp->lcp.magic) {
-			/* Line loopback mode detected. */
-			printk (KERN_WARNING "%s: loopback\n", dev->name);
-			if_down (dev);
-
-			/* Shut down the PPP link. */
-			sp->lcp.state = LCP_STATE_CLOSED;
-			sp->ipcp.state = IPCP_STATE_CLOSED;
-			sppp_clear_timeout (sp);
-			/* Initiate negotiation. */
-			sppp_lcp_open (sp);
-			break;
-		}
-		*(long*)(h+1) = htonl (sp->lcp.magic);
-		sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REPLY, h->ident, len-4, h+1);
-		break;
-	case LCP_ECHO_REPLY:
-		if (h->ident != sp->lcp.echoid)
-			break;
-		if (len < 8) {
-			if (sp->pp_flags & PP_DEBUG)
-				printk (KERN_WARNING "%s: invalid lcp echo reply packet length: %d bytes\n",
-					dev->name, len);
-			break;
-		}
-		if (ntohl (*(long*)(h+1)) != sp->lcp.magic)
-		sp->pp_alivecnt = 0;
-		break;
-	}
-}
-
-/*
- * Handle incoming Cisco keepalive protocol packets.
- */
-
-static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb)
-{
-	struct cisco_packet *h;
-	struct net_device *dev = sp->pp_if;
-
-	if (skb->len != CISCO_PACKET_LEN && skb->len != CISCO_BIG_PACKET_LEN) {
-		if (sp->pp_flags & PP_DEBUG)
-			printk (KERN_WARNING "%s: invalid cisco packet length: %d bytes\n",
-				dev->name,  skb->len);
-		return;
-	}
-	h = (struct cisco_packet *)skb->data;
-	skb_pull(skb, sizeof(struct cisco_packet*));
-	if (sp->pp_flags & PP_DEBUG)
-		printk (KERN_WARNING "%s: cisco input: %d bytes <%lxh %xh %xh %xh %xh-%xh>\n",
-			dev->name,  skb->len,
-			ntohl (h->type), h->par1, h->par2, h->rel,
-			h->time0, h->time1);
-	switch (ntohl (h->type)) {
-	default:
-		if (sp->pp_flags & PP_DEBUG)
-			printk (KERN_WARNING "%s: unknown cisco packet type: 0x%lx\n",
-				dev->name,  ntohl (h->type));
-		break;
-	case CISCO_ADDR_REPLY:
-		/* Reply on address request, ignore */
-		break;
-	case CISCO_KEEPALIVE_REQ:
-		sp->pp_alivecnt = 0;
-		sp->pp_rseq = ntohl (h->par1);
-		if (sp->pp_seq == sp->pp_rseq) {
-			/* Local and remote sequence numbers are equal.
-			 * Probably, the line is in loopback mode. */
-			int newseq;
-			if (sp->pp_loopcnt >= MAXALIVECNT) {
-				printk (KERN_WARNING "%s: loopback\n",
-					dev->name);
-				sp->pp_loopcnt = 0;
-				if (dev->flags & IFF_UP) {
-					if_down (dev);
-				}
-			}
-			++sp->pp_loopcnt;
-
-			/* Generate new local sequence number */
-			get_random_bytes(&newseq, sizeof(newseq));
-			sp->pp_seq ^= newseq;
-			break;
-		}
-		sp->pp_loopcnt = 0;
-		if (! (dev->flags & IFF_UP) &&
-		    (dev->flags & IFF_RUNNING)) {
-			dev->flags |= IFF_UP;
-			printk (KERN_INFO "%s: up\n", dev->name);
-		}
-		break;
-	case CISCO_ADDR_REQ:
-		/* Stolen from net/ipv4/devinet.c -- SIOCGIFADDR ioctl */
-		{
-		struct in_device *in_dev;
-		struct in_ifaddr *ifa;
-		u32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */
-
-		if ((in_dev=in_dev_get(dev)) != NULL)
-		{
-			read_lock(&in_dev->lock);
-			for (ifa=in_dev->ifa_list; ifa != NULL;
-				ifa=ifa->ifa_next) {
-				if (strcmp(dev->name, ifa->ifa_label) == 0) 
-				{
-					addr = ifa->ifa_local;
-					mask = ifa->ifa_mask;
-					break;
-				}
-			}
-			read_unlock(&in_dev->lock);
-			in_dev_put(in_dev);
-		}
-		/* I hope both addr and mask are in the net order */
-		sppp_cisco_send (sp, CISCO_ADDR_REPLY, addr, mask);
-		break;
-		}
-	}
-}
-
-/*
- * Send PPP LCP packet.
- */
-
-static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type,
-	u8 ident, u16 len, void *data)
-{
-	struct ppp_header *h;
-	struct lcp_header *lh;
-	struct sk_buff *skb;
-	struct net_device *dev = sp->pp_if;
-
-	skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+LCP_HEADER_LEN+len,
-		GFP_ATOMIC);
-	if (skb==NULL)
-		return;
-
-	skb_reserve(skb,dev->hard_header_len);
-	
-	h = (struct ppp_header *)skb_put(skb, sizeof(struct ppp_header));
-	h->address = PPP_ALLSTATIONS;        /* broadcast address */
-	h->control = PPP_UI;                 /* Unnumbered Info */
-	h->protocol = htons (proto);         /* Link Control Protocol */
-
-	lh = (struct lcp_header *)skb_put(skb, sizeof(struct lcp_header));
-	lh->type = type;
-	lh->ident = ident;
-	lh->len = htons (LCP_HEADER_LEN + len);
-
-	if (len)
-		memcpy(skb_put(skb,len),data, len);
-
-	if (sp->pp_flags & PP_DEBUG) {
-		printk (KERN_WARNING "%s: %s output <%s id=%xh len=%xh",
-			dev->name, 
-			proto==PPP_LCP ? "lcp" : "ipcp",
-			proto==PPP_LCP ? sppp_lcp_type_name (lh->type) :
-			sppp_ipcp_type_name (lh->type), lh->ident,
-			ntohs (lh->len));
-		if (len)
-			sppp_print_bytes ((u8*) (lh+1), len);
-		printk (">\n");
-	}
-	sp->obytes += skb->len;
-	/* Control is high priority so it doesnt get queued behind data */
-	skb->priority=TC_PRIO_CONTROL;
-	skb->dev = dev;
-	dev_queue_xmit(skb);
-}
-
-/*
- * Send Cisco keepalive packet.
- */
-
-static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2)
-{
-	struct ppp_header *h;
-	struct cisco_packet *ch;
-	struct sk_buff *skb;
-	struct net_device *dev = sp->pp_if;
-	u32 t = jiffies * 1000/HZ;
-
-	skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+CISCO_PACKET_LEN,
-		GFP_ATOMIC);
-
-	if(skb==NULL)
-		return;
-		
-	skb_reserve(skb, dev->hard_header_len);
-	h = (struct ppp_header *)skb_put (skb, sizeof(struct ppp_header));
-	h->address = CISCO_MULTICAST;
-	h->control = 0;
-	h->protocol = htons (CISCO_KEEPALIVE);
-
-	ch = (struct cisco_packet*)skb_put(skb, CISCO_PACKET_LEN);
-	ch->type = htonl (type);
-	ch->par1 = htonl (par1);
-	ch->par2 = htonl (par2);
-	ch->rel = -1;
-	ch->time0 = htons ((u16) (t >> 16));
-	ch->time1 = htons ((u16) t);
-
-	if (sp->pp_flags & PP_DEBUG)
-		printk (KERN_WARNING "%s: cisco output: <%lxh %xh %xh %xh %xh-%xh>\n",
-			dev->name,  ntohl (ch->type), ch->par1,
-			ch->par2, ch->rel, ch->time0, ch->time1);
-	sp->obytes += skb->len;
-	skb->priority=TC_PRIO_CONTROL;
-	skb->dev = dev;
-	dev_queue_xmit(skb);
-}
-
-
-int sppp_close (struct net_device *dev)
-{
-	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
-	dev->flags &= ~IFF_RUNNING;
-	sp->lcp.state = LCP_STATE_CLOSED;
-	sp->ipcp.state = IPCP_STATE_CLOSED;
-	sppp_clear_timeout (sp);
-	return 0;
-}
-
-EXPORT_SYMBOL(sppp_close);
-
-
-int sppp_open (struct net_device *dev)
-{
-	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
-	sppp_close(dev);
-	dev->flags |= IFF_RUNNING;
-	if (!(sp->pp_flags & PP_CISCO))
-		sppp_lcp_open (sp);
-	return 0;
-}
-
-EXPORT_SYMBOL(sppp_open);
-
-int sppp_reopen (struct net_device *dev)
-{
-	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
-	sppp_close(dev);
-	dev->flags |= IFF_RUNNING;
-	if (!(sp->pp_flags & PP_CISCO))
-	{
-		sp->lcp.magic = jiffies;
-		++sp->pp_seq;
-		sp->lcp.state = LCP_STATE_CLOSED;
-		sp->ipcp.state = IPCP_STATE_CLOSED;
-		/* Give it a moment for the line to settle then go */
-		sppp_set_timeout (sp, 1);
-	}
-	return 0;
-}
-
-EXPORT_SYMBOL(sppp_reopen);
-
-int sppp_change_mtu(struct net_device *dev, int new_mtu)
-{
-	if(new_mtu<128||new_mtu>PPP_MTU||(dev->flags&IFF_UP))
-		return -EINVAL;
-	dev->mtu=new_mtu;
-	return 0;
-}
-
-EXPORT_SYMBOL(sppp_change_mtu);
-
-int sppp_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
-
-	if(dev->flags&IFF_UP)
-		return -EBUSY;
-		
-	if(!capable(CAP_NET_ADMIN))
-		return -EPERM;
-	
-	switch(cmd)
-	{
-		case SPPPIOCCISCO:
-			sp->pp_flags|=PP_CISCO;
-			dev->type = ARPHRD_HDLC;
-			break;
-		case SPPPIOCPPP:
-			sp->pp_flags&=~PP_CISCO;
-			dev->type = ARPHRD_PPP;
-			break;
-		case SPPPIOCDEBUG:
-			sp->pp_flags&=~PP_DEBUG;
-			if(ifr->ifr_flags)
-				sp->pp_flags|=PP_DEBUG;
-			break;
-		default:
-			return -EINVAL;
-	}
-	return 0;
-}
-
-EXPORT_SYMBOL(sppp_do_ioctl);
-
-void sppp_attach(struct ppp_device *pd)
-{
-	struct net_device *dev=&pd->dev;
-	struct sppp *sp = &pd->sppp;
-	
-	/* Initialize keepalive handler. */
-	if (! spppq)
-	{
-		init_timer(&sppp_keepalive_timer);
-		sppp_keepalive_timer.expires=jiffies+10*HZ;
-		sppp_keepalive_timer.function=sppp_keepalive;
-		add_timer(&sppp_keepalive_timer);
-	}
-	/* Insert new entry into the keepalive list. */
-	sp->pp_next = spppq;
-	spppq = sp;
-
-	sp->pp_loopcnt = 0;
-	sp->pp_alivecnt = 0;
-	sp->pp_seq = 0;
-	sp->pp_rseq = 0;
-	sp->pp_flags = PP_KEEPALIVE|PP_CISCO|debug;/*PP_DEBUG;*/
-	sp->lcp.magic = 0;
-	sp->lcp.state = LCP_STATE_CLOSED;
-	sp->ipcp.state = IPCP_STATE_CLOSED;
-	sp->pp_if = dev;
-	
-	/* 
-	 *	Device specific setup. All but interrupt handler and
-	 *	hard_start_xmit.
-	 */
-	 
-	dev->hard_header = sppp_hard_header;
-	dev->rebuild_header = sppp_rebuild_header;
-	dev->tx_queue_len = 10;
-	dev->type = ARPHRD_HDLC;
-	dev->addr_len = 0;
-	dev->hard_header_len = sizeof(struct ppp_header);
-	dev->mtu = PPP_MTU;
-	/*
-	 *	These 4 are callers but MUST also call sppp_ functions
-	 */
-	dev->do_ioctl = sppp_do_ioctl;
-#if 0
-	dev->get_stats = NULL;		/* Let the driver override these */
-	dev->open = sppp_open;
-	dev->stop = sppp_close;
-#endif	
-	dev->change_mtu = sppp_change_mtu;
-	dev->hard_header_cache = NULL;
-	dev->header_cache_update = NULL;
-	dev->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP;
-	dev_init_buffers(dev);
-}
-
-EXPORT_SYMBOL(sppp_attach);
-
-void sppp_detach (struct net_device *dev)
-{
-	struct sppp **q, *p, *sp = &((struct ppp_device *)dev)->sppp;
-
-
-	/* Remove the entry from the keepalive list. */
-	for (q = &spppq; (p = *q); q = &p->pp_next)
-		if (p == sp) {
-			*q = p->pp_next;
-			break;
-		}
-
-	/* Stop keepalive handler. */
-	if (! spppq)
-		del_timer(&sppp_keepalive_timer);
-	sppp_clear_timeout (sp);
-}
-
-EXPORT_SYMBOL(sppp_detach);
-
-/*
- * Analyze the LCP Configure-Request options list
- * for the presence of unknown options.
- * If the request contains unknown options, build and
- * send Configure-reject packet, containing only unknown options.
- */
-static int
-sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h,
-	int len, u32 *magic)
-{
-	u8 *buf, *r, *p;
-	int rlen;
-
-	len -= 4;
-	buf = r = kmalloc (len, GFP_ATOMIC);
-	if (! buf)
-		return (0);
-
-	p = (void*) (h+1);
-	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
-		switch (*p) {
-		case LCP_OPT_MAGIC:
-			/* Magic number -- extract. */
-			if (len >= 6 && p[1] == 6) {
-				*magic = (u32)p[2] << 24 |
-					(u32)p[3] << 16 | p[4] << 8 | p[5];
-				continue;
-			}
-			break;
-		case LCP_OPT_ASYNC_MAP:
-			/* Async control character map -- check to be zero. */
-			if (len >= 6 && p[1] == 6 && ! p[2] && ! p[3] &&
-			    ! p[4] && ! p[5])
-				continue;
-			break;
-		case LCP_OPT_MRU:
-			/* Maximum receive unit -- always OK. */
-			continue;
-		default:
-			/* Others not supported. */
-			break;
-		}
-		/* Add the option to rejected list. */
-		memcpy(r, p, p[1]);
-		r += p[1];
-		rlen += p[1];
-	}
-	if (rlen)
-		sppp_cp_send (sp, PPP_LCP, LCP_CONF_REJ, h->ident, rlen, buf);
-	kfree(buf);
-	return (rlen == 0);
-}
-
-static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *skb)
-{
-	struct lcp_header *h;
-	struct net_device *dev = sp->pp_if;
-	int len = skb->len;
-
-	if (len < 4) 
-	{
-		if (sp->pp_flags & PP_DEBUG)
-			printk (KERN_WARNING "%s: invalid ipcp packet length: %d bytes\n",
-				dev->name,  len);
-		return;
-	}
-	h = (struct lcp_header *)skb->data;
-	skb_pull(skb,sizeof(struct lcp_header));
-	if (sp->pp_flags & PP_DEBUG) {
-		printk (KERN_WARNING "%s: ipcp input: %d bytes <%s id=%xh len=%xh",
-			dev->name,  len,
-			sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len));
-		if (len > 4)
-			sppp_print_bytes ((u8*) (h+1), len-4);
-		printk (">\n");
-	}
-	if (len > ntohs (h->len))
-		len = ntohs (h->len);
-	switch (h->type) {
-	default:
-		/* Unknown packet type -- send Code-Reject packet. */
-		sppp_cp_send (sp, PPP_IPCP, IPCP_CODE_REJ, ++sp->pp_seq, len, h);
-		break;
-	case IPCP_CONF_REQ:
-		if (len < 4) {
-			if (sp->pp_flags & PP_DEBUG)
-				printk (KERN_WARNING "%s: invalid ipcp configure request packet length: %d bytes\n",
-					dev->name, len);
-			return;
-		}
-		if (len > 4) {
-			sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident,
-				len-4, h+1);
-
-			switch (sp->ipcp.state) {
-			case IPCP_STATE_OPENED:
-				/* Initiate renegotiation. */
-				sppp_ipcp_open (sp);
-				/* fall through... */
-			case IPCP_STATE_ACK_SENT:
-				/* Go to closed state. */
-				sp->ipcp.state = IPCP_STATE_CLOSED;
-			}
-		} else {
-			/* Send Configure-Ack packet. */
-			sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident,
-				0, 0);
-			/* Change the state. */
-			if (sp->ipcp.state == IPCP_STATE_ACK_RCVD)
-				sp->ipcp.state = IPCP_STATE_OPENED;
-			else
-				sp->ipcp.state = IPCP_STATE_ACK_SENT;
-		}
-		break;
-	case IPCP_CONF_ACK:
-		if (h->ident != sp->ipcp.confid)
-			break;
-		sppp_clear_timeout (sp);
-		switch (sp->ipcp.state) {
-		case IPCP_STATE_CLOSED:
-			sp->ipcp.state = IPCP_STATE_ACK_RCVD;
-			sppp_set_timeout (sp, 5);
-			break;
-		case IPCP_STATE_ACK_SENT:
-			sp->ipcp.state = IPCP_STATE_OPENED;
-			break;
-		}
-		break;
-	case IPCP_CONF_NAK:
-	case IPCP_CONF_REJ:
-		if (h->ident != sp->ipcp.confid)
-			break;
-		sppp_clear_timeout (sp);
-			/* Initiate renegotiation. */
-		sppp_ipcp_open (sp);
-		if (sp->ipcp.state != IPCP_STATE_ACK_SENT)
-			/* Go to closed state. */
-			sp->ipcp.state = IPCP_STATE_CLOSED;
-		break;
-	case IPCP_TERM_REQ:
-		/* Send Terminate-Ack packet. */
-		sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, 0);
-		/* Go to closed state. */
-		sp->ipcp.state = IPCP_STATE_CLOSED;
-		/* Initiate renegotiation. */
-		sppp_ipcp_open (sp);
-		break;
-	case IPCP_TERM_ACK:
-		/* Ignore for now. */
-	case IPCP_CODE_REJ:
-		/* Ignore for now. */
-		break;
-	}
-}
-
-static void sppp_lcp_open (struct sppp *sp)
-{
-	char opt[6];
-
-	if (! sp->lcp.magic)
-		sp->lcp.magic = jiffies;
-	opt[0] = LCP_OPT_MAGIC;
-	opt[1] = sizeof (opt);
-	opt[2] = sp->lcp.magic >> 24;
-	opt[3] = sp->lcp.magic >> 16;
-	opt[4] = sp->lcp.magic >> 8;
-	opt[5] = sp->lcp.magic;
-	sp->lcp.confid = ++sp->pp_seq;
-	sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, sp->lcp.confid,
-		sizeof (opt), &opt);
-	sppp_set_timeout (sp, 2);
-}
-
-static void sppp_ipcp_open (struct sppp *sp)
-{
-	sp->ipcp.confid = ++sp->pp_seq;
-	sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0, 0);
-	sppp_set_timeout (sp, 2);
-}
-
-/*
- * Process PPP control protocol timeouts.
- */
- 
-static void sppp_cp_timeout (unsigned long arg)
-{
-	struct sppp *sp = (struct sppp*) arg;
-	unsigned long flags;
-	save_flags(flags);
-	cli();
-
-	sp->pp_flags &= ~PP_TIMO;
-	if (! (sp->pp_if->flags & IFF_RUNNING) || (sp->pp_flags & PP_CISCO)) {
-		restore_flags(flags);
-		return;
-	}
-	switch (sp->lcp.state) {
-	case LCP_STATE_CLOSED:
-		/* No ACK for Configure-Request, retry. */
-		sppp_lcp_open (sp);
-		break;
-	case LCP_STATE_ACK_RCVD:
-		/* ACK got, but no Configure-Request for peer, retry. */
-		sppp_lcp_open (sp);
-		sp->lcp.state = LCP_STATE_CLOSED;
-		break;
-	case LCP_STATE_ACK_SENT:
-		/* ACK sent but no ACK for Configure-Request, retry. */
-		sppp_lcp_open (sp);
-		break;
-	case LCP_STATE_OPENED:
-		/* LCP is already OK, try IPCP. */
-		switch (sp->ipcp.state) {
-		case IPCP_STATE_CLOSED:
-			/* No ACK for Configure-Request, retry. */
-			sppp_ipcp_open (sp);
-			break;
-		case IPCP_STATE_ACK_RCVD:
-			/* ACK got, but no Configure-Request for peer, retry. */
-			sppp_ipcp_open (sp);
-			sp->ipcp.state = IPCP_STATE_CLOSED;
-			break;
-		case IPCP_STATE_ACK_SENT:
-			/* ACK sent but no ACK for Configure-Request, retry. */
-			sppp_ipcp_open (sp);
-			break;
-		case IPCP_STATE_OPENED:
-			/* IPCP is OK. */
-			break;
-		}
-		break;
-	}
-	restore_flags(flags);
-}
-
-static char *sppp_lcp_type_name (u8 type)
-{
-	static char buf [8];
-	switch (type) {
-	case LCP_CONF_REQ:   return ("conf-req");
-	case LCP_CONF_ACK:   return ("conf-ack");
-	case LCP_CONF_NAK:   return ("conf-nack");
-	case LCP_CONF_REJ:   return ("conf-rej");
-	case LCP_TERM_REQ:   return ("term-req");
-	case LCP_TERM_ACK:   return ("term-ack");
-	case LCP_CODE_REJ:   return ("code-rej");
-	case LCP_PROTO_REJ:  return ("proto-rej");
-	case LCP_ECHO_REQ:   return ("echo-req");
-	case LCP_ECHO_REPLY: return ("echo-reply");
-	case LCP_DISC_REQ:   return ("discard-req");
-	}
-	sprintf (buf, "%xh", type);
-	return (buf);
-}
-
-static char *sppp_ipcp_type_name (u8 type)
-{
-	static char buf [8];
-	switch (type) {
-	case IPCP_CONF_REQ:   return ("conf-req");
-	case IPCP_CONF_ACK:   return ("conf-ack");
-	case IPCP_CONF_NAK:   return ("conf-nack");
-	case IPCP_CONF_REJ:   return ("conf-rej");
-	case IPCP_TERM_REQ:   return ("term-req");
-	case IPCP_TERM_ACK:   return ("term-ack");
-	case IPCP_CODE_REJ:   return ("code-rej");
-	}
-	sprintf (buf, "%xh", type);
-	return (buf);
-}
-
-static void sppp_print_bytes (u_char *p, u16 len)
-{
-	printk (" %x", *p++);
-	while (--len > 0)
-		printk ("-%x", *p++);
-}
-
-/*
- *	Protocol glue. This drives the deferred processing mode the poorer
- *	cards use.
- */
-
-int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p)
-{
-	sppp_input(dev,skb);
-	return 0;
-}
-
-EXPORT_SYMBOL(sppp_rcv);
-
-struct packet_type sppp_packet_type=
-{
-	0,
-	NULL,
-	sppp_rcv,
-	NULL,
-	NULL
-};
-
-
-void sync_ppp_init(void)
-{
-	printk(KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n");
-	printk(KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & Jan \"Yenya\" Kasprzak.\n");
-	sppp_packet_type.type=htons(ETH_P_WAN_PPP);	
-	dev_add_pack(&sppp_packet_type);
-}
-
-#ifdef MODULE
-
-int init_module(void)
-{
-	if(debug)
-		debug=PP_DEBUG;
-	sync_ppp_init();
-	return 0;
-}
-
-void cleanup_module(void)
-{
-	dev_remove_pack(&sppp_packet_type);
-}
-
-#endif
diff -u --recursive --new-file v2.3.20/linux/drivers/net/syncppp.h linux/drivers/net/syncppp.h
--- v2.3.20/linux/drivers/net/syncppp.h	Wed Aug 18 11:36:45 1999
+++ linux/drivers/net/syncppp.h	Wed Dec 31 16:00:00 1969
@@ -1,91 +0,0 @@
-/*
- * Defines for synchronous PPP/Cisco link level subroutines.
- *
- * Copyright (C) 1994 Cronyx Ltd.
- * Author: Serge Vakulenko, <vak@zebub.msk.su>
- *
- * This software is distributed with NO WARRANTIES, not even the implied
- * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Authors grant any other persons or organizations permission to use
- * or modify this software as long as this message is kept with the software,
- * all derivative works or modified versions.
- *
- * Version 1.7, Wed Jun  7 22:12:02 MSD 1995
- *
- *
- *
- */
-
-#ifndef _SYNCPPP_H_
-#define _SYNCPPP_H_ 1
-
-#ifdef __KERNEL__
-struct slcp {
-	u16	state;          /* state machine */
-	u32	magic;          /* local magic number */
-	u_char	echoid;         /* id of last keepalive echo request */
-	u_char	confid;         /* id of last configuration request */
-};
-
-struct sipcp {
-	u16	state;          /* state machine */
-	u_char  confid;         /* id of last configuration request */
-};
-
-struct sppp 
-{
-	struct sppp *	pp_next;	/* next interface in keepalive list */
-	u32		pp_flags;	/* use Cisco protocol instead of PPP */
-	u16		pp_alivecnt;	/* keepalive packets counter */
-	u16		pp_loopcnt;	/* loopback detection counter */
-	u32		pp_seq;		/* local sequence number */
-	u32		pp_rseq;	/* remote sequence number */
-	struct slcp	lcp;		/* LCP params */
-	struct sipcp	ipcp;		/* IPCP params */
-	u32		ibytes,obytes;	/* Bytes in/out */
-	u32		ipkts,opkts;	/* Packets in/out */
-	struct timer_list	pp_timer;
-	struct net_device	*pp_if;
-};
-
-struct ppp_device
-{	
-	struct net_device dev;	/* Network device */
-	struct sppp sppp;	/* Synchronous PPP */
-};
-
-#define PP_KEEPALIVE    0x01    /* use keepalive protocol */
-#define PP_CISCO        0x02    /* use Cisco protocol instead of PPP */
-#define PP_TIMO         0x04    /* cp_timeout routine active */
-#define PP_DEBUG	0x08
-
-#define PPP_MTU          1500    /* max. transmit unit */
-
-#define LCP_STATE_CLOSED        0       /* LCP state: closed (conf-req sent) */
-#define LCP_STATE_ACK_RCVD      1       /* LCP state: conf-ack received */
-#define LCP_STATE_ACK_SENT      2       /* LCP state: conf-ack sent */
-#define LCP_STATE_OPENED        3       /* LCP state: opened */
-
-#define IPCP_STATE_CLOSED       0       /* IPCP state: closed (conf-req sent) */
-#define IPCP_STATE_ACK_RCVD     1       /* IPCP state: conf-ack received */
-#define IPCP_STATE_ACK_SENT     2       /* IPCP state: conf-ack sent */
-#define IPCP_STATE_OPENED       3       /* IPCP state: opened */
-
-void sppp_attach (struct ppp_device *pd);
-void sppp_detach (struct net_device *dev);
-void sppp_input (struct net_device *dev, struct sk_buff *m);
-int sppp_do_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd);
-struct sk_buff *sppp_dequeue (struct net_device *dev);
-int sppp_isempty (struct net_device *dev);
-void sppp_flush (struct net_device *dev);
-int sppp_open (struct net_device *dev);
-int sppp_reopen (struct net_device *dev);
-int sppp_close (struct net_device *dev);
-#endif
-
-#define SPPPIOCCISCO	(SIOCDEVPRIVATE)
-#define SPPPIOCPPP	(SIOCDEVPRIVATE+1)
-#define SPPPIOCDEBUG	(SIOCDEVPRIVATE+2)
-
-#endif /* _SYNCPPP_H_ */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/tokenring/Config.in linux/drivers/net/tokenring/Config.in
--- v2.3.20/linux/drivers/net/tokenring/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/tokenring/Config.in	Mon Oct 11 10:13:24 1999
@@ -0,0 +1,15 @@
+#
+# Token Ring driver configuration
+#
+
+mainmenu_option next_comment
+comment 'Token Ring driver support'
+
+bool 'Token Ring driver support' CONFIG_TR
+if [ "$CONFIG_TR" = "y" ]; then
+   tristate '  IBM Tropic chipset based adapter support' CONFIG_IBMTR
+   tristate '  IBM Olympic chipset PCI adapter support' CONFIG_IBMOL
+   tristate '  SysKonnect adapter support' CONFIG_SKTR
+fi
+
+endmenu
diff -u --recursive --new-file v2.3.20/linux/drivers/net/tokenring/Makefile linux/drivers/net/tokenring/Makefile
--- v2.3.20/linux/drivers/net/tokenring/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/tokenring/Makefile	Mon Oct 11 10:13:24 1999
@@ -0,0 +1,51 @@
+#
+# Makefile for drivers/net/tokenring
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now inherited from the
+# parent makefile.
+#
+
+#
+# Note : at this point, these files are compiled on all systems.
+# In the future, some of these should be built conditionally.
+#
+
+SUB_DIRS     := 
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+
+L_TARGET := tr.a
+L_OBJS   := 
+M_OBJS   :=
+
+ifeq ($(CONFIG_IBMTR),y)
+  L_OBJS += ibmtr.o
+else
+  ifeq ($(CONFIG_IBMTR),m)
+    M_OBJS += ibmtr.o
+  endif
+endif
+
+ifeq ($(CONFIG_IBMOL),y)
+  L_OBJS += olympic.o
+else
+  ifeq ($(CONFIG_IBMOL),m)
+    M_OBJS += olympic.o
+  endif
+endif
+
+ifeq ($(CONFIG_SKTR),y)
+  L_OBJS += sktr.o
+else
+  ifeq ($(CONFIG_SKTR),m)
+    M_OBJS += sktr.o
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
+
diff -u --recursive --new-file v2.3.20/linux/drivers/net/tokenring/ibmtr.c linux/drivers/net/tokenring/ibmtr.c
--- v2.3.20/linux/drivers/net/tokenring/ibmtr.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/tokenring/ibmtr.c	Mon Oct 11 10:13:24 1999
@@ -0,0 +1,1809 @@
+/* ibmtr.c:  A shared-memory IBM Token Ring 16/4 driver for linux
+ *
+ *	Written 1993 by Mark Swanson and Peter De Schrijver.
+ *	This software may be used and distributed according to the terms
+ *	of the GNU Public License, incorporated herein by reference.
+ *
+ *	This device driver should work with Any IBM Token Ring Card that does
+ *	not use DMA.
+ *
+ *	I used Donald Becker's (becker@cesdis.gsfc.nasa.gov) device driver work
+ *	as a base for most of my initial work.
+ *
+ *	Changes by Peter De Schrijver (Peter.Deschrijver@linux.cc.kuleuven.ac.be) :
+ *
+ *	+ changed name to ibmtr.c in anticipation of other tr boards.
+ *	+ changed reset code and adapter open code.
+ *	+ added SAP open code.
+ *	+ a first attempt to write interrupt, transmit and receive routines.
+ *
+ *	Changes by David W. Morris (dwm@shell.portal.com) :
+ *	941003 dwm: - Restructure tok_probe for multiple adapters, devices.
+ *	+ Add comments, misc reorg for clarity.
+ *	+ Flatten interrupt handler levels.
+ *
+ *	Changes by Farzad Farid (farzy@zen.via.ecp.fr)
+ *	and Pascal Andre (andre@chimay.via.ecp.fr) (March 9 1995) :
+ *	+ multi ring support clean up.
+ *	+ RFC1042 compliance enhanced.
+ *
+ *	Changes by Pascal Andre (andre@chimay.via.ecp.fr) (September 7 1995) :
+ *	+ bug correction in tr_tx
+ *	+ removed redundant information display
+ *	+ some code reworking
+ *
+ *	Changes by Michel Lespinasse (walken@via.ecp.fr),
+ *	Yann Doussot (doussot@via.ecp.fr) and Pascal Andre (andre@via.ecp.fr)
+ *	(February 18, 1996) :
+ *	+ modified shared memory and mmio access port the driver to
+ *	  alpha platform (structure access -> readb/writeb)
+ *
+ *	Changes by Steve Kipisz (bungy@ibm.net or kipisz@vnet.ibm.com)
+ *	(January 18 1996):
+ *	+ swapped WWOR and WWCR in ibmtr.h
+ *	+ moved some init code from tok_probe into trdev_init.  The
+ *	  PCMCIA code can call trdev_init to complete initializing
+ *	  the driver.
+ *	+ added -DPCMCIA to support PCMCIA
+ *	+ detecting PCMCIA Card Removal in interrupt handler.  If
+ *	  ISRP is FF, then a PCMCIA card has been removed
+ *
+ *	Changes by Paul Norton (pnorton@cts.com) :
+ *	+ restructured the READ.LOG logic to prevent the transmit SRB
+ *	  from being rudely overwritten before the transmit cycle is
+ *	  complete. (August 15 1996)
+ *	+ completed multiple adapter support. (November 20 1996)
+ *	+ implemented csum_partial_copy in tr_rx and increased receive 
+ *        buffer size and count. Minor fixes. (March 15, 1997)
+ *
+ *	Changes by Christopher Turcksin <wabbit@rtfc.demon.co.uk>
+ *	+ Now compiles ok as a module again.
+ *
+ *	Changes by Paul Norton (pnorton@ieee.org) :
+ *      + moved the header manipulation code in tr_tx and tr_rx to
+ *        net/802/tr.c. (July 12 1997)
+ *      + add retry and timeout on open if cable disconnected. (May 5 1998)
+ *      + lifted 2000 byte mtu limit. now depends on shared-RAM size.
+ *        May 25 1998)
+ *      + can't allocate 2k recv buff at 8k shared-RAM. (20 October 1998)
+ *
+ *      Changes by Joel Sloan (jjs@c-me.com) :
+ *      + disable verbose debug messages by default - to enable verbose
+ *	  debugging, edit the IBMTR_DEBUG_MESSAGES define below 
+ *	
+ *	Changes by Mike Phillips <phillim@amtrak.com> :
+ *	+ Added extra #ifdef's to work with new PCMCIA Token Ring Code.
+ *	  The PCMCIA code now just sets up the card so it can be recognized
+ *        by ibmtr_probe. Also checks allocated memory vs. on-board memory
+ *	  for correct figure to use.
+ *
+ *	Changes by Tim Hockin (thockin@isunix.it.ilstu.edu) :
+ *	+ added spinlocks for SMP sanity (10 March 1999)
+ *
+ *      Changes by Jochen Friedrich to enable RFC1469 Option 2 multicasting
+ *      i.e. using functional address C0 00 00 04 00 00 to transmit and 
+ *      receive multicast packets.
+ */
+
+/* change the define of IBMTR_DEBUG_MESSAGES to a nonzero value 
+in the event that chatty debug messages are desired - jjs 12/30/98 */
+
+#define IBMTR_DEBUG_MESSAGES 0
+
+#ifdef PCMCIA
+#define MODULE
+#endif
+
+#include <linux/module.h>
+
+#ifdef PCMCIA
+#undef MODULE
+#endif
+
+#define NO_AUTODETECT 1
+#undef NO_AUTODETECT
+#undef ENABLE_PAGING
+
+
+#define FALSE 0
+#define TRUE (!FALSE)
+
+/* changes the output format of driver initialisation */
+#define TR_NEWFORMAT	1
+#define TR_VERBOSE	0
+
+/* some 95 OS send many non UI frame; this allow removing the warning */
+#define TR_FILTERNONUI	1
+
+/* version and credits */
+static char *version =
+"ibmtr.c: v1.3.57   8/ 7/94 Peter De Schrijver and Mark Swanson\n"
+"         v2.1.125 10/20/98 Paul Norton <pnorton@ieee.org>\n"
+"         v2.2.0   12/30/98 Joel Sloan <jjs@c-me.com>\n";
+
+static char pcchannelid[] = {
+	0x05, 0x00, 0x04, 0x09,
+	0x04, 0x03, 0x04, 0x0f,
+	0x03, 0x06, 0x03, 0x01,
+	0x03, 0x01, 0x03, 0x00,
+	0x03, 0x09, 0x03, 0x09,
+	0x03, 0x00, 0x02, 0x00
+};
+
+static char mcchannelid[] = {
+	0x04, 0x0d, 0x04, 0x01,
+	0x05, 0x02, 0x05, 0x03,
+	0x03, 0x06, 0x03, 0x03,
+	0x05, 0x08, 0x03, 0x04,
+	0x03, 0x05, 0x03, 0x01,
+	0x03, 0x08, 0x02, 0x00
+};
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/in.h>
+#include <linux/ioport.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/trdevice.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <net/checksum.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include "ibmtr.h"
+
+
+#define DPRINTK(format, args...) printk("%s: " format, dev->name , ## args)
+#define DPRINTD(format, args...) DummyCall("%s: " format, dev->name , ## args)
+#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
+#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
+
+#if TR_NEWFORMAT
+/* this allows displaying full adapter information */
+
+const char *channel_def[] __initdata = { 
+	"ISA", "MCA", "ISA P&P" 
+};
+
+char __init *adapter_def(char type)
+{
+	switch (type) 
+	{
+	      case 0xF : return "PC Adapter | PC Adapter II | Adapter/A";
+	      case 0xE : return "16/4 Adapter | 16/4 Adapter/A (long)";
+	      case 0xD : return "16/4 Adapter/A (short) | 16/4 ISA-16 Adapter";
+	      case 0xC : return "Auto 16/4 Adapter";
+	      default  : return "adapter (unknown type)";
+	};
+};
+#endif
+
+#if !TR_NEWFORMAT
+unsigned char ibmtr_debug_trace=1;  /*  Patch or otherwise alter to
+                                         control tokenring tracing.  */
+#else
+unsigned char ibmtr_debug_trace=0;
+#endif
+#define TRC_INIT 0x01              /*  Trace initialization & PROBEs */
+#define TRC_INITV 0x02             /*  verbose init trace points     */
+
+int		ibmtr_probe(struct net_device *dev);
+static int	ibmtr_probe1(struct net_device *dev, int ioaddr);
+static unsigned char	get_sram_size(struct tok_info *adapt_info);
+#ifdef PCMCIA
+extern unsigned char 	pcmcia_reality_check(unsigned char gss);
+#endif
+static int	tok_init_card(struct net_device *dev);
+void		tok_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int	trdev_init(struct net_device *dev);
+static void 	initial_tok_int(struct net_device *dev);
+static void 	open_sap(unsigned char type,struct net_device *dev);
+void		tok_open_adapter(unsigned long dev_addr);
+static		void tr_rx(struct net_device *dev);
+static		void tr_tx(struct net_device *dev);
+static int	tok_open(struct net_device *dev);
+static int	tok_close(struct net_device *dev);
+static int	tok_send_packet(struct sk_buff *skb, struct net_device *dev);
+static struct net_device_stats * tok_get_stats(struct net_device *dev);
+static void	tok_set_multicast_list(struct net_device *dev);
+void		ibmtr_readlog(struct net_device *dev);
+void		ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev);
+int             ibmtr_change_mtu(struct net_device *dev, int mtu);
+
+static unsigned int ibmtr_portlist[] __initdata = {
+	0xa20, 0xa24, 0
+};
+
+static __u32 ibmtr_mem_base = 0xd0000;
+
+static void __init PrtChanID(char *pcid, short stride) 
+{
+	short i, j;
+	for (i=0, j=0; i<24; i++, j+=stride)
+		printk("%1x", ((int) pcid[j]) & 0x0f);
+	printk("\n");
+}
+
+static void __init HWPrtChanID (__u32 pcid, short stride)
+{
+	short i, j;
+	for (i=0, j=0; i<24; i++, j+=stride)
+		printk("%1x", ((int)readb(pcid + j)) & 0x0f);
+	printk("\n");
+}
+
+/*
+ *	ibmtr_probe():  Routine specified in the network device structure
+ *	to probe for an IBM Token Ring Adapter.  Routine outline:
+ *	I.    Interrogate hardware to determine if an adapter exists
+ *	      and what the speeds and feeds are
+ *	II.   Setup data structures to control execution based upon
+ *	      adapter characteristics.
+ *	III.  Initialize adapter operation
+ *
+ *	We expect ibmtr_probe to be called once for each device entry
+ *	which references it.
+ */
+ 
+int __init ibmtr_probe(struct net_device *dev)
+{
+        int i;
+        int base_addr = dev ? dev->base_addr : 0;
+
+        if (base_addr > 0x1ff) 
+        { 
+        	/*
+        	 *	Check a single specified location. 
+ 		 */
+ 		 
+	        if (ibmtr_probe1(dev, base_addr)) 
+	        {
+#ifndef MODULE
+#ifndef PCMCIA
+		       tr_freedev(dev);
+#endif
+#endif
+		       return -ENODEV;
+		} else
+		       return 0;
+	}
+        else if (base_addr != 0)   /* Don't probe at all. */
+	        return -ENXIO;
+
+	for (i = 0; ibmtr_portlist[i]; i++) 
+	{
+	        int ioaddr = ibmtr_portlist[i];
+		if (check_region(ioaddr, IBMTR_IO_EXTENT))
+		        continue;
+                if (ibmtr_probe1(dev, ioaddr)) {
+#ifndef MODULE
+#ifndef PCMCIA
+		        tr_freedev(dev);
+#endif
+#endif
+		} else
+			return 0;
+        }
+
+        return -ENODEV;
+}
+
+static int __init ibmtr_probe1(struct net_device *dev, int PIOaddr)
+{
+	unsigned char segment=0, intr=0, irq=0, i=0, j=0, cardpresent=NOTOK,temp=0;
+	__u32 t_mmio=0;
+	struct tok_info *ti=0;
+	__u32 cd_chanid;
+	unsigned char *tchanid, ctemp;
+	unsigned long timeout;
+
+#ifndef MODULE
+#ifndef PCMCIA
+	dev = init_trdev(dev,0);
+#endif
+#endif
+
+	/*	Query the adapter PIO base port which will return
+	 *	indication of where MMIO was placed. We also have a
+	 *	coded interrupt number.
+	 */
+
+       	segment = inb(PIOaddr);
+
+	/*
+	 *	Out of range values so we'll assume non-existent IO device 
+	 */
+	 
+	if (segment < 0x40 || segment > 0xe0)
+                return -ENODEV;
+
+	/*
+	 *	Compute the linear base address of the MMIO area
+	 *	as LINUX doesn't care about segments
+	 */
+
+	t_mmio=(((__u32)(segment & 0xfc) << 11) + 0x80000);
+	intr = segment & 0x03;   /* low bits is coded interrupt # */
+	if (ibmtr_debug_trace & TRC_INIT)
+		DPRINTK("PIOaddr: %4hx seg/intr: %2x mmio base: %08X intr: %d\n",
+                         PIOaddr, (int)segment, t_mmio, (int)intr);
+
+	/*
+	 *	Now we will compare expected 'channelid' strings with
+	 *	what we is there to learn of ISA/MCA or not TR card
+	 */
+	 
+	cd_chanid = (CHANNEL_ID + t_mmio);  /* for efficiency */
+	tchanid=pcchannelid;
+	cardpresent=TR_ISA;  /* try ISA */
+
+	/*
+	 *	Suboptimize knowing first byte different
+	 */
+
+	ctemp = readb(cd_chanid) & 0x0f;
+	if (ctemp != *tchanid) { /* NOT ISA card, try MCA */
+		tchanid=mcchannelid;
+		cardpresent=TR_MCA;
+		if (ctemp != *tchanid)  /* Neither ISA nor MCA */
+			cardpresent=NOTOK;
+	}
+
+	if (cardpresent != NOTOK) 
+	{
+		/* 
+		 *	Know presumed type, try rest of ID 
+		 */
+		for (i=2,j=1; i<=46; i=i+2,j++) 
+		{
+			if ((readb(cd_chanid+i) & 0x0f) != tchanid[j]) {
+				cardpresent=NOTOK;   /* match failed, not TR card */
+				break;
+			}
+		}
+	}
+
+	/* 
+	 *	If we have an ISA board check for the ISA P&P version,
+	 *	as it has different IRQ settings 
+	 */
+
+	if (cardpresent == TR_ISA && (readb(AIPFID + t_mmio)==0x0e))
+	        cardpresent=TR_ISAPNP;
+
+	if (cardpresent == NOTOK) { /* "channel_id" did not match, report */
+		if (ibmtr_debug_trace & TRC_INIT) {
+			DPRINTK("Channel ID string not found for PIOaddr: %4hx\n", PIOaddr);
+			DPRINTK("Expected for ISA: ");  PrtChanID(pcchannelid,1);
+			DPRINTK("           found: ");  HWPrtChanID(cd_chanid,2);
+			DPRINTK("Expected for MCA: ");  PrtChanID(mcchannelid,1);
+		}
+                return -ENODEV;
+	}
+
+	/* Now, allocate some of the pl0 buffers for this driver.. */
+
+	/* If called from PCMCIA, ti is already set up, so no need to 
+	   waste the memory, just use the existing structure */
+
+#ifndef PCMCIA
+	ti = (struct tok_info *)kmalloc(sizeof(struct tok_info), GFP_KERNEL);
+	if (ti == NULL) 
+		return -ENOMEM;
+
+	memset(ti, 0, sizeof(struct tok_info));
+#else
+	ti = dev->priv ; 
+#endif
+	ti->mmio= t_mmio;
+	ti->readlog_pending = 0;
+	init_waitqueue_head(&ti->wait_for_tok_int);
+	init_waitqueue_head(&ti->wait_for_reset);
+
+	dev->priv = ti;     /* this seems like the logical use of the
+                         field ... let's try some empirical tests
+                         using the token-info structure -- that
+                         should fit with out future hope of multiple
+                         adapter support as well /dwm   */
+
+	/* if PCMCIA, then the card is recognized as TR_ISAPNP 
+	 * and there is no need to set up the interrupt, it is already done. */
+        
+#ifndef PCMCIA
+	switch (cardpresent) 
+	{
+		case TR_ISA:
+			if (intr==0)
+				irq=9; /* irq2 really is irq9 */
+			if (intr==1)
+				irq=3;
+			if (intr==2)
+				irq=6;
+			if (intr==3)
+				irq=7;
+			ti->global_int_enable=GLOBAL_INT_ENABLE+((irq==9) ? 2 : irq);
+			ti->adapter_int_enable=PIOaddr+ADAPTINTREL;
+			ti->sram=0;
+#if !TR_NEWFORMAT
+			DPRINTK("ti->global_int_enable: %04X\n",ti->global_int_enable);
+#endif
+			break;
+		case TR_MCA:
+			if (intr==0)
+				irq=9;
+			if (intr==1)
+				irq=3;
+			if (intr==2)
+				irq=10;
+			if (intr==3)
+				irq=11;
+			ti->global_int_enable=0;
+			ti->adapter_int_enable=0;
+			ti->sram=((__u32)(inb(PIOaddr+ADAPTRESETREL) & 0xfe) << 12);
+			break;
+		case TR_ISAPNP:
+			if (intr==0)
+				irq=9;
+			if (intr==1)
+				irq=3;
+			if (intr==2)
+				irq=10;
+			if (intr==3)
+				irq=11;
+			timeout = jiffies + TR_SPIN_INTERVAL;
+			while(!readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN))
+				if (time_after(jiffies, timeout)) {
+					DPRINTK("Hardware timeout during initialization.\n");
+					kfree_s(ti, sizeof(struct tok_info));
+					return -ENODEV;
+			        }
+
+			ti->sram=((__u32)readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)<<12);
+			ti->global_int_enable=PIOaddr+ADAPTINTREL;
+			ti->adapter_int_enable=PIOaddr+ADAPTINTREL;
+			break;
+	}
+#endif
+
+	if (ibmtr_debug_trace & TRC_INIT) { /* just report int */
+		DPRINTK("irq=%d",irq);
+		if (ibmtr_debug_trace & TRC_INITV) { /* full chat in verbose only */
+			DPRINTK(", ti->mmio=%08X",ti->mmio);
+			printk(", segment=%02X",segment);
+		}
+		printk(".\n");
+	}
+
+	/* Get hw address of token ring card */
+#if !TR_NEWFORMAT
+	DPRINTK("hw address: ");
+#endif
+	j=0;
+	for (i=0; i<0x18; i=i+2) 
+	{
+		/* technical reference states to do this */
+		temp = readb(ti->mmio + AIP + i) & 0x0f;
+#if !TR_NEWFORMAT
+		printk("%1X",ti->hw_address[j]=temp);
+#else
+		ti->hw_address[j]=temp;
+#endif
+		if(j&1)
+			dev->dev_addr[(j/2)]=ti->hw_address[j]+(ti->hw_address[j-1]<<4);
+		++j;
+	}
+#ifndef TR_NEWFORMAT
+	printk("\n");
+#endif
+
+	/* get Adapter type:  'F' = Adapter/A, 'E' = 16/4 Adapter II,...*/
+	ti->adapter_type = readb(ti->mmio + AIPADAPTYPE);
+
+	/* get Data Rate:  F=4Mb, E=16Mb, D=4Mb & 16Mb ?? */
+	ti->data_rate = readb(ti->mmio + AIPDATARATE);
+
+	/* Get Early Token Release support?: F=no, E=4Mb, D=16Mb, C=4&16Mb */
+	ti->token_release = readb(ti->mmio + AIPEARLYTOKEN);
+
+	/* How much shared RAM is on adapter ? */
+#ifdef PCMCIA
+	ti->avail_shared_ram = pcmcia_reality_check(get_sram_size(ti));
+	ibmtr_mem_base = ti->sram_base << 12 ; 
+#else
+	ti->avail_shared_ram = get_sram_size(ti);
+#endif
+	/* We need to set or do a bunch of work here based on previous results.. */
+	/* Support paging?  What sizes?:  F=no, E=16k, D=32k, C=16 & 32k */
+	ti->shared_ram_paging = readb(ti->mmio + AIPSHRAMPAGE);
+
+        /* Available DHB  4Mb size:   F=2048, E=4096, D=4464 */
+	switch (readb(ti->mmio + AIP4MBDHB)) {
+	case 0xe : 
+		ti->dhb_size4mb = 4096;
+		break; 
+	case 0xd : 
+		ti->dhb_size4mb = 4464;
+		break; 
+	default  : 
+		ti->dhb_size4mb = 2048;
+		break; 
+	}
+
+	/* Available DHB 16Mb size:  F=2048, E=4096, D=8192, C=16384, B=17960 */
+	switch (readb(ti->mmio + AIP16MBDHB)) {
+	case 0xe : 
+		ti->dhb_size16mb = 4096;
+		break; 
+	case 0xd : 
+		ti->dhb_size16mb = 8192;
+		break; 
+	case 0xc : 
+		ti->dhb_size16mb = 16384;
+		break; 
+	case 0xb : 
+		ti->dhb_size16mb = 17960;
+		break; 
+	default  : 
+		ti->dhb_size16mb = 2048;
+		break; 
+	}
+
+#if !TR_NEWFORMAT
+	DPRINTK("atype=%x, drate=%x, trel=%x, asram=%dK, srp=%x, "
+		"dhb(4mb=%x, 16mb=%x)\n",ti->adapter_type,
+		ti->data_rate, ti->token_release, ti->avail_shared_ram/2,
+		ti->shared_ram_paging, ti->dhb_size4mb, ti->dhb_size16mb);
+#endif
+
+	/*	We must figure out how much shared memory space this adapter
+	 *	will occupy so that if there are two adapters we can fit both
+	 *	in.  Given a choice, we will limit this adapter to 32K.  The
+	 *	maximum space will will use for two adapters is 64K so if the
+	 *	adapter we are working on demands 64K (it also doesn't support
+	 *	paging), then only one adapter can be supported.  
+	 */
+
+	/*
+	 *	determine how much of total RAM is mapped into PC space 
+	 */
+	ti->mapped_ram_size=1<<((((readb(ti->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD)) >>2) & 0x03) + 4);
+	ti->page_mask=0;
+	if (ti->shared_ram_paging == 0xf) { /* No paging in adapter */
+		ti->mapped_ram_size = ti->avail_shared_ram;
+	} else {
+#ifdef ENABLE_PAGING
+		unsigned char pg_size;
+#endif
+
+#if !TR_NEWFORMAT
+		DPRINTK("shared ram page size: %dK\n",ti->mapped_ram_size/2);
+#endif
+#ifdef ENABLE_PAGING
+	switch(ti->shared_ram_paging) 
+	{
+		case 0xf:
+			break;
+		case 0xe:
+			ti->page_mask=(ti->mapped_ram_size==32) ? 0xc0 : 0;
+			pg_size=32;   /* 16KB page size */
+			break;
+		case 0xd:
+			ti->page_mask=(ti->mapped_ram_size==64) ? 0x80 : 0;
+			pg_size=64;   /* 32KB page size */
+			break;
+		case 0xc:
+			ti->page_mask=(ti->mapped_ram_size==32) ? 0xc0 : 0;
+			ti->page_mask=(ti->mapped_ram_size==64) ? 0x80 : 0;
+			DPRINTK("Dual size shared RAM page (code=0xC), don't support it!\n");
+			/* nb/dwm: I did this because RRR (3,2) bits are documented as
+			   R/O and I can't find how to select which page size
+			   Also, the above conditional statement sequence is invalid
+			   as page_mask will always be set by the second stmt */
+			kfree_s(ti, sizeof(struct tok_info));
+			return -ENODEV;
+			break;
+		default:
+			DPRINTK("Unknown shared ram paging info %01X\n",ti->shared_ram_paging);
+			kfree_s(ti, sizeof(struct tok_info));
+			return -ENODEV;
+			break;
+	}
+	if (ti->page_mask) {
+		if (pg_size > ti->mapped_ram_size) {
+			DPRINTK("Page size (%d) > mapped ram window (%d), can't page.\n",
+				pg_size, ti->mapped_ram_size);
+				ti->page_mask = 0;    /* reset paging */
+		} else {
+			ti->mapped_ram_size=ti->avail_shared_ram;
+			DPRINTK("Shared RAM paging enabled. Page size : %uK\n",
+				((ti->page_mask^ 0xff)+1)>>2);
+		}
+#endif
+	}
+	/* finish figuring the shared RAM address */
+	if (cardpresent==TR_ISA) {
+		static __u32 ram_bndry_mask[]={0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000};
+		__u32 new_base, rrr_32, chk_base, rbm;
+
+		rrr_32 = ((readb(ti->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD))>>2) & 0x00000003;
+		rbm = ram_bndry_mask[rrr_32];
+		new_base = (ibmtr_mem_base + (~rbm)) & rbm; /* up to boundary */
+		chk_base = new_base + (ti->mapped_ram_size<<9);
+		if (chk_base > (ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE)) {
+			DPRINTK("Shared RAM for this adapter (%05x) exceeds driver"
+				" limit (%05x), adapter not started.\n",
+				chk_base, ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE);
+			kfree_s(ti, sizeof(struct tok_info));
+                        return -ENODEV;
+		} else {  /* seems cool, record what we have figured out */
+			ti->sram_base = new_base >> 12;
+			ibmtr_mem_base = chk_base;
+		}
+	}
+
+#if !TR_NEWFORMAT
+	DPRINTK("Using %dK shared RAM\n",ti->mapped_ram_size/2);
+#endif
+
+	/* The PCMCIA has already got the interrupt line and the io port, 
+	   so no chance of anybody else getting it - MLP */
+
+#ifndef PCMCIA
+	if (request_irq (dev->irq = irq, &tok_interrupt,0,"ibmtr", dev) != 0) {
+		DPRINTK("Could not grab irq %d.  Halting Token Ring driver.\n",irq);
+		kfree_s(ti, sizeof(struct tok_info));
+		return -ENODEV;
+	}
+ 
+	/*?? Now, allocate some of the PIO PORTs for this driver.. */
+	request_region(PIOaddr,IBMTR_IO_EXTENT,"ibmtr");  /* record PIOaddr range as busy */
+#endif
+
+#if !TR_NEWFORMAT
+	DPRINTK("%s",version); /* As we have passed card identification,
+                                  let the world know we're here! */
+#else
+
+	if (version) {
+	        printk("%s",version);
+                version = NULL;
+        }
+	DPRINTK("%s %s found\n",
+		channel_def[cardpresent-1], adapter_def(ti->adapter_type));
+	DPRINTK("using irq %d, PIOaddr %hx, %dK shared RAM.\n",
+	        irq, PIOaddr, ti->mapped_ram_size/2);
+	DPRINTK("Hardware address : %02X:%02X:%02X:%02X:%02X:%02X\n",
+		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+#endif
+	/* Calculate the maximum DHB we can use */
+	switch (ti->mapped_ram_size) {
+	case  16 : /* 8KB shared RAM */
+		ti->dhb_size4mb  = MIN(ti->dhb_size4mb, 2048);
+		ti->rbuf_len4 = 1032;
+		ti->rbuf_cnt4 = 2;
+		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 2048);
+		ti->rbuf_len16 = 1032;
+		ti->rbuf_cnt16 = 2;
+		break;
+	case  32 : /* 16KB shared RAM */
+		ti->dhb_size4mb  = MIN(ti->dhb_size4mb, 4464);
+		ti->rbuf_len4 = 520;
+		ti->rbuf_cnt4 = 9;
+		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 4096);
+		ti->rbuf_len16 = 1032; /* 1024 usable */
+		ti->rbuf_cnt16 = 4;
+		break;
+	case  64 : /* 32KB shared RAM */
+		ti->dhb_size4mb  = MIN(ti->dhb_size4mb, 4464);
+		ti->rbuf_len4 = 1032;
+		ti->rbuf_cnt4 = 6;
+		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 10240);
+		ti->rbuf_len16 = 1032;
+		ti->rbuf_cnt16 = 10;
+		break;
+	case 127 : /* 63KB shared RAM */
+		ti->dhb_size4mb  = MIN(ti->dhb_size4mb, 4464);
+		ti->rbuf_len4 = 1032;
+		ti->rbuf_cnt4 = 6;
+		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 16384);
+		ti->rbuf_len16 = 1032;
+		ti->rbuf_cnt16 = 16;
+		break;
+	case 128 : /* 64KB shared RAM */
+		ti->dhb_size4mb  = MIN(ti->dhb_size4mb, 4464);
+		ti->rbuf_len4 = 1032;
+		ti->rbuf_cnt4 = 6;
+		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 17960);
+		ti->rbuf_len16 = 1032;
+		ti->rbuf_cnt16 = 18;
+		break;
+	default  :
+		ti->dhb_size4mb  = 2048;
+		ti->rbuf_len4 = 1032;
+		ti->rbuf_cnt4 = 2;
+		ti->dhb_size16mb = 2048;
+		ti->rbuf_len16 = 1032;
+		ti->rbuf_cnt16 = 2;
+		break;
+	}
+
+	ti->maxmtu16 = (ti->rbuf_len16*ti->rbuf_cnt16)-((ti->rbuf_cnt16)<<3)-TR_HLEN;
+	ti->maxmtu4  = (ti->rbuf_len4*ti->rbuf_cnt4)-((ti->rbuf_cnt4)<<3)-TR_HLEN;
+	DPRINTK("Maximum MTU 16Mbps: %d, 4Mbps: %d\n",
+		ti->maxmtu16, ti->maxmtu4);
+
+	dev->base_addr=PIOaddr; /* set the value for device */
+
+	trdev_init(dev);
+	tok_init_card(dev);
+
+	return 0;  /* Return 0 to indicate we have found a Token Ring card. */
+}
+
+/* query the adapter for the size of shared RAM  */
+
+static unsigned char __init get_sram_size(struct tok_info *adapt_info)
+{
+
+	unsigned char avail_sram_code;
+	static unsigned char size_code[]={ 0,16,32,64,127,128 };
+	/* Adapter gives
+	   'F' -- use RRR bits 3,2
+	   'E' -- 8kb   'D' -- 16kb
+	   'C' -- 32kb  'A' -- 64KB
+	   'B' - 64KB less 512 bytes at top
+	   (WARNING ... must zero top bytes in INIT */
+
+	avail_sram_code=0xf-readb(adapt_info->mmio + AIPAVAILSHRAM);
+	if (avail_sram_code)
+		return size_code[avail_sram_code];
+	else  /* for code 'F', must compute size from RRR(3,2) bits */
+		return 1<<((readb(adapt_info->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD)>>2)+4);
+}
+
+static int __init trdev_init(struct net_device *dev)
+{
+	struct tok_info *ti=(struct tok_info *)dev->priv;
+
+	ti->open_status		= CLOSED;
+
+	dev->init		= tok_init_card;
+	dev->open		= tok_open;
+	dev->stop		= tok_close;
+	dev->hard_start_xmit	= tok_send_packet;
+	dev->get_stats 		= tok_get_stats;
+	dev->set_multicast_list = tok_set_multicast_list;
+	dev->change_mtu         = ibmtr_change_mtu;
+
+#ifndef MODULE
+#ifndef PCMCIA
+	tr_setup(dev);
+#endif
+#endif
+	return 0;
+}
+
+
+static void tok_set_multicast_list(struct net_device *dev)
+{
+	struct tok_info *ti=(struct tok_info *)dev->priv;
+	struct dev_mc_list *mclist;
+	unsigned char address[4];
+
+	int i;
+
+	address[0] = address[1] = address[2] = address[3] = 0;
+
+	mclist = dev->mc_list;
+	for (i=0; i< dev->mc_count; i++)
+	{
+		address[0] |= mclist->dmi_addr[2];
+		address[1] |= mclist->dmi_addr[3];
+		address[2] |= mclist->dmi_addr[4];
+		address[3] |= mclist->dmi_addr[5];
+		mclist = mclist->next;
+	}
+	SET_PAGE(ti->srb);
+	for (i=0; i<sizeof(struct srb_set_funct_addr); i++)
+		writeb(0, ti->srb+i);
+
+	writeb(DIR_SET_FUNC_ADDR, 
+               ti->srb + offsetof(struct srb_set_funct_addr, command));
+
+	DPRINTK("Setting functional address: ");
+
+	for (i=0; i<4; i++)
+	{
+		writeb(address[i], 
+		ti->srb + offsetof(struct srb_set_funct_addr, funct_address)+i);
+		printk("%02X ", address[i]);
+	}
+	writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+	printk("\n");
+}
+
+static int tok_open(struct net_device *dev)
+{
+	struct tok_info *ti=(struct tok_info *)dev->priv;
+
+	/* init the spinlock */
+	ti->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
+
+	if (ti->open_status==CLOSED) tok_init_card(dev);
+
+	if (ti->open_status==IN_PROGRESS) sleep_on(&ti->wait_for_reset);
+
+	if (ti->open_status==SUCCESS) {
+		dev->tbusy=0;
+		dev->interrupt=0;
+		dev->start=1;
+		/* NEED to see smem size *AND* reset high 512 bytes if needed */
+
+		MOD_INC_USE_COUNT;
+
+		return 0;
+	} else return -EAGAIN;
+
+}
+
+static int tok_close(struct net_device *dev)
+{
+
+	struct tok_info *ti=(struct tok_info *) dev->priv;
+
+	writeb(DIR_CLOSE_ADAPTER,
+	       ti->srb + offsetof(struct srb_close_adapter, command));
+	writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+
+	ti->open_status=CLOSED;
+
+	sleep_on(&ti->wait_for_tok_int);
+
+	if (readb(ti->srb + offsetof(struct srb_close_adapter, ret_code)))
+		DPRINTK("close adapter failed: %02X\n",
+			(int)readb(ti->srb + offsetof(struct srb_close_adapter, ret_code)));
+
+        dev->start = 0;
+#ifdef PCMCIA
+	ti->sram = 0 ;
+#endif
+	DPRINTK("Adapter closed.\n");
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned char status;
+	struct tok_info *ti;
+	struct net_device *dev;
+
+	dev = dev_id;
+#if TR_VERBOSE
+	DPRINTK("Int from tok_driver, dev : %p\n",dev);
+#endif
+	ti  = (struct tok_info *) dev->priv;
+	spin_lock(&(ti->lock));
+
+      	/* Disable interrupts till processing is finished */
+	dev->interrupt=1;
+	writeb((~INT_ENABLE), ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
+
+	/* Reset interrupt for ISA boards */
+        if (ti->adapter_int_enable)
+                outb(0,ti->adapter_int_enable);
+	else
+		outb(0,ti->global_int_enable);
+
+
+	switch (ti->do_tok_int) {
+
+	      case NOT_FIRST:
+
+		/*  Begin the regular interrupt handler HERE inline to avoid
+		    the extra levels of logic and call depth for the
+		    original solution.   */
+
+		status=readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_ODD);
+#ifdef PCMCIA
+      		/* Check if the PCMCIA card was pulled. */
+    		if (status == 0xFF)
+       		{
+		          DPRINTK("PCMCIA card removed.\n");
+			  spin_unlock(&(ti->lock));
+        		  dev->interrupt = 0;
+         		  return;
+       		}
+
+    	        /* Check ISRP EVEN too. */
+      	        if ( readb (ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) == 0xFF)
+    	        {
+         		 DPRINTK("PCMCIA card removed.\n");
+			 spin_unlock(&(ti->lock));
+         		 dev->interrupt = 0;
+         		 return;
+      		 }
+#endif
+
+
+		if (status & ADAP_CHK_INT) {
+
+			int i;
+			__u32 check_reason;
+
+			check_reason=ti->mmio + ntohs(readw(ti->sram + ACA_OFFSET + ACA_RW +WWCR_EVEN));
+
+			DPRINTK("Adapter check interrupt\n");
+			DPRINTK("8 reason bytes follow: ");
+			for(i=0; i<8; i++, check_reason++)
+				printk("%02X ", (int)readb(check_reason));
+			printk("\n");
+
+			writeb((~ADAP_CHK_INT), ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
+			writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET  + ISRP_EVEN);
+			dev->interrupt=0;
+
+		} else if (readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN)
+				 & (TCR_INT | ERR_INT | ACCESS_INT)) {
+
+			DPRINTK("adapter error: ISRP_EVEN : %02x\n",
+				(int)readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN));
+			writeb(~(TCR_INT | ERR_INT | ACCESS_INT),
+			       ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
+			writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET  + ISRP_EVEN);
+			dev->interrupt=0;
+
+		} else if (status
+			   & (SRB_RESP_INT | ASB_FREE_INT | ARB_CMD_INT | SSB_RESP_INT)) {
+			/* SRB, ASB, ARB or SSB response */
+
+			if (status & SRB_RESP_INT) { /* SRB response */
+
+				switch(readb(ti->srb)) { /* SRB command check */
+
+				      case XMIT_DIR_FRAME: {
+					      unsigned char xmit_ret_code;
+
+					      xmit_ret_code=readb(ti->srb + offsetof(struct srb_xmit, ret_code));
+					      if (xmit_ret_code != 0xff) {
+						      DPRINTK("error on xmit_dir_frame request: %02X\n",
+							      xmit_ret_code);
+						      if (ti->current_skb) {
+							      dev_kfree_skb(ti->current_skb);
+							      ti->current_skb=NULL;
+						      }
+						      dev->tbusy=0;
+						      if (ti->readlog_pending) ibmtr_readlog(dev);
+					      }
+				      }
+				      break;
+
+				      case XMIT_UI_FRAME: {
+					      unsigned char xmit_ret_code;
+
+					      xmit_ret_code=readb(ti->srb + offsetof(struct srb_xmit, ret_code));
+					      if (xmit_ret_code != 0xff) {
+						      DPRINTK("error on xmit_ui_frame request: %02X\n",
+							      xmit_ret_code);
+						      if (ti->current_skb) {
+							      dev_kfree_skb(ti->current_skb);
+							      ti->current_skb=NULL;
+						      }
+						      dev->tbusy=0;
+						      if (ti->readlog_pending) ibmtr_readlog(dev);
+					      }
+				      }
+				      break;
+
+				      case DIR_OPEN_ADAPTER: {
+					      unsigned char open_ret_code;
+					      __u16 open_error_code;
+
+					      ti->srb=ti->sram+ntohs(readw(ti->init_srb +offsetof(struct srb_open_response, srb_addr)));
+					      ti->ssb=ti->sram+ntohs(readw(ti->init_srb +offsetof(struct srb_open_response, ssb_addr)));
+					      ti->arb=ti->sram+ntohs(readw(ti->init_srb +offsetof(struct srb_open_response, arb_addr)));
+					      ti->asb=ti->sram+ntohs(readw(ti->init_srb +offsetof(struct srb_open_response, asb_addr)));
+					      ti->current_skb=NULL;
+
+					      open_ret_code = readb(ti->init_srb +offsetof(struct srb_open_response, ret_code));
+					      open_error_code = ntohs(readw(ti->init_srb +offsetof(struct srb_open_response, error_code)));
+
+					      if (open_ret_code==7) {
+
+						      if (!ti->auto_ringspeedsave && (open_error_code==0x24)) {
+							      DPRINTK("Open failed: Adapter speed must match ring "
+								      "speed if Automatic Ring Speed Save is disabled.\n");
+							      ti->open_status=FAILURE;
+							      wake_up(&ti->wait_for_reset);
+						      } else if (open_error_code==0x24)
+							      DPRINTK("Retrying open to adjust to ring speed.\n");
+						      else if ((open_error_code==0x2d) && ti->auto_ringspeedsave)
+							      DPRINTK("No signal detected for Auto Speed Detection.\n");
+						      else if (open_error_code==0x11)
+						      {
+							      if (ti->retry_count--) 
+								      DPRINTK("Ring broken/disconnected, retrying...\n");
+							      else {
+								      DPRINTK("Ring broken/disconnected, open failed.\n");
+								      ti->open_status = FAILURE;
+							      }
+						      }
+						      else DPRINTK("Unrecoverable error: error code = %04x.\n",
+								   open_error_code);
+
+					      } else if (!open_ret_code) {
+#if !TR_NEWFORMAT
+						      DPRINTK("board opened...\n");
+#else
+						      DPRINTK("Adapter initialized and opened.\n");
+#endif
+						      writeb(~(SRB_RESP_INT),
+							     ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
+						      writeb(~(CMD_IN_SRB),
+							     ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD);
+						      open_sap(EXTENDED_SAP,dev);
+
+						      /* YdW probably hates me */
+						      goto skip_reset;
+					      } else
+						      DPRINTK("open failed: ret_code = %02X, retrying\n",
+							      open_ret_code);
+
+					      if (ti->open_status != FAILURE) {
+						      ibmtr_reset_timer(&(ti->tr_timer), dev);
+					      }
+
+				      }
+				      break;
+
+				      case DIR_CLOSE_ADAPTER:
+					wake_up(&ti->wait_for_tok_int);
+					break;
+
+				      case DLC_OPEN_SAP:
+					if (readb(ti->srb+offsetof(struct dlc_open_sap, ret_code))) {
+						DPRINTK("open_sap failed: ret_code = %02X,retrying\n",
+							(int)readb(ti->srb+offsetof(struct dlc_open_sap, ret_code)));
+						ibmtr_reset_timer(&(ti->tr_timer), dev);
+					} else {
+						ti->exsap_station_id=
+							readw(ti->srb+offsetof(struct dlc_open_sap, station_id));
+						ti->open_status=SUCCESS; /* TR adapter is now available */
+						wake_up(&ti->wait_for_reset);
+					}
+					break;
+
+				      case DIR_INTERRUPT:
+				      case DIR_MOD_OPEN_PARAMS:
+				      case DIR_SET_GRP_ADDR:
+				      case DIR_SET_FUNC_ADDR:
+				      case DLC_CLOSE_SAP:
+					if (readb(ti->srb+offsetof(struct srb_interrupt, ret_code)))
+						DPRINTK("error on %02X: %02X\n",
+							(int)readb(ti->srb+offsetof(struct srb_interrupt, command)),
+							(int)readb(ti->srb+offsetof(struct srb_interrupt, ret_code)));
+					break;
+
+				      case DIR_READ_LOG:
+					if (readb(ti->srb+offsetof(struct srb_read_log, ret_code)))
+						DPRINTK("error on dir_read_log: %02X\n",
+							(int)readb(ti->srb+offsetof(struct srb_read_log, ret_code)));
+					else
+					    if (IBMTR_DEBUG_MESSAGES) {
+						DPRINTK(
+							"Line errors %02X, Internal errors %02X, Burst errors %02X\n"
+							"A/C errors %02X, Abort delimiters %02X, Lost frames %02X\n"
+							"Receive congestion count %02X, Frame copied errors %02X\n"
+							"Frequency errors %02X, Token errors %02X\n",
+							(int)readb(ti->srb+offsetof(struct srb_read_log,
+										    line_errors)),
+							(int)readb(ti->srb+offsetof(struct srb_read_log,
+										    internal_errors)),
+							(int)readb(ti->srb+offsetof(struct srb_read_log,
+										    burst_errors)),
+							(int)readb(ti->srb+offsetof(struct srb_read_log, A_C_errors)),
+							(int)readb(ti->srb+offsetof(struct srb_read_log,
+										    abort_delimiters)),
+							(int)readb(ti->srb+offsetof(struct srb_read_log,
+										    lost_frames)),
+							(int)readb(ti->srb+offsetof(struct srb_read_log,
+												    recv_congest_count)),
+							(int)readb(ti->srb+offsetof(struct srb_read_log,
+										    frame_copied_errors)),
+							(int)readb(ti->srb+offsetof(struct srb_read_log,
+										    frequency_errors)),
+							(int)readb(ti->srb+offsetof(struct srb_read_log,
+												    token_errors)));
+					    }
+					dev->tbusy=0;
+					break;
+
+				      default:
+					DPRINTK("Unknown command %02X encountered\n",
+						(int)readb(ti->srb));
+
+				} /* SRB command check */
+
+				writeb(~CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD);
+				writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
+
+			  skip_reset:
+			} /* SRB response */
+
+			if (status & ASB_FREE_INT) { /* ASB response */
+
+				switch(readb(ti->asb)) { /* ASB command check */
+
+				      case REC_DATA:
+				      case XMIT_UI_FRAME:
+				      case XMIT_DIR_FRAME:
+					break;
+
+				      default:
+					DPRINTK("unknown command in asb %02X\n",
+						(int)readb(ti->asb));
+
+				} /* ASB command check */
+
+				if (readb(ti->asb+2)!=0xff) /* checks ret_code */
+				    DPRINTK("ASB error %02X in cmd %02X\n",
+					    (int)readb(ti->asb+2),(int)readb(ti->asb));
+				writeb(~ASB_FREE_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
+
+			} /* ASB response */
+
+			if (status & ARB_CMD_INT) { /* ARB response */
+
+				switch (readb(ti->arb)) { /* ARB command check */
+
+				      case DLC_STATUS:
+					DPRINTK("DLC_STATUS new status: %02X on station %02X\n",
+						ntohs(readw(ti->arb + offsetof(struct arb_dlc_status, status))),
+						ntohs(readw(ti->arb
+									    +offsetof(struct arb_dlc_status, station_id))));
+					break;
+
+				      case REC_DATA:
+					tr_rx(dev);
+					break;
+
+				      case RING_STAT_CHANGE: {
+					      unsigned short ring_status;
+
+					      ring_status=ntohs(readw(ti->arb
+								      +offsetof(struct arb_ring_stat_change, ring_status)));
+
+					      if (ring_status & (SIGNAL_LOSS | LOBE_FAULT)) {
+
+						      DPRINTK("Signal loss/Lobe fault\n");
+						      DPRINTK("We try to reopen the adapter.\n");
+						      ibmtr_reset_timer(&(ti->tr_timer), dev);
+					      } else if (ring_status & (HARD_ERROR | XMIT_BEACON
+											| AUTO_REMOVAL | REMOVE_RECV | RING_RECOVER))
+						      DPRINTK("New ring status: %02X\n", ring_status);
+
+					      if (ring_status & LOG_OVERFLOW) {
+						      if (dev->tbusy)
+                                                              ti->readlog_pending = 1;
+						      else
+                                                              ibmtr_readlog(dev);
+					      }
+				      }
+				      break;
+
+				      case XMIT_DATA_REQ:
+					tr_tx(dev);
+					break;
+
+				      default:
+					DPRINTK("Unknown command %02X in arb\n",
+						(int)readb(ti->arb));
+					break;
+
+				} /* ARB command check */
+
+				writeb(~ARB_CMD_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
+				writeb(ARB_FREE, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+
+			} /* ARB response */
+
+			if (status & SSB_RESP_INT) { /* SSB response */
+				unsigned char retcode;
+				switch (readb(ti->ssb)) { /* SSB command check */
+				      
+				      case XMIT_DIR_FRAME:
+				      case XMIT_UI_FRAME:
+					retcode = readb(ti->ssb+2);
+					if (retcode && (retcode != 0x22)) /* checks ret_code */
+						DPRINTK("xmit ret_code: %02X xmit error code: %02X\n",
+							(int)retcode, (int)readb(ti->ssb+6));
+					else ti->tr_stats.tx_packets++;
+					break;
+
+				      case XMIT_XID_CMD:
+					DPRINTK("xmit xid ret_code: %02X\n", (int)readb(ti->ssb+2));
+
+				      default:
+					DPRINTK("Unknown command %02X in ssb\n", (int)readb(ti->ssb));
+
+				} /* SSB command check */
+
+				writeb(~SSB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
+				writeb(SSB_FREE, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+
+			} /* SSB response */
+
+		}	 /* SRB, ARB, ASB or SSB response */
+
+		dev->interrupt=0;
+		writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
+		break;
+
+	      case FIRST_INT:
+		initial_tok_int(dev);
+		break;
+
+	      default:
+		DPRINTK("Unexpected interrupt from tr adapter\n");
+
+	}
+	spin_unlock(&(ti->lock));
+}
+
+static void initial_tok_int(struct net_device *dev)
+{
+
+	__u32 encoded_addr;
+	__u32 hw_encoded_addr;
+	struct tok_info *ti;
+	ti=(struct tok_info *) dev->priv;
+
+	ti->do_tok_int=NOT_FIRST;
+
+#ifndef TR_NEWFORMAT
+	DPRINTK("Initial tok int received\n");
+#endif
+
+	/* we assign the shared-ram address for ISA devices */
+	if(!ti->sram) {
+		writeb(ti->sram_base, ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN);
+		ti->sram=((__u32)ti->sram_base << 12);
+	}
+	ti->init_srb=ti->sram
+		+ntohs((unsigned short)readw(ti->mmio+ ACA_OFFSET + WRBR_EVEN));
+	SET_PAGE(ntohs((unsigned short)readw(ti->mmio+ACA_OFFSET + WRBR_EVEN)));
+
+	dev->mem_start = ti->sram;
+	dev->mem_end = ti->sram + (ti->mapped_ram_size<<9) - 1;
+
+#if TR_VERBOSE
+	{
+		int i;
+		DPRINTK("init_srb(%p):", ti->init_srb);
+		for (i=0;i<17;i++) printk("%02X ", (int)readb(ti->init_srb+i));
+		printk("\n");
+	}
+#endif
+
+	hw_encoded_addr = readw(ti->init_srb
+				+ offsetof(struct srb_init_response, encoded_address));
+
+#if !TR_NEWFORMAT
+	DPRINTK("srb_init_response->encoded_address: %04X\n", hw_encoded_addr);
+	DPRINTK("ntohs(srb_init_response->encoded_address): %04X\n",
+		ntohs(hw_encoded_addr));
+#endif
+
+	encoded_addr=(ti->sram + ntohs(hw_encoded_addr));
+	ti->ring_speed = readb(ti->init_srb+offsetof(struct srb_init_response, init_status)) & 0x01 ? 16 : 4;
+#if !TR_NEWFORMAT
+	DPRINTK("encoded addr (%04X,%04X,%08X): ", hw_encoded_addr,
+		ntohs(hw_encoded_addr), encoded_addr);
+#else
+	DPRINTK("Initial interrupt : %d Mbps, shared RAM base %08x.\n",
+		ti->ring_speed, ti->sram);
+#endif
+
+	ti->auto_ringspeedsave=readb(ti->init_srb
+				     +offsetof(struct srb_init_response, init_status_2)) & 0x4 ? TRUE : FALSE;
+
+#if !TR_NEWFORMAT
+	for(i=0;i<TR_ALEN;i++) {
+		dev->dev_addr[i]=readb(encoded_addr + i);
+		printk("%02X%s", dev->dev_addr[i], (i==TR_ALEN-1) ? "" : ":" );
+	}
+	printk("\n");
+#endif
+
+	tok_open_adapter((unsigned long)dev);
+}
+
+static int tok_init_card(struct net_device *dev)
+{
+	struct tok_info *ti;
+	short PIOaddr;
+	unsigned long i;
+	PIOaddr = dev->base_addr;
+	ti=(struct tok_info *) dev->priv;
+
+	/* Special processing for first interrupt after reset */
+	ti->do_tok_int=FIRST_INT;
+
+	/* Reset adapter */
+	dev->tbusy=1; /* nothing can be done before reset and open completed */
+
+#ifdef ENABLE_PAGING
+	if(ti->page_mask)
+		writeb(SRPR_ENABLE_PAGING, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN);
+#endif
+
+	writeb(~INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
+
+#if !TR_NEWFORMAT
+	DPRINTK("resetting card\n");
+#endif
+
+	outb(0, PIOaddr+ADAPTRESET);
+	for (i=jiffies+TR_RESET_INTERVAL; time_before_eq(jiffies, i);); /* wait 50ms */
+	outb(0,PIOaddr+ADAPTRESETREL);
+
+#if !TR_NEWFORMAT
+	DPRINTK("card reset\n");
+#endif
+
+	ti->open_status=IN_PROGRESS;
+	writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
+	return 0;
+}
+
+static void open_sap(unsigned char type,struct net_device *dev)
+{
+	int i;
+	struct tok_info *ti=(struct tok_info *) dev->priv;
+
+	SET_PAGE(ti->srb);
+	for (i=0; i<sizeof(struct dlc_open_sap); i++)
+		writeb(0, ti->srb+i);
+
+	writeb(DLC_OPEN_SAP, ti->srb + offsetof(struct dlc_open_sap, command));
+	writew(htons(MAX_I_FIELD),
+	       ti->srb + offsetof(struct dlc_open_sap, max_i_field));
+	writeb(SAP_OPEN_IND_SAP | SAP_OPEN_PRIORITY,
+	       ti->srb + offsetof(struct dlc_open_sap, sap_options));
+	writeb(SAP_OPEN_STATION_CNT,
+	       ti->srb + offsetof(struct dlc_open_sap, station_count));
+	writeb(type, ti->srb + offsetof(struct dlc_open_sap, sap_value));
+
+	writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+
+}
+
+void tok_open_adapter(unsigned long dev_addr)
+{
+
+	struct net_device *dev=(struct net_device *)dev_addr;
+	struct tok_info *ti;
+	int i;
+
+	ti=(struct tok_info *) dev->priv;
+
+#if !TR_NEWFORMAT
+	DPRINTK("now opening the board...\n");
+#endif
+
+	writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
+	writeb(~CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD);
+
+	for (i=0; i<sizeof(struct dir_open_adapter); i++)
+		writeb(0, ti->init_srb+i);
+
+	writeb(DIR_OPEN_ADAPTER,
+	       ti->init_srb + offsetof(struct dir_open_adapter, command));
+	writew(htons(OPEN_PASS_BCON_MAC),
+	       ti->init_srb + offsetof(struct dir_open_adapter, open_options));
+	if (ti->ring_speed == 16) {
+		writew(htons(ti->dhb_size16mb),
+		       ti->init_srb + offsetof(struct dir_open_adapter, dhb_length));
+		writew(htons(ti->rbuf_cnt16),
+		       ti->init_srb + offsetof(struct dir_open_adapter, num_rcv_buf));
+		writew(htons(ti->rbuf_len16),
+		       ti->init_srb + offsetof(struct dir_open_adapter, rcv_buf_len));
+	} else {
+		writew(htons(ti->dhb_size4mb),
+		       ti->init_srb + offsetof(struct dir_open_adapter, dhb_length));
+		writew(htons(ti->rbuf_cnt4),
+		       ti->init_srb + offsetof(struct dir_open_adapter, num_rcv_buf));
+		writew(htons(ti->rbuf_len4),
+		       ti->init_srb + offsetof(struct dir_open_adapter, rcv_buf_len));
+	}
+	writeb(NUM_DHB, /* always 2 */ 
+	       ti->init_srb + offsetof(struct dir_open_adapter, num_dhb));
+	writeb(DLC_MAX_SAP,
+	       ti->init_srb + offsetof(struct dir_open_adapter, dlc_max_sap));
+	writeb(DLC_MAX_STA,
+	       ti->init_srb + offsetof(struct dir_open_adapter, dlc_max_sta));
+
+	ti->srb=ti->init_srb; /* We use this one in the interrupt handler */
+
+	writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
+	writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+
+}
+
+static void tr_tx(struct net_device *dev)
+{
+	struct tok_info *ti=(struct tok_info *) dev->priv;
+	struct trh_hdr *trhdr=(struct trh_hdr *)ti->current_skb->data;
+	unsigned int hdr_len;
+	__u32 dhb;
+	unsigned char xmit_command;
+	int i;
+	struct trllc	*llc;
+
+	if (readb(ti->asb + offsetof(struct asb_xmit_resp, ret_code))!=0xFF)
+		DPRINTK("ASB not free !!!\n");
+
+	/* in providing the transmit interrupts,
+	   is telling us it is ready for data and
+	   providing a shared memory address for us
+	   to stuff with data.  Here we compute the
+	   effective address where we will place data.*/
+	dhb=ti->sram
+		+ntohs(readw(ti->arb + offsetof(struct arb_xmit_req, dhb_address)));
+	
+	/* Figure out the size of the 802.5 header */
+	if (!(trhdr->saddr[0] & 0x80)) /* RIF present? */
+		hdr_len=sizeof(struct trh_hdr)-TR_MAXRIFLEN;
+	else 
+		hdr_len=((ntohs(trhdr->rcf) & TR_RCF_LEN_MASK)>>8)
+			+sizeof(struct trh_hdr)-TR_MAXRIFLEN;
+
+	llc = (struct trllc *)(ti->current_skb->data + hdr_len);
+
+	xmit_command = readb(ti->srb + offsetof(struct srb_xmit, command));
+
+	writeb(xmit_command, ti->asb + offsetof(struct asb_xmit_resp, command));
+	writew(readb(ti->srb + offsetof(struct srb_xmit, station_id)),
+	       ti->asb + offsetof(struct asb_xmit_resp, station_id));
+	writeb(llc->ssap, ti->asb + offsetof(struct asb_xmit_resp, rsap_value));
+	writeb(readb(ti->srb + offsetof(struct srb_xmit, cmd_corr)),
+	       ti->asb + offsetof(struct asb_xmit_resp, cmd_corr));
+	writeb(0, ti->asb + offsetof(struct asb_xmit_resp, ret_code));
+
+	if ((xmit_command==XMIT_XID_CMD) || (xmit_command==XMIT_TEST_CMD)) {
+
+		writew(htons(0x11),
+		       ti->asb + offsetof(struct asb_xmit_resp, frame_length));
+		writeb(0x0e, ti->asb + offsetof(struct asb_xmit_resp, hdr_length));
+		writeb(AC, dhb);
+		writeb(LLC_FRAME, dhb+1);
+
+		for (i=0; i<TR_ALEN; i++) writeb((int)0x0FF, dhb+i+2);
+		for (i=0; i<TR_ALEN; i++) writeb(0, dhb+i+TR_ALEN+2);
+
+		writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+		return;
+
+	}
+
+	/*
+	 *      the token ring packet is copied from sk_buff to the adapter
+	 *      buffer identified in the command data received with the interrupt.
+	 */
+	writeb(hdr_len, ti->asb + offsetof(struct asb_xmit_resp, hdr_length));
+	writew(htons(ti->current_skb->len),
+	       ti->asb + offsetof(struct asb_xmit_resp, frame_length));
+
+	memcpy_toio(dhb, ti->current_skb->data, ti->current_skb->len);
+
+	writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+	ti->tr_stats.tx_bytes+=ti->current_skb->len;
+	dev->tbusy=0;
+	dev_kfree_skb(ti->current_skb);
+	ti->current_skb=NULL;
+	mark_bh(NET_BH);
+	if (ti->readlog_pending) ibmtr_readlog(dev);
+}
+
+static void tr_rx(struct net_device *dev)
+{
+	struct tok_info *ti=(struct tok_info *) dev->priv;
+	__u32 rbuffer, rbufdata;
+	__u32 llc;
+	unsigned char *data;
+	unsigned int rbuffer_len, lan_hdr_len, hdr_len, ip_len, length;
+	struct sk_buff *skb;
+	unsigned int skb_size = 0;
+	int	IPv4_p = 0;
+	unsigned int chksum = 0;
+	struct iphdr *iph;
+
+	rbuffer=(ti->sram
+		 +ntohs(readw(ti->arb + offsetof(struct arb_rec_req, rec_buf_addr))))+2;
+ 
+	if(readb(ti->asb + offsetof(struct asb_rec, ret_code))!=0xFF)
+		DPRINTK("ASB not free !!!\n");
+
+	writeb(REC_DATA,
+	       ti->asb + offsetof(struct asb_rec, command));
+	writew(readw(ti->arb + offsetof(struct arb_rec_req, station_id)),
+	       ti->asb + offsetof(struct asb_rec, station_id));
+	writew(readw(ti->arb + offsetof(struct arb_rec_req, rec_buf_addr)),
+	       ti->asb + offsetof(struct asb_rec, rec_buf_addr));
+
+	lan_hdr_len=readb(ti->arb + offsetof(struct arb_rec_req, lan_hdr_len));
+	hdr_len = lan_hdr_len + sizeof(struct trllc) + sizeof(struct iphdr);
+	
+	llc=(rbuffer + offsetof(struct rec_buf, data) + lan_hdr_len);
+
+#if TR_VERBOSE
+	DPRINTK("offsetof data: %02X lan_hdr_len: %02X\n",
+		(unsigned int)offsetof(struct rec_buf,data), (unsigned int)lan_hdr_len);
+	DPRINTK("llc: %08X rec_buf_addr: %04X ti->sram: %p\n", llc,
+		ntohs(readw(ti->arb + offsetof(struct arb_rec_req, rec_buf_addr))),
+		ti->sram);
+	DPRINTK("dsap: %02X, ssap: %02X, llc: %02X, protid: %02X%02X%02X, "
+		"ethertype: %04X\n",
+		(int)readb(llc + offsetof(struct trllc, dsap)),
+		(int)readb(llc + offsetof(struct trllc, ssap)),
+		(int)readb(llc + offsetof(struct trllc, llc)),
+		(int)readb(llc + offsetof(struct trllc, protid)),
+		(int)readb(llc + offsetof(struct trllc, protid)+1),
+		(int)readb(llc + offsetof(struct trllc, protid)+2),
+		(int)readw(llc + offsetof(struct trllc, ethertype)));
+#endif
+	if (readb(llc + offsetof(struct trllc, llc))!=UI_CMD) {
+		writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code));
+		ti->tr_stats.rx_dropped++;
+		writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+		return;
+	}
+
+	length = ntohs(readw(ti->arb+offsetof(struct arb_rec_req, frame_len)));
+       	if ((readb(llc + offsetof(struct trllc, dsap))==EXTENDED_SAP) &&
+       	    (readb(llc + offsetof(struct trllc, ssap))==EXTENDED_SAP) &&
+		(length>=hdr_len)) {
+       		IPv4_p = 1;
+       	}
+
+#if TR_VERBOSE
+       	if (!IPv4_p){
+
+       		__u32 trhhdr;
+
+       		trhhdr=(rbuffer+offsetof(struct rec_buf,data));
+
+       		DPRINTK("Probably non-IP frame received.\n");
+       		DPRINTK("ssap: %02X dsap: %02X saddr: %02X:%02X:%02X:%02X:%02X:%02X "
+       			"daddr: %02X:%02X:%02X:%02X:%02X:%02X\n",
+       			(int)readb(llc + offsetof(struct trllc, ssap)),
+       			(int)readb(llc + offsetof(struct trllc, dsap)),
+       			(int)readb(trhhdr + offsetof(struct trh_hdr, saddr)),
+       			(int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+1),
+       			(int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+2),
+       			(int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+3),
+       			(int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+4),
+       			(int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+5),
+       			(int)readb(trhhdr + offsetof(struct trh_hdr, daddr)),
+       			(int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+1),
+       			(int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+2),
+       			(int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+3),
+       			(int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+4),
+       			(int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+5));
+       	}
+#endif
+
+       	skb_size = length-lan_hdr_len+sizeof(struct trh_hdr)+sizeof(struct trllc);
+ 
+       	if (!(skb=dev_alloc_skb(skb_size))) {
+       		DPRINTK("out of memory. frame dropped.\n");
+       		ti->tr_stats.rx_dropped++;
+       		writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code));
+       		writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+       		return;
+       	}
+
+      	skb_put(skb, length);
+	skb_reserve(skb, sizeof(struct trh_hdr)-lan_hdr_len+sizeof(struct trllc));
+       	skb->dev=dev;
+       	data=skb->data;
+	rbuffer_len=ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len)));
+	rbufdata = rbuffer + offsetof(struct rec_buf,data);
+
+	if (IPv4_p) {
+                /* Copy the headers without checksumming */
+		memcpy_fromio(data, rbufdata, hdr_len);
+
+		/* Watch for padded packets and bogons */
+		iph=(struct iphdr*)(data + lan_hdr_len + sizeof(struct trllc));
+		ip_len = ntohs(iph->tot_len) - sizeof(struct iphdr);
+		length -= hdr_len;
+		if ((ip_len <= length) && (ip_len > 7))
+			length = ip_len;
+		data += hdr_len;
+		rbuffer_len -= hdr_len;
+		rbufdata += hdr_len;
+        }
+
+	/* Copy the payload... */
+	for (;;) {
+		if (IPv4_p)
+			chksum = csum_partial_copy(bus_to_virt(rbufdata), data,
+						   length < rbuffer_len ? length : rbuffer_len,
+						   chksum);
+		else
+			memcpy_fromio(data, rbufdata, rbuffer_len);
+		rbuffer = ntohs(readw(rbuffer));
+		if (!rbuffer)
+			break;
+		length -= rbuffer_len;
+		data += rbuffer_len;
+		rbuffer += ti->sram;
+		rbuffer_len = ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len)));
+		rbufdata = rbuffer + offsetof(struct rec_buf, data);
+	}
+
+       	writeb(0, ti->asb + offsetof(struct asb_rec, ret_code));
+
+       	writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+
+	ti->tr_stats.rx_bytes += skb->len;
+       	ti->tr_stats.rx_packets++;
+
+	skb->protocol = tr_type_trans(skb,dev);
+ 	if (IPv4_p){ 
+		skb->csum      = chksum;
+		skb->ip_summed = 1;
+	}
+	netif_rx(skb);
+}
+
+static int tok_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+	struct tok_info *ti;
+	ti=(struct tok_info *) dev->priv;
+
+	if (dev->tbusy) {
+		int ticks_waited;
+
+		ticks_waited=jiffies - dev->trans_start;
+		if (ticks_waited<TR_BUSY_INTERVAL) return 1;
+
+		DPRINTK("Arrg. Transmitter busy.\n");
+		dev->trans_start+=5; /* we fake the transmission start time... */
+		return 1;
+	}
+
+	if (test_and_set_bit(0,(void *)&dev->tbusy)!=0)
+		DPRINTK("Transmitter access conflict\n");
+	else {
+		int flags;
+
+		/* lock against other CPUs */
+		spin_lock_irqsave(&(ti->lock), flags);
+
+		/* Save skb; we'll need it when the adapter asks for the data */
+		ti->current_skb=skb;
+		writeb(XMIT_UI_FRAME, ti->srb + offsetof(struct srb_xmit, command));
+		writew(ti->exsap_station_id, ti->srb
+		       +offsetof(struct srb_xmit, station_id));
+		writeb(CMD_IN_SRB, (ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD));
+		spin_unlock_irqrestore(&(ti->lock), flags);
+
+		dev->trans_start=jiffies;
+	}
+
+	return 0;
+}
+
+void ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev) {
+	tmr->expires  = jiffies + TR_RETRY_INTERVAL;
+	tmr->data     = (unsigned long) dev;
+	tmr->function = tok_open_adapter;
+	init_timer(tmr);
+	add_timer(tmr);
+}
+
+void ibmtr_readlog(struct net_device *dev) {
+	 struct tok_info *ti;
+	 ti=(struct tok_info *) dev->priv;
+
+	 ti->readlog_pending = 0;
+	 writeb(DIR_READ_LOG, ti->srb);
+	 writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
+	 writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+	 dev->tbusy=1; /* really srb busy... */
+}
+
+/* tok_get_stats():  Basically a scaffold routine which will return
+   the address of the tr_statistics structure associated with
+   this device -- the tr.... structure is an ethnet look-alike
+   so at least for this iteration may suffice.   */
+
+static struct net_device_stats * tok_get_stats(struct net_device *dev) {
+
+	struct tok_info *toki;
+	toki=(struct tok_info *) dev->priv;
+	return (struct net_device_stats *) &toki->tr_stats;
+}
+
+int ibmtr_change_mtu(struct net_device *dev, int mtu) {
+	struct tok_info *ti = (struct tok_info *) dev->priv;
+	
+	if (ti->ring_speed == 16 && mtu > ti->maxmtu16)
+		return -EINVAL;
+	if (ti->ring_speed == 4 && mtu > ti->maxmtu4)
+		return -EINVAL;
+	dev->mtu = mtu;
+	return 0;
+}
+
+#ifdef MODULE
+
+/* 3COM 3C619C supports 8 interrupts, 32 I/O ports */
+static struct net_device* dev_ibmtr[IBMTR_MAX_ADAPTERS];
+static int io[IBMTR_MAX_ADAPTERS] = {0xa20,0xa24};
+static int irq[IBMTR_MAX_ADAPTERS] = {0,0};
+static int mem[IBMTR_MAX_ADAPTERS] = {0,0};
+
+MODULE_PARM(io, "1-" __MODULE_STRING(IBMTR_MAX_ADAPTERS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(IBMTR_MAX_ADAPTERS) "i");
+MODULE_PARM(mem, "1-" __MODULE_STRING(IBMTR_MAX_ADAPTERS) "i");
+
+int init_module(void)
+{
+        int i;
+        for (i = 0; io[i] && (i<IBMTR_MAX_ADAPTERS); i++) {
+	        irq[i] = 0;
+		mem[i] = 0;
+		dev_ibmtr[i] = NULL;
+                dev_ibmtr[i] = init_trdev(dev_ibmtr[i], 0);
+                if (dev_ibmtr[i] == NULL)
+                        return -ENOMEM;
+
+	        dev_ibmtr[i]->base_addr = io[i];
+	        dev_ibmtr[i]->irq       = irq[i];
+		dev_ibmtr[i]->mem_start = mem[i];
+		dev_ibmtr[i]->init      = &ibmtr_probe;
+
+	        if (register_trdev(dev_ibmtr[i]) != 0) {
+			kfree_s(dev_ibmtr[i], sizeof(struct net_device));
+			dev_ibmtr[i] = NULL;
+		        if (i == 0) {
+			        printk("ibmtr: register_trdev() returned non-zero.\n");
+		                return -EIO;
+			} else {
+			        return 0;
+			}
+	        }
+	}
+	return 0;
+}
+
+void cleanup_module(void)
+{
+        int i;
+
+        for (i = 0; i < IBMTR_MAX_ADAPTERS; i++)
+	        if (dev_ibmtr[i]) {
+			 unregister_trdev(dev_ibmtr[i]);
+			 free_irq(dev_ibmtr[i]->irq, dev_ibmtr[i]);
+			 release_region(dev_ibmtr[i]->base_addr, IBMTR_IO_EXTENT);
+			 kfree_s(dev_ibmtr[i]->priv, sizeof(struct tok_info));
+			 kfree_s(dev_ibmtr[i], sizeof(struct net_device));
+			 dev_ibmtr[i] = NULL;
+                }
+}
+#endif /* MODULE */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/tokenring/ibmtr.h linux/drivers/net/tokenring/ibmtr.h
--- v2.3.20/linux/drivers/net/tokenring/ibmtr.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/tokenring/ibmtr.h	Mon Oct 11 10:13:24 1999
@@ -0,0 +1,449 @@
+/* Definitions for an IBM Token Ring card. */
+/* This file is distributed under the GNU GPL   */
+
+/* ported to the Alpha architecture 02/20/96 (just used the HZ macro) */
+
+#define TR_RETRY_INTERVAL (5*HZ) /* 500 on PC = 5 s */
+#define TR_RESET_INTERVAL (HZ/20) /* 5 on PC = 50 ms */
+#define TR_BUSY_INTERVAL (HZ/5) /* 5 on PC = 200 ms */
+#define TR_SPIN_INTERVAL (3*HZ) /* 3 seconds before init timeout */
+#define TR_RETRIES 6            /* number of open retries */ 
+
+#define TR_ISA 1
+#define TR_MCA 2
+#define TR_ISAPNP 3
+#define NOTOK 0
+#define TOKDEBUG 1
+
+#define IBMTR_SHARED_RAM_SIZE 0x10000
+#define IBMTR_IO_EXTENT 4
+#define IBMTR_MAX_ADAPTERS 2
+
+#define CHANNEL_ID      0X1F30
+#define AIP             0X1F00
+#define AIPCHKSUM1      0X1F60
+#define AIPCHKSUM2      0X1FF0
+#define AIPADAPTYPE     0X1FA0
+#define AIPDATARATE     0X1FA2
+#define AIPEARLYTOKEN   0X1FA4
+#define AIPAVAILSHRAM   0X1FA6
+#define AIPSHRAMPAGE    0X1FA8
+#define AIP4MBDHB       0X1FAA
+#define AIP16MBDHB      0X1FAC
+#define AIPFID		0X1FBA
+
+/* Note, 0xA20 == 0x220 since motherboard decodes 10 bits.  I left everything
+   the way my documentation had it, ie: 0x0A20.     */
+#define ADAPTINTCNTRL   0x02f0  /* Adapter interrupt control */
+#define ADAPTRESET      0x1     /* Control Adapter reset (add to base) */
+#define ADAPTRESETREL   0x2     /* Release Adapter from reset ( """)  */
+#define ADAPTINTREL	0x3 	/* Adapter interrupt release */
+
+#define MMIOStartLocP   0x0a20  /* Primary adapter's starting MMIO area */
+#define MMIOStartLocA   0x0a24  /* Alternate adapter's starting MMIO area */
+
+#define GLOBAL_INT_ENABLE 0x02f0
+
+/* MMIO bits 0-4 select register */
+#define RRR_EVEN        0x00    /* Shared RAM relocation registers - even and odd */
+/* Used to set the starting address of shared RAM  */
+/* Bits 1 through 7 of this register map to bits 13 through 19 of the shared RAM address.*/
+/* ie: 0x02 sets RAM address to ...ato!  issy su wazzoo !! GODZILLA!!! */
+#define RRR_ODD         0x01
+/* Bits 2 and 3 of this register can be read to determine shared RAM size */
+/* 00 for 8k, 01 for 16k, 10 for 32k, 11 for 64k  */
+#define WRBR_EVEN       0x02    /* Write region base registers - even and odd */
+#define WRBR_ODD        0x03
+#define WWOR_EVEN       0x04    /* Write window open registers - even and odd */
+#define WWOR_ODD        0x05
+#define WWCR_EVEN       0x06    /* Write window close registers - even and odd */
+#define WWCR_ODD        0x07
+
+/* Interrupt status registers - PC system  - even and odd */
+#define ISRP_EVEN       0x08
+
+#define TCR_INT 0x10    /* Bit 4 - Timer interrupt.  The TVR_EVEN timer has
+                                                                   expired. */
+#define ERR_INT 0x08    /* Bit 3 - Error interrupt.  The adapter has had an
+                                                                   internal error. */
+#define ACCESS_INT 0x04    /* Bit 2 - Access interrupt.  You have attempted to
+                                                           write to an invalid area of shared RAM or an invalid
+                                                                   register within the MMIO. */
+/*      In addition, the following bits within ISRP_EVEN can be turned on or off by you */
+/*      to control the interrupt processing:   */
+#define INT_IRQ 0x80    /* Bit 7 - If 0 the adapter will issue a CHCK, if 1 and
+                                                              IRQ.  This should normally be set (by you) to 1.  */
+#define INT_ENABLE 0x40 /* Bit 6 - Interrupt enable.  If 0, no interrupts will
+                                                                   occur.  If 1, interrupts will occur normally.
+                                                                   Normally set to 1.  */
+/* Bit 0 - Primary or alternate adapter.  Set to zero if this adapter is the primary adapter,*/
+/*         1 if this adapter is the alternate adapter. */
+
+
+#define ISRP_ODD        0x09
+
+#define ADAP_CHK_INT 0x40 /* Bit 6 - Adapter check.  the adapter has
+                             encountered a serious problem and has closed
+                             itself.  Whoa.  */
+#define SRB_RESP_INT 0x20 /* Bit 5 - SRB response.  The adapter has accepted
+                             an SRB request and set the return code within
+                             the SRB. */
+#define ASB_FREE_INT 0x10 /* Bit 4 - ASB free.  The adapter has read the ASB
+                                                                          and this area can be safely reused. This interrupt
+                                                                          is only used if your application has set the ASB
+                                                                          free request bit in ISRA_ODD or if an error was
+                                                                detected in your response. */
+#define ARB_CMD_INT  0x08 /* Bit 3 - ARB command.  The adapter has given you a
+                                                                          command for action.  The command is located in the
+                                                                          ARB area of shared memory. */
+#define SSB_RESP_INT 0x04 /* Bit 2 - SSB response.  The adapter has posted a
+                                                                          response to your SRB (the response is located in
+                                                                          the SSB area of shared memory). */
+/* Bit 1 - Bridge frame forward complete. */
+
+
+
+#define ISRA_EVEN       0x0A    /* Interrupt status registers - adapter  - even and odd */
+/* Bit 7 - Internal parity error (on adapter's internal bus) */
+/* Bit 6 - Timer interrupt pending */
+/* Bit 5 - Access interrupt (attempt by adapter to access illegal address) */
+/* Bit 4 - Adapter microcode problem (microcode dead-man timer expired) */
+/* Bit 3 - Adapter processor check status */
+/* Bit 2 - Reserved */
+/* Bit 1 - Adapter hardware interrupt mask (prevents internal interrupts) */
+/* Bit 0 - Adapter software interrupt mask (prevents internal software interrupts) */
+
+#define ISRA_ODD        0x0B
+#define CMD_IN_SRB 0x20 /* Bit 5  - Indicates that you have placed a new
+                           command in the SRB and are ready for the adapter to
+                           process the command. */
+#define RESP_IN_ASB 0x10 /* Bit 4 - Indicates that you have placed a response
+                                                                    (an ASB) in the shared RAM which is available for
+                                                                         the adapter's use. */
+/* Bit 3 - Indicates that you are ready to put an SRB in the shared RAM, but that a previous */
+/*         command is still pending.  The adapter will then interrupt you when the previous */
+/*         command is completed */
+/* Bit 2 - Indicates that you are ready to put an ASB in the shared RAM, but that a previous */
+/*         ASB is still pending.  The adapter will then interrupt you when the previous ASB */
+/*         is copied.  */
+#define ARB_FREE 0x2
+#define SSB_FREE 0x1
+
+#define TCR_EVEN        0x0C    /* Timer control registers - even and odd */
+#define TCR_ODD         0x0D
+#define TVR_EVEN        0x0E    /* Timer value registers - even and odd */
+#define TVR_ODD         0x0F
+#define SRPR_EVEN       0x10    /* Shared RAM paging registers - even and odd */
+#define SRPR_ENABLE_PAGING 0xc0
+#define SRPR_ODD        0x11 /* Not used. */
+#define TOKREAD         0x60
+#define TOKOR           0x40
+#define TOKAND          0x20
+#define TOKWRITE        0x00
+
+/* MMIO bits 5-6 select operation */
+/* 00 is used to write to a register */
+/* 01 is used to bitwise AND a byte with a register */
+/* 10 is used to bitwise OR a byte with a register  */
+/* 11 is used to read from a register */
+
+/* MMIO bits 7-8 select area of interest.. see below */
+/* 00 selects attachment control area. */
+/* 01 is reserved. */
+/* 10 selects adapter identification area A containing the adapter encoded address. */
+/* 11 selects the adapter identification area B containing test patterns. */
+
+#define PCCHANNELID 5049434F3631313039393020
+#define MCCHANNELID 4D4152533633583435313820
+
+#define ACA_OFFSET 0x1e00
+#define ACA_SET 0x40
+#define ACA_RESET 0x20
+#define ACA_RW 0x00
+
+#ifdef ENABLE_PAGING
+#define SET_PAGE(x) (writeb(((x>>8)&ti.page_mask), \
+  ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN))
+#else
+#define SET_PAGE(x)
+#endif
+
+typedef enum { IN_PROGRESS, SUCCESS, FAILURE, CLOSED } open_state;
+
+/* do_tok_int possible values */
+#define FIRST_INT 1
+#define NOT_FIRST 2
+
+struct tok_info {
+	unsigned char irq;
+	__u32 mmio;
+	unsigned char hw_address[32];
+	unsigned char adapter_type;
+	unsigned char data_rate;
+	unsigned char token_release;
+	unsigned char avail_shared_ram;
+	unsigned char shared_ram_paging;
+	unsigned short dhb_size4mb;
+	unsigned short rbuf_len4;
+	unsigned short rbuf_cnt4;
+	unsigned short maxmtu4;
+	unsigned short dhb_size16mb;
+	unsigned short rbuf_len16;
+	unsigned short rbuf_cnt16;
+	unsigned short maxmtu16;
+	/* Additions by David Morris       */
+	unsigned char do_tok_int;
+	wait_queue_head_t wait_for_tok_int;
+	wait_queue_head_t wait_for_reset;
+	unsigned char sram_base;
+	/* Additions by Peter De Schrijver */
+	unsigned char page_mask;          /* mask to select RAM page to Map*/
+	unsigned char mapped_ram_size;    /* size of RAM page */
+	__u32 sram;                       /* Shared memory base address */
+	__u32 init_srb;                   /* Initial System Request Block address */
+	__u32 srb;                        /* System Request Block address */
+	__u32 ssb;                        /* System Status Block address */
+	__u32 arb;                        /* Adapter Request Block address */
+	__u32 asb;                        /* Adapter Status Block address */
+	unsigned short exsap_station_id;
+	unsigned short global_int_enable;
+	struct sk_buff *current_skb;
+	struct net_device_stats tr_stats;
+	unsigned char auto_ringspeedsave;
+	open_state open_status;
+	unsigned char readlog_pending;
+	unsigned short adapter_int_enable; /* Adapter-specific int enable */
+        struct timer_list tr_timer;
+	unsigned char ring_speed;
+	__u32 func_addr;
+	unsigned int retry_count;
+	spinlock_t lock;		/* SMP protection */
+};
+
+/* token ring adapter commands */
+#define DIR_INTERRUPT 		0x00 /* struct srb_interrupt */
+#define DIR_MOD_OPEN_PARAMS 	0x01
+#define DIR_OPEN_ADAPTER 	0x03 /* struct dir_open_adapter */
+#define DIR_CLOSE_ADAPTER   	0x04
+#define DIR_SET_GRP_ADDR    	0x06
+#define DIR_SET_FUNC_ADDR   	0x07 /* struct srb_set_funct_addr */
+#define DIR_READ_LOG 		0x08 /* struct srb_read_log */
+#define DLC_OPEN_SAP 		0x15 /* struct dlc_open_sap */
+#define DLC_CLOSE_SAP       	0x16
+#define DATA_LOST 		0x20 /* struct asb_rec */
+#define REC_DATA 		0x81 /* struct arb_rec_req */
+#define XMIT_DATA_REQ 		0x82 /* struct arb_xmit_req */
+#define DLC_STATUS 		0x83 /* struct arb_dlc_status */
+#define RING_STAT_CHANGE    	0x84 /* struct dlc_open_sap ??? */
+
+/* DIR_OPEN_ADAPTER options */
+#define OPEN_PASS_BCON_MAC 0x0100
+#define NUM_RCV_BUF 2
+#define RCV_BUF_LEN 1024
+#define DHB_LENGTH 2048
+#define NUM_DHB 2
+#define DLC_MAX_SAP 2
+#define DLC_MAX_STA 1
+
+/* DLC_OPEN_SAP options */
+#define MAX_I_FIELD 0x0088
+#define SAP_OPEN_IND_SAP 0x04
+#define SAP_OPEN_PRIORITY 0x20
+#define SAP_OPEN_STATION_CNT 0x1
+#define XMIT_DIR_FRAME 0x0A
+#define XMIT_UI_FRAME  0x0d
+#define XMIT_XID_CMD   0x0e
+#define XMIT_TEST_CMD  0x11
+
+/* srb close return code */
+#define SIGNAL_LOSS  0x8000
+#define HARD_ERROR   0x4000
+#define XMIT_BEACON  0x1000
+#define LOBE_FAULT   0x0800
+#define AUTO_REMOVAL 0x0400
+#define REMOVE_RECV  0x0100
+#define LOG_OVERFLOW 0x0080
+#define RING_RECOVER 0x0020
+
+struct srb_init_response {
+	unsigned char command;
+	unsigned char init_status;
+	unsigned char init_status_2;
+	unsigned char reserved[3];
+	__u16 bring_up_code;
+	__u16 encoded_address;
+	__u16 level_address;
+	__u16 adapter_address;
+	__u16 parms_address;
+	__u16 mac_address;
+};
+
+struct dir_open_adapter {
+	unsigned char command;
+	char reserved[7];
+	__u16 open_options;
+	unsigned char node_address[6];
+	unsigned char group_address[4];
+	unsigned char funct_address[4];
+	__u16 num_rcv_buf;
+	__u16 rcv_buf_len;
+	__u16 dhb_length;
+	unsigned char num_dhb;
+	char reserved2;
+	unsigned char dlc_max_sap;
+	unsigned char dlc_max_sta;
+	unsigned char dlc_max_gsap;
+	unsigned char dlc_max_gmem;
+	unsigned char dlc_t1_tick_1;
+	unsigned char dlc_t2_tick_1;
+	unsigned char dlc_ti_tick_1;
+	unsigned char dlc_t1_tick_2;
+	unsigned char dlc_t2_tick_2;
+	unsigned char dlc_ti_tick_2;
+	unsigned char product_id[18];
+};
+
+struct srb_open_response {
+	unsigned char command;
+	unsigned char reserved1;
+	unsigned char ret_code;
+	unsigned char reserved2[3];
+	__u16 error_code;
+	__u16 asb_addr;
+	__u16 srb_addr;
+	__u16 arb_addr;
+	__u16 ssb_addr;
+};
+
+struct dlc_open_sap {
+	unsigned char command;
+	unsigned char reserved1;
+	unsigned char ret_code;
+	unsigned char reserved2;
+	__u16 station_id;
+	unsigned char timer_t1;
+	unsigned char timer_t2;
+	unsigned char timer_ti;
+	unsigned char maxout;
+	unsigned char maxin;
+	unsigned char maxout_incr;
+	unsigned char max_retry_count;
+	unsigned char gsap_max_mem;
+	__u16 max_i_field;
+	unsigned char sap_value;
+	unsigned char sap_options;
+	unsigned char station_count;
+	unsigned char sap_gsap_mem;
+	unsigned char gsap[0];
+};
+
+struct srb_xmit {
+	unsigned char command;
+	unsigned char cmd_corr;
+	unsigned char ret_code;
+	unsigned char reserved1;
+	__u16 station_id;
+};
+
+struct srb_interrupt {
+	unsigned char command;
+	unsigned char cmd_corr;
+	unsigned char ret_code;
+};
+
+struct srb_read_log {
+	unsigned char command;
+	unsigned char reserved1;
+	unsigned char ret_code;
+	unsigned char reserved2;
+	unsigned char line_errors;
+	unsigned char internal_errors;
+	unsigned char burst_errors;
+	unsigned char A_C_errors;
+	unsigned char abort_delimiters;
+	unsigned char reserved3;
+	unsigned char lost_frames;
+	unsigned char recv_congest_count;
+	unsigned char frame_copied_errors;
+	unsigned char frequency_errors;
+	unsigned char token_errors;
+};
+
+struct asb_xmit_resp {
+	unsigned char command;
+	unsigned char cmd_corr;
+	unsigned char ret_code;
+	unsigned char reserved;
+	__u16 station_id;
+	__u16 frame_length;
+	unsigned char hdr_length;
+	unsigned char rsap_value;
+};
+
+struct arb_xmit_req {
+	unsigned char command;
+	unsigned char cmd_corr;
+	unsigned char reserved1[2];
+	__u16 station_id;
+	__u16 dhb_address;
+};
+
+struct arb_rec_req {
+	unsigned char command;
+	unsigned char reserved1[3];
+	__u16 station_id;
+	__u16 rec_buf_addr;
+	unsigned char lan_hdr_len;
+	unsigned char dlc_hdr_len;
+	__u16 frame_len;
+	unsigned char msg_type;
+};
+
+struct asb_rec {
+	unsigned char command;
+	unsigned char reserved1;
+	unsigned char ret_code;
+	unsigned char reserved2;
+	__u16 station_id;
+	__u16 rec_buf_addr;
+};
+
+struct rec_buf {
+  /*	unsigned char reserved1[2]; */
+	__u16 buf_ptr;
+	unsigned char reserved2;
+	__u16 buf_len;
+	unsigned char data[0];
+};
+
+struct arb_dlc_status {
+	unsigned char command;
+	unsigned char reserved1[3];
+	__u16 station_id;
+	__u16 status;
+	unsigned char frmr_data[5];
+	unsigned char access_prio;
+	unsigned char rem_addr[TR_ALEN];
+	unsigned char rsap_value;
+};
+
+struct arb_ring_stat_change {
+	unsigned char command;
+	unsigned char reserved1[5];
+	__u16 ring_status;
+};
+
+struct srb_close_adapter {
+	unsigned char command;
+	unsigned char reserved1;
+	unsigned char ret_code;
+};
+
+struct srb_set_funct_addr {
+	unsigned char command;
+	unsigned char reserved1;
+	unsigned char ret_code;
+	unsigned char reserved2[3];
+	unsigned char funct_address[4];
+};
+
diff -u --recursive --new-file v2.3.20/linux/drivers/net/tokenring/olympic.c linux/drivers/net/tokenring/olympic.c
--- v2.3.20/linux/drivers/net/tokenring/olympic.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/tokenring/olympic.c	Mon Oct 11 10:13:24 1999
@@ -0,0 +1,1667 @@
+/*
+ *   olympic.c (c) 1999 Peter De Schrijver All Rights Reserved
+ *		   1999 Mike Phillips (phillim@amtrak.com)
+ *
+ *  Linux driver for IBM PCI tokenring cards based on the Pit/Pit-Phy/Olympic
+ *  chipset. 
+ *
+ *  Base Driver Skeleton:
+ *      Written 1993-94 by Donald Becker.
+ *
+ *      Copyright 1993 United States Government as represented by the
+ *      Director, National Security Agency.
+ *
+ *  Thanks to Erik De Cock, Adrian Bridgett and Frank Fiene for their 
+ *  assistance and perserverance with the testing of this driver.
+ *
+ *  This software may be used and distributed according to the terms
+ *  of the GNU Public License, incorporated herein by reference.
+ * 
+ *  4/27/99 - Alpha Release 0.1.0
+ *            First release to the public
+ *
+ *  6/8/99  - Official Release 0.2.0   
+ *            Merged into the kernel code 
+ *  8/18/99 - Updated driver for 2.3.13 kernel to use new pci
+ *	      resource. Driver also reports the card name returned by
+ *            the pci resource.
+ *  
+ *  To Do:
+ *
+ *  Sanitize for smp
+ *
+ *  If Problems do Occur
+ *  Most problems can be rectified by either closing and opening the interface
+ *  (ifconfig down and up) or rmmod and insmod'ing the driver (a bit difficult
+ *  if compiled into the kernel).
+ */
+
+/* Change OLYMPIC_DEBUG to 1 to get verbose, and I mean really verbose, messages */
+
+#define OLYMPIC_DEBUG 0
+
+/* Change OLYMPIC_NETWORK_MONITOR to receive mac frames through the arb channel.
+ * Will also create a /proc/net/olympic_tr entry if proc_fs is compiled into the
+ * kernel.
+ * Intended to be used to create a ring-error reporting network module 
+ * i.e. it will give you the source address of beaconers on the ring 
+ */
+
+#define OLYMPIC_NETWORK_MONITOR 0
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/in.h>
+#include <linux/ioport.h>
+#include <linux/string.h>
+#include <linux/proc_fs.h>
+#include <linux/ptrace.h>
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/trdevice.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <net/checksum.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include "olympic.h"
+
+/* I've got to put some intelligence into the version number so that Peter and I know
+ * which version of the code somebody has got. 
+ * Version Number = a.b.c.d  where a.b.c is the level of code and d is the latest author.
+ * So 0.0.1.pds = Peter, 0.0.1.mlp = Mike
+ * 
+ * Official releases will only have an a.b.c version number format.
+ */
+
+static char *version = 
+"Olympic.c v0.3.0 8/18/99 - Peter De Schrijver & Mike Phillips" ; 
+
+static char *open_maj_error[]  = {"No error", "Lobe Media Test", "Physical Insertion",
+				   "Address Verification", "Neighbor Notification (Ring Poll)",
+				   "Request Parameters","FDX Registration Request",
+				   "FDX Duplicate Address Check", "Station registration Query Wait",
+				   "Unknown stage"};
+
+static char *open_min_error[] = {"No error", "Function Failure", "Signal Lost", "Wire Fault",
+				   "Ring Speed Mismatch", "Timeout","Ring Failure","Ring Beaconing",
+				   "Duplicate Node Address","Request Parameters","Remove Received",
+				   "Reserved", "Reserved", "No Monitor Detected for RPL", 
+				   "Monitor Contention failer for RPL", "FDX Protocol Error"};
+
+/* Module paramters */
+
+/* Ring Speed 0,4,16,100 
+ * 0 = Autosense         
+ * 4,16 = Selected speed only, no autosense
+ * This allows the card to be the first on the ring
+ * and become the active monitor.
+ * 100 = Nothing at present, 100mbps is autodetected
+ * if FDX is turned on. May be implemented in the future to 
+ * fail if 100mpbs is not detected.
+ *
+ * WARNING: Some hubs will allow you to insert
+ * at the wrong speed
+ */
+
+static int ringspeed[OLYMPIC_MAX_ADAPTERS] = {0,} ;
+
+MODULE_PARM(ringspeed, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i");
+
+/* Packet buffer size */
+
+static int pkt_buf_sz[OLYMPIC_MAX_ADAPTERS] = {0,} ;
+ 
+MODULE_PARM(pkt_buf_sz, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i") ; 
+
+/* Message Level */
+
+static int message_level[OLYMPIC_MAX_ADAPTERS] = {0,} ; 
+
+MODULE_PARM(message_level, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i") ; 
+
+static int olympic_scan(struct net_device *dev);
+static int olympic_init(struct net_device *dev);
+static int olympic_open(struct net_device *dev);
+static int olympic_xmit(struct sk_buff *skb, struct net_device *dev);
+static int olympic_close(struct net_device *dev);
+static void olympic_set_rx_mode(struct net_device *dev);
+static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static struct net_device_stats * olympic_get_stats(struct net_device *dev);
+static int olympic_set_mac_address(struct net_device *dev, void *addr) ; 
+static void olympic_arb_cmd(struct net_device *dev);
+static int olympic_change_mtu(struct net_device *dev, int mtu);
+static void olympic_srb_bh(struct net_device *dev) ; 
+static void olympic_asb_bh(struct net_device *dev) ; 
+#if OLYMPIC_NETWORK_MONITOR
+#ifdef CONFIG_PROC_FS
+static int sprintf_info(char *buffer, struct net_device *dev) ; 
+#endif
+#endif
+
+int __init olympic_probe(struct net_device *dev)
+{
+	int cards_found;
+
+	cards_found=olympic_scan(dev);
+	return cards_found ? 0 : -ENODEV;
+}
+
+static int __init olympic_scan(struct net_device *dev)
+{
+	struct pci_dev *pci_device = NULL ;
+	struct olympic_private *olympic_priv;
+	int card_no = 0 ;
+	if (pci_present()) {
+
+		while((pci_device=pci_find_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR_WAKE, pci_device))) {
+
+			pci_set_master(pci_device);
+
+			/* Check to see if io has been allocated, if so, we've already done this card,
+			   so continue on the card discovery loop  */
+
+			if (check_region(pci_device->resource[0].start, OLYMPIC_IO_SPACE)) {
+				card_no++ ; 
+				continue ; 
+			}
+
+			olympic_priv=kmalloc(sizeof (struct olympic_private), GFP_KERNEL);
+			memset(olympic_priv, 0, sizeof(struct olympic_private));
+			init_waitqueue_head(&olympic_priv->srb_wait);
+			init_waitqueue_head(&olympic_priv->trb_wait);
+#ifndef MODULE
+			dev=init_trdev(dev, 0);
+#endif
+			dev->priv=(void *)olympic_priv;
+#if OLYMPIC_DEBUG  
+			printk("pci_device: %p, dev:%p, dev->priv: %p\n", pci_device, dev, dev->priv);
+#endif
+			dev->irq=pci_device->irq;
+			dev->base_addr=pci_device->resource[0].start;
+			dev->init=&olympic_init;
+			olympic_priv->olympic_card_name = (char *)pci_device->resource[0].name ; 
+			olympic_priv->olympic_mmio=ioremap(pci_device->resource[1].start,256);
+			olympic_priv->olympic_lap=ioremap(pci_device->resource[2].start,2048);
+			
+			if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000) )
+				olympic_priv->pkt_buf_sz = PKT_BUF_SZ ; 
+			else
+				olympic_priv->pkt_buf_sz = pkt_buf_sz[card_no] ; 
+
+			olympic_priv->olympic_ring_speed = ringspeed[card_no] ; 
+			olympic_priv->olympic_message_level = message_level[card_no] ; 
+			olympic_priv->olympic_multicast_set  = 0 ; 
+	
+			if(olympic_init(dev)==-1) {
+				unregister_netdevice(dev);
+				kfree(dev->priv);
+				return 0;
+			}				
+
+			dev->open=&olympic_open;
+			dev->hard_start_xmit=&olympic_xmit;
+			dev->change_mtu=&olympic_change_mtu;
+
+			dev->stop=&olympic_close;
+			dev->do_ioctl=NULL;
+			dev->set_multicast_list=&olympic_set_rx_mode;
+			dev->get_stats=&olympic_get_stats ;
+			dev->set_mac_address=&olympic_set_mac_address ;  
+			return 1; 
+		}
+	}
+	return  0 ;
+}
+
+
+static int __init olympic_init(struct net_device *dev)
+{
+    	struct olympic_private *olympic_priv;
+	__u8 *olympic_mmio, *init_srb,*adapter_addr;
+	unsigned long t; 
+	unsigned int uaa_addr;
+
+    	olympic_priv=(struct olympic_private *)dev->priv;
+	olympic_mmio=olympic_priv->olympic_mmio;
+
+	printk("%s \n", version);
+	printk("%s: %s. I/O at %hx, MMIO at %p, LAP at %p, using irq %d\n",dev->name, olympic_priv->olympic_card_name, (unsigned int) dev->base_addr,olympic_priv->olympic_mmio, olympic_priv->olympic_lap, dev->irq);
+
+	request_region(dev->base_addr, OLYMPIC_IO_SPACE, "olympic");
+	writel(readl(olympic_mmio+BCTL) | BCTL_SOFTRESET,olympic_mmio+BCTL);
+	t=jiffies;
+	while((readl(olympic_priv->olympic_mmio+BCTL)) & BCTL_SOFTRESET) {
+		schedule();		
+		if(jiffies-t > 40*HZ) {
+			printk(KERN_ERR "IBM PCI tokenring card not responding.\n");
+			release_region(dev->base_addr, OLYMPIC_IO_SPACE) ; 
+			return -1;
+		}
+	}
+
+#if OLYMPIC_DEBUG
+	printk("BCTL: %x\n",readl(olympic_mmio+BCTL));
+	printk("GPR: %x\n",readw(olympic_mmio+GPR));
+	printk("SISRMASK: %x\n",readl(olympic_mmio+SISR_MASK));
+#endif
+	/* Aaaahhh, You have got to be real careful setting GPR, the card
+	   holds the previous values from flash memory, including autosense 
+           and ring speed */
+
+	writel(readl(olympic_mmio+BCTL)|BCTL_MIMREB,olympic_mmio+BCTL);
+	
+	if (olympic_priv->olympic_ring_speed  == 0) { /* Autosense */
+		writel(readl(olympic_mmio+GPR)|GPR_AUTOSENSE,olympic_mmio+GPR);
+		if (olympic_priv->olympic_message_level) 
+			printk(KERN_INFO "%s: Ringspeed autosense mode on\n",dev->name);
+	} else if (olympic_priv->olympic_ring_speed == 16) {
+		if (olympic_priv->olympic_message_level) 
+			printk(KERN_INFO "%s: Trying to open at 16 Mbps as requested\n", dev->name);
+		writel(GPR_16MBPS, olympic_mmio+GPR);
+	} else if (olympic_priv->olympic_ring_speed == 4) {
+		if (olympic_priv->olympic_message_level) 
+			printk(KERN_INFO "%s: Trying to open at 4 Mbps as requested\n", dev->name) ; 
+		writel(0, olympic_mmio+GPR);
+	} 
+	
+	writel(readl(olympic_mmio+GPR)|GPR_NEPTUNE_BF,olympic_mmio+GPR);
+
+#if OLYMPIC_DEBUG
+	printk("GPR = %x\n",readw(olympic_mmio + GPR) ) ; 
+#endif
+	/* start solo init */
+	writel((1<<15),olympic_mmio+SISR_MASK_SUM);
+
+	t=jiffies;
+	while(!((readl(olympic_mmio+SISR_RR)) & SISR_SRB_REPLY)) {
+		schedule();		
+		if(jiffies-t > 40*HZ) {
+			printk(KERN_ERR "IBM PCI tokenring card not responding.\n");
+			release_region(dev->base_addr, OLYMPIC_IO_SPACE); 
+			return -1;
+		}
+	}
+	
+	writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
+
+#if OLYMPIC_DEBUG
+	printk("LAPWWO: %x, LAPA: %x\n",readl(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA));
+#endif
+
+	init_srb=olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWO)) & (~0xf800));
+
+#if OLYMPIC_DEBUG		
+{
+	int i;
+	printk("init_srb(%p): ",init_srb);
+	for(i=0;i<20;i++)
+		printk("%x ",readb(init_srb+i));
+	printk("\n");
+}
+#endif	
+	if(readw(init_srb+6)) {
+		printk(KERN_INFO "tokenring card intialization failed. errorcode : %x\n",readw(init_srb+6));
+		release_region(dev->base_addr, OLYMPIC_IO_SPACE);
+		return -1;
+	}
+
+	uaa_addr=ntohs(readw(init_srb+8));
+
+#if OLYMPIC_DEBUG
+	printk("UAA resides at %x\n",uaa_addr);
+#endif
+
+	writel(uaa_addr,olympic_mmio+LAPA);
+	adapter_addr=olympic_priv->olympic_lap + (uaa_addr & (~0xf800));
+
+#if OLYMPIC_DEBUG
+	printk("adapter address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+			readb(adapter_addr), readb(adapter_addr+1),readb(adapter_addr+2),
+			readb(adapter_addr+3),readb(adapter_addr+4),readb(adapter_addr+5));
+#endif
+
+	memcpy_fromio(&dev->dev_addr[0], adapter_addr,6);
+
+	olympic_priv->olympic_addr_table_addr = ntohs(readw(init_srb + 12)) ; 
+	olympic_priv->olympic_parms_addr      = ntohs(readw(init_srb + 14)) ; 
+
+	return 0;
+
+}
+
+static int olympic_open(struct net_device *dev) 
+{
+	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+	__u8 *olympic_mmio=olympic_priv->olympic_mmio,*init_srb;
+	unsigned long flags;
+	char open_error[255] ; 
+	int i, open_finished = 1 ;
+
+#if OLYMPIC_NETWORK_MONITOR
+	__u8 *oat ; 
+	__u8 *opt ; 
+#endif
+
+	if(request_irq(dev->irq, &olympic_interrupt, SA_SHIRQ , "olympic", dev)) {
+		return -EAGAIN;
+	}
+
+#if OLYMPIC_DEBUG
+	printk("BMCTL: %x\n",readl(olympic_mmio+BMCTL_SUM));
+	printk("pending ints: %x\n",readl(olympic_mmio+SISR_RR));
+#endif
+
+	writel(SISR_MI,olympic_mmio+SISR_MASK_SUM);
+
+	writel(SISR_MI | SISR_SRB_REPLY, olympic_mmio+SISR_MASK); /* more ints later, doesn't stop arb cmd interrupt */
+
+	writel(LISR_LIE,olympic_mmio+LISR); /* more ints later */
+
+	/* adapter is closed, so SRB is pointed to by LAPWWO */
+
+	writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
+	init_srb=olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWO)) & (~0xf800));
+	
+#if OLYMPIC_DEBUG
+	printk("LAPWWO: %x, LAPA: %x\n",readl(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA));
+	printk("SISR Mask = %04x\n", readl(olympic_mmio+SISR_MASK));
+	printk("Before the open command \n");
+#endif	
+	do {
+		int i;
+
+		save_flags(flags);
+		cli();
+		for(i=0;i<SRB_COMMAND_SIZE;i+=4)
+			writel(0,init_srb+i);
+		if(SRB_COMMAND_SIZE & 2)
+			writew(0,init_srb+(SRB_COMMAND_SIZE & ~3));
+		if(SRB_COMMAND_SIZE & 1)
+			writeb(0,init_srb+(SRB_COMMAND_SIZE & ~1));
+
+		writeb(SRB_OPEN_ADAPTER,init_srb) ; 	/* open */
+		writeb(OLYMPIC_CLEAR_RET_CODE,init_srb+2);
+
+		/* If Network Monitor, instruct card to copy MAC frames through the ARB */
+
+#if OLYMPIC_NETWORK_MONITOR
+		writew(ntohs(OPEN_ADAPTER_ENABLE_FDX | OPEN_ADAPTER_PASS_ADC_MAC | OPEN_ADAPTER_PASS_ATT_MAC | OPEN_ADAPTER_PASS_BEACON),init_srb+8);
+#else
+		writew(OPEN_ADAPTER_ENABLE_FDX,init_srb+8);
+#endif		
+
+		if (olympic_priv->olympic_laa[0]) {
+			writeb(olympic_priv->olympic_laa[0],init_srb+12);
+			writeb(olympic_priv->olympic_laa[1],init_srb+13);
+			writeb(olympic_priv->olympic_laa[2],init_srb+14);
+			writeb(olympic_priv->olympic_laa[3],init_srb+15);
+			writeb(olympic_priv->olympic_laa[4],init_srb+16);
+			writeb(olympic_priv->olympic_laa[5],init_srb+17);
+			memcpy(dev->dev_addr,olympic_priv->olympic_laa,dev->addr_len) ;  
+		} 	
+		writeb(1,init_srb+30);
+	
+		olympic_priv->srb_queued=1;
+
+		writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
+
+ 		while(olympic_priv->srb_queued) {        
+        		interruptible_sleep_on_timeout(&olympic_priv->srb_wait, 60*HZ);
+        		if(signal_pending(current))	{            
+				printk(KERN_WARNING "%s: SRB timed out.\n",
+                			dev->name);
+            			printk(KERN_WARNING "SISR=%x MISR=%x\n",
+                			readl(olympic_mmio+SISR),
+                			readl(olympic_mmio+LISR));
+            			olympic_priv->srb_queued=0;
+            			break;
+        		}
+    		}
+		restore_flags(flags);
+#if OLYMPIC_DEBUG
+		printk("init_srb(%p): ",init_srb);
+		for(i=0;i<20;i++)
+			printk("%x ",readb(init_srb+i));
+		printk("\n");
+#endif
+		
+		/* If we get the same return response as we set, the interrupt wasn't raised and the open
+                 * timed out.
+		 */
+
+		if(readb(init_srb+2)== OLYMPIC_CLEAR_RET_CODE) {
+			printk(KERN_WARNING "%s: Adapter Open time out or error.\n", dev->name) ; 
+			return -EIO ; 
+		}	
+
+		if(readb(init_srb+2)!=0) {
+			if (readb(init_srb+2) == 0x07) {  
+				if (!olympic_priv->olympic_ring_speed && open_finished) { /* Autosense , first time around */
+					printk(KERN_WARNING "%s: Retrying at different ring speed \n", dev->name); 
+					open_finished = 0 ;  
+				} else {
+
+					strcpy(open_error, open_maj_error[(readb(init_srb+7) & 0xf0) >> 4]) ; 
+					strcat(open_error," - ") ; 
+					strcat(open_error, open_min_error[(readb(init_srb+7) & 0x0f)]) ;
+
+					if (!olympic_priv->olympic_ring_speed && ((readb(init_srb+7) & 0x0f) == 0x0d)) { 
+						printk(KERN_WARNING "%s: Tried to autosense ring speed with no monitors present\n",dev->name);
+						printk(KERN_WARNING "%s: Please try again with a specified ring speed \n",dev->name);
+						free_irq(dev->irq, dev);
+						return -EIO ;
+					}
+
+					printk(KERN_WARNING "%s: %s\n",dev->name,open_error);
+					free_irq(dev->irq,dev) ; 
+					return -EIO ; 
+ 
+				}	/* if autosense && open_finished */
+			} else {  
+				printk(KERN_WARNING "%s: Bad OPEN response: %x\n", dev->name,init_srb[2]);
+				free_irq(dev->irq, dev);
+				return -EIO;
+			} 
+		} else 
+			open_finished = 1 ; 
+	} while (!(open_finished)) ; /* Will only loop if ring speed mismatch re-open attempted && autosense is on */	
+
+	if (readb(init_srb+18) & (1<<3)) 
+		if (olympic_priv->olympic_message_level) 
+			printk(KERN_INFO "%s: Opened in FDX Mode\n",dev->name);
+
+	if (readb(init_srb+18) & (1<<1))
+		olympic_priv->olympic_ring_speed = 100 ; 
+	else if (readb(init_srb+18) & 1)
+		olympic_priv->olympic_ring_speed = 16 ; 
+	else
+		olympic_priv->olympic_ring_speed = 4 ; 
+
+	if (olympic_priv->olympic_message_level) 
+		printk(KERN_INFO "%s: Opened in %d Mbps mode\n",dev->name, olympic_priv->olympic_ring_speed);
+
+	olympic_priv->asb=ntohs(readw(init_srb+8));
+	olympic_priv->srb=ntohs(readw(init_srb+10));
+	olympic_priv->arb=ntohs(readw(init_srb+12));
+	olympic_priv->trb=ntohs(readw(init_srb+16));
+
+	olympic_priv->olympic_receive_options = 0x01 ; 
+	olympic_priv->olympic_copy_all_options = 0 ; 
+	
+	/* setup rx ring */
+	
+	writel((3<<16),olympic_mmio+BMCTL_RWM); /* Ensure end of frame generated interrupts */ 
+
+	writel(BMCTL_RX_DIS|3,olympic_mmio+BMCTL_RWM); /* Yes, this the enables RX channel */
+
+	for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) {
+
+		struct sk_buff *skb;
+		
+		skb=dev_alloc_skb(olympic_priv->pkt_buf_sz);
+		if(skb == NULL)
+			break;
+
+		skb->dev = dev;
+
+		olympic_priv->olympic_rx_ring[i].buffer=virt_to_bus(skb->data);
+		olympic_priv->olympic_rx_ring[i].res_length = olympic_priv->pkt_buf_sz ; 
+		olympic_priv->rx_ring_skb[i]=skb;
+	}
+
+	if (i==0) {
+		printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers. Adapter disabled\n",dev->name);
+		free_irq(dev->irq, dev);
+		return -EIO;
+	}
+
+	writel(virt_to_bus(&olympic_priv->olympic_rx_ring[0]),olympic_mmio+RXDESCQ);
+	writel(virt_to_bus(&olympic_priv->olympic_rx_ring[0]),olympic_mmio+RXCDA);
+	writew(i,olympic_mmio+RXDESCQCNT);
+		
+	writel(virt_to_bus(&olympic_priv->olympic_rx_status_ring[0]),olympic_mmio+RXSTATQ);
+	writel(virt_to_bus(&olympic_priv->olympic_rx_status_ring[0]),olympic_mmio+RXCSA);
+	
+ 	olympic_priv->rx_ring_last_received=OLYMPIC_RX_RING_SIZE-1;	/* last processed rx status */
+	olympic_priv->rx_status_last_received = OLYMPIC_RX_RING_SIZE-1;  
+
+	writew(i,olympic_mmio+RXSTATQCNT);
+
+#if OLYMPIC_DEBUG 
+	printk("# of rx buffers: %d, RXENQ: %x\n",i, readw(olympic_mmio+RXENQ));
+	printk("RXCSA: %x, rx_status_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCSA)),&olympic_priv->olympic_rx_status_ring[0]);
+	printk(" stat_ring[1]: %p, stat_ring[2]: %p, stat_ring[3]: %p\n", &(olympic_priv->olympic_rx_status_ring[1]), &(olympic_priv->olympic_rx_status_ring[2]), &(olympic_priv->olympic_rx_status_ring[3]) );
+	printk(" stat_ring[4]: %p, stat_ring[5]: %p, stat_ring[6]: %p\n", &(olympic_priv->olympic_rx_status_ring[4]), &(olympic_priv->olympic_rx_status_ring[5]), &(olympic_priv->olympic_rx_status_ring[6]) );
+	printk(" stat_ring[7]: %p\n", &(olympic_priv->olympic_rx_status_ring[7])  );
+
+	printk("RXCDA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCDA)),&olympic_priv->olympic_rx_ring[0]);
+#endif
+
+	writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) | i,olympic_mmio+RXENQ);
+
+#if OLYMPIC_DEBUG 
+	printk("# of rx buffers: %d, RXENQ: %x\n",i, readw(olympic_mmio+RXENQ));
+	printk("RXCSA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCSA)),&olympic_priv->olympic_rx_status_ring[0]);
+	printk("RXCDA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCDA)),&olympic_priv->olympic_rx_ring[0]);
+#endif 
+
+	writel(SISR_RX_STATUS | SISR_RX_NOBUF,olympic_mmio+SISR_MASK_SUM);
+
+	/* setup tx ring */
+
+	writel(BMCTL_TX1_DIS,olympic_mmio+BMCTL_RWM); /* Yes, this enables TX channel 1 */
+	for(i=0;i<OLYMPIC_TX_RING_SIZE;i++) 
+		olympic_priv->olympic_tx_ring[i].buffer=0xdeadbeef;
+
+	olympic_priv->free_tx_ring_entries=OLYMPIC_TX_RING_SIZE;
+	writel(virt_to_bus(&olympic_priv->olympic_tx_ring[0]),olympic_mmio+TXDESCQ_1);
+	writel(virt_to_bus(&olympic_priv->olympic_tx_ring[0]),olympic_mmio+TXCDA_1);
+	writew(OLYMPIC_TX_RING_SIZE,olympic_mmio+TXDESCQCNT_1);
+	
+	writel(virt_to_bus(&olympic_priv->olympic_tx_status_ring[0]),olympic_mmio+TXSTATQ_1);
+	writel(virt_to_bus(&olympic_priv->olympic_tx_status_ring[0]),olympic_mmio+TXCSA_1);
+	writew(OLYMPIC_TX_RING_SIZE,olympic_mmio+TXSTATQCNT_1);
+		
+	olympic_priv->tx_ring_free=0; /* next entry in tx ring to use */
+	olympic_priv->tx_ring_last_status=OLYMPIC_TX_RING_SIZE-1; /* last processed tx status */
+
+	writel(SISR_TX1_EOF | SISR_ADAPTER_CHECK | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_ASB_FREE,olympic_mmio+SISR_MASK_SUM);
+
+#if OLYMPIC_DEBUG 
+	printk("BMCTL: %x\n",readl(olympic_mmio+BMCTL_SUM));
+	printk("SISR MASK: %x\n",readl(olympic_mmio+SISR_MASK));
+#endif
+
+#if OLYMPIC_NETWORK_MONITOR
+	oat = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; 
+	opt = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; 
+
+	printk("%s: Node Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, 
+		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), 
+		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1),
+		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2),
+		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3),
+		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4),
+		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5));
+	printk("%s: Functional Address: %02x:%02x:%02x:%02x\n",dev->name, 
+		    readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), 
+		    readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1),
+		    readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2),
+		    readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3));
+
+	printk("%s: NAUN Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, 
+			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)),
+			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1),
+			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2),
+			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3),
+			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4),
+			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5));
+
+
+#endif 	
+	
+	dev->start = 1;
+	dev->interrupt=0;
+	dev->tbusy=0;
+
+	MOD_INC_USE_COUNT ;
+	return 0;
+	
+}	
+
+/*
+ *	When we enter the rx routine we do not know how many frames have been 
+ *	queued on the rx channel.  Therefore we start at the next rx status
+ *	position and travel around the receive ring until we have completed
+ *	all the frames.
+ *
+ *	This means that we may process the frame before we receive the end
+ *	of frame interrupt. This is why we always test the status instead
+ *	of blindly processing the next frame.
+ *	
+ */
+static void olympic_rx(struct net_device *dev)
+{
+	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+	__u8 *olympic_mmio=olympic_priv->olympic_mmio;
+	struct olympic_rx_status *rx_status;
+	struct olympic_rx_desc *rx_desc ; 
+	int rx_ring_last_received,length, buffer_cnt, cpy_length, frag_len;
+	struct sk_buff *skb, *skb2;
+	int i;
+
+	rx_status=&(olympic_priv->olympic_rx_status_ring[(olympic_priv->rx_status_last_received + 1) & (OLYMPIC_RX_RING_SIZE - 1)]) ; 
+ 
+	while (rx_status->status_buffercnt) { 
+
+		olympic_priv->rx_status_last_received++ ;
+		olympic_priv->rx_status_last_received &= (OLYMPIC_RX_RING_SIZE -1);
+#if OLYMPIC_DEBUG
+		printk(" stat_ring addr: %x \n", &(olympic_priv->olympic_rx_status_ring[olympic_priv->rx_status_last_received]) ); 
+		printk("rx status: %x rx len: %x \n",rx_status->status_buffercnt,rx_status->fragmentcnt_framelen);	
+#endif
+		length=rx_status->fragmentcnt_framelen & 0xffff;
+		buffer_cnt = rx_status->status_buffercnt & 0xffff ; 
+		i = buffer_cnt ; /* Need buffer_cnt later for rxenq update */ 
+		frag_len = rx_status->fragmentcnt_framelen >> 16 ; 
+
+#if OLYMPIC_DEBUG 
+		printk("length: %x, frag_len: %x, buffer_cnt: %x\n",length,frag_len,buffer_cnt);
+#endif
+
+		if(rx_status->status_buffercnt & 0xC0000000) {
+			if (rx_status->status_buffercnt & 0x3B000000) {
+				if (olympic_priv->olympic_message_level) {
+					if (rx_status->status_buffercnt & (1<<29))  /* Rx Frame Truncated */
+						printk(KERN_WARNING "%s: Rx Frame Truncated \n",dev->name);
+					if (rx_status->status_buffercnt & (1<<28)) /*Rx receive overrun */
+						printk(KERN_WARNING "%s: Rx Frame Receive overrun \n",dev->name);
+					if (rx_status->status_buffercnt & (1<<27)) /* No receive buffers */
+						printk(KERN_WARNING "%s: No receive buffers \n",dev->name);
+					if (rx_status->status_buffercnt & (1<<25)) /* Receive frame error detect */
+						printk(KERN_WARNING "%s: Receive frame error detect \n",dev->name);
+					if (rx_status->status_buffercnt & (1<<24)) /* Received Error Detect */
+						printk(KERN_WARNING "%s: Received Error Detect \n",dev->name);
+				} 
+				olympic_priv->rx_ring_last_received += i ; 
+				olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1) ; 
+				olympic_priv->olympic_stats.rx_errors++;	 
+			} else {	
+			
+				if (buffer_cnt == 1) {
+					skb = dev_alloc_skb(olympic_priv->pkt_buf_sz) ; 
+				} else {
+					skb = dev_alloc_skb(length) ; 
+				}
+
+				if (skb == NULL) {
+					printk(KERN_WARNING "%s: Not enough memory to copy packet to upper layers. \n",dev->name) ;
+					olympic_priv->olympic_stats.rx_dropped++ ; 
+					/* Update counters even though we don't transfer the frame */
+					olympic_priv->rx_ring_last_received += i ; 
+					olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1) ;  
+				} else  {
+					skb->dev = dev ; 
+
+					/* Optimise based upon number of buffers used. 
+			   	   	   If only one buffer is used we can simply swap the buffers around.
+			   	   	   If more than one then we must use the new buffer and copy the information
+			   	   	   first. Ideally all frames would be in a single buffer, this can be tuned by
+                               	   	   altering the buffer size. */
+				
+ 					if (buffer_cnt==1) {
+						olympic_priv->rx_ring_last_received++ ; 
+						olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1);
+						rx_ring_last_received = olympic_priv->rx_ring_last_received ;
+						skb2=olympic_priv->rx_ring_skb[rx_ring_last_received] ; 
+						skb_put(skb2,length);
+						skb2->protocol = tr_type_trans(skb2,dev);
+						olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer=virt_to_bus(skb->data);
+						olympic_priv->olympic_rx_ring[rx_ring_last_received].res_length = olympic_priv->pkt_buf_sz ; 
+						olympic_priv->rx_ring_skb[rx_ring_last_received] = skb ; 
+						netif_rx(skb2) ; 
+					} else {
+						do { /* Walk the buffers */ 
+							olympic_priv->rx_ring_last_received++ ; 
+							olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1);
+							rx_ring_last_received = olympic_priv->rx_ring_last_received ; 
+							rx_desc = &(olympic_priv->olympic_rx_ring[rx_ring_last_received]);
+							cpy_length = (i == 1 ? frag_len : rx_desc->res_length); 
+							memcpy(skb_put(skb, cpy_length), bus_to_virt(rx_desc->buffer), cpy_length) ; 
+						} while (--i) ; 
+		
+						skb->protocol = tr_type_trans(skb,dev);
+						netif_rx(skb) ; 
+					} 
+					olympic_priv->olympic_stats.rx_packets++ ; 
+					olympic_priv->olympic_stats.rx_bytes += length ; 
+				} /* if skb == null */
+			} /* If status & 0x3b */
+
+		} else { /*if buffercnt & 0xC */
+			olympic_priv->rx_ring_last_received += i ; 
+			olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE - 1) ; 
+		} 
+
+		rx_status->fragmentcnt_framelen = 0 ; 
+		rx_status->status_buffercnt = 0 ; 
+		rx_status = &(olympic_priv->olympic_rx_status_ring[(olympic_priv->rx_status_last_received+1) & (OLYMPIC_RX_RING_SIZE -1) ]);
+
+		writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) |  buffer_cnt , olympic_mmio+RXENQ); 
+	} /* while */
+
+}
+
+static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs) 
+{
+	struct net_device *dev= (struct net_device *)dev_id;
+	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+	__u8 *olympic_mmio=olympic_priv->olympic_mmio;
+	__u32 sisr;
+	__u8 *adapter_check_area ; 
+	
+	sisr=readl(olympic_mmio+SISR_RR) ; /* Reset sisr */ 
+	
+	if (!(sisr & SISR_MI)) /* Interrupt isn't for us */ 
+		return ;
+
+	if (dev->interrupt) 
+		printk(KERN_WARNING "%s: Re-entering interrupt \n",dev->name) ; 
+
+	dev->interrupt = 1 ; 
+
+	if (sisr & (SISR_SRB_REPLY | SISR_TX1_EOF | SISR_RX_STATUS | SISR_ADAPTER_CHECK |  
+			SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_RX_NOBUF)) {  
+	
+		if(sisr & SISR_SRB_REPLY) {
+			if(olympic_priv->srb_queued==1) {
+				wake_up_interruptible(&olympic_priv->srb_wait);
+			} else if (olympic_priv->srb_queued==2) { 
+				olympic_srb_bh(dev) ; 
+			}
+			olympic_priv->srb_queued=0;
+		} /* SISR_SRB_REPLY */
+
+		if (sisr & SISR_TX1_EOF) {
+			olympic_priv->tx_ring_last_status++;
+			olympic_priv->tx_ring_last_status &= (OLYMPIC_TX_RING_SIZE-1);
+			olympic_priv->free_tx_ring_entries++;
+			olympic_priv->olympic_stats.tx_bytes += olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]->len;
+			olympic_priv->olympic_stats.tx_packets++ ; 
+			dev_kfree_skb(olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]);
+			olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer=0xdeadbeef;
+			olympic_priv->olympic_tx_status_ring[olympic_priv->tx_ring_last_status].status=0;
+
+			if(dev->tbusy) {
+				dev->tbusy=0;
+				mark_bh(NET_BH);
+			}
+		} /* SISR_TX1_EOF */
+	
+		if (sisr & SISR_RX_STATUS) {
+			olympic_rx(dev);
+		} /* SISR_RX_STATUS */
+	
+		if (sisr & SISR_ADAPTER_CHECK) {
+			printk(KERN_WARNING "%s: Adapter Check Interrupt Raised, 8 bytes of information follow:\n", dev->name);
+			writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
+			adapter_check_area = (__u8 *)(olympic_mmio+LAPWWO) ; 
+			printk(KERN_WARNING "%s: Bytes %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, readb(adapter_check_area+0), readb(adapter_check_area+1), readb(adapter_check_area+2), readb(adapter_check_area+3), readb(adapter_check_area+4), readb(adapter_check_area+5), readb(adapter_check_area+6), readb(adapter_check_area+7)) ; 
+			dev->interrupt = 0  ; 	
+			free_irq(dev->irq, dev) ; 
+	
+		} /* SISR_ADAPTER_CHECK */
+	
+		if (sisr & SISR_ASB_FREE) {
+			/* Wake up anything that is waiting for the asb response */  
+			if (olympic_priv->asb_queued) {
+				olympic_asb_bh(dev) ; 
+			}
+		} /* SISR_ASB_FREE */
+	
+		if (sisr & SISR_ARB_CMD) {
+			olympic_arb_cmd(dev) ; 
+		} /* SISR_ARB_CMD */
+	
+		if (sisr & SISR_TRB_REPLY) {
+			/* Wake up anything that is waiting for the trb response */
+			if (olympic_priv->trb_queued) {
+				wake_up_interruptible(&olympic_priv->trb_wait);
+			}
+			olympic_priv->trb_queued = 0 ; 
+		} /* SISR_TRB_REPLY */	
+	
+		if (sisr & SISR_RX_NOBUF) {
+			/* According to the documentation, we don't have to do anything, but trapping it keeps it out of
+                  	   	   /var/log/messages.  */
+		} /* SISR_RX_NOBUF */
+	} else { 
+		printk(KERN_WARNING "%s: Unexpected interrupt: %x\n",dev->name, sisr);
+		printk(KERN_WARNING "%s: SISR_MASK: %x\n",dev->name, readl(olympic_mmio+SISR_MASK)) ;
+	} /* One if the interrupts we want */
+
+	dev->interrupt = 0 ;  
+
+	writel(SISR_MI,olympic_mmio+SISR_MASK_SUM);
+
+}	
+
+static int olympic_xmit(struct sk_buff *skb, struct net_device *dev) 
+{
+	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+    __u8 *olympic_mmio=olympic_priv->olympic_mmio;
+
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+		return 1;
+	}
+
+	if(olympic_priv->free_tx_ring_entries) {
+		olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].buffer=virt_to_bus(skb->data);
+		olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].status_length=skb->len | (0x80000000);
+		olympic_priv->tx_ring_skb[olympic_priv->tx_ring_free]=skb;
+		olympic_priv->free_tx_ring_entries--;
+
+        	olympic_priv->tx_ring_free++;
+        	olympic_priv->tx_ring_free &= (OLYMPIC_TX_RING_SIZE-1);
+
+
+		writew((((readw(olympic_mmio+TXENQ_1)) & 0x8000) ^ 0x8000) | 1,olympic_mmio+TXENQ_1);
+
+		dev->tbusy=0;		
+
+		return 0;
+	} else 
+		return 1;
+
+}
+	
+
+static int olympic_close(struct net_device *dev) 
+{
+	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+    	__u8 *olympic_mmio=olympic_priv->olympic_mmio,*srb;
+	unsigned long flags;
+	int i;
+
+	writel(olympic_priv->srb,olympic_mmio+LAPA);
+	srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800));
+	
+    	writeb(SRB_CLOSE_ADAPTER,srb+0);
+	writeb(0,srb+1);
+	writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
+
+	save_flags(flags);
+	cli();	
+
+	olympic_priv->srb_queued=1;
+
+	writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
+
+	while(olympic_priv->srb_queued) {
+	        interruptible_sleep_on_timeout(&olympic_priv->srb_wait, jiffies+60*HZ);
+        	if(signal_pending(current))	{            
+			printk(KERN_WARNING "%s: SRB timed out.\n",
+                		dev->name);
+            		printk(KERN_WARNING "SISR=%x MISR=%x\n",
+                	readl(olympic_mmio+SISR),
+                	readl(olympic_mmio+LISR));
+            		olympic_priv->srb_queued=0;
+            		break;
+        	}
+    	}
+
+	restore_flags(flags) ; 
+	olympic_priv->rx_status_last_received++;
+	olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
+	
+	for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) {
+		dev_kfree_skb(olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received]);
+		olympic_priv->rx_status_last_received++;
+		olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
+	}
+
+	/* reset tx/rx fifo's and busmaster logic */
+
+	writel(readl(olympic_mmio+BCTL)|(3<<13),olympic_mmio+BCTL);
+	udelay(1);
+	writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL);
+
+#if OLYMPIC_DEBUG
+	printk("srb(%p): ",srb);
+	for(i=0;i<4;i++)
+		printk("%x ",readb(srb+i));
+	printk("\n");
+#endif
+    	dev->start = 0;
+	free_irq(dev->irq,dev);
+
+	MOD_DEC_USE_COUNT ; 
+	return 0;
+	
+}
+
+static void olympic_set_rx_mode(struct net_device *dev) 
+{
+	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; 
+   	__u8 *olympic_mmio = olympic_priv->olympic_mmio ; 
+	__u8 options = 0, set_mc_list = 0 ; 
+	__u8 *srb, *ata ;
+	struct dev_mc_list *dmi ; 
+
+	writel(olympic_priv->srb,olympic_mmio+LAPA);
+	srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800));
+	options = olympic_priv->olympic_copy_all_options; 
+
+	if (dev->flags&IFF_PROMISC)  
+		options |= (3<<5) ; /* All LLC and MAC frames, all through the main rx channel */  
+	else
+		options &= ~(3<<5) ; 
+
+	if (dev->mc_count) {  
+		set_mc_list = 1 ; 
+	}
+
+	/* Only issue the srb if there is a change in options */
+
+	if ((options ^ olympic_priv->olympic_copy_all_options)) { 
+	
+		/* Now to issue the srb command to alter the copy.all.options */
+	
+		writeb(SRB_MODIFY_RECEIVE_OPTIONS,srb);
+		writeb(0,srb+1);
+		writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
+		writeb(0,srb+3);
+		writeb(olympic_priv->olympic_receive_options,srb+4);
+		writeb(options,srb+5);
+
+		olympic_priv->srb_queued=2; /* Can't sleep, use srb_bh */
+
+		writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
+
+		olympic_priv->olympic_copy_all_options = options ;
+		
+		return ;  
+	} 
+
+	if (set_mc_list ^ olympic_priv->olympic_multicast_set) { /* Multicast options have changed */ 
+
+		dmi = dev->mc_list ; 
+
+		if (set_mc_list) { /* Turn multicast on */
+
+			/* RFC 1469 Says we must support using the functional address C0 00 00 04 00 00
+                         * We do this with a set functional address mask.
+			 */
+						
+			ata=olympic_priv->olympic_lap + (olympic_priv->olympic_addr_table_addr) ;
+			if (!(readb(ata+11) & 0x04)) { /* Hmmm, need to set the functional mask */ 
+				writeb(SRB_SET_FUNC_ADDRESS,srb+0);
+				writeb(0,srb+1);
+				writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
+				writeb(0,srb+3);
+				writeb(0,srb+4);
+				writeb(0,srb+5);
+				writeb(readb(ata+10),srb+6);
+				writeb(readb(ata+11)|4,srb+7);
+				writeb(readb(ata+12),srb+8);
+				writeb(readb(ata+13),srb+9);
+			
+				olympic_priv->srb_queued = 2 ; 
+				writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
+
+				olympic_priv->olympic_multicast_set = 1 ;  
+			}    
+
+
+		} else { /* Turn multicast off */
+	
+			ata=olympic_priv->olympic_lap + (olympic_priv->olympic_addr_table_addr) ;
+			if ((readb(ata+11) & 0x04)) { /* Hmmm, need to reset the functional mask */ 
+				writeb(SRB_SET_FUNC_ADDRESS,srb+0);
+				writeb(0,srb+1);
+				writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
+				writeb(0,srb+3);
+				writeb(0,srb+4);
+				writeb(0,srb+5);
+				writeb(readb(ata+10),srb+6);
+				writeb(readb(ata+11) & ~4,srb+7);
+				writeb(readb(ata+12),srb+8);
+				writeb(readb(ata+13),srb+9);
+			
+				olympic_priv->srb_queued = 2 ; 
+				writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);	
+
+				olympic_priv->olympic_multicast_set = 0 ; 
+			}
+		} 		
+
+	}
+
+
+}
+
+static void olympic_srb_bh(struct net_device *dev) 
+{ 
+	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; 
+   	__u8 *olympic_mmio = olympic_priv->olympic_mmio ; 
+	__u8 *srb;
+
+	writel(olympic_priv->srb,olympic_mmio+LAPA);
+	srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800));
+
+	switch (readb(srb)) { 
+
+		/* SRB_MODIFY_RECEIVE_OPTIONS i.e. set_multicast_list options (promiscuous) 
+                 * At some point we should do something if we get an error, such as
+                 * resetting the IFF_PROMISC flag in dev
+		 */
+
+		case SRB_MODIFY_RECEIVE_OPTIONS:
+			switch (readb(srb+2)) { 
+				case 0x01:
+					printk(KERN_WARNING "%s: Unrecognized srb command\n",dev->name) ; 
+					break ; 
+				case 0x04:
+					printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name);
+					break ; 
+				default:
+					if (olympic_priv->olympic_message_level) 
+						printk(KERN_WARNING "%s: Receive Options Modified to %x,%x\n",dev->name,olympic_priv->olympic_copy_all_options, olympic_priv->olympic_receive_options) ; 
+					break ; 	
+			} /* switch srb[2] */ 
+			break ;
+		
+		/* SRB_SET_GROUP_ADDRESS - Multicast group setting 
+                 */
+
+		case SRB_SET_GROUP_ADDRESS:
+			switch (readb(srb+2)) { 
+				case 0x00:
+					olympic_priv->olympic_multicast_set = 1 ; 
+					break ; 
+				case 0x01:
+					printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
+					break ;
+				case 0x04:
+					printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name); 
+					break ;
+				case 0x3c:
+					printk(KERN_WARNING "%s: Group/Functional address indicator bits not set correctly\n",dev->name) ; 
+					break ;
+				case 0x3e: /* If we ever implement individual multicast addresses, will need to deal with this */
+					printk(KERN_WARNING "%s: Group address registers full\n",dev->name) ; 
+					break ;  
+				case 0x55:
+					printk(KERN_INFO "%s: Group Address already set.\n",dev->name) ; 
+					break ;
+				default:
+					break ; 
+			} /* switch srb[2] */ 
+			break ; 
+
+		/* SRB_RESET_GROUP_ADDRESS - Remove a multicast address from group list
+ 		 */
+
+		case SRB_RESET_GROUP_ADDRESS:
+			switch (readb(srb+2)) { 
+				case 0x00:
+					olympic_priv->olympic_multicast_set = 0 ; 
+					break ; 
+				case 0x01:
+					printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
+					break ; 
+				case 0x04:
+					printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; 
+					break ; 
+				case 0x39: /* Must deal with this if individual multicast addresses used */
+					printk(KERN_INFO "%s: Group address not found \n",dev->name); 
+					break ;
+				default:
+					break ; 
+			} /* switch srb[2] */
+			break ; 
+
+		
+		/* SRB_SET_FUNC_ADDRESS - Called by the set_rx_mode 
+		 */
+
+		case SRB_SET_FUNC_ADDRESS:
+			switch (readb(srb+2)) { 
+				case 0x00:
+					if (olympic_priv->olympic_message_level)
+						printk(KERN_INFO "%s: Functional Address Mask Set \n",dev->name) ; 
+					break ;
+				case 0x01:
+					printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
+					break ; 
+				case 0x04:
+					printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; 
+					break ; 
+				default:
+					break ; 
+			} /* switch srb[2] */
+			break ; 
+	
+		/* SRB_READ_LOG - Read and reset the adapter error counters
+ 		 */
+
+		case SRB_READ_LOG:
+			switch (readb(srb+2)) { 
+				case 0x00: 
+					if (olympic_priv->olympic_message_level) 
+						printk(KERN_INFO "%s: Read Log issued\n",dev->name) ; 
+					break ; 
+				case 0x01:
+					printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
+					break ; 
+				case 0x04:
+					printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; 
+					break ; 
+			
+			} /* switch srb[2] */
+			break ; 
+		
+		/* SRB_READ_SR_COUNTERS - Read and reset the source routing bridge related counters */
+
+		case SRB_READ_SR_COUNTERS:
+			switch (readb(srb+2)) { 
+				case 0x00: 
+					if (olympic_priv->olympic_message_level) 
+						printk(KERN_INFO "%s: Read Source Routing Counters issued\n",dev->name) ; 
+					break ; 
+				case 0x01:
+					printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
+					break ; 
+				case 0x04:
+					printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; 
+					break ; 
+				default:
+					break ; 
+			} /* switch srb[2] */
+			break ;
+ 
+		default:
+			printk(KERN_WARNING "%s: Unrecognized srb bh return value.\n",dev->name);
+			break ; 
+	} /* switch srb[0] */
+
+} 
+
+static struct net_device_stats * olympic_get_stats(struct net_device *dev)
+{
+	struct olympic_private *olympic_priv ;
+	olympic_priv=(struct olympic_private *) dev->priv;
+	return (struct net_device_stats *) &olympic_priv->olympic_stats; 
+}
+
+static int olympic_set_mac_address (struct net_device *dev, void *addr) 
+{
+	struct sockaddr *saddr = addr ; 
+	struct olympic_private *olympic_priv = (struct olympic_private *)dev->priv ; 
+
+	if (dev->start) { 
+		printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ; 
+		return -EIO ; 
+	}
+
+	memcpy(olympic_priv->olympic_laa, saddr->sa_data,dev->addr_len) ; 
+	
+	if (olympic_priv->olympic_message_level) { 
+ 		printk(KERN_INFO "%s: MAC/LAA Set to  = %x.%x.%x.%x.%x.%x\n",dev->name, olympic_priv->olympic_laa[0],
+		olympic_priv->olympic_laa[1], olympic_priv->olympic_laa[2],
+		olympic_priv->olympic_laa[3], olympic_priv->olympic_laa[4],
+		olympic_priv->olympic_laa[5]);
+	} 
+
+	return 0 ; 
+}
+
+static void olympic_arb_cmd(struct net_device *dev)
+{
+	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv;
+    	__u8 *olympic_mmio=olympic_priv->olympic_mmio;
+	__u8 *arb_block, *asb_block, *srb  ; 
+	__u8 header_len ; 
+	__u16 frame_len, buffer_len ;
+	struct sk_buff *mac_frame ;  
+	__u8 *buf_ptr ;
+	__u8 *frame_data ;  
+	__u16 buff_off ; 
+	__u16 lan_status = 0, lan_status_diff  ; /* Initialize to stop compiler warning */
+	__u8 fdx_prot_error ; 
+	__u16 next_ptr;
+
+#if OLYMPIC_NETWORK_MONITOR
+	struct trh_hdr *mac_hdr ; 
+#endif
+
+	arb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; 
+	asb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; 
+	srb = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->srb) ; 
+	writel(readl(olympic_mmio+LAPA),olympic_mmio+LAPWWO);
+
+	if (readb(arb_block+0) == ARB_RECEIVE_DATA) { /* Receive.data, MAC frames */
+
+		header_len = readb(arb_block+8) ; /* 802.5 Token-Ring Header Length */	
+		frame_len = ntohs(readw(arb_block + 10)) ; 
+
+		buff_off = ntohs(readw(arb_block + 6)) ;
+		
+		buf_ptr = olympic_priv->olympic_lap + buff_off ; 
+
+#if OLYMPIC_DEBUG
+{
+		int i;
+		frame_data = buf_ptr+offsetof(struct mac_receive_buffer,frame_data) ; 
+
+		for (i=0 ;  i < 14 ; i++) { 
+			printk("Loc %d = %02x\n",i,readb(frame_data + i)); 
+		}
+
+		printk("next %04x, fs %02x, len %04x \n",readw(buf_ptr+offsetof(struct mac_receive_buffer,next)), readb(buf_ptr+offsetof(struct mac_receive_buffer,frame_status)), readw(buf_ptr+offsetof(struct mac_receive_buffer,buffer_length))); 
+}
+#endif 
+		mac_frame = dev_alloc_skb(frame_len) ; 
+
+		/* Walk the buffer chain, creating the frame */
+
+		do {
+			frame_data = buf_ptr+offsetof(struct mac_receive_buffer,frame_data) ; 
+			buffer_len = ntohs(readw(buf_ptr+offsetof(struct mac_receive_buffer,buffer_length))); 
+			memcpy_fromio(skb_put(mac_frame, buffer_len), frame_data , buffer_len ) ;
+			next_ptr=readw(buf_ptr+offsetof(struct mac_receive_buffer,next)); 
+
+		} while (next_ptr && (buf_ptr=olympic_priv->olympic_lap + ntohs(next_ptr)));
+
+#if OLYMPIC_NETWORK_MONITOR
+		printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name) ;
+		mac_hdr = (struct trh_hdr *)mac_frame->data ; 
+		printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->daddr[0], mac_hdr->daddr[1], mac_hdr->daddr[2], mac_hdr->daddr[3], mac_hdr->daddr[4], mac_hdr->daddr[5]) ; 
+		printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->saddr[0], mac_hdr->saddr[1], mac_hdr->saddr[2], mac_hdr->saddr[3], mac_hdr->saddr[4], mac_hdr->saddr[5]) ; 
+#endif
+		mac_frame->dev = dev ; 
+		mac_frame->protocol = tr_type_trans(mac_frame,dev);
+		netif_rx(mac_frame) ; 	
+
+		/* Now tell the card we have dealt with the received frame */
+
+		/* Set LISR Bit 1 */
+		writel(LISR_ARB_FREE,olympic_priv->olympic_lap + LISR_SUM);
+
+		/* Is the ASB free ? */ 	
+		
+		if (!(readl(olympic_priv->olympic_mmio + SISR) & SISR_ASB_FREE)) {
+			olympic_priv->asb_queued = 1 ; 
+			writel(LISR_ASB_FREE_REQ,olympic_priv->olympic_mmio+LISR_SUM); 
+			return ; 	
+			/* Drop out and wait for the bottom half to be run */
+		}
+		
+		writeb(ASB_RECEIVE_DATA,asb_block); /* Receive data */
+		writeb(OLYMPIC_CLEAR_RET_CODE,asb_block+2); /* Necessary ?? */
+		writeb(readb(arb_block+6),asb_block+6); /* Must send the address back to the adapter */
+		writeb(readb(arb_block+7),asb_block+7); /* To let it know we have dealt with the data */		
+
+		writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ,olympic_priv->olympic_mmio+LISR_SUM);
+		
+		olympic_priv->asb_queued = 2 ; 
+	
+		return ; 	
+		
+	} else if (readb(arb_block) == ARB_LAN_CHANGE_STATUS) { /* Lan.change.status */
+		lan_status = readw(arb_block+6);
+		fdx_prot_error = readb(arb_block+8) ; 
+		
+		/* Issue ARB Free */
+		writel(LISR_ARB_FREE,olympic_priv->olympic_mmio+LISR_SUM);
+
+		lan_status_diff = olympic_priv->olympic_lan_status ^ lan_status ; 
+
+		if (lan_status_diff & (LSC_LWF | LSC_ARW | LSC_FPE | LSC_RR) ) { 
+			if (lan_status_diff & LSC_LWF) 
+					printk(KERN_WARNING "%s: Short circuit detected on the lobe\n",dev->name);
+			if (lan_status_diff & LSC_ARW) 
+					printk(KERN_WARNING "%s: Auto removal error\n",dev->name);
+			if (lan_status_diff & LSC_FPE)
+					printk(KERN_WARNING "%s: FDX Protocol Error\n",dev->name);
+			if (lan_status_diff & LSC_RR) 
+					printk(KERN_WARNING "%s: Force remove MAC frame received\n",dev->name);
+		
+			/* Adapter has been closed by the hardware */
+		
+			/* reset tx/rx fifo's and busmaster logic */
+
+			writel(readl(olympic_mmio+BCTL)|(3<<13),olympic_mmio+BCTL);
+			udelay(1);
+			writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL);
+			dev->tbusy = 1 ;
+			dev->interrupt = 1 ; 
+			dev->start = 0 ; 
+			olympic_priv->srb = readw(olympic_priv->olympic_lap + LAPWWO) ; 
+			free_irq(dev->irq,dev);
+			
+			printk(KERN_WARNING "%s: Adapter has been closed \n", dev->name) ; 
+	
+		} /* If serious error */
+		
+		if (olympic_priv->olympic_message_level) { 
+			if (lan_status_diff & LSC_SIG_LOSS) 
+					printk(KERN_WARNING "%s: No receive signal detected \n", dev->name) ; 
+			if (lan_status_diff & LSC_HARD_ERR)
+					printk(KERN_INFO "%s: Beaconing \n",dev->name);
+			if (lan_status_diff & LSC_SOFT_ERR)
+					printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame \n",dev->name);
+			if (lan_status_diff & LSC_TRAN_BCN) 
+					printk(KERN_INFO "%s: We are tranmitting the beacon, aaah\n",dev->name);
+			if (lan_status_diff & LSC_SS) 
+					printk(KERN_INFO "%s: Single Station on the ring \n", dev->name);
+			if (lan_status_diff & LSC_RING_REC)
+					printk(KERN_INFO "%s: Ring recovery ongoing\n",dev->name);
+			if (lan_status_diff & LSC_FDX_MODE)
+					printk(KERN_INFO "%s: Operating in FDX mode\n",dev->name);
+		} 	
+		
+		if (lan_status_diff & LSC_CO) { 
+					
+				if (olympic_priv->olympic_message_level) 
+					printk(KERN_INFO "%s: Counter Overflow \n", dev->name);
+					
+				/* Issue READ.LOG command */
+
+				writeb(SRB_READ_LOG, srb);
+				writeb(0,srb+1);
+				writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
+				writeb(0,srb+3);
+				writeb(0,srb+4);
+				writeb(0,srb+5);
+					
+				olympic_priv->srb_queued=2; /* Can't sleep, use srb_bh */
+
+				writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
+					
+		}
+
+		if (lan_status_diff & LSC_SR_CO) { 
+
+				if (olympic_priv->olympic_message_level)
+					printk(KERN_INFO "%s: Source routing counters overflow\n", dev->name);
+
+				/* Issue a READ.SR.COUNTERS */
+				
+				writeb(SRB_READ_SR_COUNTERS,srb);
+				writeb(0,srb+1);
+				writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
+				writeb(0,srb+3);
+				
+				olympic_priv->srb_queued=2; /* Can't sleep, use srb_bh */
+
+				writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
+
+		}
+
+		olympic_priv->olympic_lan_status = lan_status ; 
+	
+	}  /* Lan.change.status */
+	else
+		printk(KERN_WARNING "%s: Unknown arb command \n", dev->name);
+}
+
+static void olympic_asb_bh(struct net_device *dev) 
+{
+	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; 
+	__u8 *arb_block, *asb_block ; 
+
+	arb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; 
+	asb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; 
+
+	if (olympic_priv->asb_queued == 1) {   /* Dropped through the first time */
+
+		writeb(ASB_RECEIVE_DATA,asb_block); /* Receive data */
+		writeb(OLYMPIC_CLEAR_RET_CODE,asb_block+2); /* Necessary ?? */
+		writeb(readb(arb_block+6),asb_block+6); /* Must send the address back to the adapter */
+		writeb(readb(arb_block+7),asb_block+7); /* To let it know we have dealt with the data */		
+
+		writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ,olympic_priv->olympic_mmio+LISR_SUM);
+		olympic_priv->asb_queued = 2 ; 
+
+		return ; 
+	}
+
+	if (olympic_priv->asb_queued == 2) { 
+		switch (readb(asb_block+2)) {
+			case 0x01:
+				printk(KERN_WARNING "%s: Unrecognized command code \n", dev->name);
+				break ;
+			case 0x26:
+				printk(KERN_WARNING "%s: Unrecognized buffer address \n", dev->name);
+				break ;
+			case 0xFF:
+				/* Valid response, everything should be ok again */
+				break ;
+			default:
+				printk(KERN_WARNING "%s: Invalid return code in asb\n",dev->name);
+				break ;
+		}
+	}
+	olympic_priv->asb_queued = 0 ; 
+}
+ 
+static int olympic_change_mtu(struct net_device *dev, int mtu) 
+{
+	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv;
+	__u16 max_mtu ; 
+
+	if (olympic_priv->olympic_ring_speed == 4)
+		max_mtu = 4500 ; 
+	else
+		max_mtu = 18000 ; 
+	
+	if (mtu > max_mtu)
+		return -EINVAL ; 
+	if (mtu < 100) 
+		return -EINVAL ; 
+
+	dev->mtu = mtu ; 
+	olympic_priv->pkt_buf_sz = mtu + TR_HLEN ; 
+
+	return 0 ; 
+}
+
+#if OLYMPIC_NETWORK_MONITOR
+#ifdef CONFIG_PROC_FS
+static int olympic_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+{
+	struct pci_dev *pci_device = NULL ;
+	int len=0;
+	off_t begin=0;
+	off_t pos=0;
+	int size;
+	
+	struct net_device *dev;
+
+
+	size = sprintf(buffer, 
+		"IBM Pit/Pit-Phy/Olympic Chipset Token Ring Adapters\n");
+	
+	pos+=size;
+	len+=size;
+	
+
+	while((pci_device=pci_find_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR_WAKE, pci_device))) {
+	
+		for (dev = dev_base; dev != NULL; dev = dev->next) 
+		{
+			if (dev->base_addr == pci_device->resource[0].start ) { /* Yep, an Olympic device */	
+				size = sprintf_info(buffer+len, dev);
+				len+=size;
+				pos=begin+len;
+				
+				if(pos<offset)
+				{
+					len=0;
+					begin=pos;
+				}
+				if(pos>offset+length)
+					break;
+			} /* if */
+		} /* for */
+	} /* While */
+
+	*start=buffer+(offset-begin);	/* Start of wanted data */
+	len-=(offset-begin);		/* Start slop */
+	if(len>length)
+		len=length;		/* Ending slop */
+	return len;
+}
+
+static int sprintf_info(char *buffer, struct net_device *dev)
+{
+	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+	__u8 *oat = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; 
+	__u8 *opt = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; 
+	int size = 0 ; 
+		
+	size = sprintf(buffer, "\n%6s: Adapter Address   : Node Address      : Functional Addr\n",
+ 	   dev->name); 
+
+	size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x\n",
+	   dev->name,
+           dev->dev_addr[0],
+	   dev->dev_addr[1],
+	   dev->dev_addr[2],
+ 	   dev->dev_addr[3],
+	   dev->dev_addr[4],
+	   dev->dev_addr[5],
+	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), 
+	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1),
+	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2),
+	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3),
+	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4),
+	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5),
+	   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), 
+	   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1),
+	   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2),
+	   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3));
+	 
+	size += sprintf(buffer+size, "\n%6s: Token Ring Parameters Table:\n", dev->name);
+
+	size += sprintf(buffer+size, "%6s: Physical Addr : Up Node Address   : Poll Address      : AccPri : Auth Src : Att Code :\n",
+	  dev->name) ; 
+	   
+	size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x   : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %04x   : %04x     :  %04x    :\n",
+	  dev->name,
+	  readb(opt+offsetof(struct olympic_parameters_table, phys_addr)),
+	  readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+1),
+	  readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+2),
+	  readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+3),
+	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)),
+	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1),
+	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2),
+	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3),
+	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4),
+	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5),
+	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)),
+	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+1),
+	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+2),
+	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+3),
+	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+4),
+	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+5),
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, acc_priority))),
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, auth_source_class))),
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, att_code))));
+
+	size += sprintf(buffer+size, "%6s: Source Address    : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n",
+	  dev->name) ; 
+	
+	size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %04x  : %04x   : %04x   : %04x   : %04x    :     %04x     : \n",
+	  dev->name,
+	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)),
+	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)+1),
+	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)+2),
+	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)+3),
+	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)+4),
+	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)+5),
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, beacon_type))),
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, major_vector))),
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, lan_status))),
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, local_ring))),
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, mon_error))),
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, frame_correl))));
+
+	size += sprintf(buffer+size, "%6s: Beacon Details :  Tx  :  Rx  : NAUN Node Address : NAUN Node Phys : \n",
+	  dev->name) ; 
+
+	size += sprintf(buffer+size, "%6s:                :  %02x  :  %02x  : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x    : \n",
+	  dev->name,
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, beacon_transmit))),
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, beacon_receive))),
+	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)),
+	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+1),
+	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+2),
+	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+3),
+	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+4),
+	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+5),
+	  readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)),
+	  readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+1),
+	  readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+2),
+	  readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+3));
+
+ 
+	return size;
+}
+#endif
+#endif 
+
+#ifdef MODULE
+
+static struct net_device* dev_olympic[OLYMPIC_MAX_ADAPTERS];
+
+int init_module(void)
+{
+        int i;
+
+#if OLYMPIC_NETWORK_MONITOR
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *ent ; 
+
+	ent = create_proc_entry("net/olympic_tr",0,0); 
+	ent->read_proc = &olympic_proc_info ; 
+#endif
+#endif
+        for (i = 0; (i<OLYMPIC_MAX_ADAPTERS); i++) {
+		dev_olympic[i] = NULL;
+                dev_olympic[i] = init_trdev(dev_olympic[i], 0);
+                if (dev_olympic[i] == NULL)
+                        return -ENOMEM;
+
+		dev_olympic[i]->init      = &olympic_probe;
+
+	        if (register_trdev(dev_olympic[i]) != 0) {
+			kfree_s(dev_olympic[i], sizeof(struct net_device));
+			dev_olympic[i] = NULL;
+		        if (i == 0) {
+			        printk("Olympic: No IBM PCI Token Ring cards found in system.\n");
+		                return -EIO;
+			} else {
+			       	printk("Olympic: %d IBM PCI Token Ring card(s) found in system.\n",i) ; 
+				return 0;
+			}
+	        }
+	}
+
+	return 0;
+}
+
+void cleanup_module(void)
+{
+        int i;
+
+        for (i = 0; i < OLYMPIC_MAX_ADAPTERS; i++)
+	        if (dev_olympic[i]) {
+			 unregister_trdev(dev_olympic[i]);
+			 release_region(dev_olympic[i]->base_addr, OLYMPIC_IO_SPACE);
+			 kfree_s(dev_olympic[i]->priv, sizeof(struct olympic_private));
+			 kfree_s(dev_olympic[i], sizeof(struct net_device));
+			 dev_olympic[i] = NULL;
+                }
+
+#if OLYMPIC_NETWORK_MONITOR
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("net/olympic_tr", NULL) ; 
+#endif 
+#endif
+}
+#endif /* MODULE */
+
diff -u --recursive --new-file v2.3.20/linux/drivers/net/tokenring/olympic.h linux/drivers/net/tokenring/olympic.h
--- v2.3.20/linux/drivers/net/tokenring/olympic.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/tokenring/olympic.h	Mon Oct 11 10:13:24 1999
@@ -0,0 +1,304 @@
+/*
+ *  olympic.h (c) 1999 Peter De Schrijver All Rights Reserved
+ *                1999 Mike Phillips (phillim@amtrak.com)
+ *
+ *  Linux driver for IBM PCI tokenring cards based on the olympic and the PIT/PHY chipset.
+ *
+ *  Base Driver Skeleton:
+ *      Written 1993-94 by Donald Becker.
+ *
+ *      Copyright 1993 United States Government as represented by the
+ *      Director, National Security Agency.
+ *
+ *  This software may be used and distributed according to the terms
+ *  of the GNU Public License, incorporated herein by reference.
+ */
+
+#define CID 0x4e
+
+#define BCTL 0x70
+#define BCTL_SOFTRESET (1<<15)
+#define BCTL_MIMREB (1<<6)
+
+#define GPR 0x4a
+#define GPR_OPTI_BF (1<<6)
+#define GPR_NEPTUNE_BF (1<<4) 
+#define GPR_AUTOSENSE (1<<2)
+#define GPR_16MBPS (1<<3) 
+
+#define PAG 0x85
+#define LBC 0x8e
+
+#define LISR 0x10
+#define LISR_SUM 0x14
+#define LISR_RWM 0x18
+
+#define LISR_LIE (1<<15)
+#define LISR_SLIM (1<<13)
+#define LISR_SLI (1<<12)
+#define LISR_PCMSRMASK (1<<11)
+#define LISR_PCMSRINT (1<<10)
+#define LISR_WOLMASK (1<<9)
+#define LISR_WOL (1<<8)
+#define LISR_SRB_CMD (1<<5)
+#define LISR_ASB_REPLY (1<<4)
+#define LISR_ASB_FREE_REQ (1<<2)
+#define LISR_ARB_FREE (1<<1)
+#define LISR_TRB_FRAME (1<<0)
+
+#define SISR 0x20
+#define SISR_SUM 0x24
+#define SISR_RWM 0x28
+#define SISR_RR 0x2C
+#define SISR_RESMASK 0x30
+#define SISR_MASK 0x54
+#define SISR_MASK_SUM 0x58
+#define SISR_MASK_RWM 0x5C
+
+#define SISR_TX2_IDLE (1<<31)
+#define SISR_TX2_HALT (1<<29)
+#define SISR_TX2_EOF (1<<28)
+#define SISR_TX1_IDLE (1<<27)
+#define SISR_TX1_HALT (1<<25)
+#define SISR_TX1_EOF (1<<24)
+#define SISR_TIMEOUT (1<<23)
+#define SISR_RX_NOBUF (1<<22)
+#define SISR_RX_STATUS (1<<21)
+#define SISR_RX_HALT (1<<18)
+#define SISR_RX_EOF_EARLY (1<<16)
+#define SISR_MI (1<<15)
+#define SISR_PI (1<<13)
+#define SISR_ERR (1<<9)
+#define SISR_ADAPTER_CHECK (1<<6)
+#define SISR_SRB_REPLY (1<<5)
+#define SISR_ASB_FREE (1<<4)
+#define SISR_ARB_CMD (1<<3)
+#define SISR_TRB_REPLY (1<<2)
+
+#define EISR 0x34
+#define EISR_RWM 0x38
+#define EISR_MASK 0x3c
+
+#define LAPA 0x60
+#define LAPWWO 0x64
+#define LAPWWC 0x68
+#define LAPCTL 0x6C
+#define LAIPD 0x78
+#define LAIPDDINC 0x7C
+
+#define TIMER 0x50
+
+#define CLKCTL 0x74
+
+#define PM_CON 0x4
+
+#define BMCTL_SUM 0x40
+#define BMCTL_RWM 0x44
+#define BMCTL_TX2_DIS (1<<30) 
+#define BMCTL_TX1_DIS (1<<26) 
+#define BMCTL_RX_DIS (1<<22) 
+
+#define BMASR 0xcc
+
+#define RXDESCQ 0x90
+#define RXDESCQCNT 0x94
+#define RXCDA 0x98
+#define RXENQ 0x9C
+#define RXSTATQ 0xA0
+#define RXSTATQCNT 0xA4
+#define RXCSA 0xA8
+#define RXCLEN 0xAC
+#define RXHLEN 0xAE
+
+#define TXDESCQ_1 0xb0
+#define TXDESCQ_2 0xd0
+#define TXDESCQCNT_1 0xb4
+#define TXDESCQCNT_2 0xd4
+#define TXCDA_1 0xb8
+#define TXCDA_2 0xd8
+#define TXENQ_1 0xbc
+#define TXENQ_2 0xdc
+#define TXSTATQ_1 0xc0
+#define TXSTATQ_2 0xe0
+#define TXSTATQCNT_1 0xc4
+#define TXSTATQCNT_2 0xe4
+#define TXCSA_1 0xc8
+#define TXCSA_2 0xe8
+
+#define OLYMPIC_IO_SPACE 256
+
+#define SRB_COMMAND_SIZE 50
+
+#define OLYMPIC_MAX_ADAPTERS 8 /* 0x08 __MODULE_STRING can't hand 0xnn */
+
+/* Defines for LAN STATUS CHANGE reports */
+#define LSC_SIG_LOSS 0x8000
+#define LSC_HARD_ERR 0x4000
+#define LSC_SOFT_ERR 0x2000
+#define LSC_TRAN_BCN 0x1000
+#define LSC_LWF      0x0800
+#define LSC_ARW      0x0400
+#define LSC_FPE      0x0200
+#define LSC_RR       0x0100
+#define LSC_CO       0x0080
+#define LSC_SS       0x0040
+#define LSC_RING_REC 0x0020
+#define LSC_SR_CO    0x0010
+#define LSC_FDX_MODE 0x0004
+
+/* Defines for OPEN ADAPTER command */
+
+#define OPEN_ADAPTER_EXT_WRAP (1<<15)
+#define OPEN_ADAPTER_DIS_HARDEE (1<<14)
+#define OPEN_ADAPTER_DIS_SOFTERR (1<<13)
+#define OPEN_ADAPTER_PASS_ADC_MAC (1<<12)
+#define OPEN_ADAPTER_PASS_ATT_MAC (1<<11)
+#define OPEN_ADAPTER_ENABLE_EC (1<<10)
+#define OPEN_ADAPTER_CONTENDER (1<<8)
+#define OPEN_ADAPTER_PASS_BEACON (1<<7)
+#define OPEN_ADAPTER_ENABLE_FDX (1<<6)
+#define OPEN_ADAPTER_ENABLE_RPL (1<<5)
+#define OPEN_ADAPTER_INHIBIT_ETR (1<<4)
+#define OPEN_ADAPTER_INTERNAL_WRAP (1<<3)
+#define OPEN_ADAPTER_USE_OPTS2 (1<<0)
+
+#define OPEN_ADAPTER_2_ENABLE_ONNOW (1<<15)
+
+/* Defines for SRB Commands */
+
+#define SRB_ACCESS_REGISTER 0x1f
+#define SRB_CLOSE_ADAPTER 0x04
+#define SRB_CONFIGURE_BRIDGE 0x0c
+#define SRB_CONFIGURE_WAKEUP_EVENT 0x1a
+#define SRB_MODIFY_BRIDGE_PARMS 0x15
+#define SRB_MODIFY_OPEN_OPTIONS 0x01
+#define SRB_MODIFY_RECEIVE_OPTIONS 0x17
+#define SRB_NO_OPERATION 0x00
+#define SRB_OPEN_ADAPTER 0x03
+#define SRB_READ_LOG 0x08
+#define SRB_READ_SR_COUNTERS 0x16
+#define SRB_RESET_GROUP_ADDRESS 0x02
+#define SRB_SAVE_CONFIGURATION 0x1b
+#define SRB_SET_BRIDGE_PARMS 0x09
+#define SRB_SET_BRIDGE_TARGETS 0x10
+#define SRB_SET_FUNC_ADDRESS 0x07
+#define SRB_SET_GROUP_ADDRESS 0x06
+#define SRB_SET_GROUP_ADDR_OPTIONS 0x11
+#define SRB_UPDATE_WAKEUP_PATTERN 0x19
+
+/* Clear return code */
+
+#define OLYMPIC_CLEAR_RET_CODE 0xfe 
+
+/* ARB Commands */
+#define ARB_RECEIVE_DATA 0x81
+#define ARB_LAN_CHANGE_STATUS 0x84
+/* ASB Response commands */
+
+#define ASB_RECEIVE_DATA 0x81
+
+
+/* Olympic defaults for buffers */
+ 
+#define OLYMPIC_RX_RING_SIZE 16 /* should be a power of 2 */
+#define OLYMPIC_TX_RING_SIZE 8 /* should be a power of 2 */
+
+#define PKT_BUF_SZ 4096 /* Default packet size */
+
+/* Olympic data structures */
+
+struct olympic_tx_desc {
+	__u32 buffer;
+	__u32 status_length;
+};
+
+struct olympic_tx_status {
+	__u32 status;
+};
+
+struct olympic_rx_desc {
+	__u32 buffer;
+	__u32 res_length ; 
+};
+
+struct olympic_rx_status {
+	__u32 fragmentcnt_framelen;
+	__u32 status_buffercnt;
+};
+
+struct mac_receive_buffer {
+	__u16 next ; 
+	__u8 padding ; 
+	__u8 frame_status ;
+	__u16 buffer_length ; 
+	__u8 frame_data ; 
+};
+
+struct olympic_private {
+	
+	__u16 srb;
+	__u16 trb;
+	__u16 arb;
+	__u16 asb;
+
+	__u8 *olympic_mmio;
+	__u8 *olympic_lap;
+	char *olympic_card_name ; 
+
+	volatile int srb_queued;    /* True if an SRB is still posted */	
+	wait_queue_head_t srb_wait;
+
+	volatile int asb_queued;    /* True if an ASB is posted */
+
+	volatile int trb_queued;   /* True if a TRB is posted */
+	wait_queue_head_t trb_wait ; 
+
+	struct olympic_rx_desc olympic_rx_ring[OLYMPIC_RX_RING_SIZE];
+	struct olympic_tx_desc olympic_tx_ring[OLYMPIC_TX_RING_SIZE];
+	struct olympic_rx_status olympic_rx_status_ring[OLYMPIC_RX_RING_SIZE];	
+	struct olympic_tx_status olympic_tx_status_ring[OLYMPIC_TX_RING_SIZE];	
+	struct sk_buff *tx_ring_skb[OLYMPIC_TX_RING_SIZE], *rx_ring_skb[OLYMPIC_RX_RING_SIZE];	
+	int tx_ring_free, tx_ring_last_status, rx_ring_last_received,rx_status_last_received, free_tx_ring_entries;
+
+	struct net_device_stats olympic_stats ;
+	__u16 olympic_lan_status ;
+	__u8 olympic_ring_speed ;
+	__u16 pkt_buf_sz ; 
+	__u8 olympic_receive_options, olympic_copy_all_options, olympic_message_level;  
+	__u8 olympic_multicast_set ; 
+	__u16 olympic_addr_table_addr, olympic_parms_addr ; 
+	__u8 olympic_laa[6] ; 
+};
+
+struct olympic_adapter_addr_table {
+
+	__u8 node_addr[6] ; 
+	__u8 reserved[4] ; 
+	__u8 func_addr[4] ; 
+} ; 
+
+struct olympic_parameters_table { 
+	
+	__u8  phys_addr[4] ; 
+	__u8  up_node_addr[6] ; 
+	__u8  up_phys_addr[6] ; 
+	__u8  poll_addr[6] ; 
+	__u16 reserved ; 
+	__u16 acc_priority ; 
+	__u16 auth_source_class ; 
+	__u16 att_code ; 
+	__u8  source_addr[6] ; 
+	__u16 beacon_type ; 
+	__u16 major_vector ; 
+	__u16 lan_status ; 
+	__u16 soft_error_time ; 
+ 	__u16 reserved1 ; 
+	__u16 local_ring ; 
+	__u16 mon_error ; 
+	__u16 beacon_transmit ; 
+	__u16 beacon_receive ; 
+	__u16 frame_correl ; 
+	__u8  beacon_naun[6] ; 
+	__u32 reserved2 ; 
+	__u8  beacon_phys[4] ; 	
+}; 
diff -u --recursive --new-file v2.3.20/linux/drivers/net/tokenring/sktr.c linux/drivers/net/tokenring/sktr.c
--- v2.3.20/linux/drivers/net/tokenring/sktr.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/tokenring/sktr.c	Mon Oct 11 10:13:24 1999
@@ -0,0 +1,2707 @@
+/*
+ *  sktr.c: A network driver for the SysKonnect Token Ring ISA/PCI Adapters.
+ *
+ *  Written 1997 by Christoph Goos
+ *
+ *  A fine result of the Linux Systems Network Architecture Project.
+ *  http://samba.anu.edu.au/linux-sna/
+ *
+ *  This software may be used and distributed according to the terms
+ *  of the GNU Public License, incorporated herein by reference.
+ *
+ *  This device driver works with the following SysKonnect adapters:
+ *	- SysKonnect TR4/16(+) ISA	(SK-4190)
+ *	- SysKonnect TR4/16(+) PCI	(SK-4590)
+ *	- SysKonnect TR4/16 PCI		(SK-4591)
+ *
+ *  Sources:
+ *  	- The hardware related parts of this driver are take from
+ *  	  the SysKonnect Token Ring driver for Windows NT.
+ *  	- I used the IBM Token Ring driver 'ibmtr.c' as a base for this
+ *  	  driver, as well as the 'skeleton.c' driver by Donald Becker.
+ *  	- Also various other drivers in the linux source tree were taken
+ *  	  as samples for some tasks.
+ *
+ *  Maintainer(s):
+ *    JS        Jay Schulist            jschlst@samba.anu.edu.au
+ *    CG	Christoph Goos          cgoos@syskonnect.de
+ *    AF	Adam Fritzler		mid@auk.cx
+ *
+ *  Modification History:
+ *	29-Aug-97	CG	Created
+ *	04-Apr-98	CG	Fixed problems caused by tok_timer_check
+ *	10-Apr-98	CG	Fixed lockups at cable disconnection
+ *	27-May-98	JS	Formated to Linux Kernel Format
+ *	31-May-98	JS	Hacked in PCI support
+ *	16-Jun-98	JS	Modulized for multiple cards with one driver
+ *	21-Sep-99	CG	Fixed source routing issues for 2.2 kernels
+ *	21-Sep-99	AF	Added multicast changes recommended by 
+ *				  Jochen Friedrich <jochen@nwe.de> (untested)
+ *				Added detection of compatible Compaq PCI card  
+ *
+ *  To do:
+ *    1. Selectable 16 Mbps or 4Mbps
+ *    2. Multi/Broadcast packet handling (might be done)
+ *
+ */
+
+static const char *version = "sktr.c: v1.01 08/29/97 by Christoph Goos\n";
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
+#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/time.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/irq.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/trdevice.h>
+
+#include "sktr.h"		/* Our Stuff */
+#include "sktr_firmware.h"	/* SysKonnect adapter firmware */
+
+/* A zero-terminated list of I/O addresses to be probed. */
+static unsigned int sktr_portlist[] __initdata = {
+	0x0A20, 0x1A20, 0x0B20, 0x1B20, 0x0980, 0x1980, 0x0900, 0x1900,
+	0
+};
+
+/* A zero-terminated list of IRQs to be probed. 
+ * Used again after initial probe for sktr_chipset_init, called from sktr_open.
+ */
+static unsigned short sktr_irqlist[] = {
+	3, 5, 9, 10, 11, 12, 15,
+	0
+};
+
+/* A zero-terminated list of DMAs to be probed. */
+static int sktr_dmalist[] __initdata = {
+	5, 6, 7,
+	0
+};
+
+/* Card names */
+static char *pci_cardname = "SK NET TR 4/16 PCI\0";
+static char *isa_cardname = "SK NET TR 4/16 ISA\0";
+static char *AdapterName;
+
+/* Use 0 for production, 1 for verification, 2 for debug, and
+ * 3 for very verbose debug.
+ */
+#ifndef SKTR_DEBUG
+#define SKTR_DEBUG 1
+#endif
+static unsigned int sktr_debug = SKTR_DEBUG;
+
+/* The number of low I/O ports used by the tokencard. */
+#define SKTR_IO_EXTENT 32
+
+/* Index to functions, as function prototypes.
+ * Alphabetical by function name.
+ */
+
+/* "B" */
+static int      sktr_bringup_diags(struct net_device *dev);
+/* "C" */
+static void	sktr_cancel_tx_queue(struct net_local* tp);
+static int 	sktr_chipset_init(struct net_device *dev);
+static void 	sktr_chk_irq(struct net_device *dev);
+static unsigned char sktr_chk_frame(struct net_device *dev, unsigned char *Addr);
+static void 	sktr_chk_outstanding_cmds(struct net_device *dev);
+static void 	sktr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr);
+static unsigned char sktr_chk_ssb(struct net_local *tp, unsigned short IrqType);
+static int 	sktr_close(struct net_device *dev);
+static void 	sktr_cmd_status_irq(struct net_device *dev);
+/* "D" */
+static void 	sktr_disable_interrupts(struct net_device *dev);
+static void 	sktr_dump(unsigned char *Data, int length);
+/* "E" */
+static void 	sktr_enable_interrupts(struct net_device *dev);
+static void 	sktr_exec_cmd(struct net_device *dev, unsigned short Command);
+static void 	sktr_exec_sifcmd(struct net_device *dev, unsigned int WriteValue);
+/* "F" */
+/* "G" */
+static struct enet_statistics *sktr_get_stats(struct net_device *dev);
+/* "H" */
+static void 	sktr_hardware_send_packet(struct net_device *dev,
+			struct net_local* tp);
+/* "I" */
+static int 	sktr_init_adapter(struct net_device *dev);
+static int 	sktr_init_card(struct net_device *dev);
+static void 	sktr_init_ipb(struct net_local *tp);
+static void 	sktr_init_net_local(struct net_device *dev);
+static void 	sktr_init_opb(struct net_local *tp);
+static void 	sktr_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int 	sktr_isa_chk_card(struct net_device *dev, int ioaddr);
+static int      sktr_isa_chk_ioaddr(int ioaddr);
+/* "O" */
+static int 	sktr_open(struct net_device *dev);
+static void	sktr_open_adapter(struct net_device *dev);
+/* "P" */
+static int 	sktr_pci_chk_card(struct net_device *dev);
+int 		sktr_probe(struct net_device *dev);
+static int 	sktr_probe1(struct net_device *dev, int ioaddr);
+/* "R" */
+static void 	sktr_rcv_status_irq(struct net_device *dev);
+static void 	sktr_read_addr(struct net_device *dev, unsigned char *Address);
+static void 	sktr_read_ptr(struct net_device *dev);
+static void 	sktr_read_ram(struct net_device *dev, unsigned char *Data,
+			unsigned short Address, int Length);
+static int 	sktr_reset_adapter(struct net_device *dev);
+static void 	sktr_reset_interrupt(struct net_device *dev);
+static void 	sktr_ring_status_irq(struct net_device *dev);
+/* "S" */
+static int 	sktr_send_packet(struct sk_buff *skb, struct net_device *dev);
+static void 	sktr_set_multicast_list(struct net_device *dev);
+/* "T" */
+static void 	sktr_timer_chk(unsigned long data);
+static void 	sktr_timer_end_wait(unsigned long data);
+static void 	sktr_tx_status_irq(struct net_device *dev);
+/* "U" */
+static void 	sktr_update_rcv_stats(struct net_local *tp,
+			unsigned char DataPtr[], unsigned int Length);
+/* "W" */
+static void 	sktr_wait(unsigned long time);
+static void 	sktr_write_rpl_status(RPL *rpl, unsigned int Status);
+static void 	sktr_write_tpl_status(TPL *tpl, unsigned int Status);
+
+/*
+ * Check for a network adapter of this type, and return '0' if one exists.
+ * If dev->base_addr == 0, probe all likely locations.
+ * If dev->base_addr == 1, always return failure.
+ */
+int __init sktr_probe(struct net_device *dev)
+{
+	int i;
+	int base_addr = dev ? dev->base_addr : 0;
+
+	if(base_addr > 0x1ff)    /* Check a single specified location. */
+		return (sktr_probe1(dev, base_addr));
+	else if(base_addr != 0)  /* Don't probe at all. */
+		return (-ENXIO);
+
+	for(i = 0; sktr_portlist[i]; i++)
+	{
+		int ioaddr = sktr_portlist[i];
+		if(check_region(ioaddr, SKTR_IO_EXTENT))
+			continue;
+		if(sktr_probe1(dev, ioaddr))
+		{
+#ifndef MODULE
+                        tr_freedev(dev);
+#endif
+                }
+		else
+			return (0);
+	}
+
+	return (-ENODEV);
+}
+
+/*
+ * Detect and setup the PCI SysKonnect TR cards in slot order.
+ */
+static int __init sktr_pci_chk_card(struct net_device *dev)
+{
+	static int pci_index = 0;
+	unsigned char pci_bus, pci_device_fn;
+
+	if(!pci_present())
+		return (-1);	/* No PCI present. */
+
+	for(; pci_index < 0xff; pci_index++)
+	{
+		unsigned int pci_irq_line;
+		struct pci_dev *pdev;
+		unsigned short pci_command, new_command, vendor, device;
+		unsigned int pci_ioaddr;
+
+		if(pcibios_find_class(PCI_CLASS_NETWORK_TOKEN_RING << 8,
+			pci_index, &pci_bus, &pci_device_fn)
+			!= PCIBIOS_SUCCESSFUL)
+		{
+			break;
+		}
+
+		pcibios_read_config_word(pci_bus, pci_device_fn,
+						PCI_VENDOR_ID, &vendor);
+		pcibios_read_config_word(pci_bus, pci_device_fn,
+						PCI_DEVICE_ID, &device);
+
+		pdev		= pci_find_slot(pci_bus, pci_device_fn);
+		pci_irq_line 	= pdev->irq;
+		pci_ioaddr 	= pdev->resource[0].start;
+
+		pcibios_read_config_word(pci_bus, pci_device_fn,
+						PCI_COMMAND, &pci_command);
+
+		/* Remove I/O space marker in bit 0. */
+		pci_ioaddr &= ~3;
+
+		if((vendor != PCI_VENDOR_ID_SK) &&
+		   (vendor != PCI_VENDOR_ID_COMPAQ))
+			continue;
+
+		if((vendor == PCI_VENDOR_ID_SK) && 
+		   (device != PCI_DEVICE_ID_SK_TR))
+			continue;
+		else if((vendor == PCI_VENDOR_ID_COMPAQ) && 
+			(device != PCI_DEVICE_ID_COMPAQ_TOKENRING))
+			continue;
+     
+		if(check_region(pci_ioaddr, SKTR_IO_EXTENT))
+			continue;
+		request_region(pci_ioaddr, SKTR_IO_EXTENT, pci_cardname);
+		if(request_irq(pdev->irq, sktr_interrupt, SA_SHIRQ,
+				pci_cardname, dev))
+			return (-ENODEV); /* continue; ?? */
+
+		AdapterName = pci_cardname;
+
+		new_command = (pci_command|PCI_COMMAND_MASTER|PCI_COMMAND_IO);
+
+		if(pci_command != new_command)
+		{
+			printk("The PCI BIOS has not enabled this"
+				"device! Updating PCI command %4.4x->%4.4x.\n",
+			  	pci_command, new_command);
+			pcibios_write_config_word(pci_bus, pci_device_fn,
+				PCI_COMMAND, new_command);
+		}
+
+		/* At this point we have found a valid PCI TR card. */
+		dev->base_addr	= pci_ioaddr;
+		dev->irq 	= pci_irq_line;
+		dev->dma	= 0;
+
+		printk("%s: %s found at %#4x, using IRQ %d.\n",
+			dev->name, AdapterName, pci_ioaddr, dev->irq);
+
+		return (0);
+	}
+
+	return (-1);
+}
+
+/*
+ * Detect and setup the ISA SysKonnect TR cards.
+ */
+static int __init sktr_isa_chk_card(struct net_device *dev, int ioaddr)
+{
+	int i, err;
+	unsigned long flags;
+
+	err = sktr_isa_chk_ioaddr(ioaddr);
+	if(err < 0)
+		return (-ENODEV);
+
+        if(virt_to_bus((void*)((unsigned long)dev->priv+sizeof(struct net_local)))
+		> ISA_MAX_ADDRESS)
+        {
+                printk("%s: Memory not accessible for DMA\n", dev->name);
+                kfree(dev->priv);
+                return (-EAGAIN);
+        }
+
+	AdapterName = isa_cardname;
+
+        /* Grab the region so that no one else tries to probe our ioports. */
+        request_region(ioaddr, SKTR_IO_EXTENT, AdapterName);
+        dev->base_addr = ioaddr;
+
+        /* Autoselect IRQ and DMA if dev->irq == 0 */
+        if(dev->irq == 0)
+        {
+                for(i = 0; sktr_irqlist[i] != 0; i++)
+                {
+                        dev->irq = sktr_irqlist[i];
+                        err = request_irq(dev->irq, &sktr_interrupt, 0, AdapterName, dev);
+                        if(!err)
+				break;
+                }
+
+                if(sktr_irqlist[i] == 0)
+                {
+                        printk("%s: AutoSelect no IRQ available\n", dev->name);
+                        return (-EAGAIN);
+                }
+        }
+        else
+        {
+                err = request_irq(dev->irq, &sktr_interrupt, 0, AdapterName, dev);
+		if(err)
+                {
+                        printk("%s: Selected IRQ not available\n", dev->name);
+                        return (-EAGAIN);
+                }
+        }
+
+        /* Always allocate the DMA channel after IRQ and clean up on failure */
+        if(dev->dma == 0)
+        {
+                for(i = 0; sktr_dmalist[i] != 0; i++)
+                {
+			dev->dma = sktr_dmalist[i];
+                        err = request_dma(dev->dma, AdapterName);
+                        if(!err)
+                                break;
+                }
+
+                if(dev->dma == 0)
+                {
+                        printk("%s: AutoSelect no DMA available\n", dev->name);
+                        free_irq(dev->irq, NULL);
+                        return (-EAGAIN);
+                }
+        }
+        else
+        {
+                err = request_dma(dev->dma, AdapterName);
+                if(err)
+                {
+                        printk("%s: Selected DMA not available\n", dev->name);
+                        free_irq(dev->irq, NULL);
+                        return (-EAGAIN);
+                }
+        }
+
+	flags=claim_dma_lock();
+	disable_dma(dev->dma);
+        set_dma_mode(dev->dma, DMA_MODE_CASCADE);
+        enable_dma(dev->dma);
+        release_dma_lock(flags);
+
+	printk("%s: %s found at %#4x, using IRQ %d and DMA %d.\n",
+                dev->name, AdapterName, ioaddr, dev->irq, dev->dma);
+
+	return (0);
+}
+
+static int __init sktr_probe1(struct net_device *dev, int ioaddr)
+{
+	static unsigned version_printed = 0;
+	struct net_local *tp;
+	int DeviceType = SK_PCI;
+	int err;
+
+	if(sktr_debug && version_printed++ == 0)
+		printk("%s", version);
+
+#ifndef MODULE
+	dev = init_trdev(dev, 0);
+	if(dev == NULL)
+		return (-ENOMEM);
+#endif
+
+	err = sktr_pci_chk_card(dev);
+	if(err < 0)
+	{
+		err = sktr_isa_chk_card(dev, ioaddr);
+		if(err < 0)
+			return (-ENODEV);
+		DeviceType = SK_ISA;
+	}
+
+	/* Setup this devices private information structure */
+	tp = (struct net_local *)kmalloc(sizeof(struct net_local), GFP_KERNEL | GFP_DMA);
+	if(tp == NULL)
+		return (-ENOMEM);
+	memset(tp, 0, sizeof(struct net_local));
+ 	tp->DeviceType = DeviceType;
+	init_waitqueue_head(&tp->wait_for_tok_int);
+	
+	dev->priv		= tp;
+	dev->init               = sktr_init_card;
+        dev->open               = sktr_open;
+        dev->stop               = sktr_close;
+        dev->hard_start_xmit    = sktr_send_packet;
+        dev->get_stats          = sktr_get_stats;
+        dev->set_multicast_list = &sktr_set_multicast_list;
+
+        return (0);
+}
+
+/* Dummy function */
+static int __init sktr_init_card(struct net_device *dev)
+{
+	if(sktr_debug > 3)
+		printk("%s: sktr_init_card\n", dev->name);
+
+	return (0);
+}
+
+/*
+ * This function tests if an adapter is really installed at the
+ * given I/O address. Return negative if no adapter at IO addr.
+ */
+static int __init sktr_isa_chk_ioaddr(int ioaddr)
+{
+	unsigned char old, chk1, chk2;
+
+	old = inb(ioaddr + SIFADR);	/* Get the old SIFADR value */
+
+	chk1 = 0;	/* Begin with check value 0 */
+	do {
+		/* Write new SIFADR value */
+		outb(chk1, ioaddr + SIFADR);
+
+		/* Read, invert and write */
+		chk2 = inb(ioaddr + SIFADD);
+		chk2 ^= 0x0FE;
+		outb(chk2, ioaddr + SIFADR);
+
+		/* Read, invert and compare */
+		chk2 = inb(ioaddr + SIFADD);
+		chk2 ^= 0x0FE;
+
+		if(chk1 != chk2)
+			return (-1);	/* No adapter */
+
+		chk1 -= 2;
+	} while(chk1 != 0);	/* Repeat 128 times (all byte values) */
+
+    	/* Restore the SIFADR value */
+	outb(old, ioaddr + SIFADR);
+
+	return (0);
+}
+
+/*
+ * Open/initialize the board. This is called 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 sktr_open(struct net_device *dev)
+{
+	struct net_local *tp = (struct net_local *)dev->priv;
+	int err;
+
+	/* Reset the hardware here. Don't forget to set the station address. */
+	err = sktr_chipset_init(dev);
+	if(err)
+	{
+		printk(KERN_INFO "%s: Chipset initialization error\n", 
+			dev->name);
+		return (-1);
+	}
+
+	dev->addr_len = 6;
+	sktr_read_addr(dev, (unsigned char*)dev->dev_addr);
+
+	init_timer(&tp->timer);
+	tp->timer.expires	= jiffies + 30*HZ;
+	tp->timer.function	= sktr_timer_end_wait;
+	tp->timer.data		= (unsigned long)dev;
+	tp->timer.next		= NULL;
+	tp->timer.prev		= NULL;
+	add_timer(&tp->timer);
+
+	sktr_read_ptr(dev);
+	sktr_enable_interrupts(dev);
+	sktr_open_adapter(dev);
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 0;
+
+	/* Wait for interrupt from hardware. If interrupt does not come,
+	 * there will be a timeout from the timer.
+	 */
+	tp->Sleeping = 1;
+	interruptible_sleep_on(&tp->wait_for_tok_int);
+	del_timer(&tp->timer);
+
+	/* If AdapterVirtOpenFlag is 1, the adapter is now open for use */
+	if(tp->AdapterVirtOpenFlag == 0)
+	{
+		sktr_disable_interrupts(dev);
+		return (-1);
+	}
+
+	dev->start = 1;
+
+	tp->StartTime = jiffies;
+
+	/* Start function control timer */
+	tp->timer.expires	= jiffies + 2*HZ;
+	tp->timer.function	= sktr_timer_chk;
+	tp->timer.data		= (unsigned long)dev;
+	add_timer(&tp->timer);
+
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+
+	return (0);
+}
+
+/*
+ * Timeout function while waiting for event
+ */
+static void sktr_timer_end_wait(unsigned long data)
+{
+	struct net_device *dev = (struct net_device*)data;
+	struct net_local *tp = (struct net_local *)dev->priv;
+
+	if(tp->Sleeping)
+	{
+		tp->Sleeping = 0;
+		wake_up_interruptible(&tp->wait_for_tok_int);
+	}
+
+	return;
+}
+
+/*
+ * Initialize the chipset
+ */
+static int sktr_chipset_init(struct net_device *dev)
+{
+	struct net_local *tp = (struct net_local *)dev->priv;
+	unsigned char PosReg, Tmp;
+	int i, err;
+
+	sktr_init_ipb(tp);
+	sktr_init_opb(tp);
+	sktr_init_net_local(dev);
+
+	/* Set pos register: selects irq and dma channel.
+	 * Only for ISA bus adapters.
+	 */
+	if(dev->dma > 0)
+	{
+		PosReg = 0;
+		for(i = 0; sktr_irqlist[i] != 0; i++)
+		{
+			if(sktr_irqlist[i] == dev->irq)
+				break;
+		}
+
+		/* Choose default cycle time, 500 nsec   */
+		PosReg |= CYCLE_TIME << 2;
+		PosReg |= i << 4;
+		i = dev->dma - 5;
+		PosReg |= i;
+
+		if(tp->DataRate == SPEED_4)
+			PosReg |= LINE_SPEED_BIT;
+		else
+			PosReg &= ~LINE_SPEED_BIT;
+
+		outb(PosReg, dev->base_addr + POSREG);
+		Tmp = inb(dev->base_addr + POSREG);
+		if((Tmp & ~CYCLE_TIME) != (PosReg & ~CYCLE_TIME))
+			printk(KERN_INFO "%s: POSREG error\n", dev->name);
+	}
+
+	err = sktr_reset_adapter(dev);
+	if(err < 0)
+		return (-1);
+
+	err = sktr_bringup_diags(dev);
+	if(err < 0)
+		return (-1);
+
+	err = sktr_init_adapter(dev);
+	if(err < 0)
+		return (-1);
+
+	return (0);
+}
+
+/*
+ * Initializes the net_local structure.
+ */
+static void sktr_init_net_local(struct net_device *dev)
+{
+	struct net_local *tp = (struct net_local *)dev->priv;
+	int i;
+
+	tp->scb.CMD	= 0;
+	tp->scb.Parm[0] = 0;
+	tp->scb.Parm[1] = 0;
+
+	tp->ssb.STS	= 0;
+	tp->ssb.Parm[0] = 0;
+	tp->ssb.Parm[1] = 0;
+	tp->ssb.Parm[2] = 0;
+
+	tp->CMDqueue	= 0;
+
+	tp->AdapterOpenFlag	= 0;
+	tp->AdapterVirtOpenFlag = 0;
+	tp->ScbInUse		= 0;
+	tp->OpenCommandIssued	= 0;
+	tp->ReOpenInProgress	= 0;
+	tp->HaltInProgress	= 0;
+	tp->TransmitHaltScheduled = 0;
+	tp->LobeWireFaultLogged	= 0;
+	tp->LastOpenStatus	= 0;
+	tp->MaxPacketSize	= DEFAULT_PACKET_SIZE;
+
+	skb_queue_head_init(&tp->SendSkbQueue);
+	tp->QueueSkb = MAX_TX_QUEUE;
+
+	/* Create circular chain of transmit lists */
+	for (i = 0; i < TPL_NUM; i++)
+	{
+		tp->Tpl[i].NextTPLAddr = htonl((unsigned long) virt_to_bus(&tp->Tpl[(i+1) % TPL_NUM]));
+		tp->Tpl[i].Status	= 0;
+		tp->Tpl[i].FrameSize	= 0;
+		tp->Tpl[i].FragList[0].DataCount	= 0;
+		tp->Tpl[i].FragList[0].DataAddr		= 0;
+		tp->Tpl[i].NextTPLPtr	= &tp->Tpl[(i+1) % TPL_NUM];
+		tp->Tpl[i].MData	= NULL;
+		tp->Tpl[i].TPLIndex	= i;
+		tp->Tpl[i].BusyFlag	= 0;
+	}
+
+	tp->TplFree = tp->TplBusy = &tp->Tpl[0];
+
+	/* Create circular chain of receive lists */
+	for (i = 0; i < RPL_NUM; i++)
+	{
+		tp->Rpl[i].NextRPLAddr = htonl((unsigned long) virt_to_bus(&tp->Rpl[(i+1) % RPL_NUM]));
+		tp->Rpl[i].Status = (RX_VALID | RX_START_FRAME | RX_END_FRAME | RX_FRAME_IRQ);
+		tp->Rpl[i].FrameSize = 0;
+		tp->Rpl[i].FragList[0].DataCount = SWAPB(tp->MaxPacketSize);
+
+		/* Alloc skb and point adapter to data area */
+		tp->Rpl[i].Skb = dev_alloc_skb(tp->MaxPacketSize);
+
+		/* skb == NULL ? then use local buffer */
+		if(tp->Rpl[i].Skb == NULL)
+		{
+			tp->Rpl[i].SkbStat = SKB_UNAVAILABLE;
+			tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[i]));
+			tp->Rpl[i].MData = tp->LocalRxBuffers[i];
+		}
+		else	/* SKB != NULL */
+		{
+			tp->Rpl[i].Skb->dev = dev;
+			skb_put(tp->Rpl[i].Skb, tp->MaxPacketSize);
+
+			/* data unreachable for DMA ? then use local buffer */
+			if(tp->DeviceType == SK_ISA &&
+				virt_to_bus(tp->Rpl[i].Skb->data) +
+				tp->MaxPacketSize > ISA_MAX_ADDRESS)
+			{
+				tp->Rpl[i].SkbStat = SKB_DATA_COPY;
+				tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[i]));
+				tp->Rpl[i].MData = tp->LocalRxBuffers[i];
+			}
+			else	/* DMA directly in skb->data */
+			{
+				tp->Rpl[i].SkbStat = SKB_DMA_DIRECT;
+				tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->Rpl[i].Skb->data));
+				tp->Rpl[i].MData = tp->Rpl[i].Skb->data;
+			}
+		}
+
+		tp->Rpl[i].NextRPLPtr = &tp->Rpl[(i+1) % RPL_NUM];
+		tp->Rpl[i].RPLIndex = i;
+	}
+
+	tp->RplHead = &tp->Rpl[0];
+	tp->RplTail = &tp->Rpl[RPL_NUM-1];
+	tp->RplTail->Status = (RX_START_FRAME | RX_END_FRAME | RX_FRAME_IRQ);
+
+	return;
+}
+
+/*
+ * Initializes the initialisation parameter block.
+ */
+static void sktr_init_ipb(struct net_local *tp)
+{
+	tp->ipb.Init_Options	= BURST_MODE;
+	tp->ipb.CMD_Status_IV	= 0;
+	tp->ipb.TX_IV		= 0;
+	tp->ipb.RX_IV		= 0;
+	tp->ipb.Ring_Status_IV	= 0;
+	tp->ipb.SCB_Clear_IV	= 0;
+	tp->ipb.Adapter_CHK_IV	= 0;
+	tp->ipb.RX_Burst_Size	= BURST_SIZE;
+	tp->ipb.TX_Burst_Size	= BURST_SIZE;
+	tp->ipb.DMA_Abort_Thrhld = DMA_RETRIES;
+	tp->ipb.SCB_Addr	= 0;
+	tp->ipb.SSB_Addr	= 0;
+
+	return;
+}
+
+/*
+ * Initializes the open parameter block.
+ */
+static void sktr_init_opb(struct net_local *tp)
+{
+	unsigned long Addr;
+	unsigned short RplSize    = RPL_SIZE;
+	unsigned short TplSize    = TPL_SIZE;
+	unsigned short BufferSize = BUFFER_SIZE;
+
+	tp->ocpl.OPENOptions 	 = 0;
+	tp->ocpl.OPENOptions 	|= ENABLE_FULL_DUPLEX_SELECTION;
+/*	tp->ocpl.OPENOptions 	|= PAD_ROUTING_FIELD; no more needed */
+	tp->ocpl.FullDuplex 	 = 0;
+	tp->ocpl.FullDuplex 	|= OPEN_FULL_DUPLEX_OFF;
+
+	/* Fixme: If mac address setable:
+	 * for (i=0; i<LENGTH_OF_ADDRESS; i++)
+	 *	mac->Vam->ocpl.NodeAddr[i] = mac->CurrentAddress[i];
+	 */
+
+	tp->ocpl.GroupAddr	 = 0;
+	tp->ocpl.FunctAddr	 = 0;
+	tp->ocpl.RxListSize	 = SWAPB(RplSize);
+	tp->ocpl.TxListSize	 = SWAPB(TplSize);
+	tp->ocpl.BufSize	 = SWAPB(BufferSize);
+	tp->ocpl.Reserved	 = 0;
+	tp->ocpl.TXBufMin	 = TX_BUF_MIN;
+	tp->ocpl.TXBufMax	 = TX_BUF_MAX;
+
+	Addr = htonl(virt_to_bus(tp->ProductID));
+
+	tp->ocpl.ProdIDAddr[0]	 = LOWORD(Addr);
+	tp->ocpl.ProdIDAddr[1]	 = HIWORD(Addr);
+
+	return;
+}
+
+/*
+ * Send OPEN command to adapter
+ */
+static void sktr_open_adapter(struct net_device *dev)
+{
+	struct net_local *tp = (struct net_local *)dev->priv;
+
+	if(tp->OpenCommandIssued)
+		return;
+
+	tp->OpenCommandIssued = 1;
+	sktr_exec_cmd(dev, OC_OPEN);
+
+	return;
+}
+
+/*
+ * Clear the adapter's interrupt flag. Clear system interrupt enable
+ * (SINTEN): disable adapter to system interrupts.
+ */
+static void sktr_disable_interrupts(struct net_device *dev)
+{
+	outb(0, dev->base_addr + SIFACL);
+
+	return;
+}
+
+/*
+ * Set the adapter's interrupt flag. Set system interrupt enable
+ * (SINTEN): enable adapter to system interrupts.
+ */
+static void sktr_enable_interrupts(struct net_device *dev)
+{
+	outb(ACL_SINTEN, dev->base_addr + SIFACL);
+
+	return;
+}
+
+/*
+ * Put command in command queue, try to execute it.
+ */
+static void sktr_exec_cmd(struct net_device *dev, unsigned short Command)
+{
+	struct net_local *tp = (struct net_local *)dev->priv;
+
+	tp->CMDqueue |= Command;
+	sktr_chk_outstanding_cmds(dev);
+
+	return;
+}
+
+/*
+ * Gets skb from system, queues it and checks if it can be sent
+ */
+static int sktr_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+	struct net_local *tp = (struct net_local *)dev->priv;
+
+	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.
+		 *
+		 * Resetting the token ring adapter takes a long time so just
+		 * fake transmission time and go on trying. Our own timeout
+		 * routine is in sktr_timer_chk()
+		 */
+		dev->tbusy 	 = 0;
+		dev->trans_start = jiffies;
+		return (1);
+	}
+
+	/*
+	 * If some higher layer thinks we've missed an tx-done interrupt we
+	 * are passed NULL.
+	 */
+	if(skb == NULL)
+		return (0);
+
+	/*
+	 * Block a timer-based transmit from overlapping. This could better be
+	 * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
+	 */
+	if(test_and_set_bit(0, (void*)&dev->tbusy) != 0)
+	{
+		printk("%s: Transmitter access conflict.\n", dev->name);
+		return (1);
+	}
+
+	if(tp->QueueSkb == 0)
+		return (1);	/* Return with tbusy set: queue full */
+
+	tp->QueueSkb--;
+	skb_queue_tail(&tp->SendSkbQueue, skb);
+	sktr_hardware_send_packet(dev, tp);
+	if(tp->QueueSkb > 0)
+		dev->tbusy = 0;
+
+	return (0);
+}
+
+/*
+ * Move frames from internal skb queue into adapter tx queue
+ */
+static void sktr_hardware_send_packet(struct net_device *dev, struct net_local* tp)
+{
+	TPL *tpl;
+	short length;
+	unsigned char *buf, *newbuf;
+	struct sk_buff *skb;
+	int i;
+    
+	for(;;)
+	{
+		/* Try to get a free TPL from the chain.
+		 *
+		 * NOTE: We *must* always leave one unused TPL in the chain, 
+		 * because otherwise the adapter might send frames twice.
+		 */
+		if(tp->TplFree->NextTPLPtr->BusyFlag)	/* No free TPL */
+		{
+			printk(KERN_INFO "%s: No free TPL\n", dev->name);
+			return;
+		}
+
+		/* Send first buffer from queue */
+		skb = skb_dequeue(&tp->SendSkbQueue);
+		if(skb == NULL)
+			return;
+
+		tp->QueueSkb++;
+		/* Is buffer reachable for Busmaster-DMA? */
+		if(tp->DeviceType == SK_ISA && 
+			virt_to_bus((void*)(((long) skb->data) + skb->len))
+			> ISA_MAX_ADDRESS)
+		{
+			/* Copy frame to local buffer */
+			i 	= tp->TplFree->TPLIndex;
+			length 	= skb->len;
+			buf 	= tp->LocalTxBuffers[i];
+			memcpy(buf, skb->data, length);
+			newbuf 	= buf;
+		}
+		else
+		{
+			/* Send direct from skb->data */
+			length = skb->len;
+			newbuf = skb->data;
+		}
+
+		/* Source address in packet? */
+		sktr_chk_src_addr(newbuf, dev->dev_addr);
+
+		tp->LastSendTime	= jiffies;
+		tpl 			= tp->TplFree;	/* Get the "free" TPL */
+		tpl->BusyFlag 		= 1;		/* Mark TPL as busy */
+		tp->TplFree 		= tpl->NextTPLPtr;
+    
+		/* Save the skb for delayed return of skb to system */
+		tpl->Skb = skb;
+		tpl->FragList[0].DataCount = (unsigned short) SWAPB(length);
+		tpl->FragList[0].DataAddr  = htonl(virt_to_bus(newbuf));
+
+		/* Write the data length in the transmit list. */
+		tpl->FrameSize 	= (unsigned short) SWAPB(length);
+		tpl->MData 	= newbuf;
+
+		/* Transmit the frame and set the status values. */
+		sktr_write_tpl_status(tpl, TX_VALID | TX_START_FRAME
+					| TX_END_FRAME | TX_PASS_SRC_ADDR
+					| TX_FRAME_IRQ);
+
+		/* Let adapter send the frame. */
+		sktr_exec_sifcmd(dev, CMD_TX_VALID);
+	}
+
+	return;
+}
+
+/*
+ * Write the given value to the 'Status' field of the specified TPL.
+ * NOTE: This function should be used whenever the status of any TPL must be
+ * modified by the driver, because the compiler may otherwise change the
+ * order of instructions such that writing the TPL status may be executed at
+ * an undesireable time. When this function is used, the status is always
+ * written when the function is called.
+ */
+static void sktr_write_tpl_status(TPL *tpl, unsigned int Status)
+{
+	tpl->Status = Status;
+}
+
+static void sktr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr)
+{
+	unsigned char SRBit;
+
+	if((((unsigned long)frame[8]) & ~0x80) != 0)	/* Compare 4 bytes */
+		return;
+	if((unsigned short)frame[12] != 0)		/* Compare 2 bytes */
+		return;
+
+	SRBit = frame[8] & 0x80;
+	memcpy(&frame[8], hw_addr, 6);
+	frame[8] |= SRBit;
+
+	return;
+}
+
+/*
+ * The timer routine: Check if adapter still open and working, reopen if not. 
+ */
+static void sktr_timer_chk(unsigned long data)
+{
+	struct net_device *dev = (struct net_device*)data;
+	struct net_local *tp = (struct net_local*)dev->priv;
+
+	if(tp->HaltInProgress)
+		return;
+
+	sktr_chk_outstanding_cmds(dev);
+	if(time_before(tp->LastSendTime + SEND_TIMEOUT, jiffies)
+		&& (tp->QueueSkb < MAX_TX_QUEUE || tp->TplFree != tp->TplBusy))
+	{
+		/* Anything to send, but stalled to long */
+		tp->LastSendTime = jiffies;
+		sktr_exec_cmd(dev, OC_CLOSE);	/* Does reopen automatically */
+	}
+
+	tp->timer.expires = jiffies + 2*HZ;
+	add_timer(&tp->timer);
+
+	if(tp->AdapterOpenFlag || tp->ReOpenInProgress)
+		return;
+	tp->ReOpenInProgress = 1;
+	sktr_open_adapter(dev);
+
+	return;
+}
+
+/*
+ * The typical workload of the driver: Handle the network interface interrupts.
+ */
+static void sktr_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct net_local *tp;
+	int ioaddr;
+	unsigned short irq_type;
+
+	if(dev == NULL)
+	{
+		printk("%s: irq %d for unknown device.\n", dev->name, irq);
+		return;
+	}
+
+	dev->interrupt = 1;
+
+	ioaddr = dev->base_addr;
+	tp = (struct net_local *)dev->priv;
+
+	irq_type = inw(ioaddr + SIFSTS);
+
+	while(irq_type & STS_SYSTEM_IRQ)
+	{
+		irq_type &= STS_IRQ_MASK;
+
+		if(!sktr_chk_ssb(tp, irq_type))
+		{
+			printk(KERN_INFO "%s: DATA LATE occurred\n", dev->name);
+			break;
+		}
+
+		switch(irq_type)
+		{
+			case STS_IRQ_RECEIVE_STATUS:
+				sktr_reset_interrupt(dev);
+				sktr_rcv_status_irq(dev);
+				break;
+
+			case STS_IRQ_TRANSMIT_STATUS:
+				/* Check if TRANSMIT.HALT command is complete */
+				if(tp->ssb.Parm[0] & COMMAND_COMPLETE)
+				{
+					tp->TransmitCommandActive = 0;
+					tp->TransmitHaltScheduled = 0;
+
+					/* Issue a new transmit command. */
+					sktr_exec_cmd(dev, OC_TRANSMIT);
+				}
+
+				sktr_reset_interrupt(dev);
+				sktr_tx_status_irq(dev);
+				break;
+
+			case STS_IRQ_COMMAND_STATUS:
+				/* The SSB contains status of last command
+				 * other than receive/transmit.
+				 */
+				sktr_cmd_status_irq(dev);
+				break;
+
+			case STS_IRQ_SCB_CLEAR:
+				/* The SCB is free for another command. */
+				tp->ScbInUse = 0;
+				sktr_chk_outstanding_cmds(dev);
+				break;
+
+			case STS_IRQ_RING_STATUS:
+				sktr_ring_status_irq(dev);
+				break;
+
+			case STS_IRQ_ADAPTER_CHECK:
+				sktr_chk_irq(dev);
+				break;
+
+			default:
+				printk(KERN_INFO "Unknown Token Ring IRQ\n");
+				break;
+		}
+
+		/* Reset system interrupt if not already done. */
+		if(irq_type != STS_IRQ_TRANSMIT_STATUS
+			&& irq_type != STS_IRQ_RECEIVE_STATUS)
+		{
+			sktr_reset_interrupt(dev);
+		}
+
+		irq_type = inw(ioaddr + SIFSTS);
+	}
+
+	dev->interrupt = 0;
+
+	return;
+}
+
+/*
+ *  Reset the INTERRUPT SYSTEM bit and issue SSB CLEAR command.
+ */
+static void sktr_reset_interrupt(struct net_device *dev)
+{
+	struct net_local *tp = (struct net_local *)dev->priv;
+	SSB *ssb = &tp->ssb;
+
+	/*
+	 * [Workaround for "Data Late"]
+	 * Set all fields of the SSB to well-defined values so we can
+	 * check if the adapter has written the SSB.
+	 */
+
+	ssb->STS	= (unsigned short) -1;
+	ssb->Parm[0] 	= (unsigned short) -1;
+	ssb->Parm[1] 	= (unsigned short) -1;
+	ssb->Parm[2] 	= (unsigned short) -1;
+
+	/* Free SSB by issuing SSB_CLEAR command after reading IRQ code
+	 * and clear STS_SYSTEM_IRQ bit: enable adapter for further interrupts.
+	 */
+	sktr_exec_sifcmd(dev, CMD_SSB_CLEAR | CMD_CLEAR_SYSTEM_IRQ);
+
+	return;
+}
+
+/*
+ * Check if the SSB has actually been written by the adapter.
+ */
+static unsigned char sktr_chk_ssb(struct net_local *tp, unsigned short IrqType)
+{
+	SSB *ssb = &tp->ssb;	/* The address of the SSB. */
+
+	/* C 0 1 2 INTERRUPT CODE
+	 * - - - - --------------
+	 * 1 1 1 1 TRANSMIT STATUS
+	 * 1 1 1 1 RECEIVE STATUS
+	 * 1 ? ? 0 COMMAND STATUS
+	 * 0 0 0 0 SCB CLEAR
+	 * 1 1 0 0 RING STATUS
+	 * 0 0 0 0 ADAPTER CHECK
+	 *
+	 * 0 = SSB field not affected by interrupt
+	 * 1 = SSB field is affected by interrupt
+	 *
+	 * C = SSB ADDRESS +0: COMMAND
+	 * 0 = SSB ADDRESS +2: STATUS 0
+	 * 1 = SSB ADDRESS +4: STATUS 1
+	 * 2 = SSB ADDRESS +6: STATUS 2
+	 */
+
+	/* Check if this interrupt does use the SSB. */
+
+	if(IrqType != STS_IRQ_TRANSMIT_STATUS
+		&& IrqType != STS_IRQ_RECEIVE_STATUS
+		&& IrqType != STS_IRQ_COMMAND_STATUS
+		&& IrqType != STS_IRQ_RING_STATUS)
+	{
+		return (1);	/* SSB not involved. */
+	}
+
+	/* Note: All fields of the SSB have been set to all ones (-1) after it
+	 * has last been used by the software (see DriverIsr()).
+	 *
+	 * Check if the affected SSB fields are still unchanged.
+	 */
+
+	if(ssb->STS == (unsigned short) -1)
+		return (0);	/* Command field not yet available. */
+	if(IrqType == STS_IRQ_COMMAND_STATUS)
+		return (1);	/* Status fields not always affected. */
+	if(ssb->Parm[0] == (unsigned short) -1)
+		return (0);	/* Status 1 field not yet available. */
+	if(IrqType == STS_IRQ_RING_STATUS)
+		return (1);	/* Status 2 & 3 fields not affected. */
+
+	/* Note: At this point, the interrupt is either TRANSMIT or RECEIVE. */
+	if(ssb->Parm[1] == (unsigned short) -1)
+		return (0);	/* Status 2 field not yet available. */
+	if(ssb->Parm[2] == (unsigned short) -1)
+		return (0);	/* Status 3 field not yet available. */
+
+	return (1);	/* All SSB fields have been written by the adapter. */
+}
+
+/*
+ * Evaluates the command results status in the SSB status field.
+ */
+static void sktr_cmd_status_irq(struct net_device *dev)
+{
+	struct net_local *tp = (struct net_local *)dev->priv;
+	unsigned short ssb_cmd, ssb_parm_0;
+	unsigned short ssb_parm_1;
+	char *open_err = "Open error -";
+	char *code_err = "Open code -";
+
+	/* Copy the ssb values to local variables */
+	ssb_cmd    = tp->ssb.STS;
+	ssb_parm_0 = tp->ssb.Parm[0];
+	ssb_parm_1 = tp->ssb.Parm[1];
+
+	if(ssb_cmd == OPEN)
+	{
+		tp->Sleeping = 0;
+		if(!tp->ReOpenInProgress)
+	    		wake_up_interruptible(&tp->wait_for_tok_int);
+
+		tp->OpenCommandIssued = 0;
+		tp->ScbInUse = 0;
+
+		if((ssb_parm_0 & 0x00FF) == GOOD_COMPLETION)
+		{
+			/* Success, the adapter is open. */
+			tp->LobeWireFaultLogged	= 0;
+			tp->AdapterOpenFlag 	= 1;
+			tp->AdapterVirtOpenFlag = 1;
+			tp->TransmitCommandActive = 0;
+			sktr_exec_cmd(dev, OC_TRANSMIT);
+			sktr_exec_cmd(dev, OC_RECEIVE);
+
+			if(tp->ReOpenInProgress)
+				tp->ReOpenInProgress = 0;
+
+			return;
+		}
+		else 	/* The adapter did not open. */
+		{
+	    		if(ssb_parm_0 & NODE_ADDR_ERROR)
+				printk(KERN_INFO "%s: Node address error\n",
+					dev->name);
+	    		if(ssb_parm_0 & LIST_SIZE_ERROR)
+				printk(KERN_INFO "%s: List size error\n",
+					dev->name);
+	    		if(ssb_parm_0 & BUF_SIZE_ERROR)
+				printk(KERN_INFO "%s: Buffer size error\n",
+					dev->name);
+	    		if(ssb_parm_0 & TX_BUF_COUNT_ERROR)
+				printk(KERN_INFO "%s: Tx buffer count error\n",
+					dev->name);
+	    		if(ssb_parm_0 & INVALID_OPEN_OPTION)
+				printk(KERN_INFO "%s: Invalid open option\n",
+					dev->name);
+	    		if(ssb_parm_0 & OPEN_ERROR)
+			{
+				/* Show the open phase. */
+				switch(ssb_parm_0 & OPEN_PHASES_MASK)
+				{
+					case LOBE_MEDIA_TEST:
+						if(!tp->LobeWireFaultLogged)
+						{
+							tp->LobeWireFaultLogged = 1;
+							printk(KERN_INFO "%s: %s Lobe wire fault (check cable !).\n", dev->name, open_err);
+		    				}
+						tp->ReOpenInProgress	= 1;
+						tp->AdapterOpenFlag 	= 0;
+						tp->AdapterVirtOpenFlag = 1;
+						sktr_open_adapter(dev);
+						return;
+
+					case PHYSICAL_INSERTION:
+						printk(KERN_INFO "%s: %s Physical insertion.\n", dev->name, open_err);
+						break;
+
+					case ADDRESS_VERIFICATION:
+						printk(KERN_INFO "%s: %s Address verification.\n", dev->name, open_err);
+						break;
+
+					case PARTICIPATION_IN_RING_POLL:
+						printk(KERN_INFO "%s: %s Participation in ring poll.\n", dev->name, open_err);
+						break;
+
+					case REQUEST_INITIALISATION:
+						printk(KERN_INFO "%s: %s Request initialisation.\n", dev->name, open_err);
+						break;
+
+					case FULLDUPLEX_CHECK:
+						printk(KERN_INFO "%s: %s Full duplex check.\n", dev->name, open_err);
+						break;
+
+					default:
+						printk(KERN_INFO "%s: %s Unknown open phase\n", dev->name, open_err);
+						break;
+				}
+
+				/* Show the open errors. */
+				switch(ssb_parm_0 & OPEN_ERROR_CODES_MASK)
+				{
+					case OPEN_FUNCTION_FAILURE:
+						printk(KERN_INFO "%s: %s OPEN_FUNCTION_FAILURE", dev->name, code_err);
+						tp->LastOpenStatus =
+							OPEN_FUNCTION_FAILURE;
+						break;
+
+					case OPEN_SIGNAL_LOSS:
+						printk(KERN_INFO "%s: %s OPEN_SIGNAL_LOSS\n", dev->name, code_err);
+						tp->LastOpenStatus =
+							OPEN_SIGNAL_LOSS;
+						break;
+
+					case OPEN_TIMEOUT:
+						printk(KERN_INFO "%s: %s OPEN_TIMEOUT\n", dev->name, code_err);
+						tp->LastOpenStatus =
+							OPEN_TIMEOUT;
+						break;
+
+					case OPEN_RING_FAILURE:
+						printk(KERN_INFO "%s: %s OPEN_RING_FAILURE\n", dev->name, code_err);
+						tp->LastOpenStatus =
+							OPEN_RING_FAILURE;
+						break;
+
+					case OPEN_RING_BEACONING:
+						printk(KERN_INFO "%s: %s OPEN_RING_BEACONING\n", dev->name, code_err);
+						tp->LastOpenStatus =
+							OPEN_RING_BEACONING;
+						break;
+
+					case OPEN_DUPLICATE_NODEADDR:
+						printk(KERN_INFO "%s: %s OPEN_DUPLICATE_NODEADDR\n", dev->name, code_err);
+						tp->LastOpenStatus =
+							OPEN_DUPLICATE_NODEADDR;
+						break;
+
+					case OPEN_REQUEST_INIT:
+						printk(KERN_INFO "%s: %s OPEN_REQUEST_INIT\n", dev->name, code_err);
+						tp->LastOpenStatus =
+							OPEN_REQUEST_INIT;
+						break;
+
+					case OPEN_REMOVE_RECEIVED:
+						printk(KERN_INFO "%s: %s OPEN_REMOVE_RECEIVED", dev->name, code_err);
+						tp->LastOpenStatus =
+							OPEN_REMOVE_RECEIVED;
+						break;
+
+					case OPEN_FULLDUPLEX_SET:
+						printk(KERN_INFO "%s: %s OPEN_FULLDUPLEX_SET\n", dev->name, code_err);
+						tp->LastOpenStatus =
+							OPEN_FULLDUPLEX_SET;
+						break;
+
+					default:
+						printk(KERN_INFO "%s: %s Unknown open err code", dev->name, code_err);
+						tp->LastOpenStatus =
+							OPEN_FUNCTION_FAILURE;
+						break;
+				}
+			}
+
+			tp->AdapterOpenFlag 	= 0;
+			tp->AdapterVirtOpenFlag = 0;
+
+			return;
+		}
+	}
+	else
+	{
+		if(ssb_cmd != READ_ERROR_LOG)
+			return;
+
+		/* Add values from the error log table to the MAC
+		 * statistics counters and update the errorlogtable
+		 * memory.
+		 */
+		tp->MacStat.line_errors += tp->errorlogtable.Line_Error;
+		tp->MacStat.burst_errors += tp->errorlogtable.Burst_Error;
+		tp->MacStat.A_C_errors += tp->errorlogtable.ARI_FCI_Error;
+		tp->MacStat.lost_frames += tp->errorlogtable.Lost_Frame_Error;
+		tp->MacStat.recv_congest_count += tp->errorlogtable.Rx_Congest_Error;
+		tp->MacStat.rx_errors += tp->errorlogtable.Rx_Congest_Error;
+		tp->MacStat.frame_copied_errors += tp->errorlogtable.Frame_Copied_Error;
+		tp->MacStat.token_errors += tp->errorlogtable.Token_Error;
+		tp->MacStat.dummy1 += tp->errorlogtable.DMA_Bus_Error;
+		tp->MacStat.dummy1 += tp->errorlogtable.DMA_Parity_Error;
+		tp->MacStat.abort_delimiters += tp->errorlogtable.AbortDelimeters;
+		tp->MacStat.frequency_errors += tp->errorlogtable.Frequency_Error;
+		tp->MacStat.internal_errors += tp->errorlogtable.Internal_Error;
+	}
+
+	return;
+}
+
+/*
+ * The inverse routine to sktr_open().
+ */
+static int sktr_close(struct net_device *dev)
+{
+	struct net_local *tp = (struct net_local *)dev->priv;
+
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	del_timer(&tp->timer);
+
+	/* Flush the Tx and disable Rx here. */
+
+	tp->HaltInProgress 	= 1;
+	sktr_exec_cmd(dev, OC_CLOSE);
+	tp->timer.expires	= jiffies + 1*HZ;
+	tp->timer.function 	= sktr_timer_end_wait;
+	tp->timer.data 		= (unsigned long)dev;
+	add_timer(&tp->timer);
+
+	sktr_enable_interrupts(dev);
+
+	tp->Sleeping = 1;
+	interruptible_sleep_on(&tp->wait_for_tok_int);
+	tp->TransmitCommandActive = 0;
+    
+	del_timer(&tp->timer);
+	sktr_disable_interrupts(dev);
+   
+	if(dev->dma > 0) 
+	{
+		unsigned long flags=claim_dma_lock();
+		disable_dma(dev->dma);
+		release_dma_lock(flags);
+	}
+	
+	outw(0xFF00, dev->base_addr + SIFCMD);
+	if(dev->dma > 0)
+		outb(0xff, dev->base_addr + POSREG);
+
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+
+	sktr_cancel_tx_queue(tp);
+
+	return (0);
+}
+
+/*
+ * Get the current statistics. This may be called with the card open
+ * or closed.
+ */
+static struct enet_statistics *sktr_get_stats(struct net_device *dev)
+{
+	struct net_local *tp = (struct net_local *)dev->priv;
+
+	return ((struct enet_statistics *)&tp->MacStat);
+}
+
+/*
+ * Set or clear the multicast filter for this adapter.
+ */
+static void sktr_set_multicast_list(struct net_device *dev)
+{
+	struct net_local *tp = (struct net_local *)dev->priv;
+        unsigned int OpenOptions;
+	
+        OpenOptions = tp->ocpl.OPENOptions &
+                ~(PASS_ADAPTER_MAC_FRAMES
+		  | PASS_ATTENTION_FRAMES
+		  | PASS_BEACON_MAC_FRAMES
+		  | COPY_ALL_MAC_FRAMES
+		  | COPY_ALL_NON_MAC_FRAMES);
+	
+        tp->ocpl.FunctAddr = 0;
+	
+        if(dev->flags & IFF_PROMISC)
+                /* Enable promiscuous mode */
+                OpenOptions |= COPY_ALL_NON_MAC_FRAMES |
+			COPY_ALL_MAC_FRAMES;
+        else
+        {
+                if(dev->flags & IFF_ALLMULTI)
+                {
+                        /* Disable promiscuous mode, use normal mode. */
+                        tp->ocpl.FunctAddr = 0xFFFFFFFF;
+			
+                }
+                else
+                {
+                        int i;
+                        struct dev_mc_list *mclist = dev->mc_list;
+                        for (i=0; i< dev->mc_count; i++)
+                        {
+                                ((char *)(&tp->ocpl.FunctAddr))[0] |=
+					mclist->dmi_addr[2];
+                                ((char *)(&tp->ocpl.FunctAddr))[1] |=
+					mclist->dmi_addr[3];
+                                ((char *)(&tp->ocpl.FunctAddr))[2] |=
+					mclist->dmi_addr[4];
+                                ((char *)(&tp->ocpl.FunctAddr))[3] |=
+					mclist->dmi_addr[5];
+                                 mclist = mclist->next;
+                         }
+                }
+                sktr_exec_cmd(dev, OC_SET_FUNCT_ADDR);
+        }
+	
+        tp->ocpl.OPENOptions = OpenOptions;
+        sktr_exec_cmd(dev, OC_MODIFY_OPEN_PARMS);
+        return;
+}
+
+/*
+ * Wait for some time (microseconds)
+ *
+ * udelay() is a bit harsh, but using a looser timer causes
+ * the bring-up-diags to stall indefinitly.  
+ *
+ */
+
+static void sktr_wait(unsigned long time)
+{
+	udelay(time);
+	return;
+}
+
+/*
+ * Write a command value to the SIFCMD register
+ */
+static void sktr_exec_sifcmd(struct net_device *dev, unsigned int WriteValue)
+{
+	int ioaddr = dev->base_addr;
+	unsigned short cmd;
+	unsigned short SifStsValue;
+	unsigned long loop_counter;
+
+	WriteValue = ((WriteValue ^ CMD_SYSTEM_IRQ) | CMD_INTERRUPT_ADAPTER);
+	cmd = (unsigned short)WriteValue;
+	loop_counter = 0,5 * 800000;
+	do {
+		SifStsValue = inw(ioaddr + SIFSTS);
+	} while((SifStsValue & CMD_INTERRUPT_ADAPTER) && loop_counter--);
+	outw(cmd, ioaddr + SIFCMD);
+
+	return;
+}
+
+/*
+ * Processes adapter hardware reset, halts adapter and downloads firmware,
+ * clears the halt bit.
+ */
+static int sktr_reset_adapter(struct net_device *dev)
+{
+	struct net_local *tp = (struct net_local *)dev->priv;
+	unsigned short *fw_ptr = (unsigned short *)&sktr_code;
+	unsigned short count, c;
+	int ioaddr = dev->base_addr;
+
+	/* Hardware adapter reset */
+	outw(ACL_ARESET, ioaddr + SIFACL);
+	sktr_wait(40);
+
+	c = inw(ioaddr + SIFACL);
+	sktr_wait(20);
+
+	if(dev->dma == 0)	/* For PCI adapters */
+	{
+		c &= ~(ACL_SPEED4 | ACL_SPEED16);	/* Clear bits */
+		if(tp->DataRate == SPEED_4)
+			c |= ACL_SPEED4;		/* Set 4Mbps */
+		else
+			c |= ACL_SPEED16;		/* Set 16Mbps */
+	}
+
+	/* In case a command is pending - forget it */
+	tp->ScbInUse = 0;
+
+	c &= ~ACL_ARESET;		/* Clear adapter reset bit */
+	c |=  ACL_CPHALT;		/* Halt adapter CPU, allow download */
+	c &= ~ACL_PSDMAEN;		/* Clear pseudo dma bit */
+	outw(c, ioaddr + SIFACL);
+	sktr_wait(40);
+
+	/* Download firmware via DIO interface: */
+	do {
+		/* Download first address part */
+		outw(*fw_ptr, ioaddr + SIFADX);
+		fw_ptr++;
+
+		/* Download second address part */
+		outw(*fw_ptr, ioaddr + SIFADD);
+		fw_ptr++;
+
+		if((count = *fw_ptr) != 0)	/* Load loop counter */
+		{
+			fw_ptr++;	/* Download block data */
+			for(; count > 0; count--)
+			{
+				outw(*fw_ptr, ioaddr + SIFINC);
+				fw_ptr++;
+			}
+		}
+		else	/* Stop, if last block downloaded */
+		{
+			c = inw(ioaddr + SIFACL);
+			c &= (~ACL_CPHALT | ACL_SINTEN);
+
+			/* Clear CPHALT and start BUD */
+			outw(c, ioaddr + SIFACL);
+			return (1);
+		}
+	} while(count == 0);
+
+	return (-1);
+}
+
+/*
+ * Starts bring up diagnostics of token ring adapter and evaluates
+ * diagnostic results.
+ */
+static int sktr_bringup_diags(struct net_device *dev)
+{
+	int loop_cnt, retry_cnt;
+	unsigned short Status;
+	int ioaddr = dev->base_addr;
+
+	sktr_wait(HALF_SECOND);
+	sktr_exec_sifcmd(dev, EXEC_SOFT_RESET);
+	sktr_wait(HALF_SECOND);
+
+	retry_cnt = BUD_MAX_RETRIES;	/* maximal number of retrys */
+
+	do {
+		retry_cnt--;
+		if(sktr_debug > 3)
+			printk(KERN_INFO "BUD-Status: \n");
+		loop_cnt = BUD_MAX_LOOPCNT;	/* maximum: three seconds*/
+		do {			/* Inspect BUD results */
+			loop_cnt--;
+			sktr_wait(HALF_SECOND);
+			Status = inw(ioaddr + SIFSTS);
+			Status &= STS_MASK;
+
+			if(sktr_debug > 3)
+				printk(KERN_INFO " %04X \n", Status);
+			/* BUD successfully completed */
+			if(Status == STS_INITIALIZE)
+				return (1);
+		/* Unrecoverable hardware error, BUD not completed? */
+		} while((loop_cnt > 0) && ((Status & (STS_ERROR | STS_TEST))
+			!= (STS_ERROR | STS_TEST)));
+
+		/* Error preventing completion of BUD */
+		if(retry_cnt > 0)
+		{
+			printk(KERN_INFO "%s: Adapter Software Reset.\n", 
+				dev->name);
+			sktr_exec_sifcmd(dev, EXEC_SOFT_RESET);
+			sktr_wait(HALF_SECOND);
+		}
+	} while(retry_cnt > 0);
+
+	Status = inw(ioaddr + SIFSTS);
+	Status &= STS_ERROR_MASK;	/* Hardware error occurred! */
+
+	printk(KERN_INFO "%s: Bring Up Diagnostics Error (%04X) occurred\n",
+		dev->name, Status);
+
+	return (-1);
+}
+
+/*
+ * Copy initialisation data to adapter memory, beginning at address
+ * 1:0A00; Starting DMA test and evaluating result bits.
+ */
+static int sktr_init_adapter(struct net_device *dev)
+{
+	struct net_local *tp = (struct net_local *)dev->priv;
+
+	const unsigned char SCB_Test[6] = {0x00, 0x00, 0xC1, 0xE2, 0xD4, 0x8B};
+	const unsigned char SSB_Test[8] = {0xFF, 0xFF, 0xD1, 0xD7,
+						0xC5, 0xD9, 0xC3, 0xD4};
+	void *ptr = (void *)&tp->ipb;
+	unsigned short *ipb_ptr = (unsigned short *)ptr;
+	unsigned char *cb_ptr = (unsigned char *) &tp->scb;
+	unsigned char *sb_ptr = (unsigned char *) &tp->ssb;
+	unsigned short Status;
+	int i, loop_cnt, retry_cnt;
+	int ioaddr = dev->base_addr;
+
+	/* Normalize: byte order low/high, word order high/low! (only IPB!) */
+	tp->ipb.SCB_Addr = SWAPW(virt_to_bus(&tp->scb));
+	tp->ipb.SSB_Addr = SWAPW(virt_to_bus(&tp->ssb));
+
+	/* Maximum: three initialization retries */
+	retry_cnt = INIT_MAX_RETRIES;
+
+	do {
+		retry_cnt--;
+
+		/* Transfer initialization block */
+		outw(0x0001, ioaddr + SIFADX);
+
+		/* To address 0001:0A00 of adapter RAM */
+		outw(0x0A00, ioaddr + SIFADD);
+
+		/* Write 11 words to adapter RAM */
+		for(i = 0; i < 11; i++)
+			outw(ipb_ptr[i], ioaddr + SIFINC);
+
+		/* Execute SCB adapter command */
+		sktr_exec_sifcmd(dev, CMD_EXECUTE);
+
+		loop_cnt = INIT_MAX_LOOPCNT;	/* Maximum: 11 seconds */
+
+		/* While remaining retries, no error and not completed */
+		do {
+			Status = 0;
+			loop_cnt--;
+			sktr_wait(HALF_SECOND);
+
+			/* Mask interesting status bits */
+			Status = inw(ioaddr + SIFSTS);
+			Status &= STS_MASK;
+		} while(((Status &(STS_INITIALIZE | STS_ERROR | STS_TEST)) != 0)
+			&& ((Status & STS_ERROR) == 0) && (loop_cnt != 0));
+
+		if((Status & (STS_INITIALIZE | STS_ERROR | STS_TEST)) == 0)
+		{
+			/* Initialization completed without error */
+			i = 0;
+			do {	/* Test if contents of SCB is valid */
+				if(SCB_Test[i] != *(cb_ptr + i))
+					/* DMA data error: wrong data in SCB */
+					return (-1);
+				i++;
+			} while(i < 6);
+
+			i = 0;
+			do {	/* Test if contents of SSB is valid */
+				if(SSB_Test[i] != *(sb_ptr + i))
+					/* DMA data error: wrong data in SSB */
+					return (-1);
+				i++;
+			} while (i < 8);
+
+			return (1);	/* Adapter successfully initialized */
+		}
+		else
+		{
+			if((Status & STS_ERROR) != 0)
+			{
+				/* Initialization error occurred */
+				Status = inw(ioaddr + SIFSTS);
+				Status &= STS_ERROR_MASK;
+				/* ShowInitialisationErrorCode(Status); */
+				return (-1); /* Unrecoverable error */
+			}
+			else
+			{
+				if(retry_cnt > 0)
+				{
+					/* Reset adapter and try init again */
+					sktr_exec_sifcmd(dev, EXEC_SOFT_RESET);
+					sktr_wait(HALF_SECOND);
+				}
+			}
+		}
+	} while(retry_cnt > 0);
+
+	return (-1);
+}
+
+/*
+ * Check for outstanding commands in command queue and tries to execute
+ * command immediately. Corresponding command flag in command queue is cleared.
+ */
+static void sktr_chk_outstanding_cmds(struct net_device *dev)
+{
+	struct net_local *tp = (struct net_local *)dev->priv;
+	unsigned long Addr = 0;
+	unsigned char i = 0;
+
+	if(tp->CMDqueue == 0)
+		return;		/* No command execution */
+
+	/* If SCB in use: no command */
+	if(tp->ScbInUse == 1)
+		return;
+
+	/* Check if adapter is opened, avoiding COMMAND_REJECT
+	 * interrupt by the adapter!
+	 */
+	if(tp->AdapterOpenFlag == 0)
+	{
+		if(tp->CMDqueue & OC_OPEN)
+		{
+			/* Execute OPEN command	*/
+			tp->CMDqueue ^= OC_OPEN;
+
+			/* Copy the 18 bytes of the product ID */
+			while((AdapterName[i] != '\0') && (i < PROD_ID_SIZE))
+			{
+				tp->ProductID[i] = AdapterName[i];
+				i++;
+			}
+
+			Addr = htonl(virt_to_bus(&tp->ocpl));
+			tp->scb.Parm[0] = LOWORD(Addr);
+			tp->scb.Parm[1] = HIWORD(Addr);
+			tp->scb.CMD = OPEN;
+		}
+		else
+			/* No OPEN command queued, but adapter closed. Note:
+			 * We'll try to re-open the adapter in DriverPoll()
+			 */
+			return;		/* No adapter command issued */
+	}
+	else
+	{
+		/* Adapter is open; evaluate command queue: try to execute
+		 * outstanding commands (depending on priority!) CLOSE
+		 * command queued
+		 */
+		if(tp->CMDqueue & OC_CLOSE)
+		{
+			tp->CMDqueue ^= OC_CLOSE;
+			tp->AdapterOpenFlag = 0;
+			tp->scb.Parm[0] = 0; /* Parm[0], Parm[1] are ignored */
+			tp->scb.Parm[1] = 0; /* but should be set to zero! */
+			tp->scb.CMD = CLOSE;
+			if(!tp->HaltInProgress)
+				tp->CMDqueue |= OC_OPEN; /* re-open adapter */
+			else
+				tp->CMDqueue = 0;	/* no more commands */
+		}
+		else
+		{
+			if(tp->CMDqueue & OC_RECEIVE)
+			{
+				tp->CMDqueue ^= OC_RECEIVE;
+				Addr = htonl(virt_to_bus(tp->RplHead));
+				tp->scb.Parm[0] = LOWORD(Addr);
+				tp->scb.Parm[1] = HIWORD(Addr);
+				tp->scb.CMD = RECEIVE;
+			}
+			else
+			{
+				if(tp->CMDqueue & OC_TRANSMIT_HALT)
+				{
+					/* NOTE: TRANSMIT.HALT must be checked 
+					 * before TRANSMIT.
+					 */
+					tp->CMDqueue ^= OC_TRANSMIT_HALT;
+					tp->scb.CMD = TRANSMIT_HALT;
+
+					/* Parm[0] and Parm[1] are ignored
+					 * but should be set to zero!
+					 */
+					tp->scb.Parm[0] = 0;
+					tp->scb.Parm[1] = 0;
+				}
+				else
+				{
+					if(tp->CMDqueue & OC_TRANSMIT)
+					{
+						/* NOTE: TRANSMIT must be 
+						 * checked after TRANSMIT.HALT
+						 */
+						if(tp->TransmitCommandActive)
+						{
+							if(!tp->TransmitHaltScheduled)
+							{
+								tp->TransmitHaltScheduled = 1;
+								sktr_exec_cmd(dev, OC_TRANSMIT_HALT) ;
+							}
+							tp->TransmitCommandActive = 0;
+							return;
+						}
+
+						tp->CMDqueue ^= OC_TRANSMIT;
+						sktr_cancel_tx_queue(tp);
+						Addr = htonl(virt_to_bus(tp->TplBusy));
+						tp->scb.Parm[0] = LOWORD(Addr);
+						tp->scb.Parm[1] = HIWORD(Addr);
+						tp->scb.CMD = TRANSMIT;
+						tp->TransmitCommandActive = 1;
+					}
+					else
+					{
+						if(tp->CMDqueue & OC_MODIFY_OPEN_PARMS)
+						{
+							tp->CMDqueue ^= OC_MODIFY_OPEN_PARMS;
+							tp->scb.Parm[0] = tp->ocpl.OPENOptions; /* new OPEN options*/
+							tp->scb.Parm[0] |= ENABLE_FULL_DUPLEX_SELECTION;
+							tp->scb.Parm[1] = 0; /* is ignored but should be zero */
+							tp->scb.CMD = MODIFY_OPEN_PARMS;
+						}
+						else
+						{
+							if(tp->CMDqueue & OC_SET_FUNCT_ADDR)
+							{
+								tp->CMDqueue ^= OC_SET_FUNCT_ADDR;
+								tp->scb.Parm[0] = LOWORD(tp->ocpl.FunctAddr);
+								tp->scb.Parm[1] = HIWORD(tp->ocpl.FunctAddr);
+								tp->scb.CMD = SET_FUNCT_ADDR;
+							}
+							else
+							{
+								if(tp->CMDqueue & OC_SET_GROUP_ADDR)
+								{
+									tp->CMDqueue ^= OC_SET_GROUP_ADDR;
+									tp->scb.Parm[0] = LOWORD(tp->ocpl.GroupAddr);
+									tp->scb.Parm[1] = HIWORD(tp->ocpl.GroupAddr);
+									tp->scb.CMD = SET_GROUP_ADDR;
+								}
+								else
+								{
+									if(tp->CMDqueue & OC_READ_ERROR_LOG)
+									{
+										tp->CMDqueue ^= OC_READ_ERROR_LOG;
+										Addr = htonl(virt_to_bus(&tp->errorlogtable));
+										tp->scb.Parm[0] = LOWORD(Addr);
+										tp->scb.Parm[1] = HIWORD(Addr);
+										tp->scb.CMD = READ_ERROR_LOG;
+									}
+									else
+									{
+										printk(KERN_WARNING "CheckForOutstandingCommand: unknown Command\n");
+										tp->CMDqueue = 0;
+										return;
+									}
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+
+	tp->ScbInUse = 1;	/* Set semaphore: SCB in use. */
+
+	/* Execute SCB and generate IRQ when done. */
+	sktr_exec_sifcmd(dev, CMD_EXECUTE | CMD_SCB_REQUEST);
+
+	return;
+}
+
+/*
+ * IRQ conditions: signal loss on the ring, transmit or receive of beacon
+ * frames (disabled if bit 1 of OPEN option is set); report error MAC
+ * frame transmit (disabled if bit 2 of OPEN option is set); open or short
+ * cirquit fault on the lobe is detected; remove MAC frame received;
+ * error counter overflow (255); opened adapter is the only station in ring.
+ * After some of the IRQs the adapter is closed!
+ */
+static void sktr_ring_status_irq(struct net_device *dev)
+{
+	struct net_local *tp = (struct net_local *)dev->priv;
+
+	tp->CurrentRingStatus = SWAPB(tp->ssb.Parm[0]);
+
+	/* First: fill up statistics */
+	if(tp->ssb.Parm[0] & SIGNAL_LOSS)
+	{
+		printk(KERN_INFO "%s: Signal Loss\n", dev->name);
+		tp->MacStat.line_errors++;
+	}
+
+	/* Adapter is closed, but initialized */
+	if(tp->ssb.Parm[0] & LOBE_WIRE_FAULT)
+	{
+		printk(KERN_INFO "%s: Lobe Wire Fault, Reopen Adapter\n", 
+			dev->name);
+		tp->MacStat.line_errors++;
+	}
+
+	if(tp->ssb.Parm[0] & RING_RECOVERY)
+		printk(KERN_INFO "%s: Ring Recovery\n", dev->name);
+
+	/* Counter overflow: read error log */
+	if(tp->ssb.Parm[0] & COUNTER_OVERFLOW)
+	{
+		printk(KERN_INFO "%s: Counter Overflow\n", dev->name);
+		sktr_exec_cmd(dev, OC_READ_ERROR_LOG);
+	}
+
+	/* Adapter is closed, but initialized */
+	if(tp->ssb.Parm[0] & REMOVE_RECEIVED)
+		printk(KERN_INFO "%s: Remove Received, Reopen Adapter\n", 
+			dev->name);
+
+	/* Adapter is closed, but initialized */
+	if(tp->ssb.Parm[0] & AUTO_REMOVAL_ERROR)
+		printk(KERN_INFO "%s: Auto Removal Error, Reopen Adapter\n", 
+			dev->name);
+
+	if(tp->ssb.Parm[0] & HARD_ERROR)
+		printk(KERN_INFO "%s: Hard Error\n", dev->name);
+
+	if(tp->ssb.Parm[0] & SOFT_ERROR)
+		printk(KERN_INFO "%s: Soft Error\n", dev->name);
+
+	if(tp->ssb.Parm[0] & TRANSMIT_BEACON)
+		printk(KERN_INFO "%s: Transmit Beacon\n", dev->name);
+
+	if(tp->ssb.Parm[0] & SINGLE_STATION)
+		printk(KERN_INFO "%s: Single Station\n", dev->name);
+
+	/* Check if adapter has been closed */
+	if(tp->ssb.Parm[0] & ADAPTER_CLOSED)
+	{
+		printk(KERN_INFO "%s: Adapter closed (Reopening)," 
+			"QueueSkb %d, CurrentRingStat %x\n",
+			dev->name, tp->QueueSkb, tp->CurrentRingStatus);
+		tp->AdapterOpenFlag = 0;
+		sktr_open_adapter(dev);
+	}
+
+	return;
+}
+
+/*
+ * Issued if adapter has encountered an unrecoverable hardware
+ * or software error.
+ */
+static void sktr_chk_irq(struct net_device *dev)
+{
+	int i;
+	unsigned short AdapterCheckBlock[4];
+	unsigned short ioaddr = dev->base_addr;
+	struct net_local *tp = (struct net_local *)dev->priv;
+
+	tp->AdapterOpenFlag = 0;	/* Adapter closed now */
+
+	/* Page number of adapter memory */
+	outw(0x0001, ioaddr + SIFADX);
+	/* Address offset */
+	outw(CHECKADDR, ioaddr + SIFADR);
+
+	/* Reading 8 byte adapter check block. */
+	for(i = 0; i < 4; i++)
+		AdapterCheckBlock[i] = inw(ioaddr + SIFINC);
+
+	if(sktr_debug > 3)
+	{
+		printk("%s: AdapterCheckBlock: ", dev->name);
+		for (i = 0; i < 4; i++)
+			printk("%04X", AdapterCheckBlock[i]);
+		printk("\n");
+	}
+
+	switch(AdapterCheckBlock[0])
+	{
+		case DIO_PARITY:
+			printk(KERN_INFO "%s: DIO parity error\n", dev->name);
+			break;
+
+		case DMA_READ_ABORT:
+			printk(KERN_INFO "%s DMA read operation aborted:\n",
+				dev->name);
+			switch (AdapterCheckBlock[1])
+			{
+				case 0:
+					printk(KERN_INFO "Timeout\n");
+					printk(KERN_INFO "Address: %04X %04X\n",
+						AdapterCheckBlock[2],
+						AdapterCheckBlock[3]);
+					break;
+
+				case 1:
+					printk(KERN_INFO "Parity error\n");
+					printk(KERN_INFO "Address: %04X %04X\n",
+						AdapterCheckBlock[2], 
+						AdapterCheckBlock[3]);
+					break;
+
+				case 2: 
+					printk(KERN_INFO "Bus error\n");
+					printk(KERN_INFO "Address: %04X %04X\n",
+						AdapterCheckBlock[2], 
+						AdapterCheckBlock[3]);
+					break;
+
+				default:
+					printk(KERN_INFO "Unknown error.\n");
+					break;
+			}
+			break;
+
+		case DMA_WRITE_ABORT:
+			printk(KERN_INFO "%s: DMA write operation aborted: \n",
+				dev->name);
+			switch (AdapterCheckBlock[1])
+			{
+				case 0: 
+					printk(KERN_INFO "Timeout\n");
+					printk(KERN_INFO "Address: %04X %04X\n",
+						AdapterCheckBlock[2], 
+						AdapterCheckBlock[3]);
+					break;
+
+				case 1: 
+					printk(KERN_INFO "Parity error\n");
+					printk(KERN_INFO "Address: %04X %04X\n",
+						AdapterCheckBlock[2], 
+						AdapterCheckBlock[3]);
+					break;
+
+				case 2: 
+					printk(KERN_INFO "Bus error\n");
+					printk(KERN_INFO "Address: %04X %04X\n",
+						AdapterCheckBlock[2], 
+						AdapterCheckBlock[3]);
+					break;
+
+				default:
+					printk(KERN_INFO "Unknown error.\n");
+					break;
+			}
+			break;
+
+		case ILLEGAL_OP_CODE:
+			printk("%s: Illegal operation code in firmware\n",
+				dev->name);
+			/* Parm[0-3]: adapter internal register R13-R15 */
+			break;
+
+		case PARITY_ERRORS:
+			printk("%s: Adapter internal bus parity error\n",
+				dev->name);
+			/* Parm[0-3]: adapter internal register R13-R15 */
+			break;
+
+		case RAM_DATA_ERROR:
+			printk("%s: RAM data error\n", dev->name);
+			/* Parm[0-1]: MSW/LSW address of RAM location. */
+			break;
+
+		case RAM_PARITY_ERROR:
+			printk("%s: RAM parity error\n", dev->name);
+			/* Parm[0-1]: MSW/LSW address of RAM location. */
+			break;
+
+		case RING_UNDERRUN:
+			printk("%s: Internal DMA underrun detected\n",
+				dev->name);
+			break;
+
+		case INVALID_IRQ:
+			printk("%s: Unrecognized interrupt detected\n",
+				dev->name);
+			/* Parm[0-3]: adapter internal register R13-R15 */
+			break;
+
+		case INVALID_ERROR_IRQ:
+			printk("%s: Unrecognized error interrupt detected\n",
+				dev->name);
+			/* Parm[0-3]: adapter internal register R13-R15 */
+			break;
+
+		case INVALID_XOP:
+			printk("%s: Unrecognized XOP request detected\n",
+				dev->name);
+			/* Parm[0-3]: adapter internal register R13-R15 */
+			break;
+
+		default:
+			printk("%s: Unknown status", dev->name);
+			break;
+	}
+
+	if(sktr_chipset_init(dev) == 1)
+	{
+		/* Restart of firmware successful */
+		tp->AdapterOpenFlag = 1;
+	}
+
+	return;
+}
+
+/*
+ * Internal adapter pointer to RAM data are copied from adapter into
+ * host system.
+ */
+static void sktr_read_ptr(struct net_device *dev)
+{
+	struct net_local *tp = (struct net_local *)dev->priv;
+	unsigned short adapterram;
+
+	sktr_read_ram(dev, (unsigned char *)&tp->intptrs.BurnedInAddrPtr,
+			ADAPTER_INT_PTRS, 16);
+	sktr_read_ram(dev, (unsigned char *)&adapterram,
+			(unsigned short)SWAPB(tp->intptrs.AdapterRAMPtr), 2);
+
+	printk(KERN_INFO "%s: Adapter RAM size: %d K\n", 
+		dev->name, SWAPB(adapterram));
+
+	return;
+}
+
+/*
+ * Reads a number of bytes from adapter to system memory.
+ */
+static void sktr_read_ram(struct net_device *dev, unsigned char *Data,
+				unsigned short Address, int Length)
+{
+	int i;
+	unsigned short old_sifadx, old_sifadr, InWord;
+	unsigned short ioaddr = dev->base_addr;
+
+	/* Save the current values */
+	old_sifadx = inw(ioaddr + SIFADX);
+	old_sifadr = inw(ioaddr + SIFADR);
+
+	/* Page number of adapter memory */
+	outw(0x0001, ioaddr + SIFADX);
+	/* Address offset in adapter RAM */
+	outw(Address, ioaddr + SIFADR);
+
+	/* Copy len byte from adapter memory to system data area. */
+	i = 0;
+	for(;;)
+	{
+		InWord = inw(ioaddr + SIFINC);
+
+		*(Data + i) = HIBYTE(InWord);	/* Write first byte */
+		if(++i == Length)		/* All is done break */
+			break;
+
+		*(Data + i) = LOBYTE(InWord);	/* Write second byte */
+		if (++i == Length)		/* All is done break */
+			break;
+	}
+
+	/* Restore original values */
+	outw(old_sifadx, ioaddr + SIFADX);
+	outw(old_sifadr, ioaddr + SIFADR);
+
+	return;
+}
+
+/*
+ * Reads MAC address from adapter ROM.
+ */
+static void sktr_read_addr(struct net_device *dev, unsigned char *Address)
+{
+	int i, In;
+	unsigned short ioaddr = dev->base_addr;
+
+	/* Address: 0000:0000 */
+	outw(0, ioaddr + SIFADX);
+	outw(0, ioaddr + SIFADR);
+
+	/* Read six byte MAC address data */
+	for(i = 0; i < 6; i++)
+	{
+		In = inw(ioaddr + SIFINC);
+		*(Address + i) = (unsigned char)(In >> 8);
+	}
+
+	return;
+}
+
+/*
+ * Cancel all queued packets in the transmission queue.
+ */
+static void sktr_cancel_tx_queue(struct net_local* tp)
+{
+	TPL *tpl;
+	struct sk_buff *skb;
+
+	/*
+	 * NOTE: There must not be an active TRANSMIT command pending, when
+	 * this function is called.
+	 */
+	if(tp->TransmitCommandActive)
+		return;
+
+	for(;;)
+	{
+		tpl = tp->TplBusy;
+		if(!tpl->BusyFlag)
+			break;
+		/* "Remove" TPL from busy list. */
+		tp->TplBusy = tpl->NextTPLPtr;
+		sktr_write_tpl_status(tpl, 0);	/* Clear VALID bit */
+		tpl->BusyFlag = 0;		/* "free" TPL */
+
+		printk(KERN_INFO "Cancel tx (%08lXh).\n", (unsigned long)tpl);
+
+		dev_kfree_skb(tpl->Skb);
+	}
+
+	for(;;)
+	{
+		skb = skb_dequeue(&tp->SendSkbQueue);
+		if(skb == NULL)
+			break;
+		tp->QueueSkb++;
+		dev_kfree_skb(skb);
+	}
+
+	return;
+}
+
+/*
+ * This function is called whenever a transmit interrupt is generated by the
+ * adapter. For a command complete interrupt, it is checked if we have to
+ * issue a new transmit command or not.
+ */
+static void sktr_tx_status_irq(struct net_device *dev)
+{
+	struct net_local *tp = (struct net_local *)dev->priv;
+	unsigned char HighByte, HighAc, LowAc;
+	TPL *tpl;
+
+	/* NOTE: At this point the SSB from TRANSMIT STATUS is no longer
+	 * available, because the CLEAR SSB command has already been issued.
+	 *
+	 * Process all complete transmissions.
+	 */
+
+	for(;;)
+	{
+		tpl = tp->TplBusy;
+		if(!tpl->BusyFlag || (tpl->Status
+			& (TX_VALID | TX_FRAME_COMPLETE))
+			!= TX_FRAME_COMPLETE)
+		{
+			break;
+		}
+
+		/* "Remove" TPL from busy list. */
+		tp->TplBusy = tpl->NextTPLPtr ;
+
+		if(sktr_debug > 3)
+			sktr_dump(tpl->MData, SWAPB(tpl->FrameSize));
+
+		/* Check the transmit status field only for directed frames*/
+		if(DIRECTED_FRAME(tpl) && (tpl->Status & TX_ERROR) == 0)
+		{
+			HighByte = GET_TRANSMIT_STATUS_HIGH_BYTE(tpl->Status);
+			HighAc   = GET_FRAME_STATUS_HIGH_AC(HighByte);
+			LowAc    = GET_FRAME_STATUS_LOW_AC(HighByte);
+
+			if((HighAc != LowAc) || (HighAc == AC_NOT_RECOGNIZED))
+			{
+				printk(KERN_INFO "%s: (DA=%08lX not recognized)",
+					dev->name,
+					*(unsigned long *)&tpl->MData[2+2]);
+			}
+			else
+			{
+				if(sktr_debug > 3)
+					printk("%s: Directed frame tx'd\n", 
+						dev->name);
+			}
+		}
+		else
+		{
+			if(!DIRECTED_FRAME(tpl))
+			{
+				if(sktr_debug > 3)
+					printk("%s: Broadcast frame tx'd\n",
+						dev->name);
+			}
+		}
+
+                tp->MacStat.tx_packets++;
+		dev_kfree_skb(tpl->Skb);
+		tpl->BusyFlag = 0;	/* "free" TPL */
+	}
+
+	dev->tbusy = 0;
+	if(tp->QueueSkb < MAX_TX_QUEUE)
+		sktr_hardware_send_packet(dev, tp);
+
+	return;
+}
+
+/*
+ * Called if a frame receive interrupt is generated by the adapter.
+ * Check if the frame is valid and indicate it to system.
+ */
+static void sktr_rcv_status_irq(struct net_device *dev)
+{
+	struct net_local *tp = (struct net_local *)dev->priv;
+	unsigned char *ReceiveDataPtr;
+	struct sk_buff *skb;
+	unsigned int Length, Length2;
+	RPL *rpl;
+	RPL *SaveHead;
+
+	/* NOTE: At this point the SSB from RECEIVE STATUS is no longer
+	 * available, because the CLEAR SSB command has already been issued.
+	 *
+	 * Process all complete receives.
+	 */
+
+	for(;;)
+	{
+		rpl = tp->RplHead;
+		if(rpl->Status & RX_VALID)
+			break;		/* RPL still in use by adapter */
+
+		/* Forward RPLHead pointer to next list. */
+		SaveHead = tp->RplHead;
+		tp->RplHead = rpl->NextRPLPtr;
+
+		/* Get the frame size (Byte swap for Intel).
+		 * Do this early (see workaround comment below)
+		 */
+		Length = (unsigned short)SWAPB(rpl->FrameSize);
+
+		/* Check if the Frame_Start, Frame_End and
+		 * Frame_Complete bits are set.
+		 */
+		if((rpl->Status & VALID_SINGLE_BUFFER_FRAME)
+			== VALID_SINGLE_BUFFER_FRAME)
+		{
+			ReceiveDataPtr = rpl->MData;
+
+			/* Workaround for delayed write of FrameSize on ISA
+			 * (FrameSize is false but valid-bit is reset)
+			 * Frame size is set to zero when the RPL is freed.
+			 * Length2 is there because there have also been
+			 * cases where the FrameSize was partially written
+			 */
+			Length2 = (unsigned short)SWAPB(rpl->FrameSize);
+
+			if(Length == 0 || Length != Length2)
+			{
+				tp->RplHead = SaveHead;
+				break;	/* Return to sktr_interrupt */
+			}
+
+			/* Drop frames sent by myself */
+			if(sktr_chk_frame(dev, rpl->MData))
+			{
+				if(rpl->Skb != NULL)
+					dev_kfree_skb(rpl->Skb);
+			}
+			else
+			{
+				sktr_update_rcv_stats(tp,ReceiveDataPtr,Length);
+
+				if(sktr_debug > 3)
+					printk("%s: Packet Length %04X (%d)\n",
+						dev->name, Length, Length);
+
+				/* Indicate the received frame to system.
+				 * The source routing padding is no more
+				 * necessary with 2.2.x kernel.
+				 * See: OpenOptions in sktr_init_opb()
+				 */
+				skb = rpl->Skb;
+				if(rpl->SkbStat == SKB_UNAVAILABLE)
+				{
+					/* Try again to allocate skb */
+					skb = dev_alloc_skb(tp->MaxPacketSize);
+					if(skb == NULL)
+					{
+						/* Update Stats ?? */
+					}
+					else
+					{
+						skb->dev	= dev;
+						skb_put(skb, tp->MaxPacketSize);
+						rpl->SkbStat 	= SKB_DATA_COPY;
+						ReceiveDataPtr 	= rpl->MData;
+					}
+				}
+
+				if(rpl->SkbStat == SKB_DATA_COPY
+					|| rpl->SkbStat == SKB_DMA_DIRECT)
+				{
+					if(rpl->SkbStat == SKB_DATA_COPY)
+					{
+						memmove(skb->data, ReceiveDataPtr, Length);
+					}
+
+					/* Deliver frame to system */
+					rpl->Skb = NULL;
+					skb_trim(skb,Length);
+					skb->dev = dev;
+					skb->protocol = tr_type_trans(skb,dev);
+					netif_rx(skb);
+				}
+			}
+		}
+		else	/* Invalid frame */
+		{
+			if(rpl->Skb != NULL)
+				dev_kfree_skb(rpl->Skb);
+
+			/* Skip list. */
+			if(rpl->Status & RX_START_FRAME)
+				/* Frame start bit is set -> overflow. */
+				tp->MacStat.rx_errors++;
+		}
+
+		/* Allocate new skb for rpl */
+		rpl->Skb = dev_alloc_skb(tp->MaxPacketSize);
+
+		/* skb == NULL ? then use local buffer */
+		if(rpl->Skb == NULL)
+		{
+			rpl->SkbStat = SKB_UNAVAILABLE;
+			rpl->FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[rpl->RPLIndex]));
+			rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex];
+		}
+		else	/* skb != NULL */
+		{
+			rpl->Skb->dev = dev;
+			skb_put(rpl->Skb, tp->MaxPacketSize);
+
+			/* Data unreachable for DMA ? then use local buffer */
+			if(tp->DeviceType == SK_ISA &&
+				virt_to_bus(rpl->Skb->data) + tp->MaxPacketSize
+				> ISA_MAX_ADDRESS)
+			{
+				rpl->SkbStat = SKB_DATA_COPY;
+				rpl->FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[rpl->RPLIndex]));
+				rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex];
+			}
+			else
+			{
+				/* DMA directly in skb->data */
+				rpl->SkbStat = SKB_DMA_DIRECT;
+				rpl->FragList[0].DataAddr = htonl(virt_to_bus(rpl->Skb->data));
+				rpl->MData = rpl->Skb->data;
+			}
+		}
+
+		rpl->FragList[0].DataCount = SWAPB(tp->MaxPacketSize);
+		rpl->FrameSize = 0;
+
+		/* Pass the last RPL back to the adapter */
+		tp->RplTail->FrameSize = 0;
+
+		/* Reset the CSTAT field in the list. */
+		sktr_write_rpl_status(tp->RplTail, RX_VALID | RX_FRAME_IRQ);
+
+		/* Current RPL becomes last one in list. */
+		tp->RplTail = tp->RplTail->NextRPLPtr;
+
+		/* Inform adapter about RPL valid. */
+		sktr_exec_sifcmd(dev, CMD_RX_VALID);
+	}
+
+	return;
+}
+
+/*
+ * This function should be used whenever the status of any RPL must be
+ * modified by the driver, because the compiler may otherwise change the
+ * order of instructions such that writing the RPL status may be executed
+ * at an undesireable time. When this function is used, the status is
+ * always written when the function is called.
+ */
+static void sktr_write_rpl_status(RPL *rpl, unsigned int Status)
+{
+	rpl->Status = Status;
+
+	return;
+}
+
+/*
+ * The function updates the statistic counters in mac->MacStat.
+ * It differtiates between directed and broadcast/multicast ( ==functional)
+ * frames.
+ */
+static void sktr_update_rcv_stats(struct net_local *tp, unsigned char DataPtr[],
+					unsigned int Length)
+{
+	tp->MacStat.rx_packets++;
+
+	/* Test functional bit */
+	if(DataPtr[2] & GROUP_BIT)
+		tp->MacStat.multicast++;
+
+	return;
+}
+
+/*
+ * Check if it is a frame of myself. Compare source address with my current
+ * address in reverse direction, and mask out the TR_RII.
+ */
+static unsigned char sktr_chk_frame(struct net_device *dev, unsigned char *Addr)
+{
+	int i;
+
+	for(i = 5; i > 0; i--)
+	{
+		if(Addr[8 + i] != dev->dev_addr[i])
+			return (0);
+	}
+
+	/* Mask out RIF bit. */
+	if((Addr[8] & ~TR_RII) != (unsigned char)(dev->dev_addr[0]))
+		return (0);
+
+	return (1);  /* It is my frame. */
+}
+
+/*
+ * Dump Packet (data)
+ */
+static void sktr_dump(unsigned char *Data, int length)
+{
+        int i, j;
+
+        for (i = 0, j = 0; i < length / 8; i++, j += 8)
+        {
+		printk(KERN_DEBUG "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+			Data[j+0],Data[j+1],Data[j+2],Data[j+3],
+                        Data[j+4],Data[j+5],Data[j+6],Data[j+7]);
+        }
+
+        return;
+}
+
+#ifdef MODULE
+
+static struct net_device* dev_sktr[SKTR_MAX_ADAPTERS];
+static int io[SKTR_MAX_ADAPTERS]	= { 0, 0 };
+static int irq[SKTR_MAX_ADAPTERS] 	= { 0, 0 };
+static int mem[SKTR_MAX_ADAPTERS] 	= { 0, 0 };
+
+MODULE_PARM(io,  "1-" __MODULE_STRING(SKTR_MAX_ADAPTERS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(SKTR_MAX_ADAPTERS) "i");
+MODULE_PARM(mem, "1-" __MODULE_STRING(SKTR_MAX_ADAPTERS) "i");
+
+int init_module(void)
+{
+	int i;
+
+	for(i = 0; i < SKTR_MAX_ADAPTERS; i++)
+	{
+                irq[i] = 0;
+                mem[i] = 0;
+                dev_sktr[i] = NULL;
+                dev_sktr[i] = init_trdev(dev_sktr[i], 0);
+                if(dev_sktr[i] == NULL)
+                        return (-ENOMEM);
+
+		dev_sktr[i]->base_addr = io[i];
+                dev_sktr[i]->irq       = irq[i];
+                dev_sktr[i]->mem_start = mem[i];
+                dev_sktr[i]->init      = &sktr_probe;
+
+                if(register_trdev(dev_sktr[i]) != 0)
+		{
+                        kfree_s(dev_sktr[i], sizeof(struct net_device));
+                        dev_sktr[i] = NULL;
+                        if(i == 0)
+			{
+                                printk("sktr: register_trdev() returned non-zero.\n");
+                                return (-EIO);
+                        }
+			else
+                                return (0);
+                }
+        }
+
+        return (0);
+}
+
+void cleanup_module(void)
+{
+	int i;
+
+        for(i = 0; i < SKTR_MAX_ADAPTERS; i++)
+	{
+		if(dev_sktr[i])
+		{
+			unregister_trdev(dev_sktr[i]);
+			release_region(dev_sktr[i]->base_addr, SKTR_IO_EXTENT);
+			if(dev_sktr[i]->irq)
+				free_irq(dev_sktr[i]->irq, dev_sktr[i]);
+			if(dev_sktr[i]->dma > 0)
+				free_dma(dev_sktr[i]->dma);
+			if(dev_sktr[i]->priv)
+				kfree_s(dev_sktr[i]->priv, sizeof(struct net_local));
+			kfree_s(dev_sktr[i], sizeof(struct net_device));
+			dev_sktr[i] = NULL;
+                }
+	}
+}
+#endif /* MODULE */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/tokenring/sktr.h linux/drivers/net/tokenring/sktr.h
--- v2.3.20/linux/drivers/net/tokenring/sktr.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/tokenring/sktr.h	Mon Oct 11 10:13:24 1999
@@ -0,0 +1,1103 @@
+/* sktr.h: SysKonnect TokenRing driver for Linux
+ *
+ * Authors:
+ * - Christoph Goos <cgoos@syskonnect.de>
+ */
+
+#ifndef __LINUX_SKTR_H
+#define __LINUX_SKTR_H
+
+#ifdef __KERNEL__
+
+#define SKTR_MAX_ADAPTERS 7
+
+#define SEND_TIMEOUT 10*HZ
+
+#define TR_RCF_LONGEST_FRAME_MASK 0x0070
+#define TR_RCF_FRAME4K 0x0030
+
+#define SK_ISA 0
+#define SK_PCI 1
+
+/*------------------------------------------------------------------*/
+/*  Bit order for adapter communication with DMA		    */
+/*  --------------------------------------------------------------  */
+/*  Bit  8 | 9| 10| 11|| 12| 13| 14| 15|| 0| 1| 2| 3|| 4| 5| 6| 7|  */
+/*  --------------------------------------------------------------  */
+/*  The bytes in a word must be byte swapped. Also, if a double	    */
+/*  word is used for storage, then the words, as well as the bytes, */
+/*  must be swapped. 						    */
+/*  Bit order for adapter communication with DIO 		    */
+/*  --------------------------------------------------------------  */
+/*  Bit  0 | 1| 2| 3|| 4| 5| 6| 7|| 8| 9| 10| 11|| 12| 13| 14| 15|  */
+/*  --------------------------------------------------------------  */
+/*------------------------------------------------------------------*/
+
+/* Swap bytes of a word.                        */
+#define SWAPB(x) (((unsigned short)((x) << 8)) | ((unsigned short)((x) >> 8)))
+
+/* Swap words of a long.                        */
+#define SWAPW(x) (((x) << 16) | ((x) >> 16))
+
+/* Get the low byte of a word.                      */
+#define LOBYTE(w)       ((unsigned char)(w))
+
+/* Get the high byte of a word.                     */
+#define HIBYTE(w)       ((unsigned char)((unsigned short)(w) >> 8))
+
+/* Get the low word of a long.                      */
+#define LOWORD(l)       ((unsigned short)(l))
+
+/* Get the high word of a long.                     */
+#define HIWORD(l)       ((unsigned short)((unsigned long)(l) >> 16))
+
+
+
+/* Token ring adapter I/O addresses for normal mode. */
+#define SIFDAT      		0L	/* SIF/DMA data. */
+#define SIFINC      		2L  	/* IO Word data with auto increment. */
+#define SIFINH      		3L  	/* IO Byte data with auto increment. */
+#define SIFADR      		4L  	/* SIF/DMA Address. */
+#define SIFCMD      		6L  	/* SIF Command. */
+#define SIFSTS      		6L  	/* SIF Status. */
+#define SIFACL      		8L  	/* SIF Adapter Control Register. */
+#define SIFADD      		10L 	/* SIF/DMA Address. */
+#define SIFADX      		12L
+#define DMALEN      		14L 	/* SIF DMA length. */
+#define POSREG      		16L 	/* Adapter Program Option Select (POS)
+			 		 * Register: base IO address + 16 byte.
+			 		 */
+#define POSREG_2    		24L 	/* only for TR4/16+ adapter
+			 		 * base IO address + 24 byte.
+			 		 */
+
+
+/* SIFCMD command codes (high-low) */
+#define CMD_INTERRUPT_ADAPTER   0x8000  /* Cause internal adapter interrupt */
+#define CMD_ADAPTER_RESET   	0x4000  /* Hardware reset of adapter */
+#define CMD_SSB_CLEAR		0x2000  /* Acknowledge to adapter to
+					 * system interrupts.
+					 */
+#define CMD_EXECUTE		0x1000	/* Execute SCB command */
+#define CMD_SCB_REQUEST		0x0800  /* Request adapter to interrupt
+					 * system when SCB is available for
+					 * another command.
+					 */
+#define CMD_RX_CONTINUE		0x0400  /* Continue receive after odd pointer
+					 * stop. (odd pointer receive method)
+					 */
+#define CMD_RX_VALID		0x0200  /* Now actual RPL is valid. */
+#define CMD_TX_VALID		0x0100  /* Now actual TPL is valid. (valid
+					 * bit receive/transmit method)
+					 */
+#define CMD_SYSTEM_IRQ		0x0080  /* Adapter-to-attached-system
+					 * interrupt is reset.
+					 */
+#define CMD_CLEAR_SYSTEM_IRQ	0x0080	/* Clear SYSTEM_INTERRUPT bit.
+					 * (write: 1=ignore, 0=reset)
+					 */
+#define EXEC_SOFT_RESET		0xFF00  /* adapter soft reset. (restart
+					 * adapter after hardware reset)
+					 */
+
+
+/* ACL commands (high-low) */
+#define ACL_SWHLDA		0x0800  /* Software hold acknowledge. */
+#define ACL_SWDDIR		0x0400  /* Data transfer direction. */
+#define ACL_SWHRQ		0x0200  /* Pseudo DMA operation. */
+#define ACL_PSDMAEN		0x0100  /* Enable pseudo system DMA. */
+#define ACL_ARESET		0x0080  /* Adapter hardware reset command.
+					 * (held in reset condition as
+					 * long as bit is set)
+					 */
+#define ACL_CPHALT		0x0040  /* Communication processor halt.
+					 * (can only be set while ACL_ARESET
+					 * bit is set; prevents adapter
+					 * processor from executing code while
+					 * downloading firmware)
+					 */
+#define ACL_BOOT		0x0020
+#define ACL_SINTEN		0x0008  /* System interrupt enable/disable
+					 * (1/0): can be written if ACL_ARESET
+					 * is zero.
+					 */
+#define ACL_SPEED4		0x0003
+#define ACL_SPEED16		0x0001
+#define PS_DMA_MASK		(ACL_SWHRQ | ACL_PSDMAEN)
+
+
+/* SIFSTS register return codes (high-low) */
+#define STS_SYSTEM_IRQ		0x0080	/* Adapter-to-attached-system
+					 * interrupt is valid.
+					 */
+#define STS_INITIALIZE		0x0040  /* INITIALIZE status. (ready to
+					 * initialize)
+					 */
+#define STS_TEST		0x0020  /* TEST status. (BUD not completed) */
+#define STS_ERROR		0x0010  /* ERROR status. (unrecoverable
+					 * HW error occurred)
+					 */
+#define STS_MASK		0x00F0  /* Mask interesting status bits. */
+#define STS_ERROR_MASK		0x000F  /* Get Error Code by masking the
+					 * interrupt code bits.
+					 */
+#define ADAPTER_INT_PTRS	0x0A00  /* Address offset of adapter internal
+					 * pointers 01:0a00 (high-low) have to
+					 * be read after init and before open.
+					 */
+
+
+/* Interrupt Codes (only MAC IRQs) */
+#define STS_IRQ_ADAPTER_CHECK   0x0000  /* unrecoverable hardware or
+					 * software error.
+					 */ 
+#define STS_IRQ_RING_STATUS     0x0004  /* SSB is updated with ring status. */
+#define STS_IRQ_SCB_CLEAR       0x0006  /* SCB clear, following an
+					 * SCB_REQUEST IRQ.
+					 */
+#define STS_IRQ_COMMAND_STATUS  0x0008  /* SSB is updated with command 
+					 * status.
+					 */ 
+#define STS_IRQ_RECEIVE_STATUS  0x000A  /* SSB is updated with receive
+					 * status.
+					 */
+#define STS_IRQ_TRANSMIT_STATUS 0x000C  /* SSB is updated with transmit
+                                         * status
+					 */
+#define STS_IRQ_MASK            0x000F  /* = STS_ERROR_MASK. */
+
+
+/* TRANSMIT_STATUS completion code: (SSB.Parm[0]) */
+#define COMMAND_COMPLETE        0x0080  /* TRANSMIT command completed
+                                         * (avoid this!) issue another transmit
+					 * to send additional frames.
+					 */
+#define FRAME_COMPLETE          0x0040  /* Frame has been transmitted;
+					 * INTERRUPT_FRAME bit was set in the
+					 * CSTAT request; indication of possibly
+					 * more than one frame transmissions!
+					 * SSB.Parm[0-1]: 32 bit pointer to
+					 * TPL of last frame.
+					 */
+#define LIST_ERROR              0x0020  /* Error in one of the TPLs that
+					 * compose the frame; TRANSMIT
+					 * terminated; Parm[1-2]: 32 bit pointer
+					 * to TPL which starts the error
+					 * frame; error details in bits 8-13.
+					 * (14?)
+					 */
+#define FRAME_SIZE_ERROR        0x8000  /* FRAME_SIZE does not equal the sum of
+					 * the valid DATA_COUNT fields;
+					 * FRAME_SIZE less than header plus
+					 * information field. (15 bytes +
+					 * routing field) Or if FRAME_SIZE
+					 * was specified as zero in one list.
+					 */
+#define TX_THRESHOLD            0x4000  /* FRAME_SIZE greater than (BUFFER_SIZE
+					 * - 9) * TX_BUF_MAX.
+					 */
+#define ODD_ADDRESS             0x2000  /* Odd forward pointer value is
+					 * read on a list without END_FRAME
+					 * indication.
+					 */
+#define FRAME_ERROR             0x1000  /* START_FRAME bit is (not) anticipated,
+					 * but (not) set.
+					 */
+#define ACCESS_PRIORITY_ERROR   0x0800  /* Access priority requested has not
+					 * been allowed.
+					 */
+#define UNENABLED_MAC_FRAME     0x0400  /* MAC frame has source class of zero
+					 * or MAC frame PCF ATTN field is
+					 * greater than one.
+					 */
+#define ILLEGAL_FRAME_FORMAT    0x0200  /* Bit 0 or FC field was set to one. */
+
+
+/*
+ * Since we need to support some functions even if the adapter is in a
+ * CLOSED state, we have a (pseudo-) command queue which holds commands
+ * that are outstandig to be executed.
+ *
+ * Each time a command completes, an interrupt occurs and the next
+ * command is executed. The command queue is actually a simple word with 
+ * a bit for each outstandig command. Therefore the commands will not be
+ * executed in the order they have been queued.
+ *
+ * The following defines the command code bits and the command queue:
+ */
+#define OC_OPEN                 0x0001	/* OPEN command */
+#define OC_TRANSMIT             0x0002  /* TRANSMIT command */
+#define OC_TRANSMIT_HALT        0x0004  /* TRANSMIT_HALT command */
+#define OC_RECEIVE              0x0008  /* RECEIVE command */
+#define OC_CLOSE                0x0010  /* CLOSE command */
+#define OC_SET_GROUP_ADDR       0x0020  /* SET_GROUP_ADDR command */
+#define OC_SET_FUNCT_ADDR       0x0040  /* SET_FUNCT_ADDR command */
+#define OC_READ_ERROR_LOG       0x0080  /* READ_ERROR_LOG command */
+#define OC_READ_ADAPTER         0x0100  /* READ_ADAPTER command */
+#define OC_MODIFY_OPEN_PARMS    0x0400  /* MODIFY_OPEN_PARMS command */
+#define OC_RESTORE_OPEN_PARMS   0x0800  /* RESTORE_OPEN_PARMS command */
+#define OC_SET_FIRST_16_GROUP   0x1000  /* SET_FIRST_16_GROUP command */
+#define OC_SET_BRIDGE_PARMS     0x2000  /* SET_BRIDGE_PARMS command */
+#define OC_CONFIG_BRIDGE_PARMS  0x4000  /* CONFIG_BRIDGE_PARMS command */
+
+#define OPEN			0x0300  /* C: open command. S: completion. */
+#define TRANSMIT		0x0400  /* C: transmit command. S: completion
+					 * status. (reject: COMMAND_REJECT if
+					 * adapter not opened, TRANSMIT already
+					 * issued or address passed in the SCB
+					 * not word aligned)
+					 */
+#define TRANSMIT_HALT		0x0500  /* C: interrupt TX TPL chain; if no
+					 * TRANSMIT command issued, the command
+					 * is ignored. (completion with TRANSMIT
+					 * status (0x0400)!)
+					 */
+#define RECEIVE			0x0600  /* C: receive command. S: completion
+					 * status. (reject: COMMAND_REJECT if
+					 * adapter not opened, RECEIVE already
+					 * issued or address passed in the SCB 
+					 * not word aligned)
+					 */
+#define CLOSE			0x0700  /* C: close adapter. S: completion.
+					 * (COMMAND_REJECT if adapter not open)
+					 */
+#define SET_GROUP_ADDR		0x0800  /* C: alter adapter group address after
+					 * OPEN.  S: completion. (COMMAND_REJECT
+					 * if adapter not open)
+					 */
+#define SET_FUNCT_ADDR		0x0900  /* C: alter adapter functional address
+					 * after OPEN. S: completion.
+					 * (COMMAND_REJECT if adapter not open)
+					 */
+#define READ_ERROR_LOG		0x0A00  /* C: read adapter error counters.
+					 * S: completion. (command ignored
+					 * if adapter not open!)
+					 */
+#define READ_ADAPTER		0x0B00  /* C: read data from adapter memory.
+					 * (important: after init and before
+					 * open!) S: completion. (ADAPTER_CHECK
+					 * interrupt if undefined storage area
+					 * read)
+					 */
+#define MODIFY_OPEN_PARMS	0x0D00  /* C: modify some adapter operational
+					 * parameters. (bit correspondend to
+					 * WRAP_INTERFACE is ignored)
+					 * S: completion. (reject: 
+					 * COMMAND_REJECT)
+					 */
+#define RESTORE_OPEN_PARMS	0x0E00  /* C: modify some adapter operational
+					 * parameters. (bit correspondend
+					 * to WRAP_INTERFACE is ignored)
+					 * S: completion. (reject:
+					 * COMMAND_REJECT)
+					 */
+#define SET_FIRST_16_GROUP	0x0F00  /* C: alter the first two bytes in
+					 * adapter group address.
+					 * S: completion. (reject:
+					 * COMMAND_REJECT)
+					 */
+#define SET_BRIDGE_PARMS	0x1000  /* C: values and conditions for the
+					 * adapter hardware to use when frames
+					 * are copied for forwarding.
+					 * S: completion. (reject:
+					 * COMMAND_REJECT)
+					 */
+#define CONFIG_BRIDGE_PARMS 0x1100	/* C: ..
+					 * S: completion. (reject:
+					 * COMMAND_REJECT)
+					 */
+
+#define SPEED_4         4
+#define SPEED_16        16	/* Default transmission speed  */
+
+
+/* Initialization Parameter Block (IPB); word alignment necessary! */
+#define BURST_SIZE      0x0018  /* Default burst size */
+#define BURST_MODE      0x9F00  /* Burst mode enable */
+#define DMA_RETRIES     0x0505  /* Magic DMA retry number... */
+
+#define CYCLE_TIME      3	/* Default AT-bus cycle time: 500 ns
+				 * (later adapter version: fix  cycle time!)
+				 */
+#define LINE_SPEED_BIT	0x80
+
+/* Macro definition for the wait function. */
+#define ONE_SECOND_TICKS	1000000
+#define HALF_SECOND		(ONE_SECOND_TICKS / 2)
+#define ONE_SECOND		(ONE_SECOND_TICKS)
+#define TWO_SECONDS		(ONE_SECOND_TICKS * 2)
+#define THREE_SECONDS		(ONE_SECOND_TICKS * 3)
+#define FOUR_SECONDS		(ONE_SECOND_TICKS * 4)
+#define FIVE_SECONDS		(ONE_SECOND_TICKS * 5)
+
+#define BUFFER_SIZE 2048	/* Buffers on Adapter */
+
+#pragma pack(1)
+typedef struct {
+	unsigned short Init_Options;	/* Initialize with burst mode;
+					 * LLC disabled. (MAC only)
+					 */
+
+	/* Interrupt vectors the adapter places on attached system bus. */
+	unsigned char CMD_Status_IV;	/* Interrupt vector: command status. */
+	unsigned char TX_IV;     	/* Interrupt vector: transmit. */
+	unsigned char RX_IV;     	/* Interrupt vector: receive. */
+	unsigned char Ring_Status_IV;	/* Interrupt vector: ring status. */
+	unsigned char SCB_Clear_IV;  	/* Interrupt vector: SCB clear. */
+	unsigned char Adapter_CHK_IV;	/* Interrupt vector: adapter check. */
+
+	unsigned short RX_Burst_Size;	/* Max. number of transfer cycles. */
+	unsigned short TX_Burst_Size;	/* During DMA burst; even value! */
+	unsigned short DMA_Abort_Thrhld; /* Number of DMA retries. */
+
+	unsigned long SCB_Addr;	/* SCB address: even, word aligned, high-low. */
+	unsigned long SSB_Addr;	/* SSB address: even, word aligned, high-low. */
+} IPB, *IPB_Ptr;
+#pragma pack()
+
+/*
+ * OPEN Command Parameter List (OCPL) (can be reused, if the adapter has to
+ * be reopened)
+ */
+#define BUFFER_SIZE	2048		/* Buffers on Adapter. */
+#define TPL_SIZE	8+6*TX_FRAG_NUM /* Depending on fragments per TPL. */
+#define RPL_SIZE	14		/* (with TI firmware v2.26 handling
+					 * up to nine fragments possible)
+					 */
+#define TX_BUF_MIN      20		/* ??? (Stephan: calculation with */
+#define TX_BUF_MAX      40		/* BUFFER_SIZE and MAX_FRAME_SIZE) ??? 
+					 */
+#define DISABLE_EARLY_TOKEN_RELEASE 0x1000
+
+/* OPEN Options (high-low) */
+#define WRAP_INTERFACE		0x0080	/* Inserting omitted for test
+					 * purposes; transmit data appears
+					 * as receive data. (usefull for
+					 * testing; change: CLOSE necessary)
+					 */
+#define DISABLE_HARD_ERROR	0x0040  /* On HARD_ERROR & TRANSMIT_BEACON
+					 * no RING.STATUS interrupt.
+					 */
+#define DISABLE_SOFT_ERROR	0x0020  /* On SOFT_ERROR, no RING.STATUS
+					 * interrupt.
+					 */
+#define PASS_ADAPTER_MAC_FRAMES 0x0010  /* Passing unsupported MAC frames
+					 * to system.
+					 */
+#define PASS_ATTENTION_FRAMES   0x0008  /* All changed attention MAC frames are
+					 * passed to the system.
+					 */
+#define PAD_ROUTING_FIELD	0x0004  /* Routing field is padded to 18
+					 * bytes.
+					 */
+#define FRAME_HOLD		0x0002  /* Adapter waits for entire frame before
+					 * initiating DMA transfer; otherwise:
+					 * DMA transfer initiation if internal
+					 * buffer filled.
+					 */
+#define CONTENDER		0x0001  /* Adapter participates in the monitor
+					 * contention process.
+					 */
+#define PASS_BEACON_MAC_FRAMES  0x8000  /* Adapter passes beacon MAC frames
+					 * to the system.
+					 */
+#define EARLY_TOKEN_RELEASE 	0x1000  /* Only valid in 16 Mbps operation;
+					 * 0 = ETR. (no effect in 4 Mbps
+					 * operation)
+					 */
+#define COPY_ALL_MAC_FRAMES	0x0400  /* All MAC frames are copied to
+					 * the system. (after OPEN: duplicate
+					 * address test (DAT) MAC frame is 
+					 * first received frame copied to the
+					 * system)
+					 */
+#define COPY_ALL_NON_MAC_FRAMES	0x0200  /* All non MAC frames are copied to
+					 * the system.
+					 */
+#define PASS_FIRST_BUF_ONLY	0x0100  /* Passes only first internal buffer
+					 * of each received frame; FrameSize
+					 * of RPLs must contain internal
+					 * BUFFER_SIZE bits for promiscous mode.
+					 */
+#define ENABLE_FULL_DUPLEX_SELECTION 0x2000 /* Enable the use of full-duplex
+					 * settings with bits in byte 22 in
+					 * ocpl. (new feature in firmware
+					 * version 3.09)
+					 */
+
+/* Full-duplex settings */
+#define OPEN_FULL_DUPLEX_OFF	0x0000
+#define OPEN_FULL_DUPLEX_ON	0x00c0
+#define OPEN_FULL_DUPLEX_AUTO	0x0080
+
+#define PROD_ID_SIZE	18	/* Length of product ID. */
+
+#define TX_FRAG_NUM	3	 /* Number of fragments used in one TPL. */
+#define TX_MORE_FRAGMENTS 0x8000 /* Bit set in DataCount to indicate more
+				  * fragments following.
+				  */
+
+#define ISA_MAX_ADDRESS 0x00ffffff
+
+#pragma pack(1)
+typedef struct {
+	unsigned short OPENOptions;
+	unsigned char NodeAddr[6];	/* Adapter node address; use ROM 
+					 * address
+					 */
+	unsigned long GroupAddr;	/* Multicast: high order
+					 * bytes = 0xC000
+					 */
+	unsigned long FunctAddr;	/* High order bytes = 0xC000 */
+	unsigned short RxListSize;	/* RPL size: 0 (=26), 14, 20 or
+					 * 26 bytes read by the adapter.
+					 * (Depending on the number of 
+					 * fragments/list)
+					 */
+	unsigned short TxListSize;	/* TPL size */
+	unsigned short BufSize;		/* Is automatically rounded up to the
+					 * nearest nK boundary.
+					 */
+	unsigned short FullDuplex;
+	unsigned short Reserved;
+	unsigned char TXBufMin;		/* Number of adapter buffers reserved
+					 * for transmission a minimum of 2
+					 * buffers must be allocated.
+					 */
+	unsigned char TXBufMax;		/* Maximum number of adapter buffers
+					 * for transmit; a minimum of 2 buffers
+					 * must be available for receive.
+					 * Default: 6
+					 */
+	unsigned short ProdIDAddr[2];	/* Pointer to product ID. */
+} OPB, *OPB_Ptr;
+#pragma pack()
+
+/*
+ * SCB: adapter commands enabled by the host system started by writing
+ * CMD_INTERRUPT_ADAPTER | CMD_EXECUTE (|SCB_REQUEST) to the SIFCMD IO
+ * register. (special case: | CMD_SYSTEM_IRQ for initialization)
+ */
+#pragma pack(1)
+typedef struct {
+	unsigned short CMD;	/* Command code */
+	unsigned short Parm[2];	/* Pointer to Command Parameter Block */
+} SCB;	/* System Command Block (32 bit physical address; big endian)*/
+#pragma pack()
+
+/*
+ * SSB: adapter command return status can be evaluated after COMMAND_STATUS
+ * adapter to system interrupt after reading SSB, the availability of the SSB
+ * has to be told the adapter by writing CMD_INTERRUPT_ADAPTER | CMD_SSB_CLEAR
+ * in the SIFCMD IO register.
+ */
+#pragma pack(1)
+typedef struct {
+	unsigned short STS;	/* Status code */
+	unsigned short Parm[3];	/* Parameter or pointer to Status Parameter
+				 * Block.
+				 */
+} SSB;	/* System Status Block (big endian - physical address)  */
+#pragma pack()
+
+typedef struct {
+	unsigned short BurnedInAddrPtr;	/* Pointer to adapter burned in
+					 * address. (BIA)
+					 */
+	unsigned short SoftwareLevelPtr;/* Pointer to software level data. */
+	unsigned short AdapterAddrPtr;	/* Pointer to adapter addresses. */
+	unsigned short AdapterParmsPtr;	/* Pointer to adapter parameters. */
+	unsigned short MACBufferPtr;	/* Pointer to MAC buffer. (internal) */
+	unsigned short LLCCountersPtr;	/* Pointer to LLC counters.  */
+	unsigned short SpeedFlagPtr;	/* Pointer to data rate flag.
+					 * (4/16 Mbps)
+					 */
+	unsigned short AdapterRAMPtr;	/* Pointer to adapter RAM found. (KB) */
+} INTPTRS;	/* Adapter internal pointers */
+
+#pragma pack(1)
+typedef struct {
+	unsigned char Line_Error;	/* Line error: code violation in
+					 * frame or in a token, or FCS error.
+					 */
+	unsigned char Internal_Error;	/* IBM specific. (Reserved_1) */
+	unsigned char Burst_Error;
+	unsigned char ARI_FCI_Error;	/* ARI/FCI bit zero in AMP or
+					 * SMP MAC frame.
+					 */
+	unsigned char AbortDelimeters;	/* IBM specific. (Reserved_2) */
+	unsigned char Reserved_3;
+	unsigned char Lost_Frame_Error;	/* Receive of end of transmitted
+					 * frame failed.
+					 */
+	unsigned char Rx_Congest_Error;	/* Adapter in repeat mode has not
+					 * enough buffer space to copy incoming
+					 * frame.
+					 */
+	unsigned char Frame_Copied_Error;/* ARI bit not zero in frame
+					 * addressed to adapter.
+					 */
+	unsigned char Frequency_Error;	/* IBM specific. (Reserved_4) */
+	unsigned char Token_Error;	/* (active only in monitor station) */
+	unsigned char Reserved_5;
+	unsigned char DMA_Bus_Error;	/* DMA bus errors not exceeding the
+					 * abort thresholds.
+					 */
+	unsigned char DMA_Parity_Error;	/* DMA parity errors not exceeding
+					 * the abort thresholds.
+					 */
+} ERRORTAB;	/* Adapter error counters */
+#pragma pack()
+
+
+/*--------------------- Send and Receive definitions -------------------*/
+#pragma pack(1)
+typedef struct {
+	unsigned short DataCount;	/* Value 0, even and odd values are
+					 * permitted; value is unaltered most
+					 * significant bit set: following
+					 * fragments last fragment: most
+					 * significant bit is not evaluated.
+					 * (???)
+					 */
+	unsigned long DataAddr;		/* Pointer to frame data fragment;
+					 * even or odd.
+					 */
+} Fragment;
+#pragma pack()
+
+#define MAX_FRAG_NUMBERS    9	/* Maximal number of fragments possible to use
+				 * in one RPL/TPL. (depending on TI firmware 
+				 * version)
+				 */
+#define MAX_TX_QUEUE	    10	/* Maximal number of skb's queued in driver. */
+
+/*
+ * AC (1), FC (1), Dst (6), Src (6), RIF (18), Data (4472) = 4504
+ * The packet size can be one of the follows: 548, 1502, 2084, 4504, 8176,
+ * 11439, 17832. Refer to TMS380 Second Generation Token Ring User's Guide
+ * Page 2-27.
+ */
+#define HEADER_SIZE		(1 + 1 + 6 + 6)
+#define SRC_SIZE		18
+#define MIN_DATA_SIZE		516
+#define DEFAULT_DATA_SIZE	4472
+#define MAX_DATA_SIZE		17800
+
+#define DEFAULT_PACKET_SIZE (HEADER_SIZE + SRC_SIZE + DEFAULT_DATA_SIZE)
+#define MIN_PACKET_SIZE     (HEADER_SIZE + SRC_SIZE + MIN_DATA_SIZE)
+#define MAX_PACKET_SIZE     (HEADER_SIZE + SRC_SIZE + MAX_DATA_SIZE)
+
+/*
+ * Macros to deal with the frame status field.
+ */
+#define AC_NOT_RECOGNIZED	0x00
+#define GROUP_BIT		0x80
+#define GET_TRANSMIT_STATUS_HIGH_BYTE(Ts) ((unsigned char)((Ts) >> 8))
+#define GET_FRAME_STATUS_HIGH_AC(Fs)	  ((unsigned char)(((Fs) & 0xC0) >> 6))
+#define GET_FRAME_STATUS_LOW_AC(Fs)       ((unsigned char)(((Fs) & 0x0C) >> 2))
+#define DIRECTED_FRAME(Context)           (!((Context)->MData[2] & GROUP_BIT))
+
+
+/*--------------------- Send Functions ---------------------------------*/
+/* define TX_CSTAT _REQUEST (R) and _COMPLETE (C) values (high-low) */
+
+#define TX_VALID		0x0080	/* R: set via TRANSMIT.VALID interrupt.
+					 * C: always reset to zero!
+					 */
+#define TX_FRAME_COMPLETE	0x0040	/* R: must be reset to zero.
+					 * C: set to one.
+					 */
+#define TX_START_FRAME		0x0020  /* R: start of a frame: 1 
+					 * C: unchanged.
+					 */
+#define TX_END_FRAME		0x0010  /* R: end of a frame: 1
+					 * C: unchanged.
+					 */
+#define TX_FRAME_IRQ		0x0008  /* R: request interrupt generation
+					 * after transmission.
+					 * C: unchanged.
+					 */
+#define TX_ERROR		0x0004  /* R: reserved.
+					 * C: set to one if Error occurred.
+					 */
+#define TX_INTERFRAME_WAIT	0x0004
+#define TX_PASS_CRC		0x0002  /* R: set if CRC value is already
+					 * calculated. (valid only in
+					 * FRAME_START TPL)
+					 * C: unchanged.
+					 */
+#define TX_PASS_SRC_ADDR	0x0001  /* R: adapter uses explicit frame
+					 * source address and does not overwrite
+					 * with the adapter node address.
+					 * (valid only in FRAME_START TPL)
+					 *
+					 * C: unchanged.
+					 */
+#define TX_STRIP_FS		0xFF00  /* R: reserved.
+					 * C: if no Transmission Error,
+					 * field contains copy of FS byte after
+					 * stripping of frame.
+					 */
+
+/*
+ * Structure of Transmit Parameter Lists (TPLs) (only one frame every TPL,
+ * but possibly multiple TPLs for one frame) the length of the TPLs has to be
+ * initialized in the OPL. (OPEN parameter list)
+ */
+#define TPL_NUM		9	/* Number of Transmit Parameter Lists.
+				 * !! MUST BE >= 3 !!
+				 */
+
+#pragma pack(1)
+typedef struct s_TPL TPL;
+
+struct s_TPL {	/* Transmit Parameter List (align on even word boundaries) */
+	unsigned long NextTPLAddr;	/* Pointer to next TPL in chain; if
+					 * pointer is odd: this is the last
+					 * TPL. Pointing to itself can cause
+					 * problems!
+					 */
+	volatile unsigned short Status;	/* Initialized by the adapter:
+					 * CSTAT_REQUEST important: update least
+					 * significant bit first! Set by the
+					 * adapter: CSTAT_COMPLETE status.
+					 */
+	unsigned short FrameSize;	/* Number of bytes to be transmitted
+					 * as a frame including AC/FC,
+					 * Destination, Source, Routing field
+					 * not including CRC, FS, End Delimiter
+					 * (valid only if START_FRAME bit in 
+					 * CSTAT nonzero) must not be zero in
+					 * any list; maximum value: (BUFFER_SIZE
+					 * - 8) * TX_BUF_MAX sum of DataCount
+					 * values in FragmentList must equal
+					 * Frame_Size value in START_FRAME TPL!
+					 * frame data fragment list.
+					 */
+
+	/* TPL/RPL size in OPEN parameter list depending on maximal
+	 * numbers of fragments used in one parameter list.
+	 */
+	Fragment FragList[TX_FRAG_NUM];	/* Maximum: nine frame fragments in one
+					 * TPL actual version of firmware: 9
+					 * fragments possible.
+					 */
+#pragma pack()
+
+	/* Special proprietary data and precalculations */
+
+	TPL *NextTPLPtr;		/* Pointer to next TPL in chain. */
+	unsigned char *MData;
+	struct sk_buff *Skb;
+	unsigned char TPLIndex;
+	volatile unsigned char BusyFlag;/* Flag: TPL busy? */
+};
+
+/* ---------------------Receive Functions-------------------------------*
+ * define RECEIVE_CSTAT_REQUEST (R) and RECEIVE_CSTAT_COMPLETE (C) values.
+ * (high-low)
+ */
+#define RX_VALID		0x0080	/* R: set; tell adapter with
+					 * RECEIVE.VALID interrupt.
+					 * C: reset to zero.
+					 */
+#define RX_FRAME_COMPLETE	0x0040  /* R: must be reset to zero,
+					 * C: set to one.
+					 */
+#define RX_START_FRAME		0x0020  /* R: must be reset to zero.
+					 * C: set to one on the list.
+					 */
+#define RX_END_FRAME		0x0010  /* R: must be reset to zero.
+					 * C: set to one on the list
+					 * that ends the frame.
+					 */
+#define RX_FRAME_IRQ		0x0008  /* R: request interrupt generation
+					 * after receive.
+					 * C: unchanged.
+					 */
+#define RX_INTERFRAME_WAIT	0x0004  /* R: after receiving a frame:
+					 * interrupt and wait for a
+					 * RECEIVE.CONTINUE.
+					 * C: unchanged.
+					 */
+#define RX_PASS_CRC		0x0002  /* R: if set, the adapter includes
+					 * the CRC in data passed. (last four 
+					 * bytes; valid only if FRAME_START is
+					 * set)
+					 * C: set, if CRC is included in
+					 * received data.
+					 */
+#define RX_PASS_SRC_ADDR	0x0001  /* R: adapter uses explicit frame
+					 * source address and does not
+					 * overwrite with the adapter node
+					 * address. (valid only if FRAME_START
+					 * is set)
+					 * C: unchanged.
+					 */
+#define RX_RECEIVE_FS		0xFC00  /* R: reserved; must be reset to zero.
+					 * C: on lists with START_FRAME, field
+					 * contains frame status field from
+					 * received frame; otherwise cleared.
+					 */
+#define RX_ADDR_MATCH		0x0300  /* R: reserved; must be reset to zero.
+					 * C: address match code mask.
+					 */ 
+#define RX_STATUS_MASK		0x00FF  /* Mask for receive status bits. */
+
+#define RX_INTERN_ADDR_MATCH    0x0100  /* C: internally address match. */
+#define RX_EXTERN_ADDR_MATCH    0x0200  /* C: externally matched via
+					 * XMATCH/XFAIL interface.
+					 */
+#define RX_INTEXT_ADDR_MATCH    0x0300  /* C: internally and externally
+					 * matched.
+					 */
+#define RX_READY (RX_VALID | RX_FRAME_IRQ) /* Ready for receive. */
+
+/* Constants for Command Status Interrupt.
+ * COMMAND_REJECT status field bit functions (SSB.Parm[0])
+ */
+#define ILLEGAL_COMMAND		0x0080	/* Set if an unknown command
+					 * is issued to the adapter
+					 */
+#define ADDRESS_ERROR		0x0040  /* Set if any address field in
+					 * the SCB is odd. (not word aligned)
+					 */
+#define ADAPTER_OPEN		0x0020  /* Command issued illegal with
+					 * open adapter.
+					 */
+#define ADAPTER_CLOSE		0x0010  /* Command issued illegal with
+					 * closed adapter.
+					 */
+#define SAME_COMMAND		0x0008  /* Command issued with same command
+					 * already executing.
+					 */
+
+/* OPEN_COMPLETION values (SSB.Parm[0], MSB) */
+#define NODE_ADDR_ERROR		0x0040  /* Wrong address or BIA read
+					 * zero address.
+					 */
+#define LIST_SIZE_ERROR		0x0020  /* If List_Size value not in 0,
+					 * 14, 20, 26.
+					 */
+#define BUF_SIZE_ERROR		0x0010  /* Not enough available memory for
+					 * two buffers.
+					 */
+#define TX_BUF_COUNT_ERROR	0x0004  /* Remaining receive buffers less than
+					 * two.
+					 */
+#define OPEN_ERROR		0x0002	/* Error during ring insertion; more
+					 * information in bits 8-15.
+					 */
+
+/* Standard return codes */
+#define GOOD_COMPLETION		0x0080  /* =OPEN_SUCCESSFULL */
+#define INVALID_OPEN_OPTION	0x0001  /* OPEN options are not supported by
+					 * the adapter.
+					 */
+
+/* OPEN phases; details of OPEN_ERROR (SSB.Parm[0], LSB)            */
+#define OPEN_PHASES_MASK            0xF000  /* Check only the bits 8-11. */
+#define LOBE_MEDIA_TEST             0x1000
+#define PHYSICAL_INSERTION          0x2000
+#define ADDRESS_VERIFICATION        0x3000
+#define PARTICIPATION_IN_RING_POLL  0x4000
+#define REQUEST_INITIALISATION      0x5000
+#define FULLDUPLEX_CHECK            0x6000
+
+/* OPEN error codes; details of OPEN_ERROR (SSB.Parm[0], LSB) */
+#define OPEN_ERROR_CODES_MASK	0x0F00  /* Check only the bits 12-15. */
+#define OPEN_FUNCTION_FAILURE   0x0100  /* Unable to transmit to itself or
+					 * frames received before insertion.
+					 */
+#define OPEN_SIGNAL_LOSS	0x0200	/* Signal loss condition detected at
+					 * receiver.
+					 */
+#define OPEN_TIMEOUT		0x0500	/* Insertion timer expired before
+					 * logical insertion.
+					 */
+#define OPEN_RING_FAILURE	0x0600	/* Unable to receive own ring purge
+					 * MAC frames.
+					 */
+#define OPEN_RING_BEACONING	0x0700	/* Beacon MAC frame received after
+					 * ring insertion.
+					 */
+#define OPEN_DUPLICATE_NODEADDR	0x0800  /* Other station in ring found
+					 * with the same address.
+					 */
+#define OPEN_REQUEST_INIT	0x0900	/* RPS present but does not respond. */
+#define OPEN_REMOVE_RECEIVED    0x0A00  /* Adapter received a remove adapter
+					 * MAC frame.
+					 */
+#define OPEN_FULLDUPLEX_SET	0x0D00	/* Got this with full duplex on when
+					 * trying to connect to a normal ring.
+					 */
+
+/* SET_BRIDGE_PARMS return codes: */
+#define BRIDGE_INVALID_MAX_LEN  0x4000  /* MAX_ROUTING_FIELD_LENGTH odd,
+					 * less than 6 or > 30.
+					 */
+#define BRIDGE_INVALID_SRC_RING 0x2000  /* SOURCE_RING number zero, too large
+					 * or = TARGET_RING.
+					 */
+#define BRIDGE_INVALID_TRG_RING 0x1000  /* TARGET_RING number zero, too large
+					 * or = SOURCE_RING.
+					 */
+#define BRIDGE_INVALID_BRDGE_NO 0x0800  /* BRIDGE_NUMBER too large. */
+#define BRIDGE_INVALID_OPTIONS  0x0400  /* Invalid bridge options. */
+#define BRIDGE_DIAGS_FAILED     0x0200  /* Diagnostics of TMS380SRA failed. */
+#define BRIDGE_NO_SRA           0x0100  /* The TMS380SRA does not exist in HW
+					 * configuration.
+					 */
+
+/*
+ * Bring Up Diagnostics error codes.
+ */
+#define BUD_INITIAL_ERROR       0x0
+#define BUD_CHECKSUM_ERROR      0x1
+#define BUD_ADAPTER_RAM_ERROR   0x2
+#define BUD_INSTRUCTION_ERROR   0x3
+#define BUD_CONTEXT_ERROR       0x4
+#define BUD_PROTOCOL_ERROR      0x5
+#define BUD_INTERFACE_ERROR	0x6
+
+/* BUD constants */
+#define BUD_MAX_RETRIES         3
+#define BUD_MAX_LOOPCNT         6
+#define BUD_TIMEOUT             3000
+
+/* Initialization constants */
+#define INIT_MAX_RETRIES        3	/* Maximum three retries. */
+#define INIT_MAX_LOOPCNT        22      /* Maximum loop counts. */
+
+/* RING STATUS field values (high/low) */
+#define SIGNAL_LOSS             0x0080  /* Loss of signal on the ring
+					 * detected.
+					 */
+#define HARD_ERROR              0x0040  /* Transmitting or receiving beacon
+					 * frames.
+					 */
+#define SOFT_ERROR              0x0020  /* Report error MAC frame
+					 * transmitted.
+					 */
+#define TRANSMIT_BEACON         0x0010  /* Transmitting beacon frames on the
+					 * ring.
+					 */
+#define LOBE_WIRE_FAULT         0x0008  /* Open or short circuit in the
+					 * cable to concentrator; adapter
+					 * closed.
+					 */
+#define AUTO_REMOVAL_ERROR      0x0004  /* Lobe wrap test failed, deinserted;
+					 * adapter closed.
+					 */
+#define REMOVE_RECEIVED         0x0001  /* Received a remove ring station MAC
+					 * MAC frame request; adapter closed.
+					 */
+#define COUNTER_OVERFLOW        0x8000  /* Overflow of one of the adapters
+					 * error counters; READ.ERROR.LOG.
+					 */
+#define SINGLE_STATION          0x4000  /* Adapter is the only station on the
+					 * ring.
+					 */
+#define RING_RECOVERY           0x2000  /* Claim token MAC frames on the ring;
+					 * reset after ring purge frame.
+					 */
+
+#define ADAPTER_CLOSED (LOBE_WIRE_FAULT | AUTO_REMOVAL_ERROR |\
+                        REMOVE_RECEIVED)
+
+/* Adapter_check_block.Status field bit assignments: */
+#define DIO_PARITY              0x8000  /* Adapter detects bad parity
+					 * through direct I/O access.
+					 */
+#define DMA_READ_ABORT          0x4000  /* Aborting DMA read operation
+					 * from system Parm[0]: 0=timeout,
+					 * 1=parity error, 2=bus error;
+					 * Parm[1]: 32 bit pointer to host
+					 * system address at failure.
+					 */
+#define DMA_WRITE_ABORT         0x2000  /* Aborting DMA write operation
+					 * to system. (parameters analogous to
+					 * DMA_READ_ABORT)
+					 */
+#define ILLEGAL_OP_CODE         0x1000  /* Illegal operation code in the
+					 * the adapters firmware Parm[0]-2:
+					 * communications processor registers
+					 * R13-R15.
+					 */
+#define PARITY_ERRORS           0x0800  /* Adapter detects internal bus
+					 * parity error.
+					 */
+#define RAM_DATA_ERROR          0x0080  /* Valid only during RAM testing;
+					 * RAM data error Parm[0-1]: 32 bit
+					 * pointer to RAM location.
+					 */
+#define RAM_PARITY_ERROR        0x0040  /* Valid only during RAM testing;
+					 * RAM parity error Parm[0-1]: 32 bit
+					 * pointer to RAM location.
+					 */
+#define RING_UNDERRUN           0x0020  /* Internal DMA underrun when
+					 * transmitting onto ring.
+					 */
+#define INVALID_IRQ             0x0008  /* Unrecognized interrupt generated
+					 * internal to adapter Parm[0-2]:
+					 * adapter register R13-R15.
+					 */
+#define INVALID_ERROR_IRQ       0x0004  /* Unrecognized error interrupt
+					 * generated Parm[0-2]: adapter register
+					 * R13-R15.
+					 */
+#define INVALID_XOP             0x0002  /* Unrecognized XOP request in
+					 * communication processor Parm[0-2]:
+					 * adapter register R13-R15.
+					 */
+#define CHECKADDR               0x05E0  /* Adapter check status information
+					 * address offset.
+					 */
+#define ROM_PAGE_0              0x0000  /* Adapter ROM page 0. */
+
+/*
+ * RECEIVE.STATUS interrupt result SSB values: (high-low)
+ * (RECEIVE_COMPLETE field bit definitions in SSB.Parm[0])
+ */
+#define RX_COMPLETE             0x0080  /* SSB.Parm[0]; SSB.Parm[1]: 32
+					 * bit pointer to last RPL.
+					 */
+#define RX_SUSPENDED            0x0040  /* SSB.Parm[0]; SSB.Parm[1]: 32
+					 * bit pointer to RPL with odd
+					 * forward pointer.
+					 */
+
+/* Valid receive CSTAT: */
+#define RX_FRAME_CONTROL_BITS (RX_VALID | RX_START_FRAME | RX_END_FRAME | \
+			       RX_FRAME_COMPLETE)
+#define VALID_SINGLE_BUFFER_FRAME (RX_START_FRAME | RX_END_FRAME | \
+				   RX_FRAME_COMPLETE)
+
+typedef enum SKB_STAT SKB_STAT;
+enum SKB_STAT {
+	SKB_UNAVAILABLE,
+	SKB_DMA_DIRECT,
+	SKB_DATA_COPY
+};
+
+/* Receive Parameter List (RPL) The length of the RPLs has to be initialized 
+ * in the OPL. (OPEN parameter list)
+ */
+#define RPL_NUM		3
+
+#define RX_FRAG_NUM     1	/* Maximal number of used fragments in one RPL.
+				 * (up to firmware v2.24: 3, now: up to 9)
+				 */
+
+#pragma pack(1)
+typedef struct s_RPL RPL;
+struct s_RPL {	/* Receive Parameter List */
+	unsigned long NextRPLAddr;	/* Pointer to next RPL in chain
+					 * (normalized = physical 32 bit
+					 * address) if pointer is odd: this
+					 * is last RPL. Pointing to itself can
+					 * cause problems!
+					 */
+	volatile unsigned short Status;	/* Set by creation of Receive Parameter
+					 * List RECEIVE_CSTAT_COMPLETE set by
+					 * adapter in lists that start or end
+					 * a frame.
+					 */
+	volatile unsigned short FrameSize; /* Number of bytes received as a
+					 * frame including AC/FC, Destination,
+					 * Source, Routing field not including 
+					 * CRC, FS (Frame Status), End Delimiter
+					 * (valid only if START_FRAME bit in 
+					 * CSTAT nonzero) must not be zero in
+					 * any list; maximum value: (BUFFER_SIZE
+					 * - 8) * TX_BUF_MAX sum of DataCount
+					 * values in FragmentList must equal
+					 * Frame_Size value in START_FRAME TPL!
+					 * frame data fragment list
+					 */
+
+	/* TPL/RPL size in OPEN parameter list depending on maximal numbers
+	 * of fragments used in one parameter list.
+	 */
+	Fragment FragList[RX_FRAG_NUM];	/* Maximum: nine frame fragments in
+					 * one TPL. Actual version of firmware:
+					 * 9 fragments possible.
+					 */
+#pragma pack()
+
+	/* Special proprietary data and precalculations. */
+	RPL *NextRPLPtr;	/* Logical pointer to next RPL in chain. */
+	unsigned char *MData;
+	struct sk_buff *Skb;
+	SKB_STAT SkbStat;
+	int RPLIndex;
+};
+
+/* Information that need to be kept for each board. */
+typedef struct net_local {
+#pragma pack(1)
+	IPB ipb;	/* Initialization Parameter Block. */
+	SCB scb;	/* System Command Block: system to adapter 
+			 * communication.
+			 */
+	SSB ssb;	/* System Status Block: adapter to system 
+			 * communication.
+			 */
+	OPB ocpl;	/* Open Options Parameter Block. */
+
+	ERRORTAB errorlogtable;	/* Adapter statistic error counters.
+				 * (read from adapter memory)
+				 */
+	unsigned char ProductID[PROD_ID_SIZE + 1]; /* Product ID */
+#pragma pack()
+
+	TPL Tpl[TPL_NUM];
+	TPL *TplFree;
+	TPL *TplBusy;
+	unsigned char LocalTxBuffers[TPL_NUM][DEFAULT_PACKET_SIZE];
+
+	RPL Rpl[RPL_NUM];
+	RPL *RplHead;
+	RPL *RplTail;
+	unsigned char LocalRxBuffers[RPL_NUM][DEFAULT_PACKET_SIZE];
+
+	int DataRate;
+	unsigned char ScbInUse;
+	unsigned short CMDqueue;
+
+	unsigned int DeviceType;
+
+	unsigned long AdapterOpenFlag:1;
+	unsigned long AdapterVirtOpenFlag:1;
+	unsigned long OpenCommandIssued:1;
+	unsigned long TransmitCommandActive:1;
+	unsigned long TransmitHaltScheduled:1;
+	unsigned long HaltInProgress:1;
+	unsigned long LobeWireFaultLogged:1;
+	unsigned long ReOpenInProgress:1;
+	unsigned long Sleeping:1;
+
+	unsigned long LastOpenStatus;
+	unsigned short CurrentRingStatus;
+	unsigned long MaxPacketSize;
+	
+	unsigned long StartTime;
+	unsigned long LastSendTime;
+
+	struct sk_buff_head SendSkbQueue;
+	unsigned short QueueSkb;
+
+	struct tr_statistics MacStat;	/* MAC statistics structure */
+
+	struct timer_list timer;
+
+	wait_queue_head_t  wait_for_tok_int;
+
+	INTPTRS intptrs;	/* Internal adapter pointer. Must be read
+				 * before OPEN command.
+				 */
+} NET_LOCAL;
+
+#endif	/* __KERNEL__ */
+#endif	/* __LINUX_SKTR_H */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/tokenring/sktr_firmware.h linux/drivers/net/tokenring/sktr_firmware.h
--- v2.3.20/linux/drivers/net/tokenring/sktr_firmware.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/tokenring/sktr_firmware.h	Mon Oct 11 10:13:24 1999
@@ -0,0 +1,3616 @@
+/*
+ * The firmware this driver downloads into the tokenring card is a
+ * separate program and is not GPL'd source code, even though the Linux
+ * side driver and the routine that loads this data into the card are.
+ *
+ * This firmware is licensed to you strictly for use in conjunction
+ * with the use of SysKonnect TokenRing adapters. There is no
+ * waranty expressed or implied about its fitness for any purpose.
+ */
+
+/* sktr_firmware.h: SysKonnect TokenRing driver firmware dump for Linux.
+ *
+ * Notes:
+ *  - Loaded from sktr_reset_adapter upon adapter reset.
+ *
+ * Authors:
+ * - Christoph Goos <cgoos@syskonnect.de>
+ */
+
+#include <linux/config.h>
+
+#if defined(CONFIG_SKTR) || defined(CONFIG_SKTR_MODULE)
+
+unsigned char sktr_code[] = {
+	0x00, 0x00, 0x00, 0xA0, 0x00, 0x20, 0x68, 0x54,
+	0x73, 0x69, 0x63, 0x20, 0x64, 0x6F, 0x20, 0x65,
+	0x73, 0x69, 0x72, 0x20, 0x6C, 0x65, 0x61, 0x65,
+	0x65, 0x73, 0x20, 0x64, 0x6E, 0x75, 0x65, 0x64,
+	0x20, 0x72, 0x69, 0x6C, 0x65, 0x63, 0x63, 0x6E,
+	0x20, 0x65, 0x6E, 0x4F, 0x79, 0x6C, 0x20, 0x2C,
+	0x6C, 0x41, 0x20, 0x6C, 0x69, 0x72, 0x68, 0x67,
+	0x73, 0x74, 0x72, 0x20, 0x73, 0x65, 0x72, 0x65,
+	0x65, 0x76, 0x2E, 0x64, 0x60, 0x01, 0x42, 0x01,
+	0x00, 0x08, 0x08, 0x16, 0xB0, 0x03, 0xE0, 0x04,
+	0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0xFF, 0xFF,
+	0xFC, 0x13, 0x80, 0x03, 0xA0, 0x07, 0x42, 0x01,
+	0x00, 0x08, 0x20, 0x07, 0x00, 0x00, 0xE0, 0x04,
+	0x00, 0x01, 0x8B, 0x07, 0x00, 0x3D, 0x60, 0x01,
+	0x42, 0x01, 0x80, 0x00, 0x09, 0x13, 0x8B, 0x07,
+	0x00, 0x2D, 0x20, 0xC0, 0x4E, 0x01, 0x80, 0x02,
+	0x41, 0x0F, 0x02, 0x11, 0x8B, 0x07, 0x00, 0x3D,
+	0x0B, 0xC8, 0x4A, 0x01, 0x00, 0x02, 0x00, 0x90,
+	0xA0, 0x09, 0x00, 0xC8, 0x66, 0x01, 0xE0, 0x02,
+	0xA0, 0x00, 0xA0, 0x07, 0x04, 0x01, 0x20, 0x00,
+	0xA0, 0x01, 0x40, 0x01, 0x00, 0xFE, 0x20, 0x48,
+	0x2A, 0xE0, 0x42, 0x01, 0xE0, 0x04, 0x02, 0x01,
+	0xE0, 0x04, 0x60, 0x09, 0xE0, 0x04, 0x82, 0x01,
+	0x60, 0x01, 0x1C, 0x01, 0x04, 0x00, 0x03, 0x16,
+	0xE0, 0x01, 0x40, 0x01, 0x00, 0x0C, 0xA0, 0x06,
+	0xBC, 0xA1, 0xA0, 0x07, 0x04, 0x01, 0x2D, 0x00,
+	0x20, 0xC2, 0x00, 0xE0, 0x88, 0x02, 0x11, 0xE3,
+	0x14, 0x16, 0xA0, 0x07, 0x04, 0x01, 0x2E, 0x00,
+	0x60, 0x01, 0x42, 0x01, 0x00, 0x03, 0x0D, 0x16,
+	0xA0, 0x07, 0x04, 0x01, 0x21, 0x00, 0x88, 0x07,
+	0x00, 0xA0, 0x89, 0x07, 0xFE, 0xFF, 0xA8, 0x09,
+	0xA9, 0x09, 0x8A, 0x07, 0x02, 0xE0, 0xA0, 0x06,
+	0x84, 0xEC, 0x56, 0x10, 0x88, 0x07, 0x00, 0x90,
+	0x89, 0x07, 0xFE, 0x9F, 0xA8, 0x09, 0xA9, 0x09,
+	0x8A, 0x07, 0x78, 0xE0, 0xA0, 0x06, 0x84, 0xEC,
+	0x4B, 0x10, 0xA0, 0x05, 0x04, 0x01, 0x88, 0x07,
+	0x08, 0x00, 0x89, 0x07, 0x7A, 0x00, 0x00, 0x03,
+	0x01, 0x00, 0xA0, 0x06, 0xD2, 0xAC, 0x40, 0x10,
+	0xA0, 0x06, 0xBC, 0xA1, 0xE0, 0x02, 0xF4, 0x03,
+	0x88, 0x07, 0xA0, 0x00, 0x89, 0x07, 0xFE, 0x00,
+	0xA0, 0x06, 0xD2, 0xAC, 0x35, 0x10, 0xE0, 0x02,
+	0xA0, 0x00, 0xE0, 0x04, 0x7E, 0x01, 0xC8, 0x04,
+	0x09, 0x02, 0xF2, 0x03, 0x48, 0x62, 0xE0, 0xC1,
+	0x40, 0x01, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x04,
+	0x18, 0xCE, 0x09, 0x06, 0xFD, 0x16, 0xA0, 0x01,
+	0x40, 0x01, 0x00, 0x40, 0x07, 0xC8, 0x40, 0x01,
+	0x88, 0x07, 0xF4, 0x03, 0x89, 0x07, 0xFE, 0x3F,
+	0xA0, 0x06, 0xD2, 0xAC, 0x19, 0x10, 0xE0, 0x02,
+	0xA0, 0x00, 0xA0, 0x06, 0xFA, 0xAD, 0x14, 0x10,
+	0x08, 0xC8, 0x44, 0x04, 0x09, 0xC8, 0x46, 0x04,
+	0xA0, 0x06, 0x28, 0xAD, 0x0D, 0x10, 0x81, 0x07,
+	0x7C, 0xE0, 0xB1, 0xC0, 0x26, 0x13, 0x01, 0xC8,
+	0xE0, 0x00, 0xA0, 0x05, 0x04, 0x01, 0x92, 0x06,
+	0x03, 0x10, 0x60, 0xC0, 0xE0, 0x00, 0xF5, 0x10,
+	0xE0, 0x01, 0x04, 0x01, 0x10, 0x00, 0xB0, 0x03,
+	0xFF, 0x10, 0xA0, 0x01, 0x04, 0x01, 0x00, 0x80,
+	0x80, 0x03, 0x80, 0x07, 0xA0, 0x00, 0xC2, 0x04,
+	0x80, 0xCC, 0x81, 0x07, 0xAA, 0xA1, 0x82, 0x02,
+	0x1E, 0x00, 0x02, 0x16, 0x81, 0x07, 0xB4, 0xA1,
+	0x81, 0xC4, 0x81, 0x8C, 0xE9, 0x16, 0x82, 0x02,
+	0x7C, 0x00, 0xF2, 0x16, 0x00, 0x03, 0x0F, 0x00,
+	0x5B, 0x04, 0x81, 0x07, 0x08, 0xE1, 0x82, 0x07,
+	0x04, 0x00, 0xE0, 0x04, 0x80, 0x01, 0xE0, 0x04,
+	0x82, 0x01, 0x91, 0xC4, 0xB1, 0x8C, 0xD8, 0x16,
+	0x82, 0x02, 0x7C, 0x00, 0xFA, 0x16, 0x20, 0xC8,
+	0x04, 0xE0, 0x82, 0x01, 0x20, 0xE8, 0x0C, 0xE0,
+	0x82, 0x01, 0x20, 0xC8, 0x10, 0xE0, 0x80, 0x01,
+	0x81, 0x07, 0x86, 0xE0, 0xB1, 0xC0, 0x07, 0x13,
+	0xB1, 0xC4, 0xFC, 0x10, 0xA0, 0x07, 0x04, 0x01,
+	0x2E, 0x00, 0x60, 0x04, 0xAA, 0xA1, 0x81, 0x07,
+	0x34, 0xE0, 0x82, 0x07, 0xFC, 0x05, 0x83, 0x07,
+	0x0A, 0x00, 0xB1, 0xCC, 0x43, 0x06, 0xFD, 0x16,
+	0x02, 0x02, 0x00, 0x06, 0x60, 0xD0, 0x4E, 0x01,
+	0xED, 0x13, 0x21, 0x02, 0x00, 0xF7, 0x21, 0x02,
+	0x00, 0xC0, 0x81, 0xDC, 0x60, 0xD0, 0x4F, 0x01,
+	0xC1, 0xC0, 0x41, 0x09, 0x21, 0x02, 0x00, 0xF0,
+	0x81, 0xDC, 0x43, 0x02, 0x00, 0x0F, 0x23, 0x02,
+	0x00, 0xF0, 0x83, 0xDC, 0x01, 0x02, 0x32, 0x0C,
+	0xA0, 0xC0, 0x44, 0x04, 0xE0, 0xC0, 0x46, 0x04,
+	0x03, 0xC1, 0x02, 0x61, 0x84, 0x05, 0x04, 0xC8,
+	0x48, 0x04, 0x03, 0xC1, 0x84, 0x05, 0x04, 0xA1,
+	0x01, 0xA1, 0x04, 0xC8, 0x30, 0x0C, 0x03, 0xC1,
+	0x84, 0x05, 0xF1, 0x04, 0x04, 0x06, 0xFD, 0x16,
+	0x08, 0x02, 0x00, 0xA0, 0xA8, 0x09, 0x60, 0xC2,
+	0x30, 0x0C, 0x29, 0x02, 0xFF, 0x03, 0xA9, 0x09,
+	0x29, 0x02, 0x40, 0x00, 0x80, 0x07, 0x00, 0x90,
+	0xA0, 0x09, 0x8A, 0x07, 0xFE, 0x9F, 0x2A, 0x02,
+	0xFF, 0x03, 0xAA, 0x09, 0x01, 0x02, 0x32, 0x0C,
+	0x05, 0x02, 0x00, 0x00, 0x03, 0xC1, 0x84, 0x05,
+	0x11, 0x07, 0xC1, 0x05, 0x85, 0x05, 0x04, 0x06,
+	0x0B, 0x13, 0x85, 0x80, 0xF9, 0x1A, 0x05, 0x80,
+	0xF8, 0x1A, 0x85, 0x82, 0xF5, 0x1A, 0x05, 0x82,
+	0xF4, 0x1A, 0x45, 0x82, 0xF1, 0x1A, 0xF1, 0x10,
+	0x20, 0x2D, 0x02, 0x00, 0x60, 0x01, 0x40, 0x01,
+	0x00, 0x40, 0x06, 0x16, 0x8A, 0x07, 0x00, 0x08,
+	0xA0, 0x01, 0x40, 0x01, 0x00, 0x40, 0x48, 0x10,
+	0x60, 0x01, 0x42, 0x01, 0x00, 0x80, 0x06, 0x16,
+	0x8A, 0x07, 0x00, 0x10, 0xA0, 0x01, 0x42, 0x01,
+	0x00, 0x80, 0x3E, 0x10, 0x60, 0x01, 0x02, 0x01,
+	0x00, 0x10, 0x0A, 0x16, 0x60, 0x01, 0x00, 0x01,
+	0x00, 0x04, 0x06, 0x16, 0x8A, 0x07, 0x00, 0x80,
+	0xA0, 0x01, 0x02, 0x01, 0x00, 0x10, 0x30, 0x10,
+	0x60, 0x01, 0x02, 0x01, 0x00, 0x08, 0x0A, 0x16,
+	0x60, 0x01, 0x00, 0x01, 0x00, 0x04, 0x06, 0x16,
+	0xA0, 0x01, 0x02, 0x01, 0x00, 0x08, 0x0D, 0x02,
+	0x01, 0x00, 0x0D, 0x10, 0x60, 0x01, 0x02, 0x01,
+	0x00, 0x04, 0x16, 0x16, 0x60, 0x01, 0x00, 0x01,
+	0x00, 0x08, 0x12, 0x16, 0xA0, 0x01, 0x02, 0x01,
+	0x00, 0x04, 0x0D, 0x02, 0x02, 0x00, 0xA0, 0xC3,
+	0x0E, 0x01, 0xE0, 0xC3, 0x10, 0x01, 0x8A, 0x07,
+	0x00, 0x20, 0x60, 0x01, 0x00, 0x01, 0x00, 0x80,
+	0x0B, 0x13, 0x8A, 0x07, 0x00, 0x40, 0x08, 0x10,
+	0x8A, 0x07, 0x04, 0x00, 0x05, 0x10, 0x8A, 0x07,
+	0x02, 0x00, 0x02, 0x10, 0x8A, 0x07, 0x08, 0x00,
+	0x00, 0x03, 0x00, 0x00, 0xE0, 0x04, 0x82, 0x01,
+	0x8B, 0x07, 0xE0, 0x05, 0xCA, 0xCE, 0xCD, 0xCE,
+	0xCE, 0xCE, 0xCF, 0xC6, 0x20, 0xC3, 0x58, 0x07,
+	0x20, 0x23, 0x04, 0xE0, 0x12, 0x13, 0x8B, 0x07,
+	0x18, 0xFF, 0x8A, 0x02, 0x00, 0x80, 0x0A, 0x13,
+	0x8B, 0x05, 0xCD, 0xA2, 0x8A, 0x02, 0x00, 0x40,
+	0x05, 0x13, 0x8A, 0x02, 0x00, 0x20, 0x02, 0x13,
+	0x8B, 0x07, 0x1D, 0xFF, 0x0B, 0xC8, 0x04, 0x01,
+	0x0D, 0x10, 0x20, 0xD3, 0x05, 0x01, 0xFD, 0x11,
+	0x20, 0xD8, 0xDF, 0x07, 0x17, 0x01, 0x8B, 0x07,
+	0x80, 0xFF, 0x0B, 0xC8, 0x04, 0x01, 0x20, 0xE8,
+	0x0A, 0xE0, 0x00, 0x01, 0xE0, 0xC2, 0x04, 0x01,
+	0xE0, 0x22, 0x86, 0xE1, 0xFB, 0x16, 0xE0, 0x02,
+	0xA0, 0x00, 0xE0, 0x04, 0x82, 0x01, 0x20, 0xE8,
+	0x0A, 0xE0, 0x00, 0x01, 0xE0, 0xC2, 0x00, 0x01,
+	0xE0, 0x22, 0x06, 0xE0, 0xF8, 0x13, 0xA0, 0x01,
+	0x40, 0x01, 0x00, 0xF6, 0x60, 0x04, 0x90, 0xA0,
+	0x00, 0x03, 0x02, 0x00, 0xA0, 0x07, 0x02, 0x01,
+	0xFF, 0xDF, 0x90, 0x03, 0xFF, 0xFF, 0x80, 0x03,
+	0x00, 0x03, 0x02, 0x00, 0x09, 0x07, 0xA0, 0xC2,
+	0x04, 0x01, 0x8A, 0x01, 0x80, 0x00, 0x4A, 0x52,
+	0x89, 0xD2, 0x0A, 0xC8, 0x04, 0x01, 0xA0, 0xD2,
+	0x04, 0x01, 0xF9, 0x16, 0x49, 0x05, 0x89, 0x01,
+	0x00, 0x80, 0x49, 0x01, 0x00, 0x40, 0x0E, 0x13,
+	0x09, 0xF8, 0x3A, 0x07, 0x60, 0xC2, 0x36, 0x07,
+	0x03, 0x16, 0x90, 0x03, 0xFF, 0xFF, 0x80, 0x03,
+	0xE0, 0x04, 0x36, 0x07, 0x54, 0x04, 0x90, 0x03,
+	0xFF, 0xFF, 0x80, 0x03, 0x60, 0x22, 0x86, 0xE1,
+	0xC2, 0x13, 0xE0, 0x04, 0x82, 0x01, 0x60, 0x04,
+	0xE0, 0xA3, 0x00, 0x03, 0x02, 0x00, 0xA0, 0x07,
+	0x62, 0x09, 0xE8, 0x03, 0xC9, 0x04, 0xA0, 0xC1,
+	0x34, 0x06, 0x04, 0x16, 0xA0, 0x06, 0x50, 0xB5,
+	0xE0, 0x04, 0x20, 0x09, 0x86, 0x07, 0xE8, 0x05,
+	0xA0, 0x01, 0x40, 0x01, 0x00, 0x80, 0x20, 0xC2,
+	0x84, 0x01, 0x20, 0x48, 0x08, 0xE0, 0x84, 0x01,
+	0x20, 0x22, 0x08, 0xE0, 0x08, 0x13, 0x60, 0x01,
+	0xAE, 0x01, 0x01, 0x00, 0x04, 0x16, 0xE0, 0x01,
+	0x34, 0x06, 0x00, 0x80, 0x06, 0x10, 0x20, 0xC2,
+	0x32, 0x09, 0x06, 0x13, 0xE0, 0x01, 0x34, 0x06,
+	0x00, 0x08, 0xE0, 0x04, 0x30, 0x06, 0x09, 0x07,
+	0xA0, 0x05, 0xEE, 0x05, 0x20, 0x06, 0xEC, 0x05,
+	0x02, 0x16, 0x16, 0xC2, 0x03, 0x16, 0x49, 0xC2,
+	0x12, 0x16, 0x80, 0x03, 0x98, 0xC5, 0xE8, 0xC1,
+	0x02, 0x00, 0xE0, 0xE9, 0x14, 0xE0, 0x04, 0x00,
+	0xD7, 0x04, 0x27, 0x02, 0x08, 0x00, 0xA0, 0x06,
+	0xE6, 0xB4, 0x16, 0xC2, 0x04, 0x13, 0x28, 0xC8,
+	0x08, 0x00, 0xEC, 0x05, 0xEF, 0x13, 0x54, 0x04,
+	0x00, 0x03, 0x02, 0x00, 0xE0, 0xC1, 0x86, 0x01,
+	0x47, 0x02, 0x0E, 0x00, 0xA7, 0xC2, 0x90, 0xE1,
+	0x5A, 0x04, 0x8A, 0x07, 0x00, 0xA0, 0x0A, 0xC8,
+	0x86, 0x01, 0xC7, 0xA1, 0x27, 0x02, 0x98, 0xE1,
+	0x37, 0xE8, 0x34, 0x06, 0x17, 0xE8, 0xD2, 0x06,
+	0xE0, 0x04, 0x30, 0x06, 0x60, 0x04, 0xF2, 0xA9,
+	0x0A, 0xE8, 0xD2, 0x06, 0xE0, 0x01, 0x34, 0x06,
+	0x00, 0x08, 0xE0, 0x04, 0x30, 0x06, 0x20, 0xE0,
+	0x18, 0xE0, 0x5B, 0x04, 0xA0, 0x05, 0x20, 0x09,
+	0x20, 0x88, 0x20, 0x09, 0x16, 0xE0, 0xE5, 0x1A,
+	0xE0, 0x04, 0x20, 0x09, 0xA0, 0x06, 0xD0, 0xD5,
+	0x80, 0x03, 0xA0, 0x05, 0x32, 0x09, 0x80, 0x03,
+	0x01, 0xC3, 0xFB, 0x13, 0x60, 0x01, 0x6A, 0x09,
+	0x01, 0x00, 0x78, 0x13, 0xA0, 0x05, 0x32, 0x09,
+	0x75, 0x10, 0x41, 0xC0, 0x06, 0x13, 0x01, 0xC8,
+	0x6C, 0x01, 0xE0, 0xC2, 0x02, 0xFC, 0x01, 0x11,
+	0x7B, 0x10, 0x60, 0x01, 0x9C, 0x01, 0x40, 0x00,
+	0x79, 0x16, 0x20, 0xD8, 0x2F, 0x09, 0x83, 0x01,
+	0x41, 0xC0, 0x04, 0x13, 0x01, 0xC8, 0x8A, 0x01,
+	0x01, 0xC8, 0x18, 0x09, 0x86, 0x07, 0x43, 0x00,
+	0x06, 0xC8, 0x6C, 0x01, 0x07, 0x02, 0x02, 0xFC,    
+	0x17, 0xC2, 0x60, 0x04, 0xFA, 0xA6, 0xE0, 0x04, 
+	0x18, 0x09, 0xC7, 0x61, 0x08, 0x07, 0x60, 0x01, 
+	0x06, 0xFC, 0x40, 0x00, 0x02, 0x13, 0x08, 0x02, 
+	0x01, 0x00, 0x09, 0x10, 0x4C, 0xC2, 0x20, 0xC3, 
+	0x00, 0xFC, 0x2A, 0x13, 0x0C, 0xC8, 0x6C, 0x01, 
+	0xE0, 0xC2, 0x02, 0xFC, 0x1B, 0x11, 0x4B, 0x01, 
+	0x00, 0x01, 0xF4, 0x16, 0xC8, 0x22, 0x12, 0x13, 
+	0xCB, 0x01, 0x00, 0x40, 0x0B, 0xC8, 0x02, 0xFC, 
+	0x0D, 0x10, 0xE0, 0xC1, 0x18, 0x09, 0x01, 0xC3, 
+	0x21, 0x13, 0x4C, 0xC2, 0x15, 0x13, 0x0C, 0xC8, 
+	0x6C, 0x01, 0xE0, 0xC2, 0x02, 0xFC, 0x06, 0x11, 
+	0xCC, 0x81, 0xD5, 0x13, 0x4C, 0xC2, 0x20, 0xC3, 
+	0x00, 0xFC, 0xF4, 0x10, 0x09, 0xC8, 0x6C, 0x01, 
+	0xE0, 0xC2, 0x02, 0xFC, 0x1E, 0x16, 0xA0, 0x07, 
+	0x02, 0xFC, 0x00, 0x80, 0x09, 0xC3, 0x19, 0x10, 
+	0x09, 0xC8, 0x6C, 0x01, 0xE0, 0xC2, 0x02, 0xFC, 
+	0x05, 0x16, 0xA0, 0x07, 0x02, 0xFC, 0x00, 0x80, 
+	0x09, 0xC3, 0x0F, 0x10, 0xE0, 0xC2, 0x02, 0x0C, 
+	0x01, 0x11, 0x1E, 0x10, 0x20, 0xD8, 0x00, 0xE2, 
+	0x83, 0x01, 0x8B, 0x09, 0x8B, 0x09, 0x8B, 0x09,  
+	0x8B, 0x09, 0xA0, 0x07, 0x8A, 0x01, 0x43, 0x00,  
+	0x13, 0x10, 0x0C, 0xC8, 0x8A, 0x01, 0x0C, 0xC8,  
+	0x18, 0x09, 0x0E, 0x10, 0x00, 0x03, 0x02, 0x00, 
+	0xE0, 0xC0, 0x6C, 0x01, 0x20, 0xC3, 0x8A, 0x01,  
+	0x20, 0x98, 0x83, 0x01, 0x00, 0xE2, 0x81, 0x13,  
+	0x60, 0x01, 0x9C, 0x01, 0x40, 0x00, 0xB9, 0x13, 
+	0x01, 0x83, 0x31, 0x16, 0x03, 0xC8, 0x6C, 0x01, 
+	0x40, 0x01, 0x10, 0x00, 0x14, 0x16, 0xE0, 0xC2, 
+	0x2E, 0x06, 0x11, 0x13, 0xE0, 0xC2, 0xF8, 0x05, 
+	0x0E, 0x13, 0xE0, 0x01, 0x3A, 0x07, 0x00, 0x80, 
+	0x80, 0x01, 0x10, 0x00, 0xE0, 0xC2, 0x36, 0x07, 
+	0x06, 0x13, 0xE0, 0x04, 0x36, 0x07, 0x80, 0x01, 
+	0x20, 0x00, 0x60, 0x04, 0xF2, 0xA9, 0x40, 0x01, 
+	0x20, 0x00, 0xF9, 0x13, 0x90, 0x03, 0xFF, 0x11, 
+	0x80, 0x03, 0x08, 0x01, 0x00, 0x04, 0x19, 0x16,  
+	0x60, 0x01, 0x6A, 0x09, 0x01, 0x00, 0x15, 0x16,  
+	0x88, 0x01, 0x00, 0x1A, 0xC8, 0x01, 0x00, 0x01, 
+	0xC8, 0xC5, 0x0F, 0x10, 0xE0, 0x04, 0x18, 0x09, 
+	0xC0, 0x01, 0x04, 0x00, 0x15, 0x10, 0x81, 0xC1, 
+	0x01, 0xC8, 0x6C, 0x01, 0x07, 0x02, 0x00, 0xFC, 
+	0x77, 0xC0, 0x17, 0xC2, 0x48, 0x01, 0x00, 0x18, 
+	0xE4, 0x13, 0x40, 0x01, 0x40, 0x00, 0x15, 0x16, 
+	0x80, 0x01, 0x45, 0x00, 0x46, 0xC1, 0x20, 0xD0, 
+	0x07, 0xFC, 0x60, 0x81, 0x18, 0x09, 0xE6, 0x13, 
+	0xE0, 0xC2, 0x08, 0xFC, 0x08, 0x11, 0xE0, 0xC2, 
+	0x0E, 0xFC, 0x07, 0x15, 0x06, 0x13, 0xE0, 0xC2, 
+	0x14, 0xFC, 0x03, 0x15, 0x02, 0x13, 0xC0, 0x01, 
+	0x01, 0x00, 0x48, 0x01, 0x00, 0x01, 0x11, 0x13, 
+	0x40, 0x01, 0x80, 0x40, 0x69, 0x13, 0x60, 0x04, 
+	0x66, 0xA6, 0x48, 0x01, 0x01, 0x00, 0x03, 0x16, 
+	0x40, 0x01, 0x00, 0x40, 0x0B, 0x16, 0xC8, 0x01, 
+	0x00, 0x40, 0xA0, 0x05, 0x32, 0x09, 0xC8, 0xC5, 
+	0x05, 0x10, 0xC0, 0x01, 0x40, 0x00, 0x40, 0x01, 
+	0x04, 0x00, 0xEF, 0x13, 0xB7, 0x01, 0x20, 0x00, 
+	0xD7, 0xC2, 0xC4, 0x62, 0x0B, 0x05, 0x2B, 0x02, 
+	0xFC, 0xFF, 0xCB, 0xC5, 0x02, 0x15, 0x46, 0x81, 
+	0x6A, 0x13, 0x08, 0x01, 0x00, 0x5E, 0x67, 0x16, 
+	0x08, 0x01, 0x88, 0x00, 0x13, 0x16, 0x86, 0x02, 
+	0x43, 0x00, 0x25, 0x16, 0x40, 0x01, 0x00, 0x40, 
+	0x0B, 0x13, 0x08, 0x01, 0x03, 0x00, 0x08, 0x13, 
+	0x84, 0xC2, 0x2A, 0x02, 0xD8, 0xFF, 0x06, 0xC8, 
+	0x6C, 0x01, 0x0A, 0x68, 0x04, 0xFC, 0x73, 0x10, 
+	0x60, 0x04, 0xD2, 0xA8, 0x40, 0x01, 0x01, 0x00, 
+	0xEA, 0x13, 0x08, 0x01, 0x02, 0x00, 0xE7, 0x16, 
+	0x48, 0x01, 0x01, 0x00, 0xE4, 0x16, 0x40, 0x01, 
+	0x00, 0x40, 0x04, 0x16, 0x60, 0x01, 0xA8, 0x09, 
+	0x80, 0x00, 0xDD, 0x13, 0x8A, 0x07, 0x80, 0x00, 
+	0xA0, 0x06, 0x32, 0xA5, 0xD8, 0x10, 0x00, 0xC0, 
+	0xE7, 0x11, 0x60, 0xC2, 0x6A, 0x09, 0x40, 0x01, 
+	0x00, 0x40, 0x0A, 0x13, 0x48, 0x01, 0x01, 0x00, 
+	0x34, 0x13, 0x48, 0x01, 0x02, 0x00, 0x0A, 0x13, 
+	0x49, 0x01, 0x04, 0x00, 0xD9, 0x16, 0x06, 0x10, 
+	0x49, 0x01, 0x02, 0x00, 0x03, 0x13, 0x08, 0x01, 
+	0x03, 0x00, 0x6E, 0x13, 0x49, 0x01, 0x01, 0x00, 
+	0x12, 0x13, 0x40, 0x01, 0x80, 0x40, 0x01, 0x16, 
+	0x46, 0xC1, 0xE0, 0x04, 0x00, 0xFC, 0x87, 0x07, 
+	0xF8, 0x05, 0x17, 0xC2, 0x14, 0x13, 0xC7, 0x05, 
+	0x17, 0xC8, 0x6C, 0x01, 0x05, 0xC8, 0x00, 0xFC,  
+	0xC6, 0xC5, 0x60, 0x04, 0x66, 0xA6, 0x07, 0x02, 
+	0x02, 0xFC, 0xE0, 0xA1, 0x2C, 0x09, 0xE0, 0xCD,  
+	0xEE, 0x05, 0xE0, 0xC5, 0x04, 0xFC, 0x20, 0xC8, 
+	0x2C, 0x09, 0x04, 0xFC, 0xE2, 0x10, 0xC5, 0xCD, 
+	0xC6, 0xC5, 0x60, 0x04, 0x66, 0xA6, 0x60, 0x04, 
+	0xB6, 0xA8, 0x06, 0xC8, 0x6C, 0x01, 0x85, 0x81, 
+	0x1A, 0x13, 0xE0, 0xC2, 0x04, 0xFC, 0x17, 0x15, 
+	0x86, 0xC2, 0x8A, 0xA2, 0xAA, 0xC1, 0x32, 0x0C, 
+	0x06, 0xC8, 0x6C, 0x01, 0x0B, 0xA8, 0x04, 0xFC, 
+	0x1A, 0x09, 0x0A, 0xC8, 0x6C, 0x01, 0xE0, 0xC2, 
+	0x02, 0xFC, 0xE0, 0x04, 0x00, 0xFC, 0x06, 0xC8, 
+	0x6C, 0x01, 0x0B, 0xC8, 0x02, 0xFC, 0xA0, 0x06, 
+	0x3E, 0xB4, 0x06, 0xC8, 0x6C, 0x01, 0xE0, 0x04, 
+	0x00, 0xFC, 0xA0, 0x01, 0x02, 0xFC, 0x02, 0x00, 
+	0x87, 0x07, 0x30, 0x06, 0xE7, 0x01, 0x04, 0x00, 
+	0x40, 0x00, 0xD7, 0x04, 0x27, 0x02, 0x0C, 0x00, 
+	0x05, 0xC2, 0x60, 0x01, 0x6A, 0x09, 0x04, 0x00, 
+	0x03, 0x16, 0xE0, 0x01, 0x02, 0xFC, 0x20, 0x00, 
+	0xA0, 0x06, 0xFC, 0xB4, 0xC0, 0x01, 0x20, 0x00, 
+	0x60, 0x04, 0x66, 0xA6, 0x48, 0x01, 0x00, 0x18, 
+	0x03, 0x13, 0x48, 0x01, 0x00, 0x10, 0x02, 0x16, 
+	0xA0, 0x05, 0x32, 0x09, 0x86, 0x02, 0x43, 0x00, 
+	0x03, 0x13, 0x40, 0x01, 0x80, 0x40, 0x98, 0x13, 
+	0x06, 0xC8, 0x6C, 0x01, 0xE0, 0x04, 0x00, 0xFC,  
+	0x85, 0xC2, 0xA0, 0x06, 0x3E, 0xB4, 0x20, 0x06, 
+	0x62, 0x09, 0xE6, 0x16, 0xA0, 0x06, 0xD0, 0xD5, 
+	0xE3, 0x10, 0xA0, 0xC2, 0xF6, 0x05, 0x56, 0x16, 
+	0x19, 0xC8, 0xF0, 0x05, 0xA9, 0xC2, 0x0A, 0x00, 
+	0x0D, 0x11, 0xA0, 0xF2, 0x2E, 0x09, 0x0A, 0xD8, 
+	0x80, 0x01, 0x29, 0xC8, 0x06, 0x00, 0x8C, 0x01, 
+	0xA0, 0x07, 0x16, 0x09, 0x04, 0x00, 0x09, 0xC8, 
+	0xF4, 0x05, 0x46, 0x10, 0x29, 0xC8, 0x06, 0x00, 
+	0x6C, 0x01, 0x20, 0xC8, 0x0E, 0xFC, 0xBC, 0x01, 
+	0x20, 0xC8, 0x10, 0xFC, 0xB0, 0x01, 0x20, 0xC8, 
+	0x12, 0xFC, 0xB2, 0x01, 0xA0, 0xF2, 0x2E, 0x09, 
+	0x8A, 0x01, 0x00, 0x10, 0xA0, 0x01, 0x80, 0x01, 
+	0x00, 0xC4, 0xE1, 0x10, 0x47, 0x01, 0x08, 0x00, 
+	0x06, 0x16, 0xA8, 0xC2, 0x06, 0x00, 0xA0, 0x06, 
+	0x3E, 0xB4, 0xE8, 0x04, 0x06, 0x00, 0x07, 0x01, 
+	0x20, 0x00, 0x31, 0x13, 0xE8, 0x04, 0x02, 0x00, 
+	0x3B, 0x10, 0xE0, 0x04, 0x00, 0xFC, 0xA0, 0x06, 
+	0x3E, 0xB4, 0x29, 0x10, 0x00, 0x03, 0x02, 0x00, 
+	0x20, 0xC2, 0x8C, 0x01, 0xE0, 0xC0, 0x6C, 0x01, 
+	0x20, 0xC2, 0xF4, 0x05, 0x28, 0xC8, 0x08, 0x00, 
+	0x6C, 0x01, 0xE8, 0xC1, 0x0A, 0x00, 0x20, 0xC3, 
+	0x02, 0xFC, 0x8C, 0x01, 0x20, 0x00, 0x0C, 0xC8, 
+	0x02, 0xFC, 0x0C, 0x01, 0x00, 0xFE, 0x3B, 0x16, 
+	0x47, 0x01, 0x40, 0x00, 0x50, 0x13, 0x60, 0xC2, 
+	0xF0, 0x05, 0xA7, 0x16, 0xE0, 0x04, 0xF4, 0x05, 
+	0x0C, 0xCA, 0x08, 0x00, 0x47, 0x01, 0x80, 0x00, 
+	0xC9, 0x16, 0x28, 0xC8, 0x06, 0x00, 0x6C, 0x01, 
+	0xA0, 0xC2, 0x00, 0xFC, 0xD2, 0x16, 0xE8, 0xC1, 
+	0x02, 0x00, 0xD7, 0xC2, 0x0F, 0x16, 0x27, 0x02, 
+	0x10, 0x00, 0xD8, 0x04, 0x57, 0xC2, 0x0E, 0x13, 
+	0xC7, 0x05, 0x57, 0xC2, 0x48, 0xC6, 0xC8, 0xC5, 
+	0x03, 0xC8, 0x6C, 0x01, 0x0D, 0x11, 0x90, 0x03, 
+	0xFF, 0x11, 0x80, 0x03, 0xD7, 0x04, 0xC3, 0x01, 
+	0x00, 0x80, 0xED, 0x10, 0xE7, 0x01, 0xF4, 0xFF, 
+	0x20, 0x00, 0xC8, 0xCD, 0xC8, 0xC5, 0xF0, 0x10, 
+	0x90, 0x03, 0xF8, 0x11, 0xE0, 0x02, 0xC0, 0x00, 
+	0x60, 0xC3, 0xFA, 0x00, 0xA0, 0xC3, 0xFC, 0x00, 
+	0xE0, 0xC3, 0xFE, 0x00, 0x54, 0x04, 0xE8, 0xC2, 
+	0x08, 0x00, 0xA8, 0xC2, 0x06, 0x00, 0x0C, 0xC3, 
+	0x33, 0x11, 0x20, 0x23, 0x0A, 0xE0, 0x45, 0x13, 
+	0x20, 0x23, 0x10, 0xE0, 0x46, 0x13, 0x20, 0x23, 
+	0x0E, 0xE0, 0x13, 0x13, 0xE0, 0x21, 0x16, 0xE0, 
+	0xB6, 0x16, 0x20, 0x23, 0x06, 0xE0, 0x03, 0x16, 
+	0x20, 0x27, 0xA8, 0xE4, 0x0A, 0x13, 0xE8, 0xC2, 
+	0x08, 0x00, 0xA8, 0xC2, 0x06, 0x00, 0x4C, 0x01, 
+	0x88, 0x00, 0xA9, 0x16, 0x0C, 0x01, 0x44, 0x00, 
+	0xA6, 0x16, 0x20, 0x06, 0x16, 0x09, 0xA3, 0x13, 
+	0x0A, 0xC8, 0x6C, 0x01, 0x20, 0xC8, 0x04, 0xE0, 
+	0x02, 0xFC, 0x0B, 0xC8, 0x6C, 0x01, 0xA0, 0x07, 
+	0x02, 0xFC, 0x00, 0x81, 0x20, 0xC3, 0x80, 0x01, 
+	0xA0, 0x01, 0x80, 0x01, 0x00, 0xC4, 0x0C, 0xC8, 
+	0x80, 0x01, 0x0A, 0xC8, 0x8C, 0x01, 0xAC, 0x10, 
+	0x0A, 0xC2, 0x0F, 0x13, 0x08, 0xC8, 0x6C, 0x01, 
+	0xA0, 0xC2, 0x00, 0xFC, 0x20, 0xC3, 0x02, 0xFC, 
+	0x20, 0x23, 0x12, 0xE0, 0xF5, 0x16, 0x0B, 0xC8, 
+	0x6C, 0x01, 0x0C, 0xC8, 0x02, 0xFC, 0x60, 0x04, 
+	0x72, 0xA9, 0x8A, 0x07, 0x00, 0x04, 0x60, 0x04, 
+	0x8A, 0xA3, 0x8A, 0x07, 0x20, 0x00, 0x60, 0x04, 
+	0x8A, 0xA3, 0x8A, 0x07, 0x00, 0x02, 0x20, 0x27, 
+	0x0E, 0xE0, 0x04, 0x16, 0xA0, 0x06, 0x32, 0xA5, 
+	0xC3, 0x01, 0x00, 0x80, 0xA8, 0xC2, 0x06, 0x00, 
+	0x60, 0x04, 0x98, 0xA9, 0x00, 0x03, 0x02, 0x00, 
+	0xC0, 0x01, 0x10, 0x00, 0xE0, 0xC2, 0x2E, 0x06, 
+	0x08, 0x13, 0xE0, 0xC2, 0xF8, 0x05, 0x05, 0x13, 
+	0xE0, 0x01, 0x3A, 0x07, 0x00, 0x80, 0x80, 0x01, 
+	0x10, 0x00, 0x90, 0x03, 0xFF, 0x7F, 0x80, 0x03, 
+	0x00, 0x03, 0x02, 0x00, 0x20, 0xC2, 0xF6, 0x05, 
+	0x20, 0xE2, 0xF4, 0x05, 0x0E, 0x16, 0x20, 0xD8, 
+	0x2E, 0x09, 0x80, 0x01, 0x2B, 0xC8, 0x06, 0x00, 
+	0x8C, 0x01, 0xA0, 0x07, 0x16, 0x09, 0x04, 0x00, 
+	0x0B, 0xC8, 0xF4, 0x05, 0x90, 0x03, 0xFF, 0xFF, 
+	0x80, 0x03, 0x87, 0x07, 0xF0, 0x05, 0xDB, 0x04, 
+	0x57, 0xC2, 0x05, 0x16, 0xCB, 0xCD, 0xCB, 0xC5, 
+	0x90, 0x03, 0xFF, 0xFF, 0x80, 0x03, 0xC7, 0x05, 
+	0x57, 0xC2, 0x4B, 0xC6, 0xCB, 0xC5, 0x90, 0x03, 
+	0xFF, 0xFF, 0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 
+	0x0B, 0xC2, 0x20, 0xC3, 0xF4, 0x05, 0x0F, 0x13, 
+	0xA8, 0xC2, 0x0A, 0x00, 0x4A, 0x01, 0x10, 0x00, 
+	0x16, 0x16, 0xA0, 0x22, 0x04, 0xE0, 0x1A, 0x16, 
+	0x08, 0xC3, 0xA0, 0x06, 0x36, 0xAC, 0x0C, 0xC2, 
+	0x20, 0xC3, 0xF4, 0x05, 0x13, 0x16, 0x68, 0x01, 
+	0x0A, 0x00, 0x10, 0x00, 0x03, 0x13, 0xE0, 0xC2, 
+	0xF6, 0x05, 0x05, 0x16, 0xA0, 0x06, 0x78, 0xAC, 
+	0x90, 0x03, 0xFF, 0xFF, 0x80, 0x03, 0x87, 0x07, 
+	0xF0, 0x05, 0xA0, 0x06, 0xE6, 0xB4, 0x90, 0x03, 
+	0xFF, 0xFF, 0x80, 0x03, 0x87, 0x07, 0xF0, 0x05, 
+	0xA0, 0x06, 0x2C, 0xB5, 0x80, 0x03, 0x00, 0x03, 
+	0x02, 0x00, 0x87, 0x07, 0xF0, 0x05, 0xCB, 0xC2, 
+	0x08, 0x16, 0xA0, 0x06, 0x36, 0xAC, 0x20, 0x07, 
+	0xF6, 0x05, 0x60, 0xCB, 0xF4, 0x05, 0x02, 0x00, 
+	0x80, 0x03, 0xE0, 0x04, 0xF6, 0x05, 0x20, 0xC2, 
+	0xF4, 0x05, 0x05, 0x16, 0x17, 0xC2, 0x03, 0x13, 
+	0xD8, 0xC5, 0xA0, 0x06, 0x78, 0xAC, 0x80, 0x03, 
+	0x00, 0x03, 0x02, 0x00, 0x0B, 0xC3, 0xA0, 0x06, 
+	0x36, 0xAC, 0x8C, 0xC2, 0xCC, 0xC1, 0x27, 0x02, 
+	0x10, 0x00, 0x88, 0x07, 0xF0, 0x05, 0x88, 0xC1, 
+	0x18, 0xC2, 0x26, 0x13, 0xA8, 0x82, 0x02, 0x00, 
+	0xFA, 0x16, 0xE8, 0xC2, 0x0A, 0x00, 0xE0, 0x22, 
+	0x1E, 0xE0, 0xF5, 0x16, 0x98, 0xC5, 0xE0, 0x22, 
+	0x1C, 0xE0, 0x0B, 0x16, 0x28, 0xC8, 0x06, 0x00, 
+	0xF4, 0x00, 0xE0, 0x02, 0xE0, 0x00, 0xA0, 0x06, 
+	0x3E, 0xB4, 0xE0, 0x02, 0xC0, 0x00, 0xE8, 0x04, 
+	0x06, 0x00, 0xE0, 0x22, 0x18, 0xE0, 0xE4, 0x13, 
+	0x20, 0xEA, 0x22, 0xE0, 0x0A, 0x00, 0xA0, 0xEA, 
+	0x18, 0xE0, 0x04, 0x00, 0xDA, 0x04, 0xA0, 0x06, 
+	0xE6, 0xB4, 0x47, 0x06, 0x06, 0xC2, 0xD8, 0x10, 
+	0x06, 0xC8, 0xF2, 0x05, 0x60, 0xCB, 0xF4, 0x05, 
+	0x02, 0x00, 0x54, 0x04, 0x20, 0xC2, 0xF4, 0x05, 
+	0x13, 0x13, 0xE0, 0x01, 0x9C, 0x01, 0x00, 0x40, 
+	0x8B, 0x0B, 0x8B, 0x0B, 0x60, 0x01, 0x9C, 0x01, 
+	0x00, 0x40, 0x0A, 0x16, 0x60, 0xC2, 0x6C, 0x01, 
+	0x28, 0xC8, 0x06, 0x00, 0x6C, 0x01, 0xA0, 0xC2, 
+	0x02, 0xFC, 0x03, 0x11, 0x09, 0xC8, 0x6C, 0x01, 
+	0x5B, 0x04, 0x09, 0xC8, 0x6C, 0x01, 0x4B, 0xC2, 
+	0x87, 0x07, 0xF0, 0x05, 0xA0, 0x06, 0x2C, 0xB5, 
+	0xE0, 0x04, 0xF4, 0x05, 0x59, 0x04, 0xA8, 0xC2, 
+	0x0A, 0x00, 0x0D, 0x11, 0xA0, 0xF2, 0x2E, 0x09, 
+	0x0A, 0xD8, 0x80, 0x01, 0x28, 0xC8, 0x06, 0x00, 
+	0x8C, 0x01, 0xA0, 0x07, 0x16, 0x09, 0x04, 0x00, 
+	0x08, 0xC8, 0xF4, 0x05, 0x5B, 0x04, 0x20, 0xC3, 
+	0x6C, 0x01, 0x28, 0xC8, 0x06, 0x00, 0x6C, 0x01, 
+	0x20, 0xC8, 0x0E, 0xFC, 0xBC, 0x01, 0x20, 0xC8, 
+	0x10, 0xFC, 0xB0, 0x01, 0x20, 0xC8, 0x12, 0xFC, 
+	0xB2, 0x01, 0x0C, 0xC8, 0x6C, 0x01, 0xA0, 0xF2, 
+	0x2E, 0x09, 0x8A, 0x01, 0x00, 0x10, 0xA0, 0x01, 
+	0x80, 0x01, 0x00, 0xC4, 0xDD, 0x10, 0x48, 0xC0, 
+	0x89, 0xC0, 0x81, 0x60, 0xC2, 0x05, 0x5B, 0x04, 
+	0x0B, 0xC3, 0xA0, 0x06, 0xC8, 0xAC, 0x41, 0xCC, 
+	0x42, 0x06, 0xFD, 0x16, 0xA0, 0x06, 0xC8, 0xAC, 
+	0x01, 0xC1, 0x44, 0x8C, 0x12, 0x16, 0xC4, 0x05, 
+	0x42, 0x06, 0xFB, 0x16, 0x04, 0x02, 0x0E, 0xAD, 
+	0x03, 0x02, 0x01, 0x01, 0x94, 0x06, 0x03, 0x02, 
+	0x5A, 0x5A, 0x94, 0x06, 0x43, 0x05, 0x94, 0x06, 
+	0x03, 0x07, 0x94, 0x06, 0xC3, 0x04, 0x94, 0x06, 
+	0xCC, 0x05, 0x5C, 0x04, 0xCB, 0xC1, 0xA0, 0x06, 
+	0xC8, 0xAC, 0x43, 0xCC, 0x42, 0x06, 0xFD, 0x16, 
+	0xA0, 0x06, 0xC8, 0xAC, 0x43, 0x8C, 0xF5, 0x16, 
+	0x42, 0x06, 0xFC, 0x16, 0x57, 0x04, 0x8B, 0xC2, 
+	0x08, 0xC0, 0x49, 0xC1, 0x85, 0x05, 0x80, 0x02, 
+	0x40, 0x00, 0x03, 0x11, 0x80, 0x02, 0x4F, 0x00, 
+	0x45, 0x12, 0x01, 0x02, 0xC8, 0xAC, 0xA1, 0x09, 
+	0x01, 0x80, 0x40, 0x13, 0x01, 0x02, 0xF8, 0xAD, 
+	0xA1, 0x09, 0x01, 0x80, 0x3B, 0x13, 0x60, 0xC0, 
+	0x06, 0x00, 0xA1, 0x09, 0x01, 0x80, 0x36, 0x13, 
+	0x81, 0x05, 0x01, 0x80, 0x33, 0x13, 0x4A, 0xC0, 
+	0xA1, 0x09, 0x01, 0x80, 0x2F, 0x13, 0x00, 0xC8, 
+	0x6A, 0x01, 0x80, 0x02, 0x80, 0x00, 0x17, 0x14, 
+	0x01, 0x02, 0x00, 0xF8, 0xA0, 0xC1, 0x40, 0x01, 
+	0xA0, 0x01, 0x40, 0x01, 0x00, 0x04, 0x02, 0x02, 
+	0x00, 0x10, 0x03, 0x02, 0x00, 0x04, 0xB1, 0xCC, 
+	0x43, 0x06, 0xFD, 0x16, 0xA0, 0x01, 0x40, 0x01, 
+	0x00, 0x40, 0x08, 0x02, 0x10, 0xF8, 0x06, 0xC8, 
+	0x40, 0x01, 0x00, 0xC0, 0x02, 0x13, 0x08, 0x02, 
+	0x00, 0xF8, 0x09, 0x02, 0xFE, 0xFB, 0xA0, 0x06, 
+	0xD2, 0xAC, 0x25, 0x10, 0x80, 0x02, 0x80, 0x00, 
+	0x09, 0x14, 0x01, 0x02, 0x00, 0xF8, 0x02, 0x02, 
+	0x00, 0x10, 0x03, 0x02, 0x00, 0x04, 0x72, 0xCC, 
+	0x43, 0x06, 0xFD, 0x16, 0x80, 0x05, 0x80, 0x02, 
+	0x80, 0x00, 0x04, 0x12, 0x60, 0x01, 0x04, 0x01, 
+	0x20, 0x00, 0x05, 0x13, 0x40, 0x81, 0xAB, 0x16, 
+	0x80, 0x02, 0x80, 0x00, 0x0B, 0x14, 0xA0, 0x07, 
+	0x6A, 0x01, 0x7E, 0x00, 0x02, 0x02, 0x00, 0x10, 
+	0x03, 0x02, 0x00, 0x04, 0xC1, 0x04, 0x81, 0xCC, 
+	0x43, 0x06, 0xFD, 0x16, 0xCA, 0x05, 0x5A, 0x04, 
+	0x00, 0x02, 0xEA, 0xAD, 0x01, 0x02, 0x1A, 0xAF, 
+	0x40, 0x02, 0x00, 0xFC, 0x41, 0x02, 0x00, 0xFC, 
+	0x40, 0x80, 0x04, 0x13, 0xA0, 0x07, 0x04, 0x01, 
+	0x3C, 0x00, 0x5B, 0x04, 0xC0, 0x04, 0x01, 0x02, 
+	0x08, 0x00, 0x02, 0x02, 0x00, 0x12, 0xE0, 0xC1, 
+	0x40, 0x01, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x04, 
+	0x03, 0x02, 0x00, 0x01, 0x00, 0xC8, 0x6A, 0x01, 
+	0xA0, 0xCC, 0x10, 0xF8, 0x80, 0x05, 0x03, 0x06, 
+	0xF9, 0x16, 0x22, 0x02, 0x00, 0x02, 0x01, 0x06, 
+	0xF3, 0x16, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x40, 
+	0x07, 0xC8, 0x40, 0x01, 0x00, 0x02, 0x00, 0x08, 
+	0x40, 0xC0, 0x01, 0x06, 0x01, 0xC8, 0x6A, 0x01, 
+	0x61, 0x02, 0x00, 0x80, 0x01, 0xC8, 0x10, 0xF8, 
+	0x00, 0x06, 0xF6, 0x16, 0xC0, 0x04, 0xC8, 0x04, 
+	0xC9, 0x04, 0x03, 0x02, 0x00, 0x08, 0x00, 0xC8, 
+	0x6A, 0x01, 0x80, 0xC1, 0x66, 0x02, 0x00, 0x80, 
+	0x20, 0xC1, 0x10, 0xF8, 0x06, 0x81, 0x15, 0x16, 
+	0x08, 0xC2, 0x06, 0x13, 0x80, 0x05, 0x03, 0x06, 
+	0xF2, 0x16, 0x08, 0xC2, 0x0D, 0x13, 0x19, 0x10, 
+	0xA0, 0x07, 0x10, 0xF8, 0x55, 0x55, 0x20, 0xC1, 
+	0x10, 0xF8, 0x84, 0x02, 0x55, 0x55, 0x02, 0x16, 
+	0x06, 0xC2, 0xF0, 0x10, 0x06, 0x81, 0xEE, 0x13, 
+	0x5B, 0x04, 0xA0, 0x07, 0x10, 0xF8, 0x55, 0x55, 
+	0x60, 0xC1, 0x10, 0xF8, 0x05, 0x81, 0x03, 0x13, 
+	0x85, 0x02, 0x55, 0x55, 0xF5, 0x16, 0x08, 0xC2, 
+	0xE1, 0x13, 0x40, 0xC2, 0x09, 0x06, 0x48, 0x02, 
+	0xFF, 0x07, 0xC0, 0x04, 0x01, 0x02, 0x08, 0x00, 
+	0x02, 0x02, 0x00, 0x12, 0x03, 0x02, 0x00, 0x01, 
+	0x00, 0xC8, 0x6A, 0x01, 0x32, 0xC8, 0x10, 0xF8, 
+	0x80, 0x05, 0x03, 0x06, 0xF9, 0x16, 0x22, 0x02, 
+	0x00, 0x02, 0x01, 0x06, 0xF3, 0x16, 0x88, 0x02, 
+	0x40, 0x00, 0x13, 0x15, 0x89, 0x02, 0x4F, 0x00, 
+	0x10, 0x11, 0xC0, 0x04, 0x02, 0x02, 0x00, 0x12, 
+	0x01, 0x02, 0x08, 0x00, 0x03, 0x02, 0x00, 0x01, 
+	0x80, 0xCC, 0x03, 0x06, 0xFD, 0x16, 0x22, 0x02, 
+	0x00, 0x02, 0x01, 0x06, 0xF7, 0x16, 0xCB, 0x05, 
+	0x5B, 0x04, 0xA0, 0x07, 0x04, 0x01, 0x37, 0x00, 
+	0x5B, 0x04, 0x33, 0x07, 0x33, 0x07, 0x0C, 0x10, 
+	0x13, 0x07, 0x23, 0x07, 0x02, 0x00, 0xCB, 0xC8, 
+	0x06, 0x00, 0x23, 0x02, 0x18, 0x00, 0xE0, 0xCC, 
+	0x6C, 0x01, 0xCD, 0xCC, 0xCE, 0xCC, 0xCF, 0xCC, 
+	0x83, 0x07, 0x30, 0x06, 0xD3, 0xC1, 0x0A, 0x13, 
+	0x83, 0x07, 0x36, 0x07, 0xD3, 0xC1, 0x06, 0x13, 
+	0x83, 0x07, 0xA0, 0x00, 0x93, 0x00, 0x0C, 0xC8, 
+	0x6C, 0x01, 0x80, 0x03, 0x63, 0x07, 0x02, 0x00, 
+	0x2A, 0x15, 0x63, 0xC2, 0x04, 0x00, 0x63, 0x42, 
+	0x06, 0x00, 0xDB, 0x13, 0x63, 0xC3, 0x1A, 0x00, 
+	0x49, 0xD2, 0x0C, 0x13, 0xC9, 0x06, 0x49, 0x72, 
+	0x69, 0xD2, 0xC0, 0xE1, 0xC9, 0x06, 0x49, 0x72, 
+	0xE9, 0x48, 0x04, 0xE0, 0x04, 0x00, 0x49, 0xCB, 
+	0x02, 0x00, 0x52, 0x04, 0x69, 0xC2, 0xC0, 0xE1, 
+	0x49, 0x72, 0x29, 0x02, 0x10, 0x00, 0xC3, 0xC2, 
+	0xE9, 0xA2, 0xA8, 0xE1, 0x1B, 0xC3, 0x89, 0x02, 
+	0x12, 0x00, 0x0F, 0x13, 0xDC, 0xC6, 0x03, 0x16, 
+	0xE9, 0x48, 0x04, 0xE0, 0x04, 0x00, 0x49, 0xCB, 
+	0x02, 0x00, 0x4C, 0xCB, 0x04, 0x00, 0x90, 0x03, 
+	0xFF, 0x01, 0x93, 0x00, 0x0C, 0xC8, 0x6C, 0x01, 
+	0x80, 0x03, 0x0C, 0xC8, 0x6C, 0x01, 0xE0, 0xC6, 
+	0x00, 0xFC, 0xF1, 0x16, 0xE9, 0x48, 0x04, 0xE0, 
+	0x04, 0x00, 0x49, 0xCB, 0x02, 0x00, 0x4C, 0xCB, 
+	0x04, 0x00, 0xED, 0x10, 0x00, 0x03, 0x02, 0x00, 
+	0xDB, 0xC2, 0x63, 0xC2, 0x04, 0x00, 0x4B, 0x42, 
+	0x9F, 0x13, 0x49, 0xD2, 0x0E, 0x13, 0xC9, 0x06, 
+	0x49, 0x72, 0x69, 0xD2, 0xC0, 0xE1, 0xC9, 0x06, 
+	0x49, 0x72, 0xE9, 0x48, 0x04, 0xE0, 0x04, 0x00, 
+	0x49, 0xCB, 0x02, 0x00, 0x90, 0x03, 0xFF, 0xFF, 
+	0x80, 0x03, 0x69, 0xC2, 0xC0, 0xE1, 0x49, 0x72, 
+	0x29, 0x02, 0x10, 0x00, 0xC3, 0xC2, 0xE9, 0xA2, 
+	0xA8, 0xE1, 0x1B, 0xC3, 0x89, 0x02, 0x12, 0x00, 
+	0x0C, 0x13, 0xDC, 0xC6, 0x03, 0x16, 0xE9, 0x48, 
+	0x04, 0xE0, 0x04, 0x00, 0x49, 0xCB, 0x02, 0x00, 
+	0x4C, 0xCB, 0x04, 0x00, 0x90, 0x03, 0xFF, 0xFF, 
+	0x80, 0x03, 0x0C, 0xC8, 0x6C, 0x01, 0xE0, 0xC6, 
+	0x00, 0xFC, 0xF4, 0x16, 0xF0, 0x10, 0x00, 0x03, 
+	0x02, 0x00, 0xBB, 0xC2, 0xBB, 0xC1, 0x86, 0xD1, 
+	0x03, 0x13, 0x86, 0xEA, 0x04, 0x00, 0x13, 0x10, 
+	0xA6, 0xD1, 0xC0, 0xE1, 0xC6, 0x06, 0x86, 0x71, 
+	0xCA, 0xC1, 0xE6, 0xA1, 0xB8, 0xE1, 0xA6, 0xEA, 
+	0x14, 0xE0, 0x04, 0x00, 0x1B, 0xC2, 0x86, 0x02, 
+	0x02, 0x00, 0x03, 0x16, 0xA0, 0x06, 0x0C, 0xB5, 
+	0x02, 0x10, 0xA0, 0x06, 0xE6, 0xB4, 0xDA, 0x04, 
+	0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 0xAB, 0xC2, 
+	0x06, 0x00, 0x8C, 0x07, 0xE8, 0x05, 0x5C, 0xC2, 
+	0x16, 0x13, 0xA0, 0xC1, 0xEC, 0x05, 0x8A, 0x81, 
+	0x1A, 0x1A, 0xC6, 0xC1, 0x09, 0xC2, 0x59, 0xC2, 
+	0x20, 0x13, 0xE9, 0xA1, 0x08, 0x00, 0x87, 0x82, 
+	0xF9, 0x12, 0xA9, 0xA2, 0x08, 0x00, 0x87, 0x62, 
+	0xCA, 0xCA, 0x08, 0x00, 0x4A, 0x6A, 0x08, 0x00, 
+	0xC9, 0xC6, 0x0B, 0xC6, 0x80, 0x03, 0xCA, 0xCA, 
+	0x08, 0x00, 0x0A, 0xC8, 0xEC, 0x05, 0xDB, 0x04, 
+	0x0B, 0xCF, 0x0B, 0xC7, 0x80, 0x03, 0x8A, 0x61, 
+	0x46, 0xCA, 0x08, 0x00, 0xCA, 0xCA, 0x08, 0x00, 
+	0x0A, 0xC8, 0xEC, 0x05, 0xC9, 0xC6, 0x0B, 0xC7, 
+	0x80, 0x03, 0x87, 0x62, 0xCA, 0xCA, 0x08, 0x00, 
+	0xDB, 0x04, 0x0B, 0xC6, 0x0B, 0xCB, 0x02, 0x00, 
+	0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 0xBB, 0xC1, 
+	0xDB, 0xC2, 0x8C, 0x07, 0xE8, 0x05, 0x4C, 0xC2, 
+	0xED, 0x04, 0x02, 0x00, 0x09, 0xC2, 0x59, 0xC2, 
+	0x18, 0x13, 0xA9, 0x81, 0x02, 0x00, 0xFA, 0x16, 
+	0xE9, 0x82, 0x04, 0x00, 0xF7, 0x16, 0x49, 0xCB, 
+	0x04, 0x00, 0x99, 0xC2, 0x0A, 0xC6, 0x0A, 0x13, 
+	0x08, 0x83, 0x04, 0x13, 0xA9, 0xAA, 0x08, 0x00, 
+	0x08, 0x00, 0x80, 0x03, 0x2A, 0xA8, 0x08, 0x00, 
+	0xEC, 0x05, 0x80, 0x03, 0x08, 0xCB, 0x02, 0x00, 
+	0x80, 0x03, 0x2D, 0x07, 0x02, 0x00, 0x8C, 0x07, 
+	0x08, 0x00, 0x06, 0xA3, 0x4C, 0xC2, 0x09, 0xC2, 
+	0x59, 0xC2, 0x13, 0x13, 0xE9, 0x82, 0x04, 0x00, 
+	0xFA, 0x16, 0xAD, 0x07, 0x02, 0x00, 0x01, 0x00, 
+	0x49, 0xCB, 0x04, 0x00, 0x19, 0xC6, 0x01, 0x13, 
+	0x80, 0x03, 0x08, 0x83, 0x04, 0x16, 0xA0, 0x49, 
+	0x14, 0xE0, 0x04, 0x00, 0x80, 0x03, 0x08, 0xCB, 
+	0x02, 0x00, 0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 
+	0x0B, 0x06, 0x1F, 0x11, 0x4D, 0x13, 0x8B, 0x07, 
+	0x00, 0x4E, 0x60, 0x01, 0x42, 0x01, 0x80, 0x00, 
+	0x09, 0x13, 0x8B, 0x07, 0x00, 0x3A, 0x20, 0xC1, 
+	0x4E, 0x01, 0x84, 0x02, 0x41, 0x0F, 0x02, 0x11, 
+	0x8B, 0x07, 0x00, 0x4E, 0x0B, 0xC8, 0x44, 0x01, 
+	0xA0, 0x07, 0x62, 0x09, 0xE8, 0x03, 0xE0, 0x01, 
+	0x40, 0x01, 0x00, 0x02, 0xE0, 0x01, 0x40, 0x01, 
+	0x00, 0x20, 0x84, 0x07, 0x34, 0xAF, 0x60, 0x04, 
+	0x42, 0xAF, 0x20, 0xC8, 0x16, 0xE0, 0xE0, 0x00, 
+	0xE0, 0xC2, 0x6A, 0x09, 0xE0, 0x22, 0x10, 0xE0, 
+	0x03, 0x13, 0x20, 0xE8, 0x14, 0xE0, 0xE0, 0x00, 
+	0x20, 0xC8, 0x04, 0xE0, 0x82, 0x01, 0x20, 0xC8, 
+	0xE2, 0x00, 0x8A, 0x01, 0xE0, 0x04, 0x18, 0x09, 
+	0xE0, 0x04, 0xF4, 0x05, 0xE0, 0x04, 0xF8, 0x05, 
+	0xE0, 0x04, 0xF0, 0x05, 0xE0, 0x04, 0x42, 0x07, 
+	0xA0, 0x07, 0x88, 0x01, 0x20, 0x00, 0xE0, 0xC2, 
+	0x30, 0x09, 0x09, 0x13, 0xA0, 0x07, 0x88, 0x01, 
+	0x80, 0x00, 0x20, 0xE8, 0x16, 0xE0, 0x80, 0x01, 
+	0xE0, 0x01, 0x82, 0x01, 0x00, 0x03, 0x8B, 0x07, 
+	0x00, 0xA0, 0x0B, 0xE8, 0x86, 0x01, 0x80, 0x03, 
+	0xE0, 0x04, 0x86, 0x01, 0xE0, 0x01, 0x9C, 0x01, 
+	0x40, 0x00, 0xE0, 0x01, 0x9C, 0x01, 0x00, 0x40, 
+	0xCB, 0x04, 0xB0, 0x03, 0x0B, 0x06, 0x04, 0x13, 
+	0x60, 0x01, 0x9C, 0x01, 0x00, 0x40, 0xF9, 0x16, 
+	0xE0, 0x04, 0x82, 0x01, 0x20, 0xE8, 0x08, 0xE0, 
+	0x6A, 0x09, 0x8B, 0x07, 0x00, 0x80, 0x0B, 0xC8, 
+	0x98, 0x07, 0x0B, 0xC8, 0x78, 0x07, 0x20, 0xC8, 
+	0x04, 0xE0, 0x82, 0x01, 0x8B, 0x07, 0x6F, 0x87, 
+	0x0B, 0x48, 0x3A, 0x07, 0xE0, 0xC2, 0x50, 0x07, 
+	0x8B, 0x02, 0x58, 0x07, 0x10, 0x13, 0x20, 0xE8, 
+	0x0A, 0xE0, 0x00, 0x01, 0xE0, 0xC2, 0x00, 0x01, 
+	0xE0, 0x22, 0x06, 0xE0, 0xF8, 0x13, 0x8B, 0x07, 
+	0x58, 0x07, 0x0B, 0xC8, 0x50, 0x07, 0x8B, 0x07, 
+	0x0C, 0xB8, 0x0B, 0xC8, 0x52, 0x07, 0x80, 0x03, 
+	0x00, 0x03, 0x02, 0x00, 0xE0, 0xC2, 0x1A, 0x09, 
+	0x0C, 0x13, 0x20, 0x06, 0x1C, 0x09, 0x0B, 0xC8, 
+	0x6C, 0x01, 0x20, 0xC8, 0x00, 0xFC, 0x1A, 0x09, 
+	0x4B, 0xCB, 0x02, 0x00, 0x90, 0x03, 0xFF, 0xFF, 
+	0x80, 0x03, 0x41, 0xC0, 0x0F, 0x13, 0x81, 0x80, 
+	0x0D, 0x13, 0x82, 0xA0, 0xE2, 0xC2, 0x32, 0x0C, 
+	0x12, 0x09, 0x0B, 0xC8, 0x6C, 0x01, 0xE0, 0x04, 
+	0x00, 0xFC, 0x20, 0xC3, 0x02, 0xFC, 0x07, 0x11, 
+	0x02, 0xC8, 0x00, 0xFC, 0xED, 0x04, 0x02, 0x00, 
+	0xE0, 0x04, 0x6C, 0x01, 0x80, 0x03, 0x42, 0xCB, 
+	0x02, 0x00, 0x02, 0xC8, 0x6C, 0x01, 0x8B, 0xC0, 
+	0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 0x83, 0x07, 
+	0x00, 0x80, 0x60, 0xC2, 0x7E, 0x09, 0x09, 0xC1, 
+	0x24, 0x02, 0xF8, 0xFF, 0xA9, 0x08, 0x01, 0x02, 
+	0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x0B, 0x02, 
+	0x00, 0x00, 0x0C, 0x02, 0x00, 0x00, 0x07, 0x02, 
+	0x00, 0x00, 0x2C, 0xCB, 0x32, 0x0C, 0x32, 0x0C, 
+	0x06, 0x13, 0x8B, 0x05, 0xCC, 0x05, 0x0B, 0x88, 
+	0x46, 0x04, 0x27, 0x1B, 0xF6, 0x10, 0x09, 0xC2, 
+	0x8B, 0xC2, 0x08, 0x06, 0x0A, 0x13, 0x8B, 0x05, 
+	0xCC, 0x05, 0x0B, 0x88, 0x46, 0x04, 0x1D, 0x1B, 
+	0x2C, 0xCB, 0x32, 0x0C, 0x32, 0x0C, 0xED, 0x16, 
+	0xF4, 0x10, 0x82, 0xC0, 0x14, 0x13, 0x02, 0xC8, 
+	0x6C, 0x01, 0x0A, 0xC8, 0x00, 0xFC, 0x0A, 0xC8, 
+	0x6C, 0x01, 0xE0, 0x04, 0x00, 0xFC, 0xA0, 0x07, 
+	0x02, 0xFC, 0x00, 0x80, 0x04, 0xC8, 0x04, 0xFC, 
+	0x0A, 0xC2, 0x08, 0xA2, 0x02, 0xCA, 0x32, 0x0C, 
+	0x8A, 0xC0, 0x87, 0x05, 0xD6, 0x10, 0x4A, 0xC0, 
+	0xEE, 0x10, 0x47, 0xCB, 0x02, 0x00, 0xE0, 0x04, 
+	0x6C, 0x01, 0x8B, 0x07, 0x43, 0x00, 0xE0, 0x04, 
+	0x00, 0x0C, 0x00, 0x03, 0x02, 0x00, 0x0B, 0xC8, 
+	0x6C, 0x01, 0x8B, 0x02, 0x43, 0x00, 0x04, 0x13, 
+	0x60, 0x01, 0x02, 0xFC, 0x20, 0x00, 0x06, 0x13, 
+	0x8B, 0xC2, 0xA0, 0x06, 0x42, 0xB4, 0x90, 0x03, 
+	0x7F, 0x00, 0x80, 0x03, 0xA0, 0x01, 0x02, 0xFC, 
+	0x20, 0x00, 0x60, 0x01, 0x6A, 0x09, 0x01, 0x00, 
+	0x0B, 0x16, 0x0A, 0x02, 0x02, 0xFC, 0xA0, 0xA2, 
+	0x2C, 0x09, 0xA0, 0xCE, 0xEE, 0x05, 0xA0, 0xC6, 
+	0x04, 0xFC, 0x20, 0xC8, 0x2C, 0x09, 0x04, 0xFC, 
+	0x8A, 0x07, 0xF8, 0x05, 0x5A, 0xC2, 0x08, 0x13, 
+	0xCA, 0x05, 0x5A, 0xC2, 0x09, 0xC8, 0x6C, 0x01, 
+	0x0B, 0xC8, 0x00, 0xFC, 0x8B, 0xC6, 0x02, 0x10, 
+	0x8B, 0xCE, 0x8B, 0xC6, 0x20, 0x20, 0x1A, 0xE0, 
+	0x05, 0x16, 0x20, 0xE8, 0x04, 0xE0, 0x3A, 0x07, 
+	0xE0, 0x04, 0x36, 0x07, 0x90, 0x03, 0x7F, 0x00, 
+	0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 0x0B, 0xC8, 
+	0x6C, 0x01, 0xCC, 0x04, 0xE0, 0x04, 0x00, 0xFC, 
+	0x8B, 0xC2, 0xA0, 0x06, 0x50, 0xB4, 0x90, 0x03, 
+	0x7F, 0x00, 0x80, 0x03, 0xA0, 0x07, 0x02, 0xFC, 
+	0x00, 0x80, 0x20, 0xC8, 0x8C, 0xE1, 0x04, 0xFC, 
+	0x41, 0xC0, 0x0F, 0x16, 0x20, 0xD8, 0x00, 0xE2, 
+	0x83, 0x01, 0x8B, 0x0B, 0x8B, 0x0B, 0x8B, 0x0B, 
+	0x8B, 0x0B, 0x8B, 0x0B, 0x8B, 0x0B, 0x8B, 0x0B, 
+	0x8B, 0x0B, 0x8B, 0x0B, 0x8B, 0x0B, 0x0A, 0xC8, 
+	0x8A, 0x01, 0x5B, 0x04, 0x0A, 0xC8, 0x6C, 0x01, 
+	0x20, 0xC3, 0x00, 0xFC, 0xE0, 0x04, 0x00, 0xFC, 
+	0x8A, 0x02, 0x43, 0x00, 0xDF, 0x13, 0xA0, 0x07, 
+	0x02, 0xFC, 0x00, 0x80, 0x04, 0xC8, 0x04, 0xFC, 
+	0x20, 0x98, 0x84, 0x09, 0x1D, 0x09, 0x0A, 0x13, 
+	0x20, 0xC8, 0x1A, 0x09, 0x00, 0xFC, 0x0A, 0xC8, 
+	0x1A, 0x09, 0xA0, 0x05, 0x1C, 0x09, 0x8C, 0xC2, 
+	0xE5, 0x16, 0x5B, 0x04, 0x41, 0xC0, 0x10, 0x13, 
+	0x8A, 0xA2, 0x82, 0xCA, 0x32, 0x0C, 0x1A, 0x09, 
+	0x02, 0xC8, 0x6C, 0x01, 0x0A, 0xC8, 0x00, 0xFC, 
+	0x8A, 0xC0, 0x20, 0x98, 0x83, 0x01, 0x00, 0xE2, 
+	0x09, 0x13, 0x8C, 0xC2, 0xD3, 0x16, 0x5B, 0x04, 
+	0x4A, 0xC0, 0x8A, 0xC0, 0x20, 0x98, 0x83, 0x01, 
+	0x00, 0xE2, 0x1B, 0x16, 0xE0, 0x01, 0x9C, 0x01, 
+	0x40, 0x00, 0xA0, 0x07, 0x64, 0x09, 0x00, 0x70, 
+	0x60, 0x01, 0x9C, 0x01, 0x40, 0x00, 0x07, 0x13, 
+	0x20, 0x06, 0x64, 0x09, 0xF9, 0x16, 0x0A, 0x02, 
+	0x00, 0x01, 0x60, 0x04, 0x8A, 0xA3, 0x60, 0x01, 
+	0x02, 0x0C, 0x00, 0x01, 0xE2, 0x13, 0x20, 0xD8, 
+	0x2F, 0x09, 0x83, 0x01, 0xA0, 0x07, 0x02, 0x0C, 
+	0x00, 0x80, 0x0A, 0xC8, 0x8A, 0x01, 0x0A, 0xC8, 
+	0x18, 0x09, 0xD7, 0x10, 0xD8, 0x04, 0x57, 0xC2, 
+	0x03, 0x16, 0xC8, 0xCD, 0xC8, 0xC5, 0x5B, 0x04, 
+	0xC7, 0x05, 0x57, 0xC2, 0x48, 0xC6, 0xC8, 0xC5, 
+	0x5B, 0x04, 0x08, 0xC8, 0x6C, 0x01, 0x08, 0xA2, 
+	0x20, 0xCA, 0x00, 0xFC, 0x32, 0x0C, 0x18, 0x09, 
+	0x02, 0x10, 0x08, 0xC8, 0x6C, 0x01, 0xE0, 0x04, 
+	0x00, 0xFC, 0x57, 0xC2, 0x03, 0x16, 0xC8, 0xCD, 
+	0xC8, 0xC5, 0x5B, 0x04, 0xC7, 0x05, 0x17, 0xC8, 
+	0x6C, 0x01, 0x08, 0xC8, 0x00, 0xFC, 0xC8, 0xC5, 
+	0x5B, 0x04, 0x17, 0xC6, 0x02, 0x16, 0xC8, 0xC9, 
+	0x02, 0x00, 0xC8, 0xC5, 0x5B, 0x04, 0x17, 0xC2, 
+	0x08, 0xC8, 0x6C, 0x01, 0x07, 0x13, 0xE0, 0xC5, 
+	0x00, 0xFC, 0x08, 0xA2, 0x28, 0xC8, 0x32, 0x0C, 
+	0x00, 0xFC, 0x18, 0x09, 0x5B, 0x04, 0x60, 0x01, 
+	0x82, 0x01, 0x00, 0x20, 0x0A, 0x16, 0x60, 0xC2, 
+	0x84, 0x01, 0xA0, 0x01, 0x82, 0x01, 0x00, 0x20, 
+	0xE0, 0x01, 0x82, 0x01, 0x00, 0x20, 0x09, 0xC8, 
+	0x84, 0x01, 0xC9, 0x04, 0x5B, 0x04, 0xA0, 0x06, 
+	0xBE, 0xB7, 0xD3, 0x04, 0xE0, 0x04, 0x02, 0x01, 
+	0x20, 0xE8, 0x14, 0xE0, 0x00, 0x01, 0x20, 0xC8, 
+	0x16, 0xE0, 0x04, 0x01, 0x05, 0x2C, 0x20, 0x48, 
+	0x14, 0xE0, 0x00, 0x01, 0x8C, 0x07, 0x00, 0x0A, 
+	0x8D, 0x07, 0xD8, 0x07, 0x8E, 0x07, 0x18, 0x00, 
+	0x7C, 0xCF, 0x4E, 0x06, 0xFD, 0x16, 0xE0, 0x02, 
+	0xD8, 0x07, 0x8F, 0x07, 0x11, 0xFF, 0x8B, 0x02, 
+	0x3B, 0x59, 0x21, 0x16, 0x8A, 0x02, 0x3B, 0x59, 
+	0x1E, 0x13, 0x8F, 0x05, 0x20, 0x20, 0x16, 0xE0, 
+	0x01, 0x16, 0x19, 0x10, 0x20, 0x20, 0x04, 0xE0, 
+	0x16, 0x16, 0x00, 0x01, 0xBF, 0x00, 0x13, 0x16, 
+	0x8B, 0x07, 0xC0, 0x40, 0x00, 0x01, 0x00, 0x60, 
+	0x10, 0x13, 0x40, 0x01, 0x00, 0x60, 0x0B, 0x16, 
+	0x8B, 0x07, 0xC4, 0x44, 0xA0, 0xC3, 0x02, 0x01, 
+	0x0E, 0x48, 0x02, 0x01, 0x4E, 0x01, 0x00, 0x10, 
+	0x04, 0x16, 0x8F, 0x07, 0x18, 0xFF, 0x60, 0x04, 
+	0x94, 0xB7, 0x0B, 0xC3, 0x4B, 0xC3, 0x20, 0x20, 
+	0x0A, 0xE0, 0x02, 0x16, 0x6B, 0x02, 0x20, 0x20, 
+	0x20, 0x20, 0x0C, 0xE0, 0x02, 0x16, 0x6C, 0x02, 
+	0x00, 0x20, 0x20, 0x20, 0x0E, 0xE0, 0x02, 0x16, 
+	0x6C, 0x02, 0x20, 0x00, 0x8F, 0x05, 0x20, 0x20, 
+	0x10, 0xE0, 0x07, 0x16, 0x6D, 0x02, 0x20, 0x00, 
+	0x20, 0x21, 0x22, 0xE0, 0xE4, 0x13, 0x04, 0xC1, 
+	0x02, 0x16, 0x84, 0x07, 0xFE, 0x7F, 0x8F, 0x05, 
+	0x20, 0x20, 0x12, 0xE0, 0x02, 0x16, 0x6D, 0x02, 
+	0x00, 0x20, 0x60, 0x21, 0x22, 0xE0, 0xD7, 0x13, 
+	0x45, 0xC1, 0x02, 0x16, 0x85, 0x07, 0xFE, 0x7F, 
+	0x8F, 0x05, 0x86, 0xD1, 0x0B, 0x13, 0xA0, 0x25, 
+	0x26, 0xE0, 0x08, 0x13, 0x8F, 0x05, 0x20, 0x26, 
+	0x22, 0xE0, 0x04, 0x16, 0x8F, 0x05, 0xA0, 0x26, 
+	0x22, 0xE0, 0x02, 0x13, 0x60, 0x04, 0x94, 0xB7, 
+	0x01, 0xD8, 0xEC, 0x08, 0x20, 0xD8, 0xDB, 0x07, 
+	0x00, 0x09, 0x02, 0xD8, 0xF6, 0x08, 0x20, 0xD8, 
+	0xDD, 0x07, 0xE2, 0x08, 0xE0, 0x02, 0x58, 0x07, 
+	0x20, 0xD8, 0xEF, 0x07, 0xF4, 0x07, 0x20, 0xD8, 
+	0xF1, 0x07, 0xF6, 0x07, 0x20, 0xD8, 0xF3, 0x07, 
+	0xF8, 0x07, 0x09, 0x02, 0x06, 0x00, 0xCB, 0x04, 
+	0x0F, 0x02, 0xEE, 0x07, 0x8F, 0x05, 0xCB, 0xDF, 
+	0x09, 0x06, 0xFC, 0x16, 0xA0, 0x06, 0xBE, 0xB7, 
+	0x89, 0x07, 0x5C, 0xE3, 0xE0, 0x04, 0x1A, 0x01, 
+	0x20, 0xC8, 0xE4, 0x07, 0x18, 0x01, 0x19, 0xC8, 
+	0x0C, 0x01, 0x39, 0xC8, 0x0A, 0x01, 0x39, 0xC8, 
+	0x12, 0x01, 0x09, 0x16, 0x79, 0xC3, 0x0F, 0x02, 
+	0x00, 0xE0, 0x4F, 0x63, 0x2D, 0x02, 0x00, 0x90, 
+	0x0D, 0xC8, 0x14, 0x01, 0x02, 0x10, 0x39, 0xC8, 
+	0x14, 0x01, 0xF9, 0xC3, 0x3F, 0xC8, 0x0E, 0x01, 
+	0x1F, 0xC8, 0x10, 0x01, 0xE0, 0x04, 0x14, 0x09, 
+	0xB9, 0xC2, 0x1A, 0xC8, 0x00, 0x01, 0x96, 0x06, 
+	0x89, 0x02, 0x84, 0xE3, 0xE0, 0x16, 0x8F, 0x07, 
+	0x1C, 0xFF, 0x8C, 0x07, 0x00, 0x0A, 0x8D, 0x07, 
+	0x84, 0xE3, 0x8E, 0x07, 0x10, 0x00, 0x7C, 0x8F, 
+	0x44, 0x16, 0x4E, 0x06, 0xFC, 0x16, 0xA0, 0xC3, 
+	0xE2, 0x07, 0xE0, 0xC3, 0xE0, 0x07, 0xCE, 0x83, 
+	0x01, 0x14, 0xCE, 0xC3, 0x0F, 0xC8, 0x1A, 0x01, 
+	0x8C, 0x07, 0x94, 0xE3, 0x8D, 0x07, 0x00, 0x0A, 
+	0x8E, 0x07, 0xA4, 0xE3, 0x8C, 0x63, 0x7C, 0xCF, 
+	0x4E, 0x06, 0xFD, 0x16, 0xE0, 0x04, 0x30, 0x09, 
+	0x20, 0x01, 0x42, 0x01, 0x00, 0x04, 0x02, 0x16, 
+	0x20, 0x07, 0x30, 0x09, 0x60, 0xC2, 0x62, 0x01, 
+	0xE0, 0x04, 0x62, 0x01, 0x8E, 0x07, 0x00, 0x80, 
+	0x8C, 0x07, 0x34, 0x09, 0x8D, 0x07, 0x06, 0x00, 
+	0x3E, 0xDF, 0x8E, 0x05, 0x0D, 0x06, 0xFC, 0x16, 
+	0xFE, 0xD3, 0xCF, 0x06, 0x8E, 0x05, 0xFE, 0xD3, 
+	0xCF, 0x06, 0x8C, 0x07, 0x34, 0x09, 0x09, 0xC8, 
+	0x62, 0x01, 0xC9, 0x04, 0x5C, 0xA3, 0x7C, 0xE2, 
+	0x5C, 0xA3, 0x7C, 0xE2, 0x5C, 0xA3, 0x7C, 0xE2, 
+	0x02, 0x13, 0xCD, 0x83, 0x09, 0x13, 0x20, 0x07, 
+	0x34, 0x09, 0x06, 0x10, 0x8F, 0x07, 0x19, 0xFF, 
+	0xCD, 0xA3, 0x0F, 0xC8, 0x04, 0x01, 0xFF, 0x10, 
+	0xA0, 0x01, 0x02, 0x01, 0x00, 0x10, 0xE0, 0xC3, 
+	0xEE, 0x07, 0xE0, 0x43, 0x06, 0xE0, 0x0F, 0xC8, 
+	0x00, 0x01, 0x20, 0xC0, 0x04, 0xE0, 0xE0, 0x04, 
+	0xFE, 0x06, 0xD3, 0x04, 0xE0, 0x04, 0x04, 0x01, 
+	0x60, 0x04, 0x0C, 0xB8, 0x8C, 0x07, 0x00, 0x0A, 
+	0x8D, 0x07, 0x18, 0x00, 0x8E, 0x07, 0x3B, 0x59, 
+	0x0E, 0xCF, 0x4D, 0x06, 0xFD, 0x16, 0x5B, 0x04, 
+	0x93, 0x01, 0x00, 0x80, 0x20, 0x04, 0xC0, 0xE2, 
+	0x60, 0xD0, 0x98, 0x07, 0x1C, 0x13, 0x00, 0x03, 
+	0x02, 0x00, 0xA0, 0xC0, 0x46, 0x07, 0x12, 0xC8, 
+	0x46, 0x07, 0x02, 0x16, 0x93, 0x01, 0x20, 0x00, 
+	0x00, 0x03, 0x0F, 0x00, 0x20, 0x04, 0xE8, 0xE2, 
+	0x93, 0x01, 0x00, 0x20, 0x80, 0x01, 0x00, 0x40, 
+	0x00, 0x01, 0xFE, 0x00, 0x49, 0x16, 0xC4, 0xC3, 
+	0x25, 0x16, 0xD3, 0xC3, 0xC5, 0x43, 0x0C, 0x16, 
+	0xE0, 0xC3, 0x98, 0x07, 0x03, 0x11, 0xE0, 0x02, 
+	0x98, 0x07, 0x51, 0x04, 0xE0, 0xC3, 0x78, 0x07, 
+	0x0A, 0x11, 0xE0, 0x02, 0x78, 0x07, 0x51, 0x04, 
+	0xD3, 0x11, 0x4F, 0x01, 0x00, 0x20, 0xE4, 0x13, 
+	0x4F, 0x01, 0x20, 0x00, 0xD1, 0x13, 0x05, 0x2C, 
+	0x41, 0xA0, 0x21, 0x04, 0xC0, 0xE2, 0x8B, 0x07, 
+	0x0C, 0xB8, 0x00, 0x01, 0x00, 0x40, 0x0F, 0x13, 
+	0xDD, 0xC3, 0x4F, 0x02, 0x0F, 0x00, 0x2F, 0xE1, 
+	0x14, 0xE0, 0x5B, 0x04, 0xE4, 0xC3, 0xC0, 0xE1, 
+	0xCF, 0x73, 0x2F, 0x41, 0x14, 0xE0, 0x6F, 0xC3, 
+	0xEC, 0xEA, 0x8B, 0x07, 0x0C, 0xB8, 0x4B, 0xC2, 
+	0xA0, 0xC2, 0xF4, 0x07, 0x8C, 0x07, 0x08, 0x00, 
+	0xBD, 0xC0, 0xA0, 0xC3, 0xEA, 0x07, 0xE0, 0xC3, 
+	0xEC, 0x07, 0xA0, 0x06, 0x00, 0xBA, 0xC0, 0x01, 
+	0x00, 0x40, 0x02, 0xD8, 0x17, 0x01, 0x62, 0x02, 
+	0x80, 0xFF, 0xA0, 0x06, 0x54, 0xBA, 0x02, 0xC8, 
+	0x04, 0x01, 0x90, 0x03, 0x3F, 0x60, 0x59, 0x04, 
+	0xC0, 0xC3, 0xCF, 0x73, 0xEF, 0xC3, 0xC0, 0xE1, 
+	0xCF, 0x73, 0xAF, 0xC3, 0xDE, 0xEA, 0x9E, 0xC3, 
+	0x4E, 0x02, 0x0F, 0x00, 0x2E, 0x21, 0x14, 0xE0, 
+	0x08, 0x13, 0x2F, 0x40, 0x14, 0xE0, 0xCF, 0xA3, 
+	0x2F, 0x04, 0xF0, 0xE2, 0x40, 0x01, 0x00, 0x40, 
+	0xA4, 0x13, 0xC4, 0xC3, 0xC7, 0x16, 0x00, 0x01, 
+	0xFE, 0x00, 0xE6, 0x16, 0x9E, 0x10, 0x40, 0x01, 
+	0x00, 0x40, 0x05, 0x16, 0x20, 0xE0, 0x14, 0xE0, 
+	0x65, 0x02, 0x00, 0x58, 0x96, 0x10, 0x20, 0xD8, 
+	0xDE, 0x07, 0x17, 0x01, 0x8F, 0x07, 0x86, 0xFF, 
+	0x0F, 0xC8, 0x04, 0x01, 0xC0, 0x01, 0x00, 0x40, 
+	0x45, 0x02, 0xFF, 0xA7, 0x8A, 0x10, 0x20, 0xC3, 
+	0xFE, 0x06, 0x20, 0x27, 0x38, 0xE3, 0x07, 0x13, 
+	0x20, 0x23, 0x22, 0xE0, 0x1A, 0x13, 0x65, 0x02, 
+	0xFF, 0xDF, 0x20, 0x40, 0x14, 0xE0, 0x20, 0xE0, 
+	0x16, 0xE0, 0x0C, 0xC8, 0xE6, 0x08, 0x8D, 0x07, 
+	0xE2, 0x08, 0x58, 0x04, 0x20, 0x48, 0x08, 0xE0, 
+	0xFE, 0x06, 0x20, 0xC3, 0xE6, 0x08, 0x20, 0x27, 
+	0x38, 0xE3, 0x19, 0x16, 0x80, 0x03, 0x02, 0xC3,  
+	0x6C, 0xC2, 0x0A, 0x00, 0x99, 0x06, 0x60, 0x04,  
+	0x0C, 0xB8, 0xA0, 0xC2, 0xF4, 0x07, 0x8C, 0x07, 
+	0x01, 0x00, 0x8D, 0x07, 0x06, 0x06, 0xCE, 0x04, 
+	0xE0, 0xC3, 0x08, 0x06, 0x01, 0x13, 0x97, 0x06, 
+	0x20, 0xD8, 0x07, 0x06, 0x17, 0x01, 0x8B, 0x07, 
+	0x82, 0xFF, 0x0B, 0xC8, 0x04, 0x01, 0xA0, 0x06, 
+	0xB4, 0xBE, 0x60, 0x04, 0x0C, 0xB8, 0xA0, 0xC2, 
+	0xEE, 0x07, 0x8C, 0x07, 0x06, 0x00, 0x8D, 0x07, 
+	0xEE, 0x08, 0xA0, 0xC3, 0xE6, 0x07, 0xE0, 0xC3, 
+	0xE8, 0x07, 0x97, 0x06, 0xA0, 0xC2, 0xF4, 0x07, 
+	0x8D, 0x07, 0xF4, 0x08, 0xDD, 0x04, 0x8C, 0x07, 
+	0x02, 0x00, 0x97, 0x06, 0x8D, 0x07, 0x00, 0x80, 
+	0xA0, 0xC2, 0xEE, 0x08, 0x0A, 0x88, 0x0C, 0x06, 
+	0x14, 0x1B, 0x82, 0x07, 0xD0, 0xB9, 0xA0, 0xC3, 
+	0xF0, 0x08, 0xE0, 0xC3, 0xF2, 0x08, 0x8B, 0x07, 
+	0x0C, 0xE3, 0x8A, 0x02, 0x14, 0x00, 0x04, 0x1A, 
+	0x8B, 0x07, 0xBA, 0xEA, 0x2A, 0x02, 0xEC, 0xFF, 
+	0x8A, 0xA2, 0xCA, 0xA2, 0xDB, 0xC2, 0x01, 0x13, 
+	0x9B, 0x06, 0x20, 0xC8, 0xEE, 0x08, 0xF2, 0x08, 
+	0x20, 0xC8, 0x20, 0xE0, 0xEE, 0x08, 0x0D, 0xC8, 
+	0xF0, 0x08, 0x8D, 0x07, 0xEC, 0x08, 0x20, 0xE0, 
+	0x18, 0xE0, 0x65, 0x02, 0x00, 0x58, 0x58, 0x04, 
+	0x45, 0x02, 0xFF, 0xA7, 0x80, 0x03, 0x60, 0xC0, 
+	0xEE, 0x05, 0x21, 0x02, 0xE8, 0x03, 0x20, 0x01, 
+	0x02, 0x01, 0x06, 0x00, 0x07, 0x16, 0x01, 0x88, 
+	0xEE, 0x05, 0xF9, 0x16, 0x39, 0x10, 0x60, 0xD0, 
+	0x03, 0x01, 0xF1, 0x13, 0x01, 0x02, 0x0A, 0x01, 
+	0x4C, 0xCC, 0x4C, 0xCC, 0x4E, 0xCC, 0x4F, 0xCC, 
+	0xB1, 0x07, 0x40, 0x00, 0x4D, 0xCC, 0x0A, 0xC8, 
+	0x00, 0x01, 0x5B, 0x04, 0x60, 0xC0, 0xEE, 0x05, 
+	0x21, 0x02, 0xE8, 0x03, 0x20, 0x01, 0x02, 0x01, 
+	0x06, 0x00, 0x07, 0x16, 0x01, 0x88, 0xEE, 0x05, 
+	0xF9, 0x16, 0x1E, 0x10, 0x60, 0xD0, 0x03, 0x01, 
+	0xF1, 0x13, 0x01, 0x02, 0x0A, 0x01, 0x4C, 0xCC, 
+	0x4C, 0xCC, 0x4E, 0xCC, 0x4F, 0xCC, 0xB1, 0x07, 
+	0x40, 0x00, 0x4D, 0xCC, 0x0A, 0xC8, 0x00, 0x01, 
+	0xA0, 0x03, 0x60, 0xD0, 0x03, 0x01, 0x01, 0x13, 
+	0x5B, 0x04, 0x60, 0xC0, 0xEE, 0x05, 0x21, 0x02, 
+	0xE8, 0x03, 0x20, 0x01, 0x02, 0x01, 0x06, 0x00, 
+	0xF7, 0x16, 0x01, 0x88, 0xEE, 0x05, 0xF9, 0x16, 
+	0xCD, 0x04, 0x8A, 0x07, 0x00, 0x40, 0x20, 0xC3, 
+	0x00, 0x01, 0x0C, 0x01, 0x00, 0x80, 0x02, 0x13, 
+	0x8A, 0x07, 0x00, 0x20, 0xA0, 0xC3, 0x0E, 0x01, 
+	0xE0, 0xC3, 0x10, 0x01, 0xB0, 0x03, 0x20, 0xC3, 
+	0x58, 0x07, 0x20, 0x23, 0x04, 0xE0, 0x02, 0x13, 
+	0x60, 0x04, 0x8E, 0xB7, 0x60, 0x04, 0x8A, 0xA3, 
+	0x8D, 0x07, 0x00, 0x20, 0x20, 0x20, 0x0A, 0xE0, 
+	0x01, 0x16, 0x5B, 0x04, 0x0D, 0x02, 0x32, 0x0C, 
+	0x5D, 0xC2, 0x01, 0x11, 0xDD, 0x04, 0xCD, 0x05, 
+	0x0D, 0x88, 0x30, 0x0C, 0xF9, 0x16, 0x60, 0xC2, 
+	0x0A, 0x06, 0x8D, 0x07, 0x6A, 0x09, 0xA0, 0x06, 
+	0xF4, 0xBE, 0x09, 0x02, 0x48, 0x00, 0xE0, 0xC3, 
+	0x30, 0x09, 0x03, 0x16, 0xE0, 0x01, 0x6A, 0x09, 
+	0x10, 0x00, 0xE0, 0xC2, 0x6A, 0x09, 0x0F, 0x02, 
+	0x00, 0x01, 0xC9, 0x26, 0x02, 0x13, 0x60, 0x04, 
+	0x86, 0xBD, 0x09, 0x02, 0x00, 0x12, 0x4B, 0x01, 
+	0x10, 0x00, 0x02, 0x13, 0x09, 0x02, 0x00, 0x13, 
+	0x09, 0xD8, 0x2E, 0x09, 0x8F, 0x07, 0x00, 0x40, 
+	0x89, 0x07, 0x6C, 0x09, 0xCB, 0x04, 0xF9, 0xE2, 
+	0xF9, 0xE2, 0xF9, 0xE2, 0x07, 0x16, 0x8B, 0x07, 
+	0x34, 0x09, 0x8C, 0x07, 0x6C, 0x09, 0x3B, 0xCF, 
+	0x3B, 0xCF, 0x1B, 0xC7, 0x20, 0xC3, 0x6C, 0x09, 
+	0x19, 0x11, 0x8F, 0x07, 0x00, 0x20, 0x89, 0x07, 
+	0x7A, 0x09, 0xA0, 0x06, 0x3A, 0xBB, 0xA0, 0x06, 
+	0x3A, 0xBB, 0x12, 0x10, 0x4C, 0xCE, 0x5B, 0x04, 
+	0x19, 0xC3, 0x02, 0x16, 0x8C, 0x07, 0x1A, 0x00, 
+	0x4C, 0xC3, 0x2D, 0x02, 0xF8, 0xFF, 0x0A, 0x02, 
+	0x09, 0x00, 0x2D, 0x02, 0xFA, 0xFF, 0xF2, 0x13, 
+	0x0A, 0x06, 0xFB, 0x16, 0x60, 0x04, 0x86, 0xBD, 
+	0x8F, 0x07, 0x00, 0x10, 0xD9, 0xC2, 0xFA, 0x11, 
+	0x02, 0x16, 0x8B, 0x07, 0x00, 0x04, 0x4B, 0xC3, 
+	0x8D, 0x02, 0x20, 0x00, 0x02, 0x14, 0x0D, 0x02, 
+	0x20, 0x00, 0x8D, 0x02, 0x00, 0x04, 0x02, 0x12, 
+	0x0D, 0x02, 0x00, 0x04, 0x2D, 0x02, 0xF8, 0xFF, 
+	0x0D, 0xC8, 0x2C, 0x09, 0x2B, 0x02, 0xFF, 0x03, 
+	0x8B, 0x01, 0xFF, 0x03, 0x4B, 0xCE, 0x60, 0xC3, 
+	0x6A, 0x09, 0x60, 0x23, 0x18, 0xE0, 0x0C, 0x16, 
+	0x49, 0xC3, 0xDD, 0xC2, 0x0F, 0x02, 0x01, 0x01, 
+	0x8B, 0x01, 0x80, 0xC0, 0xD7, 0x16, 0x8F, 0x05, 
+	0xED, 0xC2, 0x02, 0x00, 0xD3, 0x16, 0x02, 0x10, 
+	0x8D, 0x07, 0xBA, 0xEA, 0x3D, 0xC8, 0xA8, 0x09, 
+	0x1D, 0xC8, 0xAA, 0x09, 0xCB, 0x04, 0xE0, 0x04, 
+	0xF8, 0x05, 0xE0, 0x04, 0x66, 0x09, 0x20, 0xC8, 
+	0x30, 0x0C, 0x80, 0x09, 0xA0, 0x07, 0x82, 0x09, 
+	0xFE, 0xDF, 0x8D, 0x07, 0xFE, 0xDF, 0xE0, 0xC3, 
+	0xD8, 0x07, 0xE0, 0x23, 0x16, 0xE0, 0x24, 0x16, 
+	0xE0, 0xC3, 0x30, 0x0C, 0x4F, 0x63, 0xFF, 0x04, 
+	0xFF, 0x04, 0x4D, 0x06, 0xFD, 0x16, 0x8D, 0x07, 
+	0xFE, 0xDF, 0x20, 0x04, 0xA2, 0xEA, 0xA0, 0xC3, 
+	0xA2, 0xEA, 0xEE, 0xC3, 0x12, 0x00, 0xAA, 0x16, 
+	0x6E, 0xC3, 0x18, 0x00, 0xAD, 0x09, 0x8C, 0x07, 
+	0x00, 0xE0, 0xAC, 0x09, 0x0D, 0x63, 0x0C, 0x13, 
+	0x6E, 0xC3, 0x18, 0x00, 0xAD, 0x09, 0x2D, 0x02, 
+	0x40, 0x00, 0x1D, 0x0A, 0x2D, 0x02, 0x32, 0x0C, 
+	0xBD, 0x07, 0xFF, 0x7F, 0x0C, 0x06, 0xFC, 0x16, 
+	0x20, 0xC3, 0x46, 0x04, 0x8C, 0x02, 0x80, 0x00, 
+	0x13, 0x1A, 0xAC, 0x02, 0x0C, 0xC8, 0x9A, 0x00, 
+	0xE0, 0x02, 0x80, 0x00, 0x88, 0x07, 0x80, 0x00, 
+	0x60, 0xC2, 0x46, 0x04, 0xA0, 0x06, 0x28, 0xAD, 
+	0x02, 0x10, 0x9D, 0x00, 0x05, 0x10, 0x9D, 0x00, 
+	0x8F, 0x07, 0x00, 0x08, 0x60, 0x04, 0x86, 0xBD, 
+	0x4B, 0x2D, 0x81, 0xC3, 0xC9, 0x05, 0x8F, 0x07, 
+	0x00, 0x10, 0x8E, 0x02, 0x02, 0x00, 0xF6, 0x11, 
+	0x8F, 0x07, 0x00, 0x04, 0xC9, 0x05, 0xD9, 0xC2, 
+	0xE0, 0x26, 0x26, 0xE0, 0x02, 0x16, 0x2B, 0x02, 
+	0x06, 0x00, 0x4B, 0xC6, 0x4B, 0xC3, 0xCB, 0x72, 
+	0x2E, 0x02, 0xFE, 0xFF, 0x8B, 0x83, 0xE6, 0x1B, 
+	0xCD, 0x06, 0x4D, 0x73, 0xCD, 0x82, 0xE2, 0x1B, 
+	0xE0, 0x04, 0x1A, 0x09, 0xE0, 0x04, 0x1C, 0x09, 
+	0x4D, 0xC3, 0x02, 0x13, 0x60, 0x66, 0x12, 0xE0, 
+	0xC9, 0x05, 0xCF, 0x04, 0x81, 0x2D, 0x01, 0xC8, 
+	0x6C, 0x01, 0xD4, 0x13, 0x0F, 0xC8, 0x00, 0xFC, 
+	0xC1, 0xC3, 0x0D, 0x06, 0xF7, 0x15, 0x0D, 0x02, 
+	0x36, 0x07, 0x0E, 0x02, 0x98, 0x08, 0x0C, 0x02, 
+	0x03, 0x00, 0x8D, 0xCB, 0x02, 0x00, 0x81, 0x2D, 
+	0x81, 0xCB, 0x06, 0x00, 0xC3, 0x13, 0xEE, 0x04, 
+	0x0C, 0x00, 0x2E, 0x02, 0x18, 0x00, 0x0C, 0x06, 
+	0xF4, 0x16, 0xE0, 0x04, 0x96, 0x08, 0x1F, 0x2E, 
+	0xB9, 0xC3, 0xD9, 0xC3, 0x89, 0x07, 0x12, 0x00, 
+	0x8D, 0x07, 0x3A, 0x09, 0xA0, 0x06, 0xF4, 0xBE, 
+	0x60, 0xC3, 0xD8, 0x07, 0x60, 0x23, 0x16, 0xE0, 
+	0x09, 0x16, 0x20, 0xE8, 0x10, 0xE0, 0x6A, 0x09, 
+	0x20, 0xE8, 0x18, 0xE0, 0x98, 0x07, 0x20, 0xE8, 
+	0x12, 0xE0, 0x78, 0x07, 0x60, 0xC3, 0x6A, 0x09, 
+	0x60, 0x23, 0x1E, 0xE0, 0x03, 0x16, 0x20, 0x48, 
+	0xA4, 0xE3, 0x6A, 0x09, 0x60, 0x23, 0x22, 0xE0, 
+	0x06, 0x13, 0x60, 0x27, 0xA6, 0xE3, 0x03, 0x13, 
+	0x20, 0xE8, 0x10, 0xE0, 0x6A, 0x09, 0x20, 0x2D, 
+	0x00, 0x00, 0x8E, 0x07, 0x00, 0x00, 0xA0, 0x06, 
+	0xD4, 0xBE, 0x4E, 0x05, 0x0E, 0x2C, 0xA0, 0xC0, 
+	0x04, 0x08, 0xEF, 0xC3, 0x06, 0x00, 0x1B, 0x16, 
+	0xA0, 0xC3, 0x72, 0x09, 0xE0, 0xC3, 0x74, 0x09, 
+	0xA0, 0x06, 0xC2, 0xBD, 0xA0, 0xC3, 0x76, 0x09, 
+	0xE0, 0xC3, 0x78, 0x09, 0xA0, 0x06, 0xE0, 0xBD, 
+	0x20, 0xE0, 0x0A, 0xE0, 0x60, 0xC3, 0xD8, 0x07, 
+	0x60, 0x23, 0x16, 0xE0, 0x05, 0x16, 0xE0, 0x04, 
+	0x2E, 0x06, 0x60, 0x41, 0x04, 0xE0, 0x4D, 0x2E, 
+	0x8D, 0x07, 0x00, 0x80, 0x52, 0x04, 0xCF, 0x73, 
+	0x2F, 0x02, 0x00, 0x02, 0x4F, 0xC3, 0x52, 0x04, 
+	0x20, 0x20, 0x0A, 0xE0, 0x03, 0x13, 0x8D, 0x07, 
+	0x00, 0x10, 0x5B, 0x04, 0x20, 0x40, 0x0A, 0xE0, 
+	0x40, 0x02, 0xFF, 0xF0, 0x8E, 0x07, 0x02, 0x00, 
+	0xA0, 0x06, 0xD4, 0xBE, 0x4E, 0x05, 0x0E, 0x2C, 
+	0xA0, 0xC0, 0x04, 0x08, 0xA0, 0x06, 0xB4, 0xBE, 
+	0x60, 0xC3, 0xD8, 0x07, 0x60, 0x23, 0x16, 0xE0, 
+	0x66, 0x16, 0x20, 0x04, 0xB6, 0xEA, 0x63, 0x10, 
+	0x6E, 0x02, 0x00, 0x80, 0x8D, 0x07, 0x00, 0xC0, 
+	0x0D, 0xC8, 0xA6, 0x01, 0x0E, 0xC8, 0x72, 0x09, 
+	0x0F, 0xC8, 0x74, 0x09, 0x0E, 0xC8, 0xA8, 0x01, 
+	0x0F, 0xC8, 0xAA, 0x01, 0x12, 0x10, 0x8F, 0x01, 
+	0x01, 0x00, 0x8A, 0x07, 0x76, 0x09, 0xA0, 0xE3, 
+	0x4E, 0x09, 0x8E, 0xCE, 0x9A, 0x01, 0xFE, 0xFF, 
+	0xE0, 0xE3, 0x50, 0x09, 0x8F, 0xE6, 0x8A, 0x07, 
+	0xAC, 0x01, 0x8E, 0xCE, 0x9A, 0x01, 0xFE, 0xFF, 
+	0x8F, 0xE6, 0x20, 0x20, 0x0A, 0xE0, 0x3F, 0x13, 
+	0x8D, 0x07, 0x00, 0x10, 0x5B, 0x04, 0x20, 0x20, 
+	0x0A, 0xE0, 0x03, 0x13, 0x0D, 0x02, 0x00, 0x10, 
+	0x5B, 0x04, 0x8E, 0xC3, 0x04, 0x13, 0xE0, 0x01, 
+	0x50, 0x09, 0x00, 0x01, 0x06, 0x10, 0xA0, 0x01, 
+	0x50, 0x09, 0x00, 0x01, 0xA0, 0x01, 0x78, 0x09, 
+	0x00, 0x01, 0xA0, 0xC3, 0x76, 0x09, 0xE0, 0xC3, 
+	0x78, 0x09, 0xA0, 0xE3, 0x4E, 0x09, 0xE0, 0xE3, 
+	0x50, 0x09, 0x0E, 0xC8, 0xAC, 0x01, 0x0F, 0xC8, 
+	0xAE, 0x01, 0x0E, 0xC8, 0x76, 0x09, 0x0F, 0xC8, 
+	0x78, 0x09, 0x19, 0x10, 0x6E, 0x02, 0x00, 0x80, 
+	0x0E, 0xC8, 0xA6, 0x01, 0x20, 0x20, 0x0A, 0xE0, 
+	0x12, 0x13, 0x0D, 0x02, 0x00, 0x10, 0x5B, 0x04, 
+	0x8D, 0x07, 0x28, 0x07, 0x89, 0x07, 0x0E, 0x00, 
+	0xA0, 0x06, 0xFA, 0xBE, 0x8D, 0x07, 0x28, 0x07, 
+	0xFD, 0x04, 0x8D, 0x02, 0x36, 0x07, 0xFC, 0x16, 
+	0x20, 0x48, 0x14, 0xE0, 0xFE, 0x06, 0x8D, 0x07, 
+	0x00, 0x80, 0x52, 0x04, 0xA0, 0xC2, 0xEE, 0x07, 
+	0x8C, 0x07, 0x04, 0x00, 0x8D, 0x07, 0xF0, 0x08, 
+	0x97, 0x06, 0x7D, 0xC2, 0x5D, 0xC3, 0x60, 0x43, 
+	0x22, 0xE0, 0xA0, 0x06, 0xFA, 0xBE, 0xEF, 0x10, 
+	0x0E, 0xC8, 0x06, 0x06, 0x0F, 0xC8, 0x08, 0x06, 
+	0xEA, 0x10, 0xB0, 0x03, 0xA0, 0x01, 0x60, 0x07, 
+	0x26, 0x00, 0x40, 0x02, 0x00, 0xC0, 0xE0, 0x04, 
+	0x06, 0x06, 0x8C, 0x07, 0x10, 0x40, 0xCC, 0x44, 
+	0xE0, 0x04, 0xFE, 0x06, 0x85, 0x07, 0x40, 0x80, 
+	0x5B, 0x04, 0x02, 0xC8, 0x04, 0x08, 0x8F, 0x07, 
+	0xFA, 0x07, 0xCE, 0xCB, 0x02, 0x00, 0x8E, 0x07, 
+	0x36, 0x07, 0xCE, 0xCB, 0x04, 0x00, 0x8D, 0x07, 
+	0x30, 0x06, 0x8E, 0x07, 0x10, 0x00, 0x4D, 0x2C, 
+	0x5B, 0x04, 0xA0, 0xC2, 0xF2, 0x07, 0x02, 0x10, 
+	0xA0, 0xC2, 0xF8, 0x07, 0x0B, 0xC8, 0xEA, 0x08, 
+	0x09, 0xC3, 0x0A, 0x13, 0xA0, 0x06, 0x36, 0xBA, 
+	0xA0, 0xC2, 0x00, 0x01, 0xA0, 0xE2, 0x06, 0xE0, 
+	0x4C, 0xA3, 0xCC, 0xA3, 0x01, 0x17, 0x8E, 0x05, 
+	0x4C, 0x62, 0xE0, 0xC2, 0xEA, 0x08, 0x5B, 0x04, 
+	0x8D, 0x07, 0x00, 0x10, 0x20, 0x20, 0x0A, 0xE0, 
+	0x01, 0x13, 0x5B, 0x04, 0x0D, 0x02, 0x48, 0x00, 
+	0xE0, 0xC3, 0x30, 0x09, 0x02, 0x16, 0xCE, 0x01, 
+	0x10, 0x00, 0x8D, 0x27, 0x03, 0x13, 0x0D, 0x02, 
+	0x00, 0x01, 0x52, 0x04, 0x00, 0x03, 0x02, 0x00, 
+	0x60, 0xC3, 0x6A, 0x09, 0x4D, 0x02, 0x08, 0x80, 
+	0x4E, 0x02, 0xF7, 0x7F, 0x8D, 0xE3, 0xE0, 0xC3, 
+	0xD8, 0x07, 0xE0, 0x23, 0x16, 0xE0, 0x04, 0x13, 
+	0x8D, 0x07, 0x06, 0x00, 0x8D, 0x27, 0x02, 0x13, 
+	0xA0, 0xE3, 0x10, 0xE0, 0x0E, 0xC8, 0x6A, 0x09, 
+	0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, 0x09, 0x13, 
+	0x0D, 0x02, 0x00, 0x12, 0x4E, 0x01, 0x10, 0x00, 
+	0x02, 0x13, 0x0D, 0x02, 0x00, 0x13, 0x0D, 0xD8, 
+	0x2E, 0x09, 0x60, 0xC3, 0x80, 0x01, 0x4E, 0x02, 
+	0x01, 0x00, 0x4D, 0x02, 0xFE, 0xFF, 0x4E, 0xE3, 
+	0x0D, 0xC8, 0x80, 0x01, 0x20, 0xD8, 0x40, 0xE2, 
+	0x2F, 0x09, 0x20, 0x01, 0x6A, 0x09, 0x06, 0x00, 
+	0x03, 0x13, 0x20, 0xD8, 0xD0, 0xE1, 0x2F, 0x09, 
+	0x20, 0x98, 0x83, 0x01, 0x00, 0xE2, 0x03, 0x13, 
+	0x20, 0xD8, 0x2F, 0x09, 0x83, 0x01, 0x00, 0x03, 
+	0x0F, 0x00, 0x60, 0x04, 0x88, 0xBE, 0x20, 0x20, 
+	0x0A, 0xE0, 0x03, 0x13, 0x0D, 0x02, 0x00, 0x10, 
+	0x5B, 0x04, 0x09, 0x02, 0x08, 0x00, 0x0D, 0x02, 
+	0x58, 0x09, 0xA0, 0x06, 0xF4, 0xBE, 0xA0, 0x07, 
+	0x02, 0x02, 0x00, 0x00, 0x0D, 0x02, 0x00, 0x04, 
+	0xE0, 0xC3, 0x58, 0x09, 0x0F, 0x01, 0x00, 0x7C, 
+	0x01, 0x13, 0x52, 0x04, 0x8F, 0xC3, 0x4E, 0x02, 
+	0x0F, 0x00, 0xFB, 0x13, 0x8E, 0x02, 0x0F, 0x00, 
+	0xF8, 0x13, 0x0D, 0x02, 0x00, 0x40, 0x4F, 0xC2, 
+	0x49, 0x09, 0x49, 0x02, 0x3F, 0x00, 0x09, 0x01, 
+	0x01, 0x00, 0xEF, 0x16, 0x89, 0x02, 0x06, 0x00, 
+	0xEC, 0x1A, 0x89, 0x02, 0x20, 0x00, 0xE9, 0x14, 
+	0xC9, 0x06, 0x1F, 0x09, 0x4F, 0x02, 0x00, 0x40, 
+	0x4F, 0xE2, 0x69, 0x02, 0x00, 0x80, 0x09, 0xC8, 
+	0x58, 0x09, 0x0F, 0x02, 0xFF, 0xFF, 0x4E, 0xC2, 
+	0x1F, 0x09, 0x09, 0x06, 0xFD, 0x16, 0x4F, 0x05, 
+	0x0D, 0x02, 0x00, 0x20, 0x60, 0xC2, 0x5A, 0x09, 
+	0xD4, 0x13, 0x4F, 0x26, 0xD2, 0x16, 0x0D, 0x02, 
+	0x00, 0x10, 0x60, 0xC2, 0x5C, 0x09, 0xCD, 0x13, 
+	0x4F, 0x26, 0xCB, 0x16, 0x0D, 0x02, 0x00, 0x30, 
+	0x20, 0x88, 0x5A, 0x09, 0x5C, 0x09, 0xC5, 0x13, 
+	0xE0, 0xC3, 0x5A, 0x09, 0x4E, 0xC2, 0x1F, 0x0A, 
+	0x09, 0x06, 0xFD, 0x16, 0xE0, 0xE3, 0x5E, 0x09, 
+	0x0F, 0xC8, 0x5A, 0x09, 0xE0, 0xC3, 0x5C, 0x09, 
+	0x4E, 0xC2, 0x1F, 0x0A, 0x09, 0x06, 0xFD, 0x16, 
+	0xE0, 0xE3, 0x5E, 0x09, 0x0F, 0xC8, 0x5C, 0x09, 
+	0x0F, 0x02, 0xFF, 0xFF, 0x4E, 0xC2, 0x1F, 0x0A, 
+	0x09, 0x06, 0xFD, 0x16, 0x0D, 0x02, 0x00, 0x08, 
+	0x60, 0xC2, 0x5E, 0x09, 0x4F, 0x26, 0xA5, 0x16, 
+	0x4F, 0x05, 0x0F, 0xC8, 0x5E, 0x09, 0x0F, 0x02, 
+	0x02, 0x02, 0x0E, 0x02, 0x03, 0x00, 0x60, 0xC3, 
+	0x40, 0x01, 0x0C, 0x02, 0xFE, 0xC0, 0xA0, 0x01, 
+	0x40, 0x01, 0x00, 0x04, 0xCF, 0x05, 0x09, 0x02, 
+	0x55, 0x55, 0x9C, 0x06, 0x49, 0x05, 0x9C, 0x06, 
+	0x09, 0x07, 0x9C, 0x06, 0x49, 0x05, 0x9C, 0x06, 
+	0x0E, 0x06, 0xF4, 0x16, 0xA0, 0x01, 0x40, 0x01, 
+	0x00, 0x40, 0x0D, 0xC8, 0x40, 0x01, 0x09, 0x02, 
+	0x08, 0x00, 0x0E, 0x02, 0x58, 0x09, 0x0F, 0x02, 
+	0x02, 0x02, 0xFE, 0xCF, 0x49, 0x06, 0xFD, 0x16, 
+	0x60, 0x04, 0x88, 0xBE, 0xC9, 0xC7, 0x5F, 0x82, 
+	0x01, 0x16, 0x5B, 0x04, 0xA0, 0x01, 0x40, 0x01, 
+	0x00, 0x40, 0x0D, 0xC8, 0x40, 0x01, 0x0D, 0x02, 
+	0x00, 0x01, 0x52, 0x04, 0x8D, 0x07, 0x00, 0x10, 
+	0x20, 0x20, 0x0A, 0xE0, 0x0A, 0x16, 0x8D, 0x07, 
+	0x00, 0x08, 0x20, 0x20, 0x10, 0xE0, 0x05, 0x13, 
+	0x8D, 0x07, 0x00, 0x40, 0x4F, 0x01, 0x01, 0x00, 
+	0x01, 0x16, 0x5B, 0x04, 0x20, 0xE0, 0x10, 0xE0, 
+	0x20, 0x07, 0x9C, 0x08, 0x20, 0x07, 0xB4, 0x08, 
+	0x20, 0x07, 0xCC, 0x08, 0xA0, 0x07, 0xA2, 0x08, 
+	0x84, 0x02, 0xA0, 0x07, 0xBA, 0x08, 0x84, 0x02, 
+	0xA0, 0x07, 0xD2, 0x08, 0x84, 0x02, 0xA0, 0x07, 
+	0x04, 0x09, 0x00, 0x40, 0xE0, 0x04, 0x06, 0x09, 
+	0xE0, 0x04, 0x08, 0x09, 0x0E, 0xC8, 0x4C, 0x08, 
+	0x0F, 0xC8, 0x4E, 0x08, 0x0E, 0xC8, 0x8E, 0x08, 
+	0x0F, 0xC8, 0x90, 0x08, 0xE0, 0x04, 0x5A, 0x08, 
+	0xE0, 0x04, 0x60, 0x08, 0xE0, 0x02, 0x78, 0x07, 
+	0xE0, 0x04, 0x94, 0x08, 0x20, 0x40, 0x40, 0xE3, 
+	0x20, 0xE0, 0x0C, 0xE0, 0x60, 0x04, 0xBC, 0xC6, 
+	0x80, 0x01, 0x00, 0xF0, 0xC0, 0x01, 0x00, 0x40, 
+	0x10, 0x10, 0x80, 0x01, 0x00, 0xF0, 0x0D, 0x10, 
+	0xC0, 0x01, 0x00, 0xF0, 0x20, 0x40, 0x06, 0xE0, 
+	0x08, 0x10, 0xC0, 0x01, 0x00, 0xF0, 0x80, 0x01, 
+	0x00, 0x20, 0xE0, 0xC3, 0x94, 0x08, 0x01, 0x16, 
+	0x5B, 0x04, 0x4B, 0xC0, 0x20, 0x04, 0xDA, 0xEA, 
+	0x40, 0x01, 0x00, 0x20, 0xFB, 0x16, 0x51, 0x04, 
+	0xA0, 0xC2, 0xD8, 0x07, 0x4A, 0x01, 0x40, 0x00, 
+	0x01, 0x16, 0x5B, 0x04, 0xE0, 0x02, 0x78, 0x07, 
+	0x20, 0x20, 0x0C, 0xE0, 0xEF, 0x16, 0x43, 0xC2, 
+	0x02, 0x13, 0xA0, 0x06, 0x1A, 0xC3, 0x20, 0x2F, 
+	0x36, 0x07, 0x20, 0x40, 0x0C, 0xE0, 0xA0, 0x06, 
+	0xAC, 0xC1, 0xA0, 0xC3, 0x94, 0x08, 0xFB, 0x16, 
+	0xA0, 0x06, 0x3A, 0xC2, 0x8E, 0x07, 0x04, 0x09, 
+	0x9E, 0x07, 0x00, 0x80, 0x20, 0x20, 0x10, 0xE0, 
+	0x05, 0x16, 0x8F, 0x07, 0x4C, 0x08, 0xBF, 0xCF, 
+	0xBF, 0xCF, 0x9F, 0xC7, 0xA0, 0x06, 0x5A, 0xC2, 
+	0x20, 0xE8, 0x3C, 0xE3, 0x62, 0x07, 0xA0, 0x06, 
+	0x3A, 0xC2, 0x20, 0x48, 0x3C, 0xE3, 0x62, 0x07, 
+	0x20, 0x40, 0x40, 0xE3, 0x20, 0xE0, 0x04, 0xE0, 
+	0x20, 0x48, 0x10, 0xE0, 0x58, 0x07, 0x5B, 0x04, 
+	0x80, 0x01, 0x00, 0xF0, 0x20, 0xE0, 0x04, 0xE0, 
+	0x60, 0x01, 0x60, 0x07, 0x02, 0x00, 0x02, 0x13, 
+	0x9B, 0x06, 0xB8, 0x10, 0x20, 0xE8, 0x1E, 0xE0, 
+	0x58, 0x07, 0xB4, 0x10, 0x9B, 0x06, 0x80, 0x03, 
+	0xE0, 0x02, 0x58, 0x07, 0x00, 0x01, 0x00, 0x40, 
+	0x07, 0x16, 0x8D, 0x07, 0x00, 0x09, 0xA0, 0x06, 
+	0x68, 0xB8, 0xE0, 0x02, 0x78, 0x07, 0x5B, 0x04, 
+	0xC4, 0x01, 0x02, 0x00, 0xE0, 0x02, 0x78, 0x07, 
+	0x5B, 0x04, 0x0E, 0x68, 0x96, 0x08, 0xE9, 0x04, 
+	0x0C, 0x00, 0x11, 0x10, 0x0E, 0x02, 0x00, 0x23, 
+	0x4E, 0xDB, 0x01, 0x00, 0xCC, 0x01, 0x00, 0x04, 
+	0x4C, 0xD7, 0x1C, 0x10, 0x60, 0xC2, 0x5C, 0x07, 
+	0x20, 0x06, 0x94, 0x08, 0xA9, 0xC2, 0x08, 0x00, 
+	0xA9, 0xC3, 0x0C, 0x00, 0xEA, 0x16, 0x29, 0x07, 
+	0x04, 0x00, 0x69, 0x01, 0x0A, 0x00, 0x01, 0x00, 
+	0x2D, 0x13, 0x49, 0xC3, 0x2D, 0x02, 0x0E, 0x00, 
+	0x0A, 0xC3, 0x1D, 0xD3, 0x8C, 0x01, 0x00, 0x84, 
+	0xCC, 0x01, 0x00, 0x40, 0x0A, 0x01, 0x00, 0x5E, 
+	0xDD, 0x16, 0x4C, 0xC7, 0xA9, 0xC3, 0x10, 0x00, 
+	0xE9, 0xC3, 0x12, 0x00, 0x41, 0xCA, 0x10, 0x00, 
+	0x2F, 0x02, 0x04, 0x00, 0x01, 0x17, 0x8E, 0x05, 
+	0x8C, 0x07, 0x02, 0x00, 0xA0, 0xC2, 0xF6, 0x07, 
+	0xA0, 0x06, 0x00, 0xBA, 0x69, 0xC0, 0x10, 0x00, 
+	0x29, 0xC8, 0x14, 0x00, 0x06, 0x09, 0x29, 0xC8, 
+	0x16, 0x00, 0x08, 0x09, 0x69, 0x01, 0x0E, 0x00, 
+	0x00, 0x08, 0x04, 0x16, 0x90, 0x03, 0x7F, 0x00, 
+	0xA0, 0x06, 0x5A, 0xC2, 0x40, 0x01, 0x00, 0x40, 
+	0x01, 0x16, 0x51, 0x04, 0x60, 0x04, 0xBE, 0xC1, 
+	0xA9, 0xC3, 0x0C, 0x00, 0x0B, 0x13, 0x0E, 0x68, 
+	0x96, 0x08, 0xE9, 0x04, 0x0C, 0x00, 0x29, 0xC8, 
+	0x06, 0x00, 0x6C, 0x01, 0xA0, 0xC3, 0x00, 0xFC, 
+	0x01, 0x13, 0x1E, 0x2E, 0x29, 0x07, 0x04, 0x00, 
+	0x5B, 0x04, 0x81, 0x07, 0x20, 0x20, 0x89, 0x07, 
+	0x4C, 0x08, 0x41, 0xCE, 0x63, 0xCE, 0x10, 0x00, 
+	0x63, 0xC6, 0x12, 0x00, 0xA0, 0x06, 0x54, 0xBA, 
+	0x43, 0xC2, 0x02, 0x13, 0xA0, 0x06, 0x1A, 0xC3, 
+	0x20, 0xE0, 0x10, 0xE0, 0x60, 0x04, 0xEC, 0xC1, 
+	0x40, 0x01, 0x00, 0x04, 0xEA, 0x16, 0xA0, 0x06, 
+	0xAC, 0xC1, 0xA0, 0xC2, 0xF0, 0x07, 0x8C, 0x07, 
+	0x04, 0x00, 0x8D, 0x07, 0x4C, 0x08, 0xA0, 0xC3, 
+	0x8E, 0x08, 0xE0, 0xC3, 0x90, 0x08, 0xA0, 0x06, 
+	0x36, 0xBA, 0xE0, 0xC3, 0x4E, 0x08, 0x4F, 0x01, 
+	0x01, 0x00, 0x13, 0x16, 0xE0, 0xC2, 0x94, 0x08, 
+	0xEA, 0x16, 0x60, 0x04, 0xEC, 0xC1, 0xE0, 0xC3, 
+	0x4E, 0x08, 0x4F, 0x01, 0x01, 0x00, 0x09, 0x16, 
+	0x60, 0x04, 0xEC, 0xC1, 0xA0, 0x06, 0x54, 0xBA, 
+	0xE0, 0xC3, 0x4E, 0x08, 0x4F, 0x01, 0x01, 0x00, 
+	0xD7, 0x13, 0xA0, 0xC2, 0xF0, 0x07, 0x20, 0xC3, 
+	0x7C, 0x09, 0x8D, 0x07, 0x4C, 0x08, 0x9D, 0xC3, 
+	0xA0, 0x06, 0x36, 0xBA, 0xC0, 0x06, 0x20, 0xD0, 
+	0x50, 0x08, 0xC0, 0x06, 0x40, 0x01, 0x00, 0x04, 
+	0x0A, 0x16, 0x40, 0x01, 0x80, 0x00, 0x07, 0x13, 
+	0x0E, 0xC8, 0x4C, 0x08, 0x0F, 0xC8, 0x4E, 0x08, 
+	0xA0, 0x06, 0xA2, 0xC1, 0xD8, 0x10, 0x0E, 0xC8, 
+	0x8E, 0x08, 0x0F, 0xC8, 0x90, 0x08, 0x40, 0x01, 
+	0x00, 0x04, 0x0C, 0x13, 0x40, 0x01, 0x20, 0x00, 
+	0x58, 0x16, 0x81, 0x07, 0x10, 0x20, 0x9F, 0x10, 
+	0xA0, 0x06, 0xAC, 0xC1, 0xA0, 0xC3, 0x8E, 0x08, 
+	0xE0, 0xC3, 0x90, 0x08, 0x83, 0x07, 0x98, 0x08, 
+	0x63, 0x07, 0x04, 0x00, 0x2D, 0x11, 0x83, 0x07, 
+	0xB0, 0x08, 0x63, 0x07, 0x04, 0x00, 0x28, 0x11, 
+	0x83, 0x07, 0xC8, 0x08, 0x63, 0x07, 0x04, 0x00, 
+	0x23, 0x11, 0xC3, 0x60, 0x60, 0xC2, 0x46, 0x07, 
+	0xE7, 0x13, 0x69, 0x01, 0x0E, 0x00, 0x00, 0x08, 
+	0xE3, 0x13, 0x00, 0x03, 0x02, 0x00, 0x19, 0xC8, 
+	0x46, 0x07, 0x03, 0x16, 0xA0, 0x01, 0x3A, 0x07, 
+	0x20, 0x00, 0x00, 0x03, 0x0F, 0x00, 0xC0, 0x01, 
+	0x00, 0xF0, 0x80, 0x01, 0x00, 0x20, 0x01, 0x02, 
+	0x06, 0xC4, 0x60, 0x04, 0x9A, 0xC2, 0x81, 0x07, 
+	0x80, 0x20, 0xE0, 0xC8, 0x8E, 0x08, 0x14, 0x00, 
+	0xE0, 0xC8, 0x90, 0x08, 0x16, 0x00, 0xC7, 0x10, 
+	0xE0, 0xC8, 0x50, 0x08, 0x0E, 0x00, 0xCE, 0xC8, 
+	0x10, 0x00, 0xCF, 0xC8, 0x12, 0x00, 0x40, 0x01, 
+	0x20, 0x00, 0xBB, 0x16, 0xE3, 0xC1, 0x06, 0x00, 
+	0xC7, 0xC8, 0x08, 0x00, 0x07, 0xC8, 0x6C, 0x01, 
+	0x07, 0xC8, 0xE0, 0x08, 0x08, 0x02, 0x02, 0xFC, 
+	0xB8, 0x07, 0x00, 0x81, 0xE0, 0xC1, 0xE8, 0x00, 
+	0x07, 0xCE, 0x20, 0xC8, 0x52, 0x08, 0x92, 0x08, 
+	0xDA, 0x13, 0xCE, 0xC8, 0x14, 0x00, 0xCF, 0xC8, 
+	0x16, 0x00, 0x80, 0x01, 0x00, 0x04, 0x82, 0x07, 
+	0x54, 0x08, 0x32, 0xC1, 0x08, 0x11, 0x72, 0xC1, 
+	0x92, 0xC1, 0x82, 0x07, 0x8A, 0x08, 0x04, 0xC1, 
+	0x07, 0x16, 0x60, 0x04, 0x8E, 0xC5, 0x72, 0xC1, 
+	0xB2, 0xC1, 0x84, 0x01, 0x00, 0x80, 0xF9, 0x13, 
+	0x04, 0x68, 0x92, 0x08, 0xC7, 0xC1, 0x37, 0x16, 
+	0x20, 0x98, 0x97, 0x08, 0x85, 0x09, 0x16, 0x16, 
+	0x81, 0x07, 0x40, 0x20, 0xE0, 0xC1, 0x94, 0x08, 
+	0x57, 0x13, 0xA0, 0x06, 0xAC, 0xC1, 0xF4, 0x10, 
+	0xE0, 0xC2, 0x3A, 0x07, 0xE0, 0x42, 0x62, 0x07, 
+	0xE0, 0x26, 0x3A, 0xE3, 0x02, 0x13, 0xA0, 0x06, 
+	0x92, 0xC1, 0xA0, 0x06, 0x54, 0xBA, 0x22, 0x10, 
+	0xA0, 0x06, 0x9C, 0xC1, 0x81, 0x2D, 0x01, 0xC2, 
+	0xFB, 0x13, 0xA0, 0x05, 0x96, 0x08, 0x23, 0xC8, 
+	0x08, 0x00, 0x6C, 0x01, 0xA0, 0x07, 0x02, 0xFC, 
+	0x00, 0x80, 0xC3, 0xC1, 0x27, 0x02, 0x06, 0x00, 
+	0xA0, 0x06, 0x0C, 0xB5, 0xA3, 0x05, 0x0C, 0x00, 
+	0x08, 0xC8, 0x6C, 0x01, 0x08, 0xC8, 0xE0, 0x08, 
+	0x08, 0x02, 0x02, 0xFC, 0xB8, 0x07, 0x00, 0x81, 
+	0xF8, 0xC1, 0x04, 0xC1, 0x37, 0x13, 0xE0, 0xD2, 
+	0x03, 0x01, 0xD2, 0x13, 0x0B, 0x02, 0x0A, 0x01, 
+	0xC4, 0xCE, 0xC7, 0xCE, 0xC5, 0xCE, 0xC6, 0xCE, 
+	0xFB, 0x04, 0x09, 0x02, 0x00, 0x04, 0x48, 0xA2, 
+	0xC9, 0xC6, 0x20, 0xA8, 0xE0, 0x08, 0x12, 0x01, 
+	0x20, 0xC8, 0xF2, 0x07, 0x00, 0x01, 0x47, 0xC2, 
+	0xC4, 0x81, 0x01, 0x14, 0x44, 0xC2, 0xC9, 0x61, 
+	0x09, 0xA2, 0x89, 0xA1, 0x01, 0x17, 0x85, 0x05, 
+	0x09, 0x61, 0xA8, 0x16, 0x82, 0x02, 0x8A, 0x08, 
+	0x05, 0x16, 0x40, 0x01, 0x10, 0x00, 0x12, 0x13, 
+	0x60, 0x04, 0xA6, 0xC3, 0x60, 0x04, 0xBC, 0xC4, 
+	0x60, 0x04, 0x40, 0xC3, 0x81, 0x07, 0x80, 0x20, 
+	0xFB, 0x10, 0x81, 0x07, 0x80, 0x20, 0xF8, 0x10, 
+	0x81, 0x07, 0x02, 0x20, 0xF5, 0x10, 0x81, 0x07, 
+	0x04, 0x20, 0xF2, 0x10, 0x23, 0xC8, 0x08, 0x00, 
+	0x6C, 0x01, 0x07, 0x05, 0xE0, 0xA1, 0xE8, 0x00, 
+	0x0C, 0x02, 0x04, 0xFC, 0x07, 0xCF, 0xE0, 0xC2, 
+	0x92, 0x08, 0xE8, 0x16, 0xE0, 0xD2, 0x03, 0x01, 
+	0x10, 0x16, 0xE0, 0xC2, 0x3A, 0x07, 0xE0, 0x42, 
+	0x62, 0x07, 0xE0, 0x26, 0x3A, 0xE3, 0x07, 0x13, 
+	0x90, 0x03, 0xC8, 0x2F, 0xA0, 0x06, 0x92, 0xC1, 
+	0xE0, 0xD2, 0x03, 0x01, 0x02, 0x16, 0xA0, 0x06, 
+	0x54, 0xBA, 0x23, 0xC8, 0x06, 0x00, 0x6C, 0x01, 
+	0xA3, 0xC2, 0x0E, 0x00, 0x4A, 0x01, 0x00, 0x01, 
+	0x0B, 0x13, 0x0C, 0x02, 0x0E, 0xFC, 0x5C, 0xC2, 
+	0x49, 0x02, 0x00, 0x80, 0x0D, 0x02, 0x6C, 0x09, 
+	0x7D, 0xE2, 0x09, 0xCF, 0x3D, 0xCF, 0x3D, 0xCF, 
+	0x0C, 0x02, 0x00, 0xFC, 0x6C, 0xC3, 0x06, 0x00, 
+	0x4D, 0x02, 0xFF, 0xE0, 0x4A, 0x02, 0x00, 0x02, 
+	0x8A, 0xA2, 0x8A, 0xA2, 0x4A, 0xE3, 0x60, 0xE3,  
+	0x9E, 0x09, 0x0D, 0xCB, 0x06, 0x00, 0xCD, 0x06, 
+	0x0B, 0x02, 0x0F, 0x00, 0xEC, 0x82, 0x04, 0x00, 
+	0xAD, 0x11, 0xEC, 0xC3, 0x0E, 0x00, 0x11, 0x15, 
+	0x10, 0x13, 0x6C, 0xC2, 0x14, 0x00, 0x49, 0x02, 
+	0x00, 0x1F, 0xA7, 0x13, 0xC9, 0x06, 0x89, 0x02, 
+	0x12, 0x00, 0xA3, 0x1B, 0x49, 0x01, 0x01, 0x00, 
+	0xA0, 0x13, 0xC9, 0xA2, 0xEC, 0x82, 0x04, 0x00, 
+	0x9C, 0x11, 0x4D, 0xA3, 0x9D, 0x18, 0x14, 0x11, 
+	0x60, 0x01, 0x6A, 0x09, 0x00, 0x80, 0x18, 0x13, 
+	0x1D, 0x09, 0xCC, 0xA2, 0xEB, 0xC2, 0x08, 0x00, 
+	0x7B, 0x09, 0x4B, 0x02, 0x1E, 0x00, 0xA0, 0xC3, 
+	0xF0, 0x06, 0xAB, 0x23, 0x04, 0xE0, 0x8F, 0x16, 
+	0x60, 0x27, 0x3E, 0xE3, 0x8C, 0x16, 0x4D, 0xA3, 
+	0x4D, 0xA3, 0x4D, 0xA3, 0xCD, 0x06, 0x4D, 0x02, 
+	0x07, 0x00, 0x0D, 0x88, 0xEE, 0x06, 0x0A, 0x15, 
+	0x90, 0x03, 0xFF, 0x6F, 0x53, 0x2F, 0xA0, 0x05, 
+	0x94, 0x08, 0xC3, 0x04, 0xC0, 0x01, 0x00, 0x04, 
+	0x60, 0x04, 0xAA, 0xC3, 0x60, 0x01, 0x6A, 0x09, 
+	0x00, 0x80, 0xF2, 0x13, 0x01, 0x02, 0x08, 0x20, 
+	0x60, 0x04, 0xA2, 0xC5, 0x8D, 0x07, 0x00, 0x10, 
+	0x20, 0x20, 0x0A, 0xE0, 0x0A, 0x16, 0x8D, 0x07, 
+	0x00, 0x08, 0x20, 0x20, 0x0E, 0xE0, 0x05, 0x13, 
+	0x8D, 0x07, 0x00, 0x40, 0x4F, 0x01, 0x01, 0x00, 
+	0x01, 0x16, 0x5B, 0x04, 0x20, 0xE0, 0x0E, 0xE0, 
+	0xA0, 0x07, 0xFA, 0x08, 0x00, 0x80, 0x0E, 0xC8,  
+	0xFA, 0x07, 0x0F, 0xC8, 0xFC, 0x07, 0x0E, 0xC8,  
+	0x3C, 0x08, 0x0F, 0xC8, 0x3E, 0x08, 0xE0, 0x04,  
+	0x08, 0x08, 0xE0, 0x04, 0x0E, 0x08, 0xE0, 0x02,  
+	0x98, 0x07, 0x20, 0x40, 0x4C, 0xE3, 0x20, 0x07, 
+	0x2E, 0x06, 0x60, 0x04, 0x12, 0xCA, 0x00, 0x70, 
+	0x4B, 0xC0, 0xE0, 0x04, 0x2E, 0x06, 0x0B, 0x10, 
+	0x20, 0xF0, 0x4B, 0xE3, 0x02, 0x10, 0x20, 0xF0, 
+	0x4A, 0xE3, 0x4B, 0xC0, 0xE0, 0x04, 0x2E, 0x06, 
+	0xE0, 0x01, 0x62, 0x07, 0x40, 0x00, 0x20, 0xE8, 
+	0x46, 0xE3, 0x62, 0x07, 0x20, 0x04, 0xDA, 0xEA,  
+	0x40, 0x01, 0x00, 0x20, 0x04, 0x13, 0xFA, 0x10,  
+	0x40, 0x01, 0x00, 0x40, 0xF7, 0x16, 0x20, 0x07,  
+	0x2E, 0x06, 0x20, 0x50, 0x50, 0xE3, 0x51, 0x04, 
+	0xF1, 0x10, 0xE0, 0x02, 0x58, 0x07, 0x00, 0x01, 
+	0x00, 0x40, 0x07, 0x16, 0x8D, 0x07, 0xF6, 0x08, 
+	0xA0, 0x06, 0x68, 0xB8, 0xE0, 0x02, 0x98, 0x07, 
+	0x5B, 0x04, 0xC4, 0x01, 0x04, 0x00, 0xE0, 0x02, 
+	0x98, 0x07, 0x5B, 0x04, 0x60, 0x01, 0x60, 0x07, 
+	0x04, 0x00, 0x06, 0x16, 0x20, 0xE8, 0x1C, 0xE0, 
+	0x58, 0x07, 0x80, 0x03, 0xE0, 0x02, 0x98, 0x07, 
+	0x20, 0xD8, 0xDC, 0x07, 0x17, 0x01, 0x8F, 0x07, 
+	0x8E, 0xFF, 0x0F, 0xC8, 0x04, 0x01, 0x20, 0xE8, 
+	0x06, 0xE0, 0x58, 0x07, 0x80, 0x01, 0x00, 0x80, 
+	0x5B, 0x04, 0xE0, 0xC2, 0x4A, 0x08, 0xC3, 0x82, 
+	0x03, 0x13, 0xDB, 0x2D, 0x03, 0xC8, 0x4A, 0x08, 
+	0x49, 0x01, 0x00, 0x01, 0x02, 0x16, 0x60, 0x04, 
+	0x52, 0xC9, 0xE0, 0xC0, 0xF8, 0x05, 0xFD, 0x13, 
+	0x03, 0xC8, 0x6C, 0x01, 0x20, 0xC8, 0x00, 0xFC, 
+	0xF8, 0x05, 0x88, 0x07, 0x02, 0xFC, 0x78, 0xC2, 
+	0xF8, 0xC1, 0x28, 0x02, 0x00, 0x04, 0x49, 0x01, 
+	0x00, 0x01, 0x4D, 0x16, 0x09, 0x01, 0x00, 0x5E, 
+	0x29, 0x16, 0x49, 0x01, 0x02, 0x00, 0x0B, 0x16, 
+	0x60, 0x01, 0x46, 0x08, 0x00, 0x02, 0x0A, 0x16, 
+	0x27, 0x02, 0x04, 0x00, 0x07, 0x88, 0x7E, 0x09, 
+	0x05, 0x12, 0x27, 0x02, 0xFC, 0xFF, 0xA0, 0x01, 
+	0x46, 0x08, 0x00, 0x02, 0xC7, 0xC1, 0x37, 0x15, 
+	0xD3, 0x2D, 0xE0, 0xC0, 0x4A, 0x08, 0x07, 0xA8, 
+	0x48, 0x08, 0x07, 0xA8, 0x44, 0x08, 0x0C, 0x15, 
+	0x20, 0xC8, 0x3C, 0x08, 0xFA, 0x07, 0x20, 0xC8, 
+	0x3E, 0x08, 0xFC, 0x07, 0x20, 0xC8, 0x40, 0x08, 
+	0x3C, 0x08, 0x20, 0xC8, 0x42, 0x08, 0x3E, 0x08, 
+	0x60, 0x04, 0x52, 0xC9, 0xA0, 0x06, 0x54, 0xBA, 
+	0xD3, 0x2D, 0xE0, 0xC2, 0x4A, 0x08, 0xC3, 0x82, 
+	0x01, 0x13, 0xDB, 0x2D, 0x20, 0x88, 0x3E, 0x08, 
+	0x3A, 0x08, 0x0D, 0x16, 0x20, 0x88, 0x3C, 0x08, 
+	0x38, 0x08, 0x09, 0x16, 0xE0, 0x04, 0x44, 0x08, 
+	0x82, 0x07, 0x02, 0x08, 0x04, 0x61, 0xE0, 0x04, 
+	0x48, 0x08, 0x60, 0x04, 0x1E, 0xCA, 0x20, 0xC8, 
+	0x38, 0x08, 0xFA, 0x07, 0x20, 0xC8, 0x3A, 0x08, 
+	0xFC, 0x07, 0x60, 0x04, 0x12, 0xCA, 0x07, 0xA8, 
+	0x48, 0x08, 0x04, 0xC1, 0x1B, 0x16, 0x82, 0x02, 
+	0x38, 0x08, 0x0A, 0x16, 0x60, 0x01, 0xFC, 0x07, 
+	0x01, 0x00, 0x02, 0x16, 0xA0, 0x06, 0x6E, 0xCB, 
+	0xA0, 0x06, 0xFC, 0xCA, 0x80, 0x01, 0x10, 0x00, 
+	0x32, 0xC1, 0x07, 0x11, 0x72, 0xC1, 0x92, 0xC1, 
+	0x82, 0x07, 0x38, 0x08, 0x04, 0xC1, 0x06, 0x16, 
+	0xEA, 0x10, 0x72, 0xC1, 0xB2, 0xC1, 0x84, 0x01, 
+	0x00, 0x80, 0xE5, 0x13, 0xE0, 0xD2, 0x03, 0x01, 
+	0x34, 0x13, 0x0B, 0x02, 0x0A, 0x01, 0xC4, 0xCE, 
+	0xC7, 0xCE, 0xC5, 0xCE, 0xC6, 0xCE, 0xFB, 0x04, 
+	0xC8, 0xC6, 0x03, 0xA8, 0x12, 0x01, 0x20, 0xC8, 
+	0xF8, 0x07, 0x00, 0x01, 0xC7, 0xC2, 0xC4, 0x81, 
+	0x01, 0x14, 0xC4, 0xC2, 0x0B, 0xA8, 0x44, 0x08, 
+	0x0B, 0x61, 0x0B, 0xA2, 0x8B, 0xA1, 0x01, 0x17, 
+	0x85, 0x05, 0xCB, 0x61, 0xC6, 0x16, 0x40, 0x01, 
+	0x40, 0x00, 0x15, 0x16, 0x87, 0x07, 0x20, 0x00, 
+	0xE0, 0x61, 0x44, 0x08, 0xC4, 0x81, 0x08, 0x1A, 
+	0x07, 0xA8, 0x48, 0x08, 0x07, 0xA8, 0x44, 0x08, 
+	0x07, 0x61, 0x87, 0xA1, 0x01, 0x17, 0x85, 0x05, 
+	0x80, 0x01, 0x40, 0x00, 0x03, 0xC8, 0x6C, 0x01, 
+	0xE0, 0xC1, 0x04, 0xFC, 0xAC, 0x10, 0x60, 0x04, 
+	0xBC, 0xC7, 0x20, 0x01, 0x3A, 0x07, 0x00, 0x70, 
+	0x04, 0x13, 0xA0, 0x06, 0x28, 0xC7, 0x20, 0x07, 
+	0x2E, 0x06, 0xA0, 0x06, 0x54, 0xBA, 0xC1, 0x10, 
+	0xE0, 0xD2, 0x03, 0x01, 0x0A, 0x16, 0x20, 0x01, 
+	0x3A, 0x07, 0x00, 0x70, 0x04, 0x13, 0xA0, 0x06, 
+	0x28, 0xC7, 0x20, 0x07, 0x2E, 0x06, 0xA0, 0x06, 
+	0x54, 0xBA, 0x90, 0x03, 0xBF, 0x4F, 0xD3, 0x2D, 
+	0x60, 0x01, 0xFC, 0x07, 0x01, 0x00, 0x02, 0x16, 
+	0xA0, 0x06, 0x6E, 0xCB, 0x60, 0xD2, 0x46, 0x08, 
+	0x89, 0x01, 0x00, 0xF1, 0xC9, 0x01, 0x00, 0x70, 
+	0x40, 0x01, 0x10, 0x00, 0x1C, 0x13, 0x20, 0x88, 
+	0x3E, 0x08, 0x3A, 0x08, 0x04, 0x16, 0x20, 0x88, 
+	0x3C, 0x08, 0x38, 0x08, 0x14, 0x13, 0x89, 0x01, 
+	0x00, 0x10, 0x8D, 0x07, 0x44, 0x08, 0x9D, 0x07, 
+	0x00, 0x50, 0xA0, 0xC2, 0xF6, 0x07, 0x8C, 0x07, 
+	0x02, 0x00, 0xA0, 0xC3, 0x3C, 0x08, 0xE0, 0xC3, 
+	0x3E, 0x08, 0x2F, 0x02, 0x04, 0x00, 0x01, 0x17, 
+	0x8E, 0x05, 0xA0, 0x06, 0x00, 0xBA, 0x8D, 0x07, 
+	0x46, 0x08, 0x49, 0xC7, 0xA0, 0xC2, 0xF6, 0x07, 
+	0x8C, 0x07, 0x04, 0x00, 0xA0, 0xC3, 0x38, 0x08, 
+	0xE0, 0xC3, 0x3A, 0x08, 0xCC, 0xA3, 0x01, 0x17, 
+	0x8E, 0x05, 0xA0, 0x06, 0x00, 0xBA, 0x20, 0xC8, 
+	0x3C, 0x08, 0xFC, 0x08, 0x20, 0xC8, 0x3E, 0x08, 
+	0xFE, 0x08, 0x09, 0x01, 0x00, 0x0C, 0x0C, 0x13, 
+	0x49, 0x01, 0x00, 0x04, 0x05, 0x16, 0xA0, 0x06, 
+	0x6C, 0xC7, 0xA0, 0x06, 0x38, 0xC7, 0x04, 0x10, 
+	0x90, 0x03, 0x7F, 0x40, 0xA0, 0x06, 0x6C, 0xC7, 
+	0xC0, 0x01, 0x90, 0x00, 0xA0, 0x06, 0xFC, 0xCA, 
+	0x0B, 0xC8, 0x46, 0x08, 0xE0, 0xC2, 0x42, 0x07, 
+	0x2D, 0x13, 0xE0, 0xC2, 0x2E, 0x06, 0x2A, 0x13, 
+	0xE0, 0x02, 0x58, 0x07, 0x8F, 0x07, 0xBF, 0xFF, 
+	0x0F, 0x2C, 0xE0, 0x02, 0x98, 0x07, 0xE0, 0xC0, 
+	0x5C, 0x07, 0x03, 0xC8, 0x4A, 0x08, 0x03, 0xC8, 
+	0x6C, 0x01, 0xC3, 0xC2, 0xCB, 0xA2, 0xEB, 0xC2, 
+	0x32, 0x0C, 0x32, 0x13, 0x0B, 0xC8, 0x00, 0xFC, 
+	0x0B, 0xC3, 0x4B, 0xC3, 0x0B, 0xC8, 0x6C, 0x01, 
+	0xE0, 0xC2, 0x00, 0xFC, 0xFA, 0x16, 0x00, 0x03, 
+	0x02, 0x00, 0x20, 0xC8, 0xF8, 0x05, 0x00, 0xFC, 
+	0x02, 0x16, 0x0D, 0xC8, 0xFA, 0x05, 0x0C, 0xC8, 
+	0xF8, 0x05, 0x00, 0x03, 0x0F, 0x00, 0x03, 0xC8, 
+	0x6C, 0x01, 0x1A, 0x10, 0xA0, 0xC3, 0x2E, 0x06, 
+	0x03, 0x13, 0xE0, 0xC0, 0xF8, 0x05, 0x0D, 0x16, 
+	0x4F, 0x2E, 0xC0, 0x01, 0x00, 0x80, 0xA0, 0x01, 
+	0x62, 0x07, 0x00, 0x80, 0x8E, 0xC3, 0x03, 0x13, 
+	0xA0, 0x01, 0x62, 0x07, 0x40, 0x00, 0x60, 0x04, 
+	0x4E, 0xC7, 0x03, 0xC8, 0x6C, 0x01, 0x20, 0xC8, 
+	0x00, 0xFC, 0xF8, 0x05, 0x03, 0xC8, 0x4A, 0x08, 
+	0x60, 0x01, 0x6A, 0x09, 0x00, 0x04, 0x02, 0x13, 
+	0x60, 0x04, 0xE4, 0xC7, 0x8C, 0x07, 0x0E, 0x00, 
+	0x20, 0xC2, 0x0E, 0xFC, 0x0A, 0x15, 0x09, 0x13, 
+	0x20, 0xC2, 0x14, 0xFC, 0x48, 0x02, 0x00, 0x1F, 
+	0xC8, 0x06, 0x88, 0x02, 0x12, 0x00, 0xF0, 0x1B, 
+	0x08, 0xA3, 0x88, 0x07, 0x02, 0xFC, 0x78, 0xC2, 
+	0xF8, 0xC1, 0x28, 0x02, 0x00, 0x04, 0x07, 0x83, 
+	0xE7, 0x1A, 0xCC, 0x61, 0x07, 0xC8, 0x04, 0xFC, 
+	0xCC, 0xC1, 0xC0, 0x01, 0x40, 0x00, 0x60, 0x04, 
+	0xF0, 0xC7, 0x4B, 0xC1, 0xA0, 0xC2, 0xF0, 0x07, 
+	0x20, 0xC3, 0x7A, 0x09, 0x8D, 0x07, 0xFA, 0x07, 
+	0x9D, 0xC3, 0xE0, 0xC3, 0xFC, 0x07, 0xA0, 0x06, 
+	0x00, 0xBA, 0x20, 0xC8, 0x3C, 0x08, 0x40, 0x08, 
+	0x20, 0xC8, 0x3E, 0x08, 0x42, 0x08, 0x0E, 0xC8, 
+	0x3C, 0x08, 0x0F, 0xC8, 0x3E, 0x08, 0xC4, 0x04, 
+	0x82, 0x07, 0x02, 0x08, 0xE0, 0x04, 0x44, 0x08, 
+	0x40, 0x01, 0x80, 0x00, 0x06, 0x16, 0x0E, 0xC8, 
+	0x38, 0x08, 0x0F, 0xC8, 0x3A, 0x08, 0xE0, 0x04, 
+	0x48, 0x08, 0xA0, 0x06, 0x54, 0xBA, 0xE0, 0xC2, 
+	0xFE, 0x07, 0x0D, 0x11, 0x0E, 0xC8, 0xFA, 0x07, 
+	0x0F, 0xC8, 0xFC, 0x07, 0x20, 0xC8, 0x40, 0x08, 
+	0x3C, 0x08, 0x20, 0xC8, 0x42, 0x08, 0x3E, 0x08, 
+	0xA0, 0x06, 0x32, 0xC7, 0xCB, 0x10, 0x80, 0x01, 
+	0x80, 0x00, 0x55, 0x04, 0x8B, 0xC0, 0xA0, 0xC2, 
+	0xF0, 0x07, 0x8C, 0x07, 0x04, 0x00, 0x8D, 0x07, 
+	0xFA, 0x07, 0xA0, 0xC3, 0x3C, 0x08, 0xE0, 0xC3, 
+	0x3E, 0x08, 0xA0, 0x06, 0x36, 0xBA, 0x60, 0x01, 
+	0xFC, 0x07, 0x01, 0x00, 0x04, 0x13, 0xA0, 0x07, 
+	0xFA, 0x08, 0x00, 0x80, 0x52, 0x04, 0x60, 0x01, 
+	0x60, 0x07, 0x04, 0x00, 0x07, 0x16, 0x20, 0xD0, 
+	0x04, 0xE0, 0x20, 0xE8, 0x1A, 0xE0, 0x58, 0x07, 
+	0x60, 0x04, 0x3E, 0xC7, 0xA0, 0x07, 0xFA, 0x08, 
+	0x00, 0x40, 0x20, 0xC8, 0x3C, 0x08, 0xFC, 0x08, 
+	0x20, 0xC8, 0x3E, 0x08, 0xFE, 0x08, 0xA0, 0x06, 
+	0x6C, 0xC7, 0xA0, 0x06, 0x38, 0xC7, 0xD3, 0x10, 
+	0xAD, 0xC2, 0x02, 0x00, 0x6D, 0xC2, 0x00, 0x00, 
+	0x05, 0x16, 0xAA, 0x07, 0x02, 0x00, 0x36, 0x07, 
+	0x9A, 0x2C, 0x80, 0x03, 0xEA, 0x2C, 0x02, 0x00, 
+	0x41, 0xCB, 0x00, 0x00, 0x80, 0x03, 0x2D, 0xC3, 
+	0x18, 0x00, 0xAC, 0x07, 0x02, 0x00, 0x36, 0x07, 
+	0x20, 0x4B, 0x06, 0xEB, 0x0A, 0x00, 0x20, 0xEB, 
+	0x00, 0xEB, 0x0A, 0x00, 0x9C, 0x2E, 0x80, 0x03, 
+	0xA0, 0xC2, 0x22, 0xE0, 0x60, 0x04, 0x8A, 0xA3, 
+	0xED, 0xC0, 0x18, 0x00, 0xA0, 0x06, 0x3A, 0xCC, 
+	0x80, 0x03, 0x44, 0xC2, 0xC3, 0xC0, 0x02, 0x13, 
+	0xA0, 0x06, 0x3A, 0xCC, 0x19, 0xC3, 0x09, 0xCB, 
+	0x18, 0x00, 0xC9, 0x05, 0x19, 0xCB, 0x16, 0x00, 
+	0x4C, 0xC2, 0x2C, 0x02, 0x1A, 0x00, 0x0D, 0xCF, 
+	0x0E, 0xCF, 0x0F, 0xC7, 0x99, 0x00, 0x5B, 0x04, 
+	0x8C, 0x07, 0x0A, 0x09, 0x9C, 0xC2, 0xA0, 0x22, 
+	0x14, 0xE0, 0x06, 0x13, 0xA0, 0xC2, 0x58, 0x07, 
+	0xA0, 0x22, 0x20, 0xE0, 0x01, 0x16, 0x80, 0x03, 
+	0x03, 0xC1, 0xC3, 0x04, 0x8A, 0x07, 0x04, 0x00, 
+	0x84, 0xA2, 0x3A, 0xCF, 0x3A, 0xCF, 0x3A, 0xCF, 
+	0x3A, 0xCF, 0x3A, 0xCF, 0xE0, 0x02, 0x58, 0x07, 
+	0x8D, 0x07, 0x0A, 0x09, 0x0B, 0xC8, 0xC2, 0x07, 
+	0xA0, 0x06, 0x44, 0xB8, 0xE0, 0xC2, 0xC2, 0x07, 
+	0x20, 0xE0, 0x20, 0xE0, 0xE0, 0x02, 0xB8, 0x07, 
+	0x5B, 0x04, 0x2D, 0xC3, 0x18, 0x00, 0x8C, 0xC2, 
+	0x60, 0xC2, 0x6C, 0x01, 0x0A, 0xC8, 0x6C, 0x01, 
+	0xE0, 0xC2, 0x00, 0xFC, 0x02, 0x13, 0x8B, 0xC2, 
+	0xF9, 0x10, 0x09, 0xC8, 0x6C, 0x01, 0x8B, 0x07, 
+	0xF8, 0x05, 0x5B, 0xC2, 0x0C, 0x13, 0xCB, 0x05, 
+	0x5B, 0xC2, 0xCA, 0xC6, 0xE0, 0xC2, 0x6C, 0x01, 
+	0x09, 0xC8, 0x6C, 0x01, 0x0C, 0xC8, 0x00, 0xFC, 
+	0x0B, 0xC8, 0x6C, 0x01, 0x02, 0x10, 0xCC, 0xCE, 
+	0xCA, 0xC6, 0xA0, 0xC2, 0xE0, 0x00, 0xA0, 0x22, 
+	0x1A, 0xE0, 0x06, 0x16, 0x20, 0xE8, 0x04, 0xE0, 
+	0x3A, 0x07, 0x20, 0x48, 0x1A, 0xE0, 0xE0, 0x00, 
+	0x80, 0x03, 0xE0, 0xD3, 0xAB, 0xE3, 0xE0, 0x04, 
+	0x8E, 0x09, 0xE0, 0xC1, 0xA8, 0x06, 0x05, 0x16, 
+	0x07, 0x02, 0xA2, 0x06, 0xA0, 0x06, 0x38, 0xB5, 
+	0x0B, 0x16, 0xE0, 0xC1, 0xBA, 0x06, 0x23, 0x16, 
+	0x07, 0x02, 0xB4, 0x06, 0xA0, 0x06, 0x38, 0xB5, 
+	0x1E, 0x13, 0x07, 0x02, 0xB8, 0x06, 0x02, 0x10, 
+	0x07, 0x02, 0xA6, 0x06, 0x60, 0xC1, 0x02, 0xFC, 
+	0x25, 0xC8, 0x0C, 0x00, 0x02, 0xFC, 0xC5, 0xC9, 
+	0x0C, 0x00, 0xF5, 0xCD, 0xF5, 0xCD, 0xF5, 0xCD, 
+	0xF5, 0xCD, 0xF5, 0xCD, 0xF5, 0xC5, 0xB7, 0x01, 
+	0x28, 0x00, 0x27, 0x02, 0xF4, 0xFF, 0xA7, 0x07, 
+	0x04, 0x00, 0x52, 0xCE, 0x20, 0xE8, 0x9E, 0x09, 
+	0x06, 0xFC, 0x97, 0x2E, 0xD2, 0x10, 0x00, 0x03, 
+	0x02, 0x00, 0xA0, 0x06, 0x50, 0xB5, 0x00, 0x03, 
+	0x0F, 0x00, 0x20, 0x2C, 0xF0, 0xED, 0xE0, 0x93, 
+	0xAB, 0xE3, 0x03, 0x16, 0x81, 0x02, 0x16, 0x00, 
+	0xC4, 0x16, 0x21, 0xC1, 0x10, 0xEB, 0x54, 0x04, 
+	0xE0, 0x93, 0x10, 0xE0, 0x03, 0x16, 0xA0, 0xD2, 
+	0xA8, 0xE3, 0x0B, 0x10, 0xCF, 0xD3, 0x09, 0x16, 
+	0xA0, 0x23, 0x08, 0xE0, 0x06, 0x16, 0x84, 0x07, 
+	0x20, 0x00, 0x04, 0xE8, 0xD2, 0x06, 0xA0, 0xD2, 
+	0x0C, 0xE0, 0x60, 0x04, 0xD2, 0xCE, 0x60, 0x04, 
+	0x70, 0xD1, 0x22, 0xC1, 0x04, 0x00, 0xE2, 0x04, 
+	0x02, 0x00, 0x54, 0x04, 0x02, 0xC8, 0x6C, 0x01, 
+	0x82, 0xA0, 0x22, 0xC8, 0x32, 0x0C, 0x00, 0xFC, 
+	0x02, 0x02, 0x00, 0xFC, 0xE0, 0x93, 0xAA, 0xE3, 
+	0x13, 0x16, 0xB0, 0x03, 0x20, 0x98, 0xAA, 0xE3, 
+	0x65, 0x06, 0x0D, 0x16, 0x8B, 0x07, 0x17, 0xFC, 
+	0xDB, 0xD2, 0x8B, 0x09, 0x8B, 0x02, 0x15, 0x00, 
+	0x7B, 0x1B, 0xEB, 0xD2, 0xC4, 0xEA, 0x06, 0x13, 
+	0x77, 0x15, 0x20, 0x07, 0xA0, 0x09, 0x74, 0x10, 
+	0xA0, 0x06, 0x02, 0xD0, 0xA0, 0x48, 0x04, 0xE0, 
+	0x0E, 0x00, 0x85, 0x02, 0x07, 0x00, 0x0E, 0x13, 
+	0x0E, 0x01, 0x03, 0x00, 0x0B, 0x13, 0xA0, 0x23, 
+	0x22, 0xE0, 0x03, 0x16, 0xA0, 0xD2, 0x0E, 0xE0, 
+	0x02, 0x10, 0xA0, 0xD2, 0xA8, 0xE3, 0x8E, 0x01, 
+	0x03, 0x00, 0x5E, 0x10, 0x05, 0xC8, 0xFC, 0x06, 
+	0xC3, 0xC0, 0x57, 0x16, 0xA0, 0x43, 0x10, 0xE0, 
+	0x22, 0x88, 0x0E, 0x00, 0x6C, 0x09, 0x0A, 0x16, 
+	0x22, 0x88, 0x10, 0x00, 0x6E, 0x09, 0x06, 0x16, 
+	0x22, 0x88, 0x12, 0x00, 0x70, 0x09, 0x02, 0x16, 
+	0xA0, 0xE3, 0x10, 0xE0, 0x85, 0x02, 0x09, 0x00, 
+	0x02, 0x13, 0xA0, 0x06, 0xB8, 0xD7, 0x45, 0xA1, 
+	0x65, 0xC1, 0xAC, 0xE3, 0x55, 0x04, 0x62, 0xC0, 
+	0x04, 0x00, 0x22, 0xC8, 0x06, 0x00, 0x6C, 0x01, 
+	0x82, 0x02, 0x48, 0x04, 0x02, 0x1B, 0xA0, 0x43, 
+	0x0C, 0xE0, 0x22, 0xC1, 0x0E, 0x00, 0x51, 0x04, 
+	0x42, 0xC0, 0xE1, 0x04, 0x02, 0x00, 0xA2, 0xC0, 
+	0x0C, 0x00, 0x22, 0xC1, 0x0A, 0x00, 0x20, 0x21, 
+	0x18, 0xE0, 0x07, 0x13, 0xA1, 0xC8, 0x0A, 0x00, 
+	0x0A, 0x00, 0xA1, 0xC8, 0x08, 0x00, 0x08, 0x00, 
+	0xE2, 0x10, 0x22, 0xC8, 0x06, 0x00, 0x6C, 0x01, 
+	0xA0, 0x06, 0x66, 0xD6, 0x60, 0x04, 0xB0, 0xCE, 
+	0x02, 0xC8, 0xD4, 0x06, 0x62, 0xC1, 0x02, 0x00, 
+	0x65, 0xC1, 0xD8, 0xE3, 0x55, 0x04, 0x0F, 0x10, 
+	0x0E, 0x10, 0x85, 0x07, 0xF4, 0x03, 0xF5, 0x04, 
+	0x60, 0xCD, 0xCE, 0xED, 0xA0, 0x06, 0xA2, 0xD8, 
+	0xA0, 0xE3, 0x0C, 0xE0, 0x20, 0xE8, 0x9E, 0x09, 
+	0x06, 0x04, 0xA0, 0x2E, 0xF4, 0x03, 0x60, 0x04, 
+	0xE4, 0xCC, 0xA0, 0x06, 0x26, 0xD5, 0x0C, 0x10, 
+	0xA0, 0x06, 0x66, 0xD6, 0x09, 0x10, 0xA0, 0x06, 
+	0x2A, 0xD8, 0x06, 0x10, 0xA0, 0x06, 0x66, 0xD6, 
+	0x03, 0xC8, 0x2A, 0x09, 0xA0, 0xD2, 0xAA, 0xE3, 
+	0xA0, 0x06, 0x6E, 0xCF, 0xA0, 0x92, 0x26, 0xE0, 
+	0x0C, 0x16, 0xE0, 0xD3, 0x26, 0xE0, 0xE0, 0x23, 
+	0x14, 0xE0, 0x0A, 0x13, 0x0A, 0xC1, 0xC4, 0x83, 
+	0x07, 0x13, 0xC4, 0xC3, 0x24, 0xC1, 0xDC, 0xE3, 
+	0x54, 0x04, 0xCA, 0x93, 0xDC, 0x13, 0xCA, 0xD3, 
+	0xB0, 0x03, 0x0F, 0xD8, 0x59, 0x06, 0x04, 0x71, 
+	0x24, 0xC1, 0xEC, 0xE3, 0x54, 0x04, 0xA0, 0x23, 
+	0x0C, 0xE0, 0xD1, 0x13, 0x4D, 0xC3, 0xCF, 0x13, 
+	0x4D, 0x01, 0x00, 0x04, 0x0B, 0x13, 0x86, 0x07, 
+	0x02, 0x00, 0x84, 0x07, 0x26, 0x00, 0x46, 0x23, 
+	0x03, 0x13, 0x44, 0x06, 0x86, 0xA1, 0xFB, 0x10, 
+	0x46, 0x43, 0xB3, 0x10, 0x84, 0x07, 0x18, 0x00, 
+	0x8D, 0x01, 0x00, 0x04, 0x85, 0x07, 0xF4, 0x03, 
+	0xF5, 0x04, 0x60, 0xCD, 0xCE, 0xED, 0xA0, 0x06, 
+	0xA2, 0xD8, 0x20, 0xE8, 0x9C, 0x09, 0xFE, 0x03, 
+	0x20, 0xE8, 0x9E, 0x09, 0x06, 0x04, 0xA8, 0x10, 
+	0x85, 0x07, 0x1C, 0x07, 0x86, 0x07, 0x1A, 0x04, 
+	0x76, 0x6D, 0x76, 0x6D, 0x76, 0x6D, 0xC6, 0x05, 
+	0x76, 0x6D, 0x76, 0x6D, 0x76, 0x6D, 0x83, 0x07, 
+	0x00, 0x90, 0xA9, 0x10, 0x0B, 0xC3, 0x86, 0x07, 
+	0x00, 0x01, 0x85, 0x07, 0x00, 0x80, 0x20, 0xC1, 
+	0xD2, 0x06, 0x37, 0x13, 0xC4, 0x04, 0x60, 0xC0, 
+	0xD2, 0x06, 0x45, 0x20, 0x04, 0x13, 0x84, 0x05, 
+	0x15, 0x09, 0xF9, 0x16, 0x2E, 0x10, 0xCF, 0xD3, 
+	0x06, 0x16, 0xE0, 0x23, 0x14, 0xE0, 0x03, 0x16, 
+	0x0E, 0x01, 0x03, 0x00, 0x03, 0x13, 0xE0, 0x04, 
+	0xD2, 0x06, 0x23, 0x10, 0x64, 0xD0, 0x1C, 0x07, 
+	0x46, 0xB0, 0x10, 0x18, 0x01, 0xD9, 0x1C, 0x07, 
+	0x60, 0x23, 0x20, 0xE0, 0x0B, 0x13, 0x81, 0x07, 
+	0x18, 0x00, 0x61, 0xC0, 0xFC, 0xE3, 0x11, 0x88, 
+	0xCE, 0xED, 0x04, 0x13, 0x08, 0x02, 0x18, 0x80, 
+	0xA0, 0x06, 0xDA, 0xD4, 0x64, 0xD0, 0x28, 0x07, 
+	0x46, 0xB0, 0x08, 0x18, 0x01, 0xD9, 0x28, 0x07, 
+	0x46, 0xB0, 0x04, 0x17, 0x83, 0x07, 0x40, 0x80, 
+	0xA0, 0x06, 0x2A, 0xD8, 0x05, 0x48, 0xD2, 0x06, 
+	0xCA, 0x16, 0x20, 0xC1, 0x32, 0x09, 0x01, 0x16, 
+	0x5C, 0x04, 0x04, 0x02, 0x07, 0x00, 0x20, 0x06, 
+	0x32, 0x09, 0x05, 0x02, 0x00, 0x01, 0xC7, 0x10, 
+	0x0B, 0xC3, 0xC5, 0x04, 0x42, 0xC0, 0xC7, 0x04, 
+	0x20, 0xC2, 0x6C, 0x01, 0xE1, 0xA1, 0x04, 0x00, 
+	0x11, 0xC8, 0x6C, 0x01, 0xFB, 0x16, 0x08, 0xC8, 
+	0x6C, 0x01, 0xC8, 0x04, 0xA0, 0x43, 0x1A, 0xE0, 
+	0x22, 0xC1, 0x0E, 0x00, 0x0D, 0x15, 0x0C, 0x13, 
+	0xA0, 0xE3, 0x1A, 0xE0, 0xA0, 0x06, 0x14, 0xD8, 
+	0x08, 0xC2, 0x48, 0x13, 0x88, 0x02, 0x12, 0x00, 
+	0x45, 0x1B, 0x20, 0x22, 0x22, 0xE0, 0x42, 0x13, 
+	0x02, 0xC1, 0x08, 0xA1, 0x08, 0x05, 0x28, 0x02, 
+	0xF2, 0xFF, 0x07, 0xA2, 0x83, 0x07, 0x01, 0x80, 
+	0x88, 0x02, 0x04, 0x00, 0x6E, 0x11, 0x64, 0xC2, 
+	0x16, 0x00, 0x49, 0xD2, 0x02, 0x16, 0x02, 0x81, 
+	0x31, 0x16, 0x09, 0x01, 0x00, 0xF0, 0x28, 0x16, 
+	0x49, 0xC1, 0x45, 0x71, 0xC3, 0x04, 0x85, 0x02, 
+	0x09, 0x00, 0x7C, 0x13, 0x83, 0x07, 0x02, 0x80, 
+	0xA4, 0xC1, 0x14, 0x00, 0x88, 0x81, 0x76, 0x16, 
+	0x83, 0x05, 0x85, 0x02, 0x15, 0x00, 0x13, 0x1B, 
+	0x83, 0x05, 0x49, 0x99, 0x30, 0xEB, 0x0A, 0x13, 
+	0x09, 0x98, 0x0E, 0xE0, 0x6B, 0x16, 0x25, 0x98, 
+	0x30, 0xEB, 0x0C, 0xE0, 0x67, 0x16, 0xE0, 0xC1, 
+	0xEC, 0x06, 0x64, 0x16, 0xC3, 0x04, 0x52, 0xC2, 
+	0x0F, 0x13, 0x83, 0x07, 0x09, 0x80, 0xE0, 0xC1, 
+	0x6A, 0x09, 0x47, 0x01, 0x00, 0x10, 0x5A, 0x16, 
+	0xA0, 0xC0, 0x6C, 0x01, 0xA0, 0x06, 0xBE, 0xD6, 
+	0x60, 0x04, 0xB0, 0xCE, 0x60, 0x04, 0xBA, 0xCE, 
+	0x89, 0x07, 0x0E, 0x07, 0xC7, 0x04, 0xE5, 0xD1, 
+	0x46, 0xEB, 0x05, 0x13, 0xC7, 0x06, 0x27, 0x02, 
+	0x5C, 0xEB, 0x77, 0xCE, 0xFE, 0x15, 0x44, 0xC0, 
+	0x21, 0x02, 0x18, 0x00, 0x28, 0x02, 0xFC, 0xFF, 
+	0x36, 0x13, 0x91, 0xC1, 0x86, 0xD1, 0x1F, 0x13, 
+	0xC6, 0x06, 0x87, 0x07, 0x0E, 0x07, 0xF7, 0xC0, 
+	0x46, 0x02, 0xFF, 0xBF, 0x43, 0x02, 0xFF, 0x3F, 
+	0xA0, 0x91, 0xF5, 0xED, 0x09, 0x16, 0xB0, 0x03, 
+	0x20, 0x98, 0x0E, 0xE0, 0x5D, 0x06, 0x0F, 0x16, 
+	0x21, 0xC8, 0x02, 0x00, 0x0C, 0x07, 0x17, 0x10, 
+	0x47, 0x82, 0x0C, 0x1B, 0xC6, 0x90, 0xEB, 0x16, 
+	0x47, 0x06, 0xF7, 0x04, 0xB0, 0x03, 0x20, 0x98, 
+	0x5D, 0x06, 0x57, 0x06, 0x0C, 0x13, 0x83, 0x07, 
+	0x05, 0x80, 0x1C, 0x10, 0xD1, 0xC0, 0xE0, 0x20, 
+	0x16, 0xE0, 0x03, 0x16, 0x83, 0x07, 0x08, 0x80, 
+	0x15, 0x10, 0x60, 0x44, 0x26, 0xE0, 0x86, 0x71, 
+	0x46, 0xA0, 0x06, 0x62, 0x83, 0x07, 0x05, 0x80, 
+	0x08, 0xC2, 0xCB, 0x15, 0x0B, 0x16, 0xC3, 0x04, 
+	0x87, 0x07, 0x0E, 0x07, 0x77, 0xC0, 0x47, 0x82, 
+	0x05, 0x1B, 0x60, 0x20, 0x06, 0xE0, 0xFA, 0x16, 
+	0x83, 0x07, 0x07, 0x80, 0x5C, 0x04, 0xA0, 0x92, 
+	0x0E, 0xE0, 0x11, 0x16, 0x20, 0xC8, 0x20, 0xE0, 
+	0x08, 0x07, 0xE0, 0x04, 0x84, 0x01, 0x60, 0x05, 
+	0x02, 0x07, 0x4B, 0x13, 0x20, 0x48, 0x06, 0xE0, 
+	0x82, 0x01, 0xA0, 0x06, 0xD0, 0xD4, 0x83, 0x07, 
+	0x00, 0xC0, 0xA0, 0x06, 0x2A, 0xD8, 0x20, 0xC8, 
+	0x1E, 0xE0, 0x02, 0x07, 0xA0, 0xE3, 0x04, 0xE0, 
+	0x08, 0x02, 0x24, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 
+	0x42, 0x10, 0x20, 0xC1, 0x84, 0x01, 0x44, 0x02, 
+	0x00, 0x88, 0x2A, 0x13, 0x04, 0x48, 0x84, 0x01, 
+	0x20, 0x06, 0x02, 0x07, 0xF1, 0x16, 0x60, 0x01, 
+	0x8E, 0x09, 0x00, 0x80, 0x15, 0x13, 0xA0, 0x23, 
+	0x22, 0xE0, 0x05, 0x16, 0xA0, 0x43, 0x22, 0xE0, 
+	0xA0, 0xD2, 0x0E, 0xE0, 0xCF, 0x10, 0xE0, 0x23, 
+	0x14, 0xE0, 0x04, 0x13, 0x20, 0x98, 0xA9, 0xE3, 
+	0x65, 0x06, 0x0C, 0x16, 0xA0, 0x92, 0x0E, 0xE0, 
+	0xC5, 0x13, 0xA0, 0xD2, 0xA8, 0xE3, 0xD3, 0x10, 
+	0x20, 0xC8, 0x20, 0xE0, 0x08, 0x07, 0x83, 0x07, 
+	0x00, 0xC0, 0x04, 0x10, 0x83, 0x07, 0x02, 0x00, 
+	0x60, 0x04, 0xCA, 0xCE, 0x60, 0x04, 0xC0, 0xCE, 
+	0x20, 0xE8, 0x06, 0xE0, 0x82, 0x01, 0xA0, 0x06, 
+	0xD0, 0xD4, 0x20, 0x07, 0x02, 0x07, 0xA0, 0x43, 
+	0x04, 0xE0, 0x20, 0xC8, 0xAE, 0xE4, 0x86, 0x01, 
+	0x20, 0x88, 0x20, 0xE0, 0x08, 0x07, 0x03, 0x16, 
+	0x20, 0xC8, 0x78, 0xEB, 0x08, 0x07, 0x60, 0x04, 
+	0xD2, 0xCE, 0x0E, 0x01, 0x03, 0x00, 0x16, 0x13, 
+	0xCF, 0xD3, 0x08, 0x16, 0xA0, 0x23, 0x20, 0xE0, 
+	0x03, 0x16, 0xA0, 0xD2, 0xA8, 0xE3, 0x02, 0x10, 
+	0xA0, 0xD2, 0x0E, 0xE0, 0x8E, 0x01, 0x03, 0x00, 
+	0x09, 0x10, 0x60, 0xC1, 0x84, 0x01, 0x60, 0x21, 
+	0x0A, 0xE0, 0x04, 0x16, 0x83, 0x07, 0x00, 0x84, 
+	0x60, 0x04, 0xCA, 0xCE, 0x20, 0xC8, 0x2E, 0xE0, 
+	0x84, 0x01, 0x08, 0x02, 0x06, 0x80, 0xA0, 0x06, 
+	0xDA, 0xD4, 0x60, 0x04, 0xD2, 0xCE, 0x60, 0xE3, 
+	0x20, 0xE0, 0x60, 0x04, 0xD2, 0xCE, 0xE0, 0x93, 
+	0x26, 0xE0, 0x10, 0x16, 0xA0, 0x23, 0x08, 0xE0, 
+	0x0D, 0x16, 0xA0, 0x23, 0x06, 0xE0, 0x02, 0x13, 
+	0x60, 0xE3, 0x1C, 0xE0, 0x60, 0xE3, 0x18, 0xE0, 
+	0xA0, 0x43, 0x06, 0xE0, 0x08, 0x02, 0x3C, 0x80, 
+	0xA0, 0x06, 0xDA, 0xD4, 0x60, 0x04, 0xD2, 0xCE, 
+	0xA0, 0x92, 0xA8, 0xE3, 0x03, 0x13, 0xA0, 0x92, 
+	0xA9, 0xE3, 0x1E, 0x16, 0xE0, 0x23, 0x14, 0xE0, 
+	0x08, 0x13, 0x20, 0x98, 0xA9, 0xE3, 0x65, 0x06, 
+	0x04, 0x13, 0x83, 0x07, 0x07, 0x00, 0x60, 0x04, 
+	0xCA, 0xCE, 0xA0, 0xD2, 0x0E, 0xE0, 0x20, 0xC8, 
+	0x20, 0xE0, 0x08, 0x07, 0xA0, 0x27, 0x04, 0xE0, 
+	0x0B, 0x16, 0x20, 0xC8, 0x1E, 0xE0, 0x08, 0x07, 
+	0xE0, 0x93, 0xA8, 0xE3, 0x05, 0x16, 0xA0, 0x23, 
+	0x12, 0xE0, 0x02, 0x13, 0x20, 0x06, 0x08, 0x07, 
+	0x60, 0x04, 0xD2, 0xCE, 0xE0, 0x23, 0x14, 0xE0, 
+	0x3E, 0x13, 0xB0, 0x03, 0x20, 0x98, 0x0E, 0xE0, 
+	0x6F, 0x06, 0x0F, 0x16, 0xCF, 0xD3, 0x37, 0x16, 
+	0xA0, 0xD2, 0xA8, 0xE3, 0x60, 0x04, 0xD2, 0xCE, 
+	0xA0, 0x92, 0x0C, 0xE0, 0x30, 0x16, 0xE0, 0x23, 
+	0x14, 0xE0, 0xF6, 0x13, 0x83, 0x07, 0x06, 0x00, 
+	0x07, 0x10, 0x83, 0x07, 0x05, 0x00, 0xE0, 0x93, 
+	0x0E, 0xE0, 0x02, 0x16, 0x83, 0x07, 0x07, 0x00, 
+	0x60, 0x04, 0xCA, 0xCE, 0x60, 0xE3, 0x12, 0xE0, 
+	0xE0, 0x23, 0x14, 0xE0, 0x11, 0x13, 0x20, 0x98, 
+	0x0C, 0xE0, 0x65, 0x06, 0x03, 0x16, 0x20, 0xD8, 
+	0xA9, 0xE3, 0x65, 0x06, 0x14, 0x10, 0x60, 0x01, 
+	0x8E, 0x09, 0x00, 0x80, 0x10, 0x13, 0x20, 0xC1, 
+	0x84, 0x01, 0x20, 0x21, 0x06, 0xE0, 0xD2, 0x16, 
+	0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, 0x07, 0x13, 
+	0x20, 0x48, 0x06, 0xE0, 0x84, 0x01, 0x08, 0x02, 
+	0x30, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x60, 0x04, 
+	0xD2, 0xCE, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x20, 
+	0xFA, 0x16, 0x08, 0x02, 0x78, 0x80, 0xA0, 0x06, 
+	0xDA, 0xD4, 0x20, 0xC2, 0xA2, 0x09, 0x03, 0x13, 
+	0x20, 0x06, 0xA2, 0x09, 0x21, 0x13, 0x20, 0xC2, 
+	0xA4, 0x09, 0xED, 0x13, 0x20, 0x06, 0xA4, 0x09, 
+	0xEA, 0x16, 0xA0, 0x07, 0xA4, 0x09, 0x05, 0x00, 
+	0xCD, 0x01, 0x00, 0x04, 0xE4, 0x10, 0x60, 0x01, 
+	0x8E, 0x09, 0x80, 0x00, 0x3E, 0x13, 0x60, 0x01, 
+	0x8E, 0x09, 0x00, 0x10, 0x02, 0x16, 0xA0, 0x06, 
+	0xE6, 0xD5, 0xA0, 0x01, 0x8E, 0x09, 0x00, 0x10, 
+	0xE0, 0x01, 0x8E, 0x09, 0x80, 0x00, 0x83, 0x07, 
+	0x00, 0xA8, 0xA0, 0x06, 0x2A, 0xD8, 0x16, 0x10, 
+	0x60, 0x01, 0x8E, 0x09, 0x00, 0x04, 0x21, 0x13, 
+	0xE0, 0x01, 0x8E, 0x09, 0x00, 0x10, 0xA0, 0x07, 
+	0x08, 0x07, 0x05, 0x00, 0x83, 0x07, 0x08, 0xA8, 
+	0xA0, 0x23, 0x04, 0xE0, 0x05, 0x16, 0x20, 0xC8,  
+	0x20, 0xE0, 0x08, 0x07, 0x83, 0x07, 0x08, 0xE8,  
+	0xA0, 0x06, 0x2A, 0xD8, 0xA0, 0x01, 0x8E, 0x09, 
+	0x00, 0x20, 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x01, 
+	0xE0, 0x01, 0x82, 0x01, 0x00, 0x08, 0xA0, 0xD2, 
+	0x0E, 0xE0, 0x83, 0x07, 0x10, 0x80, 0x60, 0x04, 
+	0xC0, 0xCE, 0x08, 0x02, 0x78, 0x00, 0xA0, 0x06, 
+	0xDA, 0xD4, 0x83, 0x07, 0x00, 0x82, 0x60, 0x04, 
+	0xCA, 0xCE, 0x60, 0x04, 0xD2, 0xCE, 0x20, 0x06, 
+	0x90, 0x09, 0x07, 0x15, 0xA0, 0xD2, 0x10, 0xE0, 
+	0xCA, 0x06, 0xA0, 0xD2, 0x26, 0xE0, 0xCF, 0x04, 
+	0xF4, 0x10, 0x08, 0x02, 0x7E, 0x80, 0xA0, 0x06, 
+	0xDA, 0xD4, 0x20, 0xC2, 0x90, 0x09, 0x88, 0x02,  
+	0x96, 0x00, 0x0D, 0x1B, 0xEA, 0x16, 0x20, 0x48,  
+	0x08, 0xE0, 0x82, 0x01, 0xA0, 0x01, 0x8E, 0x09, 
+	0x00, 0x10, 0xA0, 0x06, 0xE6, 0xD5, 0x83, 0x07, 
+	0x00, 0x28, 0x60, 0x04, 0xC0, 0xCE, 0x60, 0x01, 
+	0x8E, 0x09, 0x00, 0x10, 0xDA, 0x16, 0x84, 0x07, 
+	0x04, 0x00, 0x85, 0x07, 0xF4, 0x03, 0xF5, 0x04, 
+	0xB5, 0x07, 0x30, 0x06, 0xA0, 0x06, 0xA2, 0xD8, 
+	0xA0, 0x07, 0xF8, 0x03, 0x34, 0xD4, 0x60, 0x04, 
+	0xC0, 0xDB, 0xA0, 0x07, 0x90, 0x09, 0xF4, 0x01, 
+	0x08, 0x02, 0x7E, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 
+	0x08, 0x02, 0x36, 0x00, 0xA0, 0x06, 0xDA, 0xD4, 
+	0x20, 0xE8, 0x0C, 0xE0, 0x82, 0x01, 0xA0, 0x23, 
+	0x18, 0xE0, 0x06, 0x13, 0xA0, 0xE3, 0x18, 0xE0, 
+	0xE0, 0x2E, 0x00, 0x00, 0x41, 0xC0, 0xFA, 0x16, 
+	0xA0, 0x06, 0xE6, 0xD5, 0xB2, 0x10, 0x04, 0x02, 
+	0x64, 0x00, 0x04, 0x06, 0xFE, 0x16, 0x5B, 0x04, 
+	0xA0, 0xE3, 0x0A, 0xE0, 0x08, 0xC2, 0x02, 0x11, 
+	0xA0, 0x43, 0x0A, 0xE0, 0x20, 0x42, 0x04, 0xE0, 
+	0x28, 0x02, 0xFC, 0xE3, 0x58, 0xC0, 0x02, 0xC0, 
+	0x11, 0x88, 0xCE, 0xED, 0x03, 0x16, 0xD1, 0x2C, 
+	0x58, 0xC0, 0xD1, 0x04, 0x80, 0xC0, 0x0E, 0x01, 
+	0x00, 0x10, 0x0F, 0x13, 0x60, 0xCC, 0xCE, 0xED, 
+	0xC8, 0x05, 0x78, 0xCC, 0x03, 0x16, 0x41, 0x06, 
+	0x60, 0xCC, 0xD6, 0x06, 0x58, 0xC4, 0x02, 0x16, 
+	0x60, 0xC4, 0x00, 0x07, 0x21, 0x02, 0xFA, 0xFF, 
+	0x91, 0x2C, 0x5B, 0x04, 0x0B, 0xC3, 0xA0, 0x06, 
+	0xC2, 0xD5, 0xA0, 0x06, 0x9C, 0xD5, 0x08, 0xC2, 
+	0x05, 0x16, 0x62, 0xC2, 0x02, 0x00, 0x60, 0x26, 
+	0xA8, 0xE4, 0x0D, 0x16, 0x42, 0xC2, 0xC9, 0x05, 
+	0x60, 0xCE, 0xF2, 0xED, 0x60, 0xC6, 0x7C, 0xEB, 
+	0xA0, 0x06, 0x10, 0xD6, 0x18, 0xCA, 0x0A, 0x00, 
+	0x20, 0x46, 0x26, 0xE0, 0x04, 0x16, 0xA0, 0xC0, 
+	0x6C, 0x01, 0x12, 0x2E, 0x1D, 0x10, 0x12, 0xC1, 
+	0x05, 0x13, 0x60, 0xC1, 0x6C, 0x01, 0x14, 0x2E, 
+	0x05, 0xC8, 0x6C, 0x01, 0xD2, 0x04, 0x48, 0x06, 
+	0x84, 0x07, 0x02, 0x00, 0x48, 0xC1, 0xA0, 0xC0, 
+	0x6C, 0x01, 0x02, 0xC0, 0xA0, 0x06, 0xA2, 0xD8, 
+	0x60, 0xC5, 0x02, 0xFC, 0x07, 0x02, 0xA2, 0x06, 
+	0x25, 0x02, 0xF4, 0xFF, 0x05, 0xC8, 0x02, 0xFC, 
+	0x20, 0xC2, 0x6C, 0x01, 0xA0, 0x06, 0xFC, 0xB4, 
+	0x5C, 0x04, 0x42, 0xC2, 0x29, 0x02, 0x08, 0x00, 
+	0x39, 0xC2, 0x48, 0x02, 0x00, 0xC0, 0x88, 0x02, 
+	0x00, 0xC0, 0x08, 0x16, 0x60, 0x8E, 0x2E, 0xE0, 
+	0x05, 0x16, 0x60, 0x86, 0x2E, 0xE0, 0x02, 0x16, 
+	0xC8, 0x04, 0x5B, 0x04, 0x08, 0x07, 0x5B, 0x04, 
+	0x20, 0x88, 0x8E, 0xE1, 0x6C, 0x01, 0x02, 0x16,  
+	0x60, 0x04, 0xBA, 0xCE, 0x5B, 0x04, 0x88, 0x07,  
+	0xAE, 0x01, 0x20, 0xE8, 0x0E, 0xE0, 0x80, 0x01, 
+	0x08, 0x06, 0xFE, 0x16, 0x20, 0x48, 0x0E, 0xE0, 
+	0x80, 0x01, 0x5B, 0x04, 0xC2, 0x04, 0xA0, 0x23, 
+	0x0C, 0xE0, 0x10, 0x16, 0x20, 0x2F, 0x30, 0x06, 
+	0x82, 0x07, 0xDF, 0xFF, 0x02, 0x2C, 0x82, 0x02, 
+	0xF4, 0x03, 0x06, 0x13, 0xE2, 0x04, 0x02, 0x00, 
+	0xA2, 0xC0, 0x06, 0x00, 0x12, 0x2E, 0xF4, 0x10, 
+	0xA0, 0x43, 0x0C, 0xE0, 0x5B, 0x04, 0x42, 0xC2, 
+	0x88, 0x07, 0x0E, 0x00, 0x09, 0xA2, 0x29, 0x02, 
+	0x08, 0x00, 0x78, 0xCE, 0x78, 0xCE, 0x78, 0xCE, 
+	0x60, 0xCE, 0x6C, 0x09, 0x60, 0xCE, 0x6E, 0x09, 
+	0x60, 0xCE, 0x70, 0x09, 0xA0, 0x23, 0x1A, 0xE0, 
+	0x0F, 0x16, 0x58, 0xC2, 0x49, 0x02, 0x80, 0x1F, 
+	0x60, 0x2A, 0x14, 0xE0, 0xA0, 0xE8, 0x04, 0xE0, 
+	0x0E, 0x00, 0x09, 0xC6, 0x49, 0x02, 0x00, 0x1F, 
+	0xC9, 0x06, 0x09, 0xA2, 0x89, 0xA8, 0x04, 0x00, 
+	0x28, 0x02, 0x02, 0x00, 0x58, 0xC2, 0x49, 0x0A, 
+	0x49, 0x02, 0x00, 0xF0, 0x09, 0xD6, 0xE2, 0x04, 
+	0x06, 0x00, 0x5B, 0x04, 0x00, 0x07, 0x82, 0xC0, 
+	0x53, 0x13, 0xA0, 0xC0, 0x6C, 0x01, 0xA0, 0xC1, 
+	0x06, 0xFC, 0x46, 0x02, 0x0F, 0x00, 0x86, 0x02, 
+	0x01, 0x00, 0x3D, 0x12, 0x06, 0x88, 0xF2, 0x06, 
+	0x12, 0x16, 0x01, 0x02, 0x0E, 0xFC, 0x31, 0x88, 
+	0xF4, 0x06, 0x0D, 0x16, 0x31, 0x88, 0xF6, 0x06, 
+	0x0A, 0x16, 0x31, 0x88, 0xF8, 0x06, 0x07, 0x16, 
+	0x86, 0x02, 0x02, 0x00, 0x2C, 0x16, 0x20, 0x88, 
+	0x0A, 0x07, 0xFA, 0x06, 0x28, 0x13, 0x20, 0xC1, 
+	0x6A, 0x09, 0x44, 0x01, 0x00, 0x08, 0x06, 0x13, 
+	0x86, 0x02, 0x02, 0x00, 0x20, 0x16, 0x44, 0x01, 
+	0x80, 0x00, 0x1D, 0x16, 0x00, 0x07, 0xE0, 0x23, 
+	0x14, 0xE0, 0x19, 0x16, 0x82, 0x02, 0x43, 0x00, 
+	0x16, 0x13, 0x00, 0x02, 0x02, 0xFC, 0x40, 0xC0, 
+	0xB0, 0x01, 0x20, 0x00, 0x60, 0x01, 0x6A, 0x09, 
+	0x01, 0x00, 0x07, 0x16, 0x60, 0xA0, 0x2C, 0x09, 
+	0x60, 0xCC, 0xEE, 0x05, 0x50, 0xC4, 0x20, 0xC4, 
+	0x2C, 0x09, 0x80, 0x07, 0x36, 0x07, 0x81, 0x07, 
+	0x40, 0x00, 0x40, 0x2C, 0xC0, 0x04, 0x84, 0x07, 
+	0xF2, 0x06, 0x06, 0xCD, 0x01, 0x02, 0x0E, 0xFC, 
+	0x31, 0xCD, 0x31, 0xCD, 0x31, 0xCD, 0x20, 0xC5, 
+	0x0A, 0x07, 0x00, 0xC0, 0x01, 0x13, 0x12, 0x2E, 
+	0xE0, 0x04, 0x6C, 0x01, 0x5B, 0x04, 0x60, 0x01, 
+	0x8A, 0x09, 0x00, 0x80, 0x12, 0x13, 0x0B, 0xC8, 
+	0x22, 0x09, 0xA0, 0x06, 0x3E, 0xD7, 0x08, 0x02, 
+	0x42, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x08, 0x02, 
+	0x30, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0xE0, 0xC2, 
+	0x22, 0x09, 0x5B, 0x04, 0x20, 0x48, 0xAC, 0xE4, 
+	0x80, 0x01, 0x20, 0x48, 0x7E, 0xEB, 0x82, 0x01, 
+	0x20, 0x48, 0x22, 0xE0, 0xAE, 0x01, 0x20, 0x48, 
+	0x22, 0xE0, 0x78, 0x09, 0x60, 0x43, 0x18, 0xE0, 
+	0xA0, 0x43, 0x08, 0xE0, 0x60, 0x01, 0x8A, 0x09, 
+	0x00, 0x80, 0xEB, 0x13, 0x0B, 0xC3, 0x08, 0x02, 
+	0x42, 0x00, 0xA0, 0x06, 0xDA, 0xD4, 0x5C, 0x04, 
+	0x0B, 0xC3, 0x20, 0xE8, 0x0E, 0xE0, 0x82, 0x01, 
+	0x20, 0xE8, 0x22, 0xE0, 0xAE, 0x01, 0x20, 0xE8, 
+	0x22, 0xE0, 0x78, 0x09, 0xA0, 0xE3, 0x08, 0xE0, 
+	0x60, 0xE3, 0x18, 0xE0, 0xA0, 0x43, 0x06, 0xE0, 
+	0x08, 0x02, 0x3C, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 
+	0x08, 0x02, 0x42, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 
+	0x5C, 0x04, 0x0B, 0xC3, 0x83, 0x07, 0x00, 0x68, 
+	0xA0, 0x06, 0x2A, 0xD8, 0x83, 0x07, 0x10, 0x80, 
+	0xA0, 0x06, 0x2A, 0xD8, 0x5C, 0x04, 0x0B, 0xC3, 
+	0xA0, 0x06, 0x14, 0xD8, 0x02, 0xA2, 0x68, 0xC2, 
+	0x14, 0x00, 0x29, 0x02, 0xFC, 0xFF, 0x24, 0x13, 
+	0x28, 0x02, 0x18, 0x00, 0x87, 0x07, 0x0E, 0x00, 
+	0x81, 0x07, 0x0E, 0x07, 0xF1, 0x04, 0x47, 0x06, 
+	0xFD, 0x15, 0x58, 0xC0, 0xB0, 0x03, 0x01, 0x78, 
+	0x63, 0x06, 0x41, 0x02, 0x3F, 0x00, 0x0E, 0x13, 
+	0x81, 0x02, 0x1F, 0x00, 0x0B, 0x1B, 0x41, 0xA0, 
+	0x61, 0xC0, 0x86, 0xE4, 0xF8, 0xC1, 0xC7, 0x06, 
+	0xC7, 0x71, 0x47, 0x06, 0x78, 0xCC, 0x47, 0x06, 
+	0xFD, 0x15, 0x04, 0x10, 0x58, 0xC0, 0xC1, 0x06, 
+	0x41, 0x70, 0x01, 0xA2, 0x49, 0xC2, 0xE5, 0x15, 
+	0x5C, 0x04, 0xA0, 0x23, 0x1A, 0xE0, 0x02, 0x13, 
+	0xC8, 0x04, 0x5B, 0x04, 0x22, 0xC2, 0x14, 0x00, 
+	0x48, 0x02, 0x00, 0x1F, 0xC8, 0x06, 0x5B, 0x04, 
+	0x83, 0x02, 0x0F, 0x00, 0x17, 0x1B, 0xA0, 0xC1, 
+	0xD4, 0x06, 0x35, 0x13, 0x26, 0x02, 0x04, 0x00, 
+	0xA0, 0xCD, 0xCE, 0xED, 0x83, 0xC5, 0x04, 0x13, 
+	0x4A, 0xC2, 0x39, 0x0A, 0xC9, 0xE0, 0x83, 0xC5, 
+	0x86, 0x07, 0x36, 0x07, 0x87, 0x07, 0x10, 0x00, 
+	0x20, 0xC2, 0xD4, 0x06, 0xE0, 0x04, 0xD4, 0x06, 
+	0x46, 0x2C, 0x5B, 0x04, 0x60, 0xC0, 0xFE, 0x06, 
+	0x20, 0xC2, 0x6A, 0x09, 0x48, 0x02, 0x00, 0x60, 
+	0x20, 0x22, 0x06, 0xE0, 0x04, 0x16, 0x20, 0xE2, 
+	0x0A, 0xE0, 0x20, 0xE2, 0x18, 0xE0, 0x13, 0x0A, 
+	0x04, 0x18, 0x41, 0x05, 0x03, 0x48, 0xFE, 0x06, 
+	0x06, 0x10, 0x83, 0x02, 0x02, 0x00, 0x01, 0x16, 
+	0x13, 0x09, 0x03, 0xE8, 0xFE, 0x06, 0xC8, 0x40, 
+	0xC1, 0x40, 0x05, 0x13, 0x88, 0x07, 0x36, 0x07, 
+	0x89, 0x07, 0x00, 0x40, 0x48, 0x2C, 0x5B, 0x04, 
+	0xC9, 0x04, 0x24, 0xC1, 0x94, 0xEB, 0x84, 0xC1, 
+	0x86, 0x71, 0x86, 0xA1, 0x26, 0x02, 0x56, 0xEC, 
+	0xC4, 0x06, 0x04, 0x71, 0x24, 0x02, 0xC2, 0xEB, 
+	0x14, 0xD2, 0xC8, 0x09, 0x08, 0xA2, 0xB0, 0x03, 
+	0x34, 0xD8, 0x5F, 0x06, 0x47, 0x02, 0x0F, 0x00, 
+	0xC7, 0xA1, 0x28, 0xC2, 0x82, 0xEB, 0x58, 0x04, 
+	0x76, 0xCD, 0x47, 0x06, 0xFD, 0x16, 0x32, 0x10, 
+	0x36, 0xC2, 0x26, 0x10, 0x17, 0x09, 0x47, 0xA1, 
+	0x2D, 0x10, 0x17, 0x09, 0x47, 0x61, 0x2A, 0x10, 
+	0xA0, 0x43, 0x16, 0xE0, 0x5B, 0x04, 0xA0, 0x43, 
+	0x16, 0xE0, 0x49, 0xC2, 0x03, 0x16, 0x44, 0xC2, 
+	0x06, 0xC8, 0x22, 0x09, 0x27, 0xC1, 0x8E, 0xED, 
+	0x84, 0xC1, 0x86, 0x71, 0x26, 0x02, 0xC4, 0xED, 
+	0xC4, 0x06, 0x04, 0x71, 0x24, 0x02, 0xAA, 0xED, 
+	0xD3, 0x10, 0x09, 0xC1, 0xA0, 0xC1, 0x22, 0x09, 
+	0xC9, 0x04, 0x10, 0x10, 0x36, 0xC2, 0x78, 0xD5,  
+	0x60, 0x41, 0x22, 0xE0, 0xC5, 0x05, 0x0A, 0x10, 
+	0x78, 0xCD, 0x47, 0x06, 0xFD, 0x15, 0x06, 0x10, 
+	0xA0, 0x23, 0x16, 0xE0, 0xCD, 0x16, 0x49, 0xC2, 
+	0xEC, 0x16, 0xD6, 0x10, 0xA0, 0xE3, 0x16, 0xE0, 
+	0xBB, 0x10, 0x08, 0x02, 0x5A, 0x80, 0xA0, 0x06, 
+	0xDA, 0xD4, 0x44, 0x10, 0xA0, 0x92, 0x0C, 0xE0, 
+	0x15, 0x16, 0x44, 0x02, 0x00, 0x5E, 0x14, 0x16, 
+	0x20, 0x48, 0xAC, 0xE4, 0x80, 0x01, 0xA0, 0x06, 
+	0x72, 0xD7, 0x20, 0xC8, 0x9E, 0x01, 0x9E, 0x01, 
+	0xE0, 0x2E, 0x01, 0x00, 0xA0, 0x43, 0x18, 0xE0, 
+	0xA0, 0xD2, 0x26, 0xE0, 0x83, 0x07, 0x10, 0x00, 
+	0xA0, 0x06, 0x2A, 0xD8, 0x60, 0x04, 0xD2, 0xCE, 
+	0x84, 0x07, 0x08, 0x00, 0x60, 0x04, 0x94, 0xCE, 
+	0x85, 0x07, 0x03, 0x02, 0x05, 0xC8, 0xCE, 0x06, 
+	0xA0, 0x43, 0x12, 0xE0, 0xE0, 0x04, 0xFA, 0x06, 
+	0xA0, 0x06, 0xA4, 0xD7, 0x08, 0x02, 0x48, 0x80, 
+	0xA0, 0x06, 0xDA, 0xD4, 0x17, 0x10, 0x60, 0x01, 
+	0x8E, 0x09, 0x00, 0x80, 0x02, 0x16, 0x60, 0x04, 
+	0x9C, 0xD4, 0xA0, 0x27, 0x2C, 0xE0, 0x04, 0x16, 
+	0x08, 0x02, 0x54, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 
+	0x83, 0x07, 0x00, 0xA8, 0x20, 0x88, 0x08, 0x07, 
+	0x20, 0xE0, 0x02, 0x16, 0x83, 0x07, 0x00, 0xE8, 
+	0xA0, 0x06, 0x2A, 0xD8, 0x08, 0x02, 0x36, 0x00, 
+	0xA0, 0x06, 0xDA, 0xD4, 0x20, 0xE8, 0x0C, 0xE0, 
+	0x82, 0x01, 0xA0, 0x23, 0x18, 0xE0, 0x06, 0x13, 
+	0xA0, 0xE3, 0x18, 0xE0, 0xE0, 0x2E, 0x00, 0x00, 
+	0x41, 0xC0, 0xFA, 0x16, 0xA0, 0x06, 0xE6, 0xD5, 
+	0x82, 0xC0, 0x02, 0x13, 0x4F, 0x02, 0x80, 0xFF, 
+	0xC4, 0x04, 0x0F, 0xD1, 0xC4, 0x06, 0x60, 0x04, 
+	0x94, 0xCE, 0xA0, 0x06, 0x32, 0xDA, 0x08, 0x02, 
+	0x36, 0x80, 0xA0, 0x07, 0xD6, 0x06, 0x20, 0xDA, 
+	0xA0, 0x06, 0xDA, 0xD4, 0x10, 0x10, 0xA0, 0x06, 
+	0x32, 0xDA, 0x20, 0xD1, 0xCE, 0x06, 0xE6, 0x13, 
+	0x20, 0x78, 0x12, 0xE0, 0xCE, 0x06, 0xE2, 0x10, 
+	0x20, 0xC1, 0x16, 0x04, 0x14, 0x0A, 0xC4, 0x06, 
+	0x0A, 0x91, 0x01, 0x16, 0x5B, 0x04, 0x60, 0x04, 
+	0xD2, 0xCE, 0xB0, 0x03, 0x20, 0x98, 0xAB, 0xE3, 
+	0x65, 0x06, 0x02, 0x13, 0x60, 0x04, 0xBA, 0xCE, 
+	0x60, 0xC1, 0x94, 0x09, 0x02, 0x13, 0x60, 0x04, 
+	0x22, 0xDE, 0x60, 0xD1, 0x0E, 0xE0, 0x3D, 0x10, 
+	0x85, 0x07, 0xBE, 0xEA, 0x35, 0xC8, 0x8A, 0x09, 
+	0x15, 0xC8, 0x8C, 0x09, 0x0B, 0x10, 0xE0, 0x04, 
+	0xA0, 0x09, 0x20, 0xD8, 0x2E, 0x09, 0xA6, 0x09, 
+	0x20, 0xC8, 0xA8, 0x09, 0x8A, 0x09, 0x20, 0xC8, 
+	0xAA, 0x09, 0x8C, 0x09, 0xE0, 0x04, 0x8E, 0x09, 
+	0xCA, 0x04, 0xCD, 0x04, 0xCE, 0x04, 0xCF, 0x04, 
+	0xE0, 0x04, 0xA8, 0x06, 0xE0, 0x04, 0xBA, 0x06, 
+	0x84, 0x07, 0xA0, 0x01, 0x85, 0x07, 0x10, 0x00, 
+	0xF4, 0x04, 0x45, 0x06, 0xFD, 0x15, 0x84, 0x07, 
+	0xD8, 0x06, 0x85, 0x07, 0x34, 0x07, 0x44, 0x61, 
+	0xF4, 0x04, 0x45, 0x06, 0xFD, 0x15, 0x84, 0x07, 
+	0xC8, 0x00, 0x04, 0xC8, 0x00, 0x07, 0x84, 0x07, 
+	0xFF, 0x7F, 0x04, 0xC8, 0xF0, 0x06, 0x84, 0x07, 
+	0x06, 0x00, 0x04, 0xC8, 0xEE, 0x06, 0x85, 0x07, 
+	0x02, 0x0C, 0x20, 0xC1, 0x8A, 0x09, 0x01, 0x11, 
+	0xC5, 0x06, 0xB0, 0x03, 0x05, 0xD8, 0x65, 0x06, 
+	0x60, 0x04, 0xD2, 0xCE, 0xB0, 0x03, 0x20, 0x98, 
+	0xAA, 0xE3, 0x65, 0x06, 0x79, 0x16, 0x60, 0xD1, 
+	0x10, 0xE0, 0xF3, 0x10, 0x60, 0xD1, 0xAB, 0xE3, 
+	0xA0, 0x01, 0x8E, 0x09, 0x00, 0x02, 0xE0, 0x01, 
+	0x80, 0x01, 0x00, 0x20, 0xC8, 0x04, 0x20, 0xD2, 
+	0x80, 0x01, 0x08, 0xC8, 0x9C, 0x09, 0x08, 0xD8, 
+	0x2E, 0x09, 0xE3, 0x10, 0x20, 0xF8, 0x19, 0xEE, 
+	0x82, 0x01, 0x20, 0xC8, 0x10, 0xE0, 0xC6, 0x06, 
+	0x20, 0xC8, 0x20, 0xE0, 0xC8, 0x06, 0x20, 0xC8, 
+	0xC2, 0xEA, 0x90, 0x09, 0xE0, 0x2E, 0x00, 0x00, 
+	0xA0, 0x06, 0xE6, 0xD5, 0x20, 0xC8, 0x6C, 0x09, 
+	0xA0, 0x01, 0x20, 0xC8, 0x6E, 0x09, 0xA2, 0x01, 
+	0x20, 0xC8, 0x70, 0x09, 0xA4, 0x01, 0x20, 0xC8, 
+	0x6E, 0x09, 0xB0, 0x01, 0x20, 0xC8, 0x70, 0x09, 
+	0xB2, 0x01, 0x20, 0xC8, 0x70, 0x09, 0xCC, 0x06, 
+	0x20, 0xF8, 0x18, 0xEE, 0x80, 0x01, 0xB0, 0x03, 
+	0xA0, 0x01, 0x8E, 0x09, 0x00, 0x02, 0x20, 0x98, 
+	0xAA, 0xE3, 0x65, 0x06, 0x3A, 0x13, 0xE0, 0x01, 
+	0x8E, 0x09, 0x00, 0x02, 0x88, 0x07, 0x56, 0xDF, 
+	0xE0, 0xC2, 0x8A, 0x09, 0x05, 0x11, 0xA0, 0x01, 
+	0x8E, 0x09, 0x00, 0x02, 0x88, 0x07, 0x9A, 0xDF, 
+	0x98, 0x06, 0x08, 0x02, 0x12, 0x80, 0xA0, 0x06, 
+	0xDA, 0xD4, 0x84, 0x07, 0x0A, 0x00, 0x85, 0x07, 
+	0xF4, 0x03, 0x20, 0x88, 0xC6, 0x06, 0x20, 0xE0, 
+	0x08, 0x1B, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, 
+	0xA5, 0x13, 0x84, 0x07, 0x1C, 0x00, 0x85, 0x07, 
+	0xF8, 0x03, 0xA0, 0x06, 0xA2, 0xD8, 0x85, 0x07, 
+	0x42, 0xDC, 0x05, 0xC8, 0xF8, 0x03, 0x20, 0xC8, 
+	0xA0, 0x09, 0xA0, 0x09, 0x6C, 0x16, 0x20, 0xE8, 
+	0x9C, 0x09, 0xFE, 0x03, 0x20, 0xE8, 0x9E, 0x09, 
+	0x06, 0x04, 0xA0, 0x23, 0x0C, 0xE0, 0x32, 0x13, 
+	0xA0, 0xE3, 0x0C, 0xE0, 0xA0, 0x2E, 0xF4, 0x03, 
+	0x2D, 0x10, 0xA0, 0x06, 0x56, 0xDF, 0x60, 0x01, 
+	0x8E, 0x09, 0x00, 0x40, 0x08, 0x13, 0x08, 0x02, 
+	0x6C, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x22, 0x10, 
+	0xE0, 0x01, 0x8E, 0x09, 0x00, 0x40, 0x08, 0x02, 
+	0x60, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x84, 0x07, 
+	0x2A, 0x00, 0x85, 0x07, 0xF4, 0x03, 0xA0, 0x06, 
+	0xA2, 0xD8, 0xD5, 0x10, 0xB0, 0x03, 0x20, 0x98, 
+	0xAA, 0xE3, 0x65, 0x06, 0x0F, 0x16, 0x20, 0x06, 
+	0x90, 0x09, 0x9A, 0x16, 0x60, 0x01, 0x8A, 0x09, 
+	0x00, 0x40, 0x39, 0x13, 0xE0, 0x04, 0x8A, 0x09, 
+	0xE0, 0x04, 0x8C, 0x09, 0xE0, 0x04, 0x8E, 0x09, 
+	0x60, 0x04, 0x62, 0xDA, 0x60, 0x04, 0xB0, 0xCE, 
+	0xB0, 0x03, 0x20, 0x98, 0x10, 0xE0, 0x65, 0x06, 
+	0xF9, 0x16, 0x44, 0x02, 0x00, 0x5E, 0x04, 0x16, 
+	0x20, 0x06, 0xC6, 0x06, 0x9A, 0x16, 0x0A, 0x10, 
+	0xB0, 0x03, 0x20, 0x98, 0x10, 0xE0, 0x65, 0x06, 
+	0xED, 0x16, 0x20, 0x06, 0xC8, 0x06, 0x02, 0x13, 
+	0x60, 0x04, 0x5A, 0xDB, 0x60, 0x01, 0x8E, 0x09, 
+	0x00, 0x01, 0x02, 0x16, 0xCE, 0x01, 0x03, 0x00, 
+	0x0E, 0x01, 0x03, 0x00, 0x03, 0x13, 0x83, 0x07, 
+	0x00, 0x82, 0x07, 0x10, 0x83, 0x07, 0x01, 0x00, 
+	0xE0, 0x04, 0x8E, 0x09, 0x20, 0xE8, 0x0C, 0xE0, 
+	0x82, 0x01, 0x60, 0x04, 0xCA, 0xCE, 0x60, 0x01, 
+	0x8A, 0x09, 0x00, 0x40, 0xC7, 0x16, 0x83, 0x07, 
+	0x0D, 0x00, 0xF2, 0x10, 0xB0, 0x03, 0x20, 0x98, 
+	0xAA, 0xE3, 0x65, 0x06, 0xC7, 0x16, 0x20, 0x88, 
+	0x98, 0x09, 0x20, 0xE0, 0xF0, 0x16, 0x22, 0xC8, 
+	0x0E, 0x00, 0xDC, 0x06, 0x22, 0xC8, 0x10, 0x00, 
+	0xDE, 0x06, 0x22, 0xC8, 0x12, 0x00, 0xE0, 0x06, 
+	0xE0, 0x01, 0x8E, 0x09, 0x00, 0x80, 0x08, 0x02, 
+	0x66, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0xB2, 0x10, 
+	0xA0, 0x07, 0x9A, 0x09, 0x5A, 0x00, 0xA0, 0x07, 
+	0xA2, 0x09, 0x19, 0x00, 0xA0, 0x07, 0xA4, 0x09, 
+	0x05, 0x00, 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x20, 
+	0xE0, 0x01, 0x8E, 0x09, 0x00, 0x04, 0x08, 0x02, 
+	0x78, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0xB0, 0x03, 
+	0x20, 0x98, 0xAB, 0xE3, 0x65, 0x06, 0x9A, 0x16, 
+	0x08, 0x02, 0x72, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 
+	0x20, 0xE8, 0x0C, 0xE0, 0x82, 0x01, 0xA0, 0x06, 
+	0xD0, 0xD5, 0x20, 0x06, 0x9A, 0x09, 0xBF, 0x13, 
+	0x84, 0x07, 0x2C, 0x00, 0x85, 0x07, 0xF4, 0x03, 
+	0xA0, 0x06, 0xA2, 0xD8, 0x60, 0x04, 0xC0, 0xDB, 
+	0x20, 0x48, 0x0C, 0xE0, 0x82, 0x01, 0x82, 0x10, 
+	0x0E, 0x01, 0x03, 0x00, 0x0A, 0x13, 0x08, 0x02, 
+	0x0C, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0xE0, 0xE3, 
+	0x14, 0xE0, 0x20, 0xC8, 0xAE, 0xE4, 0x86, 0x01, 
+	0x26, 0x10, 0x20, 0x48, 0x0C, 0xE0, 0x82, 0x01, 
+	0xE0, 0x2E, 0x01, 0x00, 0x60, 0xC1, 0x1E, 0x09, 
+	0x35, 0x0A, 0x05, 0xE8, 0x82, 0x01, 0x20, 0xC1, 
+	0x6A, 0x09, 0x04, 0x01, 0x06, 0x00, 0x06, 0x13, 
+	0x20, 0xD8, 0xD0, 0xE1, 0x2F, 0x09, 0x20, 0xD8, 
+	0xD0, 0xE1, 0x83, 0x01, 0x20, 0x21, 0x22, 0xE0, 
+	0x03, 0x16, 0x20, 0xE8, 0x22, 0xE0, 0x80, 0x01, 
+	0x20, 0x21, 0x04, 0xE0, 0x04, 0x16, 0xA0, 0xE3, 
+	0x14, 0xE0, 0x60, 0x04, 0x0A, 0xD3, 0x08, 0x02, 
+	0x00, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x20, 0xE8, 
+	0x08, 0xE0, 0x82, 0x01, 0xE0, 0xC2, 0x8A, 0x09, 
+	0x02, 0x11, 0x60, 0x04, 0xB0, 0xCE, 0xA0, 0x01, 
+	0x8E, 0x09, 0x00, 0x04, 0x6B, 0x10, 0x20, 0xC8, 
+	0xAE, 0xE4, 0x86, 0x01, 0x08, 0x02, 0x00, 0x80, 
+	0xA0, 0x06, 0xDA, 0xD4, 0x20, 0xC2, 0x1E, 0x09, 
+	0x08, 0xA2, 0x08, 0x05, 0x28, 0xC8, 0x22, 0xE0, 
+	0xCA, 0x06, 0x20, 0xC8, 0x20, 0xE0, 0xC6, 0x06, 
+	0x20, 0xC8, 0x20, 0xE0, 0xC8, 0x06, 0x60, 0xE3, 
+	0x16, 0xE0, 0x60, 0x04, 0xD2, 0xCE, 0x44, 0xC1, 
+	0x44, 0x02, 0x00, 0x5E, 0xF8, 0x16, 0x60, 0x25, 
+	0xA8, 0xE4, 0x0F, 0x16, 0x20, 0x06, 0xC6, 0x06, 
+	0xF2, 0x16, 0x20, 0x06, 0xCA, 0x06, 0x03, 0x13, 
+	0xA0, 0x05, 0xCC, 0x06, 0xE6, 0x10, 0xB0, 0x03, 
+	0x20, 0xD8, 0x0C, 0xE0, 0x65, 0x06, 0x60, 0x04, 
+	0xD2, 0xCE, 0x20, 0x06, 0xC8, 0x06, 0xE3, 0x16, 
+	0x20, 0x88, 0x70, 0x09, 0xCC, 0x06, 0x03, 0x16, 
+	0x83, 0x07, 0x08, 0x00, 0x02, 0x10, 0x83, 0x07, 
+	0x0C, 0x00, 0x60, 0x04, 0x8A, 0xDC, 0x60, 0x04, 
+	0xD2, 0xCE, 0xA0, 0x23, 0x08, 0xE0, 0x03, 0x13, 
+	0x60, 0x23, 0x12, 0xE0, 0x06, 0x16, 0xB0, 0x03, 
+	0x20, 0xD8, 0xA9, 0xE3, 0x65, 0x06, 0x60, 0x04, 
+	0xD2, 0xCE, 0x08, 0x02, 0x00, 0x80, 0xA0, 0x06, 
+	0xDA, 0xD4, 0x60, 0x04, 0xB0, 0xCE, 0x08, 0x02, 
+	0x00, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x20, 0xC8, 
+	0x1E, 0xE0, 0xC6, 0x06, 0x20, 0xC8, 0x1E, 0xE0, 
+	0xC8, 0x06, 0x60, 0xE3, 0x10, 0xE0, 0x60, 0x04, 
+	0xD2, 0xCE, 0xE0, 0x23, 0x14, 0xE0, 0x30, 0x13, 
+	0x44, 0xC1, 0x44, 0x02, 0x00, 0x1E, 0xF5, 0x16, 
+	0x60, 0x25, 0xA8, 0xE4, 0x1D, 0x16, 0x20, 0x06, 
+	0xC8, 0x06, 0xEF, 0x16, 0x60, 0x01, 0x8E, 0x09, 
+	0x00, 0x80, 0x13, 0x16, 0x60, 0x01, 0x8E, 0x09, 
+	0x00, 0x01, 0x0C, 0x16, 0xA0, 0x01, 0x8E, 0x09, 
+	0x00, 0x01, 0xA0, 0x01, 0x8E, 0x09, 0x80, 0x00, 
+	0xA0, 0x43, 0x04, 0xE0, 0x83, 0x07, 0x18, 0x68, 
+	0xA0, 0x06, 0x2A, 0xD8, 0x20, 0xC8, 0xAE, 0xE4, 
+	0x86, 0x01, 0xC2, 0x04, 0x60, 0x04, 0x2C, 0xE4, 
+	0x08, 0x02, 0x1E, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 
+	0x07, 0x10, 0x20, 0x06, 0xC6, 0x06, 0xCD, 0x16, 
+	0x83, 0x07, 0x09, 0x00, 0xA0, 0x06, 0x8A, 0xDC, 
+	0x60, 0x04, 0xB0, 0xCE, 0xCE, 0x04, 0xE0, 0x04, 
+	0x2A, 0x09, 0xE0, 0xD3, 0xAA, 0xE3, 0x8F, 0xC2, 
+	0x20, 0xC8, 0xB0, 0xE4, 0x86, 0x01, 0x20, 0x48, 
+	0x08, 0xE0, 0x82, 0x01, 0x86, 0x07, 0x05, 0x00, 
+	0x84, 0x07, 0x72, 0x06, 0x54, 0xC1, 0x01, 0x13, 
+	0xD4, 0x2C, 0x24, 0x02, 0x0A, 0x00, 0x06, 0x06, 
+	0xF9, 0x16, 0x08, 0x02, 0x2A, 0x80, 0xA0, 0x06, 
+	0xDA, 0xD4, 0x20, 0x2C, 0x1A, 0xE0, 0x60, 0x04, 
+	0x50, 0xCD, 0xA0, 0x06, 0x3E, 0xD7, 0xCD, 0x04, 
+	0xA0, 0x23, 0x1C, 0xE0, 0x0D, 0x13, 0x0E, 0x01, 
+	0x03, 0x00, 0x0A, 0x13, 0xA0, 0xE3, 0x1C, 0xE0, 
+	0xB0, 0x03, 0x20, 0xD8, 0x10, 0xE0, 0x65, 0x06, 
+	0xA0, 0xD2, 0x26, 0xE0, 0xCF, 0x04, 0x08, 0x10, 
+	0x20, 0x2D, 0x01, 0x00, 0xE0, 0xC0, 0x2A, 0x09, 
+	0xA0, 0x06, 0x2A, 0xD8, 0xA0, 0xD2, 0xAB, 0xE3, 
+	0x60, 0x04, 0xD2, 0xCE, 0xA0, 0x01, 0x80, 0x01, 
+	0x00, 0x01, 0xE0, 0x01, 0x80, 0x01, 0x00, 0xAC, 
+	0xA0, 0x01, 0x82, 0x01, 0x00, 0x03, 0xE0, 0x01, 
+	0x82, 0x01, 0x00, 0x08, 0x88, 0x07, 0xAE, 0x01, 
+	0x08, 0x06, 0xFE, 0x16, 0x60, 0x01, 0x8E, 0x09, 
+	0x00, 0x02, 0x03, 0x16, 0xA0, 0x01, 0x80, 0x01, 
+	0x00, 0x20, 0xC8, 0x04, 0x20, 0xD2, 0x80, 0x01, 
+	0x08, 0xC8, 0x9C, 0x09, 0x08, 0xD8, 0x2E, 0x09, 
+	0xA0, 0x07, 0x9E, 0x09, 0x00, 0x10, 0x5B, 0x04, 
+	0x20, 0xD8, 0xA6, 0x09, 0x2E, 0x09, 0xE0, 0x01, 
+	0x80, 0x01, 0x00, 0x04, 0xE0, 0x01, 0x82, 0x01, 
+	0x00, 0x08, 0xA0, 0x01, 0x82, 0x01, 0x00, 0x03, 
+	0x20, 0xC2, 0x30, 0x09, 0x03, 0x13, 0xE0, 0x01, 
+	0x82, 0x01, 0x00, 0x03, 0xA0, 0x01, 0x80, 0x01, 
+	0x00, 0xA1, 0x20, 0xF8, 0x2E, 0x09, 0x80, 0x01, 
+	0x88, 0x07, 0xAE, 0x01, 0x08, 0x06, 0xFE, 0x16, 
+	0xA0, 0x01, 0x80, 0x01, 0x00, 0x0C, 0xE0, 0x04, 
+	0x9E, 0x01, 0xE0, 0x04, 0x9C, 0x09, 0xE0, 0x04, 
+	0x9E, 0x09, 0x5B, 0x04, 0x20, 0x01, 0xA8, 0x09, 
+	0x00, 0x80, 0x11, 0x13, 0xE0, 0x93, 0x26, 0xE0, 
+	0x0E, 0x16, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, 
+	0x0A, 0x13, 0x08, 0x02, 0x84, 0x80, 0x00, 0x00, 
+	0x00, 0xE0, 0xDC, 0x0F, 0xA0, 0x06, 0xDA, 0xD4, 
+	0x20, 0x48, 0x08, 0xE0, 0x82, 0x01, 0x02, 0x10, 
+	0x60, 0x04, 0x70, 0xDA, 0x60, 0x04, 0xBA, 0xCE, 
+	0xA0, 0x06, 0x9C, 0xD5, 0x08, 0xC2, 0x19, 0x13, 
+	0x83, 0x07, 0x80, 0x80, 0xE0, 0x23, 0x14, 0xE0, 
+	0x02, 0x13, 0x83, 0x07, 0x0A, 0x00, 0x60, 0x04, 
+	0xC6, 0xCE, 0x20, 0xC1, 0x06, 0x06, 0x0D, 0x13, 
+	0xA0, 0x06, 0x9C, 0xD5, 0x08, 0xC2, 0x09, 0x13, 
+	0x83, 0x07, 0x0B, 0x00, 0xE0, 0x23, 0x14, 0xE0, 
+	0x02, 0x16, 0x83, 0x07, 0x01, 0x80, 0x60, 0x04, 
+	0xC6, 0xCE, 0x83, 0x07, 0x0A, 0x80, 0x60, 0x04, 
+	0xB4, 0xCE, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, 
+	0x06, 0x16, 0xA0, 0x06, 0xA8, 0xE5, 0x47, 0x10, 
+	0xD0, 0x03, 0x60, 0x04, 0xB0, 0xD3, 0xE0, 0x93, 
+	0x0E, 0xE0, 0x5E, 0x13, 0xE0, 0x93, 0x10, 0xE0, 
+	0x17, 0x13, 0xE0, 0x23, 0x14, 0xE0, 0x04, 0x13,  
+	0x83, 0x07, 0x07, 0x00, 0x60, 0x04, 0xC6, 0xCE, 
+	0x83, 0x07, 0x00, 0xA0, 0xA0, 0x06, 0x2A, 0xD8,  
+	0x83, 0x07, 0x00, 0x48, 0xA0, 0x06, 0x2A, 0xD8, 
+	0xA0, 0xD2, 0x10, 0xE0, 0x20, 0xC8, 0x1C, 0xE0, 
+	0xCA, 0x06, 0x20, 0xC8, 0x20, 0xE0, 0xCC, 0x06, 
+	0xA0, 0x06, 0x3E, 0xD7, 0x08, 0x02, 0x4E, 0x80, 
+	0xA0, 0x06, 0xDA, 0xD4, 0xA0, 0x23, 0x1C, 0xE0, 
+	0x20, 0x13, 0x20, 0x88, 0x6C, 0x09, 0x0E, 0x07, 
+	0x1C, 0x16, 0x20, 0x88, 0x6E, 0x09, 0x10, 0x07, 
+	0x18, 0x16, 0x20, 0x88, 0x70, 0x09, 0x12, 0x07, 
+	0x14, 0x16, 0x20, 0x88, 0x0A, 0x07, 0x22, 0xE0, 
+	0x10, 0x13, 0x20, 0x06, 0xCA, 0x06, 0x38, 0x16, 
+	0xA0, 0xE3, 0x20, 0xE0, 0x06, 0x10, 0xE0, 0x23, 
+	0x14, 0xE0, 0xCA, 0x16, 0xA0, 0xE3, 0x22, 0xE0, 
+	0xC2, 0x04, 0xA0, 0xD2, 0xAA, 0xE3, 0x60, 0x04, 
+	0xBA, 0xCE, 0x20, 0xC8, 0x1C, 0xE0, 0xCA, 0x06, 
+	0xA0, 0x88, 0xDC, 0x06, 0x0E, 0x00, 0x10, 0x16, 
+	0xA0, 0x88, 0xDE, 0x06, 0x10, 0x00, 0x0C, 0x16, 
+	0xA0, 0x88, 0xE0, 0x06, 0x12, 0x00, 0x08, 0x16, 
+	0x20, 0x06, 0xCC, 0x06, 0x19, 0x16, 0x20, 0xE8, 
+	0x0E, 0xE0, 0x82, 0x01, 0xA0, 0xE3, 0x1E, 0xE0, 
+	0x20, 0xC8, 0x20, 0xE0, 0xCC, 0x06, 0x10, 0x10, 
+	0xA0, 0x23, 0x10, 0xE0, 0x08, 0x16, 0x64, 0xC1, 
+	0x06, 0x00, 0x60, 0x21, 0x0C, 0xE0, 0x08, 0x13, 
+	0xA0, 0xD2, 0xA8, 0xE3, 0x05, 0x10, 0x20, 0x88, 
+	0x0A, 0x07, 0x08, 0x07, 0x96, 0x12, 0x00, 0x10, 
+	0x60, 0x04, 0xBA, 0xCE, 0x60, 0x01, 0x8E, 0x09, 
+	0x00, 0x80, 0x06, 0x16, 0x83, 0x07, 0x00, 0x82, 
+	0xA0, 0x06, 0x2A, 0xD8, 0x60, 0x04, 0xCA, 0xCE, 
+	0xE0, 0x93, 0x0E, 0xE0, 0x50, 0x13, 0xE0, 0x93, 
+	0xA9, 0xE3, 0x4D, 0x13, 0xE0, 0x93, 0xA8, 0xE3, 
+	0x1C, 0x13, 0xA0, 0x06, 0xA4, 0xD7, 0xA0, 0x23, 
+	0x10, 0xE0, 0x45, 0x13, 0xA0, 0x23, 0x08, 0xE0, 
+	0x06, 0x16, 0x60, 0xE3, 0x1E, 0xE0, 0x20, 0xC8, 
+	0x22, 0xE0, 0x06, 0x07, 0x34, 0x10, 0xE0, 0x23, 
+	0x14, 0xE0, 0x31, 0x16, 0x60, 0xC1, 0x6A, 0x09, 
+	0x60, 0x21, 0x12, 0xE0, 0x2C, 0x16, 0xA0, 0x06, 
+	0x0E, 0xE2, 0x31, 0x10, 0xA0, 0xD2, 0xA8, 0xE3, 
+	0x2E, 0x10, 0xA0, 0xE3, 0x12, 0xE0, 0xA0, 0x06, 
+	0x0E, 0xE2, 0x64, 0xC1, 0x06, 0x00, 0x60, 0x21, 
+	0x0C, 0xE0, 0x25, 0x13, 0x20, 0x88, 0x0E, 0x07, 
+	0xDC, 0x06, 0x14, 0x16, 0x20, 0x88, 0x10, 0x07, 
+	0xDE, 0x06, 0x10, 0x16, 0x20, 0x88, 0x12, 0x07, 
+	0xE0, 0x06, 0x0C, 0x16, 0x20, 0x98, 0xCE, 0x06, 
+	0xCF, 0x06, 0x15, 0x13, 0x20, 0x06, 0xCE, 0x06, 
+	0x12, 0x16, 0x60, 0xE3, 0x1A, 0xE0, 0xA0, 0xD2, 
+	0x0C, 0xE0, 0x0D, 0x10, 0x60, 0xE3, 0x1E, 0xE0,  
+	0x20, 0xC8, 0x32, 0xE0, 0x06, 0x07, 0xA0, 0x06, 
+	0x3E, 0xD7, 0x08, 0x02, 0x48, 0x80, 0xA0, 0x06, 
+	0xDA, 0xD4, 0xA0, 0xD2, 0xA9, 0xE3, 0x60, 0x04, 
+	0xBA, 0xCE, 0x22, 0x88, 0x0E, 0x00, 0x6C, 0x09, 
+	0xC9, 0x1A, 0x0B, 0x1B, 0x22, 0x88, 0x10, 0x00, 
+	0x6E, 0x09, 0xC4, 0x1A, 0x06, 0x1B, 0x22, 0x88, 
+	0x12, 0x00, 0x70, 0x09, 0xBF, 0x1A, 0x01, 0x1B, 
+	0x5B, 0x04, 0x60, 0xC1, 0x6C, 0x01, 0x85, 0x02, 
+	0x43, 0x00, 0xE1, 0x13, 0xE0, 0x93, 0xA8, 0xE3, 
+	0xDE, 0x16, 0xA0, 0xC8, 0x00, 0xEE, 0x02, 0x00, 
+	0x84, 0x07, 0x0E, 0x00, 0x42, 0xC1, 0xA0, 0xC0, 
+	0x6C, 0x01, 0x02, 0xC0, 0x25, 0x02, 0x48, 0x00, 
+	0x81, 0x07, 0x60, 0xE2, 0x83, 0x07, 0x14, 0xAE, 
+	0x60, 0x04, 0x9E, 0xE5, 0x02, 0x02, 0x00, 0xFC, 
+	0xCA, 0x10, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, 
+	0x06, 0x16, 0x83, 0x07, 0x00, 0x82, 0xA0, 0x06, 
+	0x2A, 0xD8, 0x60, 0x04, 0xCA, 0xCE, 0x20, 0x98, 
+	0x0E, 0xE0, 0x65, 0x06, 0x03, 0x16, 0x20, 0xD8, 
+	0xA8, 0xE3, 0x65, 0x06, 0xE0, 0x93, 0xA9, 0xE3, 
+	0x0D, 0x13, 0xA0, 0x23, 0x08, 0xE0, 0x19, 0x16, 
+	0xA0, 0x23, 0x10, 0xE0, 0x16, 0x13, 0x60, 0xE3, 
+	0x1E, 0xE0, 0x20, 0xC8, 0x20, 0xE0, 0x06, 0x07, 
+	0xA0, 0x06, 0x3E, 0xD7, 0xA0, 0x43, 0x18, 0xE0, 
+	0xE0, 0x2E, 0x01, 0x00, 0xA0, 0xD2, 0x26, 0xE0, 
+	0x83, 0x07, 0x10, 0x00, 0xA0, 0x06, 0x2A, 0xD8, 
+	0xE0, 0x23, 0x14, 0xE0, 0x02, 0x16, 0xA0, 0x06, 
+	0x18, 0xD7, 0xA0, 0x43, 0x2C, 0xE0, 0x20, 0xC8, 
+	0x20, 0xE0, 0x24, 0x09, 0x60, 0x04, 0xBA, 0xCE, 
+	0xA0, 0x06, 0xA8, 0xE5, 0x01, 0x10, 0x03, 0x10, 
+	0x20, 0x07, 0xA0, 0x09, 0x03, 0x10, 0xA0, 0x07, 
+	0xA2, 0x09, 0x19, 0x00, 0x60, 0x04, 0xBA, 0xCE, 
+	0xA0, 0x43, 0x0E, 0xE0, 0xA0, 0xC1, 0x24, 0x09, 
+	0x02, 0x13, 0x20, 0x06, 0x24, 0x09, 0xE0, 0x23, 
+	0x14, 0xE0, 0x03, 0x13, 0xA0, 0x23, 0x08, 0xE0, 
+	0x29, 0x16, 0x20, 0xC2, 0x8A, 0x09, 0xE4, 0x11, 
+	0x08, 0x02, 0x42, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 
+	0xA0, 0x23, 0x08, 0xE0, 0x1F, 0x16, 0xA0, 0x23, 
+	0x10, 0xE0, 0x0A, 0x16, 0x22, 0xC1, 0x02, 0x00, 
+	0x20, 0x25, 0xA8, 0xE4, 0x23, 0x16, 0x83, 0x07, 
+	0x20, 0x80, 0xA0, 0x06, 0x2A, 0xD8, 0x12, 0x10, 
+	0xA0, 0x06, 0x3E, 0xD7, 0xE0, 0x23, 0x14, 0xE0, 
+	0x02, 0x16, 0xA0, 0x06, 0x18, 0xD7, 0x60, 0xE3, 
+	0x1E, 0xE0, 0x20, 0xC8, 0x20, 0xE0, 0x06, 0x07, 
+	0xA0, 0x23, 0x08, 0xE0, 0x03, 0x16, 0xA0, 0x23, 
+	0x06, 0xE0, 0x51, 0x13, 0x20, 0x98, 0x0E, 0xE0, 
+	0x65, 0x06, 0x03, 0x16, 0x20, 0xD8, 0xA8, 0xE3, 
+	0x65, 0x06, 0x22, 0xC1, 0x02, 0x00, 0x20, 0x25, 
+	0xA8, 0xE4, 0x0E, 0x13, 0x83, 0x07, 0x20, 0x00, 
+	0xA0, 0x06, 0x2A, 0xD8, 0x22, 0xC8, 0x0E, 0x00, 
+	0xE6, 0x06, 0x22, 0xC8, 0x10, 0x00, 0xE8, 0x06, 
+	0x22, 0xC8, 0x12, 0x00, 0xEA, 0x06, 0x37, 0x10, 
+	0x22, 0x88, 0x0E, 0x00, 0xDC, 0x06, 0x08, 0x16, 
+	0x22, 0x88, 0x10, 0x00, 0xDE, 0x06, 0x04, 0x16, 
+	0x22, 0x88, 0x12, 0x00, 0xE0, 0x06, 0x0B, 0x13, 
+	0x22, 0xC8, 0x0E, 0x00, 0xDC, 0x06, 0x22, 0xC8, 
+	0x10, 0x00, 0xDE, 0x06, 0x22, 0xC8, 0x12, 0x00,  
+	0xE0, 0x06, 0x60, 0xE3, 0x14, 0xE0, 0xA0, 0x23, 
+	0x0E, 0xE0, 0x08, 0x16, 0xA0, 0xC1, 0x24, 0x09, 
+	0x1A, 0x16, 0x86, 0x07, 0x00, 0x10, 0x06, 0xE8, 
+	0xD2, 0x06, 0x15, 0x10, 0xA0, 0xE3, 0x0E, 0xE0, 
+	0xA0, 0x23, 0x08, 0xE0, 0x09, 0x16, 0xA0, 0xE3, 
+	0x06, 0xE0, 0xE0, 0x04, 0xE6, 0x06, 0xE0, 0x04, 
+	0xE8, 0x06, 0xE0, 0x04, 0xEA, 0x06, 0x07, 0x10, 
+	0x08, 0x02, 0x36, 0x80, 0xA0, 0x07, 0xD6, 0x06, 
+	0x36, 0xD3, 0xA0, 0x06, 0xDA, 0xD4, 0x60, 0x04, 
+	0xBA, 0xCE, 0x20, 0x98, 0x65, 0x06, 0x10, 0xE0, 
+	0x03, 0x16, 0x20, 0xD8, 0x0E, 0xE0, 0x65, 0x06, 
+	0x60, 0x04, 0xBA, 0xCE, 0xE0, 0x23, 0x14, 0xE0, 
+	0x02, 0x13, 0x60, 0x04, 0xBA, 0xCE, 0x2E, 0x10, 
+	0xB0, 0x03, 0x20, 0x98, 0xA9, 0xE3, 0x6F, 0x06, 
+	0x19, 0x16, 0x24, 0xC2, 0x08, 0x00, 0x16, 0x11, 
+	0xE0, 0xE3, 0x14, 0xE0, 0x83, 0x07, 0x00, 0x00, 
+	0xA0, 0x06, 0x2A, 0xD8, 0xA0, 0x23, 0x14, 0xE0, 
+	0x04, 0x13, 0x08, 0x02, 0x06, 0x80, 0xA0, 0x06, 
+	0xDA, 0xD4, 0x08, 0x02, 0x1E, 0x00, 0xA0, 0x06, 
+	0xDA, 0xD4, 0xA0, 0x23, 0x08, 0xE0, 0x02, 0x13, 
+	0xA0, 0x06, 0x18, 0xD7, 0x82, 0xC0, 0x02, 0x16, 
+	0x60, 0x04, 0xD2, 0xCE, 0x20, 0xE8, 0x1C, 0xEE, 
+	0xF0, 0x06, 0x20, 0x99, 0x0E, 0xE0, 0x16, 0x00, 
+	0x05, 0x16, 0xE0, 0x04, 0xEC, 0x06, 0x20, 0x48, 
+	0x14, 0xE0, 0xF0, 0x06, 0x83, 0x07, 0x01, 0x00, 
+	0x60, 0x04, 0xB4, 0xCE, 0x64, 0xC2, 0x14, 0x00, 
+	0x24, 0x02, 0x18, 0x00, 0xC4, 0xC1, 0xC2, 0x61, 
+	0x27, 0x02, 0xFC, 0xFF, 0x74, 0xC1, 0x85, 0xC1, 
+	0x45, 0x71, 0x85, 0x02, 0x27, 0x00, 0x46, 0x16, 
+	0x54, 0xC1, 0x45, 0x02, 0xCF, 0xFF, 0x42, 0x16, 
+	0xC8, 0x04, 0x64, 0xC1, 0x08, 0x00, 0x06, 0x15, 
+	0x05, 0x13, 0x24, 0xC2, 0x0E, 0x00, 0x48, 0x02, 
+	0x00, 0x1F, 0xC8, 0x06, 0x28, 0x02, 0x11, 0x00, 
+	0x04, 0xA2, 0x18, 0x98, 0x21, 0xEE, 0x32, 0x16, 
+	0x42, 0xC1, 0x25, 0x02, 0x04, 0x00, 0x47, 0x65, 
+	0x35, 0xC2, 0x74, 0xCD, 0x48, 0x06, 0xFD, 0x15, 
+	0xA0, 0xC0, 0x6C, 0x01, 0x02, 0xC1, 0x04, 0xC8, 
+	0x6C, 0x01, 0xA0, 0xC1, 0x00, 0xFC, 0x05, 0x13, 
+	0x20, 0xC8, 0x80, 0xEB, 0x02, 0xFC, 0x06, 0xC1, 
+	0xF6, 0x10, 0x20, 0xC8, 0x00, 0xEE, 0x02, 0xFC, 
+	0x02, 0xC8, 0x6C, 0x01, 0x81, 0x07, 0x08, 0xE5, 
+	0x04, 0xC0, 0x83, 0x07, 0x10, 0x02, 0x84, 0x07, 
+	0x0E, 0x00, 0x3B, 0x10, 0x84, 0x07, 0x0C, 0x00, 
+	0xE2, 0xC0, 0x08, 0x00, 0x05, 0x02, 0x00, 0xFC, 
+	0xA0, 0xC0, 0x6C, 0x01, 0x02, 0xC0, 0x95, 0xC1, 
+	0x30, 0x13, 0xD5, 0x04, 0x16, 0x2E, 0x02, 0xC8, 
+	0x6C, 0x01, 0x2B, 0x10, 0xA0, 0xC8, 0x22, 0xEE, 
+	0x0E, 0x00, 0xA0, 0xC8, 0x24, 0xEE, 0x10, 0x00, 
+	0xA0, 0xC8, 0x26, 0xEE, 0x12, 0x00, 0x83, 0x07, 
+	0x06, 0x80, 0x60, 0x04, 0xB4, 0xCE, 0x60, 0x04, 
+	0xD2, 0xCE, 0x84, 0x07, 0x10, 0x00, 0x85, 0x07, 
+	0x34, 0x00, 0x09, 0x10, 0x84, 0x07, 0x12, 0x00, 
+	0x85, 0x07, 0x32, 0x00, 0x04, 0x10, 0x84, 0x07, 
+	0x14, 0x00, 0x85, 0x07, 0x38, 0x00, 0xA0, 0x06, 
+	0xC2, 0xD5, 0x85, 0xC8, 0x04, 0x00, 0xA0, 0x06, 
+	0x10, 0xD6, 0xA0, 0xC8, 0x00, 0xEE, 0x02, 0x00, 
+	0xA0, 0xC0, 0x6C, 0x01, 0x02, 0xC0, 0x48, 0x06, 
+	0x48, 0xC1, 0xA0, 0x06, 0xA2, 0xD8, 0x07, 0x02, 
+	0xA2, 0x06, 0x60, 0xC5, 0x02, 0xFC, 0x25, 0x02, 
+	0xF4, 0xFF, 0x05, 0xC8, 0x02, 0xFC, 0x20, 0xC2, 
+	0x6C, 0x01, 0xA0, 0x06, 0xFC, 0xB4, 0x60, 0x04, 
+	0xB0, 0xCE, 0xA0, 0x06, 0xA2, 0xD8, 0x07, 0x02, 
+	0xB4, 0x06, 0xEF, 0x10, 0x22, 0x88, 0x12, 0x00, 
+	0x70, 0x09, 0x08, 0x16, 0x22, 0x88, 0x10, 0x00, 
+	0x6E, 0x09, 0x04, 0x16, 0x22, 0x88, 0x0E, 0x00, 
+	0x6C, 0x09, 0x0E, 0x13, 0x22, 0x88, 0x12, 0x00, 
+	0xE0, 0x06, 0x08, 0x16, 0x22, 0x88, 0x10, 0x00, 
+	0xDE, 0x06, 0x04, 0x16, 0x22, 0x88, 0x0E, 0x00, 
+	0xDC, 0x06, 0x01, 0x13, 0xCB, 0x05, 0xCB, 0x05, 
+	0x5B, 0x04, 0x0B, 0xC3, 0x00, 0x03, 0x02, 0x00, 
+	0x82, 0x07, 0xC0, 0x00, 0x20, 0xC8, 0x0C, 0x00, 
+	0xC0, 0x00, 0x20, 0xC8, 0x0E, 0x00, 0xC2, 0x00, 
+	0x20, 0xC8, 0x10, 0x00, 0xC4, 0x00, 0x20, 0xC8, 
+	0x12, 0x00, 0xC6, 0x00, 0x20, 0xC8, 0x14, 0x00, 
+	0xC8, 0x00, 0x20, 0xC8, 0x16, 0x00, 0xCA, 0x00, 
+	0x20, 0xC8, 0x04, 0x00, 0xCC, 0x00, 0x20, 0xC8, 
+	0x06, 0x00, 0xCE, 0x00, 0x02, 0xC8, 0x0C, 0x00, 
+	0xA0, 0x07, 0x0E, 0x00, 0x7E, 0xE6, 0x02, 0xC8, 
+	0x10, 0x00, 0xA0, 0x07, 0x12, 0x00, 0x88, 0xE6, 
+	0x02, 0xC8, 0x14, 0x00, 0xA0, 0x07, 0x16, 0x00, 
+	0xB8, 0xE6, 0x02, 0xC8, 0x04, 0x00, 0xA0, 0x07, 
+	0x06, 0x00, 0xCE, 0xE6, 0x60, 0x01, 0x1C, 0x01, 
+	0x04, 0x00, 0x09, 0x16, 0xE0, 0x01, 0x40, 0x01, 
+	0x00, 0x08, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x40, 
+	0xE0, 0x01, 0x40, 0x01, 0x00, 0x04, 0xA0, 0x06, 
+	0x8E, 0xE9, 0x05, 0x02, 0x00, 0x80, 0x05, 0xD8, 
+	0x80, 0x04, 0xC7, 0x04, 0x00, 0x03, 0x0F, 0x00, 
+	0x88, 0x07, 0x00, 0x10, 0x09, 0x02, 0x00, 0x20, 
+	0x8A, 0x07, 0xE6, 0xE6, 0x03, 0x02, 0x3E, 0xE6, 
+	0x5A, 0x04, 0x00, 0x03, 0x00, 0x00, 0x20, 0xD2, 
+	0x87, 0x01, 0x06, 0x10, 0x00, 0x03, 0x00, 0x00, 
+	0x20, 0xC2, 0x8A, 0x01, 0x08, 0x02, 0x00, 0x1A, 
+	0x60, 0xC2, 0xAE, 0x00, 0x48, 0xDA, 0x80, 0x04, 
+	0x89, 0x05, 0x89, 0x02, 0x06, 0x00, 0x07, 0x15, 
+	0x88, 0x07, 0x00, 0x80, 0x48, 0xDA, 0x80, 0x04, 
+	0x09, 0xC8, 0xAE, 0x00, 0x80, 0x03, 0xE0, 0x02, 
+	0xA0, 0x00, 0x5C, 0x04, 0x00, 0x03, 0x00, 0x00, 
+	0x60, 0x01, 0x9C, 0x01, 0x20, 0x00, 0xE2, 0x13, 
+	0x20, 0xC2, 0x8C, 0x01, 0x08, 0x02, 0x00, 0x1C, 
+	0xE3, 0x10, 0x00, 0x03, 0x00, 0x00, 0x60, 0x01,  
+	0x40, 0x01, 0x00, 0x40, 0xEC, 0x16, 0xA0, 0x01,  
+	0x40, 0x01, 0x00, 0x40, 0x08, 0x02, 0x00, 0x02, 
+	0xD7, 0x10, 0xB3, 0xC0, 0x92, 0x06, 0xFD, 0x10, 
+	0xB3, 0xC0, 0x48, 0xC0, 0x72, 0xCC, 0x72, 0xCC, 
+	0x32, 0xC1, 0x44, 0xCC, 0x72, 0xDC, 0x04, 0x06, 
+	0xFD, 0x16, 0x5B, 0x04, 0x48, 0xC0, 0x02, 0x02, 
+	0xD0, 0xE9, 0x84, 0x07, 0x06, 0x00, 0xF6, 0x10, 
+	0x02, 0x02, 0x1E, 0xE6, 0x49, 0xC0, 0x84, 0x07, 
+	0x06, 0x00, 0xF0, 0x10, 0xB3, 0xC0, 0x32, 0xC1, 
+	0x01, 0x02, 0x01, 0x00, 0x44, 0xD0, 0xC1, 0x06, 
+	0x44, 0x02, 0xFF, 0x00, 0xE7, 0x10, 0x33, 0xC1, 
+	0x73, 0xC0, 0x44, 0xD1, 0x44, 0x02, 0xFF, 0x00, 
+	0x45, 0xDC, 0x04, 0x06, 0xFD, 0x16, 0x5A, 0x04, 
+	0xA0, 0x06, 0x0E, 0xE9, 0x33, 0xC8, 0x9E, 0x01, 
+	0x5A, 0x04, 0xA0, 0x06, 0x0C, 0xE7, 0x89, 0xC1, 
+	0xA6, 0x09, 0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, 
+	0x8A, 0x01, 0x88, 0xC1, 0xA6, 0x09, 0x66, 0x02,  
+	0x40, 0x00, 0x06, 0xC8, 0x8C, 0x01, 0xC2, 0x04,  
+	0xC7, 0xC1, 0x03, 0x16, 0x02, 0x06, 0xFC, 0x16,  
+	0x4D, 0x10, 0x5A, 0x04, 0xA0, 0x06, 0x58, 0xE8, 
+	0x89, 0xC1, 0xA6, 0x09, 0x66, 0x02, 0x40, 0x00, 
+	0x06, 0xC8, 0x8A, 0x01, 0x88, 0xC1, 0xA6, 0x09, 
+	0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, 0x8C, 0x01, 
+	0x33, 0xC8, 0x9E, 0x01, 0xE8, 0x10, 0x33, 0x8A, 
+	0x02, 0x00, 0x38, 0x16, 0x73, 0x8A, 0x02, 0x00, 
+	0x35, 0x16, 0x5A, 0x04, 0x20, 0x8A, 0xCA, 0xE9, 
+	0x02, 0x00, 0x30, 0x16, 0x60, 0x8A, 0xCE, 0xE9, 
+	0x02, 0x00, 0x2C, 0x16, 0x82, 0x07, 0x74, 0xEA, 
+	0x01, 0x10, 0xB3, 0xC0, 0x04, 0x02, 0x80, 0x04, 
+	0x52, 0xD1, 0x03, 0x13, 0x32, 0x9D, 0x22, 0x16, 
+	0xFB, 0x10, 0x85, 0x07, 0x00, 0x80, 0x05, 0xD8, 
+	0x80, 0x04, 0xC7, 0x04, 0x5A, 0x04, 0x20, 0xC8, 
+	0xC0, 0x00, 0x0C, 0x00, 0x20, 0xC8, 0xC2, 0x00, 
+	0x0E, 0x00, 0x20, 0xC8, 0xC4, 0x00, 0x10, 0x00, 
+	0x20, 0xC8, 0xC6, 0x00, 0x12, 0x00, 0x20, 0xC8, 
+	0xC8, 0x00, 0x14, 0x00, 0x20, 0xC8, 0xCA, 0x00, 
+	0x16, 0x00, 0x20, 0xC8, 0xCC, 0x00, 0x04, 0x00, 
+	0x20, 0xC8, 0xCE, 0x00, 0x06, 0x00, 0x00, 0x03, 
+	0x0F, 0x00, 0xCC, 0x05, 0x5C, 0x04, 0xE0, 0x04, 
+	0x82, 0x01, 0x02, 0x02, 0x18, 0xE6, 0x32, 0xC8, 
+	0x82, 0x01, 0x32, 0xC8, 0x80, 0x01, 0xA0, 0x06, 
+	0x24, 0xE8, 0x12, 0xC8, 0x82, 0x01, 0xCA, 0xC2, 
+	0x84, 0x07, 0xD0, 0x07, 0xE0, 0x04, 0x84, 0x01, 
+	0x04, 0x06, 0xFC, 0x16, 0x20, 0xC1, 0x84, 0x01, 
+	0xE9, 0x16, 0x04, 0x02, 0x32, 0x00, 0x85, 0x07, 
+	0x00, 0x80, 0x05, 0xD8, 0x80, 0x04, 0xC7, 0x04, 
+	0x60, 0xC1, 0x86, 0x01, 0x04, 0x06, 0xFC, 0x16, 
+	0x20, 0xC1, 0x84, 0x01, 0x5B, 0x04, 0xB3, 0xC0, 
+	0xB3, 0xC4, 0x5B, 0x04, 0x48, 0xC0, 0xB3, 0xC0, 
+	0x73, 0xA0, 0x42, 0xC4, 0x5B, 0x04, 0x33, 0x88, 
+	0x84, 0x01, 0xE6, 0x16, 0x5A, 0x04, 0x89, 0xC1, 
+	0xA6, 0x09, 0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, 
+	0x8A, 0x01, 0x5B, 0x04, 0xC5, 0x04, 0xA0, 0x07, 
+	0x9C, 0x01, 0x40, 0x00, 0x60, 0x01, 0x9C, 0x01, 
+	0x40, 0x00, 0x03, 0x13, 0x05, 0x06, 0xF7, 0x16, 
+	0x5C, 0x04, 0x5B, 0x04, 0xA0, 0x06, 0xAC, 0xE8, 
+	0x60, 0xC0, 0x40, 0x01, 0x05, 0xC8, 0x40, 0x01, 
+	0x02, 0xC5, 0x01, 0xC8, 0x40, 0x01, 0x5A, 0x04, 
+	0xA0, 0x06, 0xAC, 0xE8, 0x08, 0xA1, 0xF4, 0x10, 
+	0xB3, 0xC0, 0x33, 0xC1, 0x60, 0xC1, 0x40, 0x01, 
+	0x85, 0x01, 0x00, 0x04, 0xC5, 0x01, 0x00, 0x10,  
+	0x5B, 0x04, 0x08, 0xC1, 0x09, 0xC2, 0x44, 0xC2, 
+	0x5B, 0x04, 0x05, 0x02, 0xC8, 0x00, 0x05, 0x06, 
+	0xFE, 0x16, 0x5B, 0x04, 0x33, 0xC1, 0x03, 0xC0, 
+	0xC4, 0xC0, 0x5B, 0x04, 0xC0, 0xC0, 0x5B, 0x04, 
+	0xE0, 0x94, 0x9E, 0x01, 0xC2, 0x16, 0xC3, 0x05, 
+	0x5B, 0x04, 0x73, 0xC0, 0xA0, 0x06, 0x26, 0xE9, 
+	0x2D, 0x02, 0x08, 0x00, 0x85, 0x07, 0x08, 0x00, 
+	0x71, 0x9F, 0xB7, 0x16, 0x05, 0x06, 0xFC, 0x16, 
+	0x5A, 0x04, 0x02, 0x02, 0x24, 0xE6, 0x60, 0x04, 
+	0x10, 0xE7, 0xE9, 0x8C, 0x04, 0x00, 0xAD, 0x16, 
+	0x5B, 0x04, 0x20, 0xC1, 0x80, 0x01, 0x85, 0x07, 
+	0xD0, 0x07, 0xE0, 0x01, 0x80, 0x01, 0x00, 0x04, 
+	0x45, 0x06, 0xFE, 0x16, 0x04, 0xC8, 0x80, 0x01, 
+	0x5B, 0x04, 0x33, 0xC1, 0x48, 0xC3, 0x04, 0xC1, 
+	0x04, 0x13, 0x2D, 0x02, 0x00, 0x04, 0x04, 0x06, 
+	0xFC, 0x16, 0x5B, 0x04, 0x8D, 0xC3, 0xA0, 0x06, 
+	0x26, 0xE9, 0x8D, 0xC1, 0xA6, 0x09, 0x66, 0x02, 
+	0x40, 0x00, 0x86, 0xC7, 0x5A, 0x04, 0x8D, 0xC1, 
+	0xA6, 0x09, 0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, 
+	0x8A, 0x01, 0x5B, 0x04, 0x8D, 0xC1, 0xA6, 0x09, 
+	0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, 0x8C, 0x01, 
+	0x5B, 0x04, 0x4D, 0xC0, 0x04, 0x02, 0x28, 0x00, 
+	0x85, 0x07, 0x00, 0x55, 0x60, 0x04, 0x34, 0xE7, 
+	0x4D, 0xC0, 0xB3, 0xC0, 0x32, 0xC1, 0x60, 0x04, 
+	0xF8, 0xE6, 0x33, 0xC1, 0x60, 0x01, 0x1C, 0x01, 
+	0x04, 0x00, 0x01, 0x16, 0x5B, 0x04, 0xC4, 0xC0, 
+	0x5B, 0x04, 0x89, 0x07, 0x66, 0xE5, 0x39, 0xC2, 
+	0x07, 0x13, 0x39, 0xC6, 0x39, 0x86, 0x25, 0x16, 
+	0x39, 0xC6, 0x39, 0x86, 0x22, 0x16, 0xF7, 0x10, 
+	0x02, 0x02, 0xAC, 0xE9, 0xC4, 0x04, 0xC5, 0x04, 
+	0x39, 0xC2, 0x02, 0x13, 0x60, 0x04, 0xE8, 0xE9, 
+	0x02, 0x02, 0xBA, 0xE9, 0xC4, 0x04, 0x39, 0xC2, 
+	0x03, 0x13, 0x79, 0xC1, 0x60, 0x04, 0xE8, 0xE9, 
+	0x02, 0x02, 0xCA, 0xE9, 0xC5, 0x04, 0x39, 0xC2, 
+	0x03, 0x13, 0x39, 0xC1, 0x60, 0x04, 0xE8, 0xE9, 
+	0x79, 0xC0, 0xB9, 0xC0, 0x81, 0x60, 0xC2, 0x05, 
+	0x12, 0x09, 0xF1, 0x04, 0x02, 0x06, 0xFD, 0x16, 
+	0x5B, 0x04, 0x5C, 0x04, 0x01, 0x02, 0xAA, 0xAA, 
+	0x01, 0xC6, 0x44, 0xE0, 0x45, 0x40, 0x58, 0x80, 
+	0xF8, 0x16, 0x01, 0x02, 0x14, 0x00, 0x01, 0x06, 
+	0xFE, 0x16, 0x01, 0x02, 0x55, 0x55, 0x01, 0xC6, 
+	0x44, 0xE0, 0x45, 0x40, 0x58, 0x80, 0xED, 0x16, 
+	0x52, 0x04, 0xE0, 0x02, 0xA0, 0x00, 0x88, 0x07, 
+	0xC0, 0x00, 0x09, 0x02, 0x62, 0xEA, 0x84, 0x07, 
+	0x2A, 0xE6, 0x05, 0x02, 0x01, 0x00, 0x8B, 0xC2, 
+	0xCC, 0x04, 0xA0, 0x06, 0x6C, 0xEA, 0x60, 0x2C, 
+	0x01, 0x00, 0x99, 0x06, 0xA0, 0x2C, 0x02, 0x00, 
+	0x99, 0x06, 0x20, 0x2D, 0x04, 0x00, 0x99, 0x06, 
+	0x20, 0x2E, 0x08, 0x00, 0x99, 0x06, 0xA0, 0x2F, 
+	0x10, 0x00, 0x8C, 0x05, 0x09, 0x16, 0x80, 0xCC, 
+	0x81, 0xC4, 0x83, 0x07, 0xB0, 0xEA, 0x88, 0xC0, 
+	0x02, 0x04, 0x8C, 0x05, 0x01, 0x16, 0x33, 0x10, 
+	0xE0, 0x02, 0xA0, 0x00, 0x5A, 0x04, 0x8C, 0x05, 
+	0xFB, 0x16, 0x80, 0xCC, 0x81, 0xC4, 0x15, 0x0A, 
+	0xB4, 0xC0, 0x12, 0xC0, 0x88, 0xCC, 0x52, 0xC0, 
+	0xB4, 0xC4, 0x42, 0x06, 0x5B, 0x04, 0x2D, 0x07, 
+	0x18, 0x00, 0x41, 0x8B, 0x0A, 0x00, 0xEC, 0x16, 
+	0xC1, 0x82, 0xEA, 0x16, 0xC2, 0x02, 0x42, 0x02, 
+	0x00, 0x02, 0xE6, 0x16, 0x80, 0x03, 0x81, 0x07, 
+	0x01, 0x00, 0xF1, 0x10, 0x01, 0x02, 0x02, 0x00, 
+	0xEE, 0x10, 0x01, 0x02, 0x04, 0x00, 0xEB, 0x10, 
+	0x01, 0x02, 0x08, 0x00, 0xE8, 0x10, 0x01, 0x02, 
+	0x10, 0x00, 0xE5, 0x10, 0xA1, 0x02, 0x41, 0x8B, 
+	0x10, 0x00, 0x02, 0x13, 0x60, 0x04, 0x5C, 0xEA, 
+	0x2D, 0x07, 0x18, 0x00, 0x80, 0x03, 0x09, 0x02, 
+	0x00, 0x08, 0x03, 0x02, 0x04, 0x00, 0xC7, 0x04, 
+	0xA0, 0x06, 0xDC, 0xEB, 0x60, 0x01, 0x1C, 0x01, 
+	0x04, 0x00, 0x1C, 0x16, 0xA0, 0x01, 0x40, 0x01, 
+	0x00, 0x08, 0xE0, 0x01, 0x40, 0x01, 0x00, 0x10, 
+	0x04, 0x02, 0x01, 0x00, 0x44, 0xCE, 0xC4, 0x06, 
+	0x44, 0xC6, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x10, 
+	0x49, 0x06, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x40, 
+	0xE0, 0x01, 0x40, 0x01, 0x00, 0x04, 0xE0, 0x01, 
+	0x40, 0x01, 0x00, 0x08, 0xA0, 0x06, 0x7A, 0xEC, 
+	0xA0, 0x06, 0x7A, 0xEC, 0xC7, 0x05, 0x04, 0x02, 
+	0xE4, 0xE4, 0xE0, 0x04, 0xD0, 0x03, 0x74, 0xC1, 
+	0xB4, 0xC1, 0x86, 0x05, 0x1C, 0x13, 0xE0, 0x02, 
+	0xC0, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, 0xC0, 
+	0x80, 0xC0, 0xC0, 0xC0, 0x00, 0xC1, 0x40, 0xC1, 
+	0x80, 0xC1, 0xC0, 0xC1, 0x00, 0xC2, 0x40, 0xC2, 
+	0x80, 0xC2, 0xC0, 0xC2, 0x00, 0xC3, 0x40, 0xC3, 
+	0x80, 0xC3, 0xC0, 0xC3, 0xA0, 0x04, 0xAA, 0x00, 
+	0xD0, 0x03, 0xD0, 0x03, 0x3F, 0x10, 0x85, 0x05, 
+	0x85, 0x81, 0xE1, 0x13, 0xE4, 0x10, 0xC7, 0x05, 
+	0x05, 0x02, 0xFF, 0x7F, 0x45, 0xA1, 0xD0, 0x03, 
+	0xD0, 0x03, 0x34, 0x10, 0xC0, 0xCC, 0xC1, 0xC4, 
+	0x03, 0x02, 0x28, 0x00, 0xA0, 0x06, 0xDC, 0xEB, 
+	0xE0, 0x01, 0x42, 0x01, 0x00, 0x10, 0xC7, 0x05, 
+	0xD0, 0x03, 0xD0, 0x03, 0x27, 0x10, 0xC7, 0x05, 
+	0xA0, 0xC1, 0x4A, 0x01, 0xA0, 0x07, 0x4A, 0x01, 
+	0x00, 0x0E, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x02, 
+	0x20, 0x07, 0x44, 0x01, 0x60, 0xC1, 0x44, 0x01, 
+	0x85, 0x02, 0x00, 0xFF, 0x17, 0x16, 0xE0, 0x01, 
+	0x40, 0x01, 0x00, 0x22, 0x05, 0x02, 0xC0, 0x00, 
+	0x05, 0x06, 0xD0, 0x03, 0xFD, 0x16, 0x60, 0xC1, 
+	0x46, 0x01, 0x85, 0x02, 0x00, 0xFF, 0x0A, 0x13, 
+	0x05, 0x02, 0x93, 0x33, 0x05, 0x06, 0x00, 0x10, 
+	0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 
+	0xD0, 0x03, 0xF8, 0x16, 0x51, 0x10, 0x06, 0xC8, 
+	0x4A, 0x01, 0xC0, 0xCC, 0xC1, 0xC4, 0x4B, 0x10, 
+	0x13, 0xC0, 0xC8, 0xCC, 0x53, 0xC0, 0x02, 0x02, 
+	0xEC, 0xEB, 0xC2, 0xC4, 0x43, 0x06, 0x5B, 0x04, 
+	0x60, 0xC0, 0xAE, 0x00, 0xC4, 0x02, 0x44, 0x02, 
+	0x0F, 0x00, 0x44, 0x88, 0xCA, 0xE4, 0x3C, 0x16, 
+	0x81, 0x02, 0x08, 0x00, 0x27, 0x13, 0x21, 0xC1, 
+	0xDC, 0xE4, 0x14, 0xC1, 0x21, 0x21, 0xBA, 0xE4, 
+	0x33, 0x16, 0x21, 0xC1, 0xC2, 0xE4, 0x81, 0x02, 
+	0x00, 0x00, 0x0B, 0x13, 0x0D, 0x02, 0xA0, 0x00, 
+	0x84, 0x83, 0x09, 0x13, 0xC4, 0x05, 0x84, 0x83, 
+	0x06, 0x13, 0xC4, 0x05, 0x84, 0x83, 0x03, 0x13, 
+	0x23, 0x10, 0x0E, 0x81, 0x21, 0x16, 0x21, 0xC1, 
+	0xDC, 0xE4, 0x21, 0x45, 0xBA, 0xE4, 0xE0, 0x01, 
+	0x42, 0x01, 0x00, 0x10, 0xA0, 0x01, 0x42, 0x01, 
+	0x00, 0x10, 0xA1, 0xC3, 0xD4, 0xE4, 0x0F, 0x02, 
+	0x2F, 0x00, 0x80, 0x03, 0xA0, 0x01, 0x40, 0x01, 
+	0x00, 0x02, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x80, 
+	0x6D, 0xC0, 0x0A, 0x00, 0x09, 0x13, 0x81, 0x02, 
+	0x5C, 0x12, 0x06, 0x1B, 0x0E, 0x02, 0xD2, 0xEB, 
+	0x0F, 0x02, 0x0F, 0x00, 0x80, 0x03, 0xCA, 0x05, 
+	0xE0, 0x02, 0xA0, 0x00, 0x5A, 0x04, 0x59, 0xCE, 
+	0x20, 0x88, 0xE4, 0xE4, 0xE4, 0xE4, 0xF8, 0x10, 
+	0xC1, 0x04, 0x48, 0x62, 0x89, 0x05, 0xA0, 0xC0, 
+	0x6C, 0x01, 0x08, 0xC8, 0x6C, 0x01, 0x03, 0x02, 
+	0x00, 0xFC, 0x04, 0x02, 0x00, 0x02, 0x73, 0xA0, 
+	0x04, 0x06, 0xFD, 0x16, 0x88, 0x05, 0x09, 0x06, 
+	0xF4, 0x16, 0x02, 0xC8, 0x6C, 0x01, 0x81, 0x86, 
+	0x02, 0x16, 0xD0, 0x03, 0xCB, 0x05, 0x5B, 0x04, 
+	0x43, 0x28, 0x31, 0x29, 0x38, 0x39, 0x2D, 0x33, 
+	0x38, 0x38, 0x42, 0x20, 0x20, 0x59, 0x49, 0x54, 
+	0x4B, 0xC2, 0xA8, 0x02, 0x98, 0x00, 0x83, 0x07, 
+	0x02, 0x00, 0x28, 0x02, 0x08, 0x00, 0x23, 0xC6, 
+	0x36, 0xE5, 0x48, 0x06, 0xC4, 0xC0, 0x73, 0x0A, 
+	0x65, 0x17, 0xA0, 0x06, 0xAA, 0xED, 0xC8, 0xC1, 
+	0xC7, 0x05, 0x03, 0x02, 0xA5, 0x00, 0xB0, 0x03, 
+	0xF8, 0xCD, 0xF8, 0xCD, 0xA6, 0x02, 0x06, 0x62, 
+	0x88, 0x02, 0x0A, 0x00, 0x57, 0x16, 0x03, 0x29, 
+	0x55, 0x16, 0x05, 0x29, 0xC4, 0x80, 0x52, 0x16, 
+	0x15, 0x09, 0x50, 0x17, 0x15, 0x09, 0x4E, 0x18, 
+	0x85, 0x02, 0x29, 0x00, 0x4B, 0x16, 0xC6, 0x05, 
+	0x96, 0x00, 0x03, 0x07, 0xC4, 0x04, 0x45, 0x06, 
+	0x95, 0x00, 0x44, 0x05, 0x43, 0x16, 0x44, 0x81, 
+	0x41, 0x16, 0x00, 0x03, 0x05, 0x00, 0xC4, 0x02, 
+	0x00, 0x03, 0x0A, 0x00, 0x44, 0x02, 0x0F, 0x00, 
+	0x84, 0x02, 0x05, 0x00, 0x37, 0x16, 0xC4, 0x02, 
+	0x00, 0x03, 0x0F, 0x00, 0x44, 0x02, 0x0F, 0x00, 
+	0x84, 0x02, 0x0A, 0x00, 0x2F, 0x16, 0x04, 0x02, 
+	0xFE, 0xFF, 0x2C, 0x13, 0x2B, 0x15, 0x2A, 0x1A, 
+	0x84, 0x05, 0x28, 0x12, 0x27, 0x15, 0x26, 0x1A, 
+	0x25, 0x18, 0x84, 0x05, 0x23, 0x16, 0x22, 0x1B, 
+	0x21, 0x17, 0x84, 0x05, 0x1F, 0x13, 0x1E, 0x1A, 
+	0x1D, 0x11, 0x04, 0x06, 0x1B, 0x16, 0xA5, 0x02, 
+	0xC5, 0xC1, 0x25, 0x02, 0x06, 0x00, 0x03, 0x02, 
+	0xA5, 0xA5, 0x83, 0xC1, 0x95, 0x00, 0x03, 0x38, 
+	0x94, 0x00, 0x83, 0x02, 0x2E, 0x6B, 0x0E, 0x16, 
+	0x84, 0x02, 0x59, 0x1C, 0x0B, 0x16, 0x24, 0x02, 
+	0x69, 0x00, 0x95, 0x00, 0x03, 0x3C, 0x94, 0x00, 
+	0x83, 0x81, 0x04, 0x16, 0x84, 0x02, 0x69, 0x00, 
+	0x01, 0x16, 0xC9, 0x05, 0x59, 0x04, 0xC3, 0xD0, 
+	0xFD, 0x13, 0x01, 0x1C, 0xFB, 0x10, 0xE0, 0x90, 
+	0x3D, 0xE5, 0xF8, 0x16, 0xC3, 0x06, 0xC3, 0xD0, 
+	0xF5, 0x1C, 0xF4, 0x16, 0xE0, 0x90, 0x3A, 0xE5, 
+	0xF1, 0x16, 0x5B, 0x04, 0x0B, 0xC3, 0x09, 0x02, 
+	0x3E, 0xE5, 0xA0, 0x06, 0x92, 0xE9, 0xCC, 0x05, 
+	0x5C, 0x04, 0x88, 0x07, 0x00, 0xA0, 0x89, 0x07, 
+	0xFE, 0xFF, 0xA8, 0x09, 0xA9, 0x09, 0x8A, 0x07, 
+	0x02, 0xE0, 0xA0, 0x06, 0x84, 0xEC, 0x00, 0x00, 
+	0x88, 0x07, 0x00, 0x90, 0x89, 0x07, 0xFE, 0x9F, 
+	0xA8, 0x09, 0xA9, 0x09, 0x8A, 0x07, 0x78, 0xE0, 
+	0xA0, 0x06, 0x84, 0xEC, 0x00, 0x00, 0xA0, 0x06, 
+	0xC4, 0xEC, 0x00, 0x00, 0xE6, 0x10, 0xE5, 0x10, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 
+	0x00, 0x08, 0x11, 0xE3, 0x6C, 0xCC, 0x00, 0x80, 
+	0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 
+	0x00, 0x04, 0x00, 0x02, 0x00, 0x01, 0x80, 0x00, 
+	0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 0x00, 
+	0x04, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0xFF, 
+	0xFF, 0x00, 0xF0, 0xFF, 0x00, 0xF0, 0x0F, 0x00,  
+	0xFF, 0xFF, 0xFF, 0x7F, 0x03, 0x00, 0x00, 0x00,  
+	0xC3, 0x00, 0xE7, 0xE7, 0xF3, 0xE7, 0xF1, 0xF1, 
+	0x43, 0x28, 0x20, 0x29, 0x4F, 0x43, 0x59, 0x50, 
+	0x49, 0x52, 0x48, 0x47, 0x20, 0x54, 0x42, 0x49, 
+	0x20, 0x4D, 0x39, 0x31, 0x33, 0x38, 0x34, 0x2C, 
+	0x35, 0x2C, 0x36, 0x2C, 0x43, 0x28, 0x20, 0x29, 
+	0x4F, 0x43, 0x59, 0x50, 0x49, 0x52, 0x48, 0x47, 
+	0x20, 0x54, 0x49, 0x54, 0x31, 0x20, 0x38, 0x39, 
+	0x2D, 0x33, 0x39, 0x38, 0x39, 0x2C, 0x2D, 0x30, 
+	0x38, 0x39, 0x00, 0x00, 0x61, 0x9B, 0xC4, 0xEC, 
+	0x0E, 0xEA, 0xDE, 0xE5, 0xC8, 0xED, 0x00, 0x00, 
+	0xC4, 0x00, 0xB8, 0xAF, 0x4A, 0x06, 0x50, 0x06, 
+	0x4C, 0x06, 0xDC, 0xCC, 0x4E, 0x06, 0x0F, 0x00, 
+	0x32, 0x06, 0x01, 0x00, 0x50, 0x07, 0x58, 0x07, 
+	0x52, 0x07, 0x70, 0xB5, 0x54, 0x07, 0x0F, 0x00, 
+	0x38, 0x07, 0x01, 0x00, 0xBA, 0x00, 0xA0, 0x00, 
+	0xBC, 0x00, 0xD6, 0xED, 0xBE, 0x00, 0x0F, 0x00, 
+	0x5E, 0x07, 0x3A, 0x07, 0x62, 0x07, 0x40, 0x80, 
+	0x64, 0x07, 0x54, 0xBA, 0x66, 0x07, 0x36, 0xBA, 
+	0x68, 0x07, 0x40, 0xB8, 0x98, 0x07, 0x00, 0x80, 
+	0x78, 0x07, 0x00, 0x80, 0xE2, 0x08, 0x04, 0x00, 
+	0xE4, 0x08, 0x01, 0x00, 0xEC, 0x08, 0x08, 0x00, 
+	0xF6, 0x08, 0x0A, 0x00, 0xF8, 0x08, 0x06, 0x00, 
+	0x00, 0x09, 0x0C, 0x00, 0x02, 0x09, 0x04, 0x00, 
+	0xAE, 0x01, 0x00, 0x00, 0x1E, 0x09, 0x00, 0x00, 
+	0x66, 0x09, 0x00, 0x00, 0x0C, 0x06, 0x13, 0x00, 
+	0x0A, 0x06, 0x20, 0x00, 0x00, 0x00, 0xE0, 0x00, 
+	0x86, 0xA3, 0xE0, 0x00, 0xE6, 0xA2, 0xE0, 0x00, 
+	0x86, 0xA3, 0xE0, 0x00, 0x02, 0xA5, 0xE0, 0x00, 
+	0x5E, 0xA6, 0xE0, 0x00, 0x66, 0xA9, 0xE0, 0x00, 
+	0x12, 0xA4, 0xC0, 0x00, 0x22, 0xA4, 0xE0, 0x00, 
+	0x86, 0xA3, 0xE0, 0x00, 0x86, 0xA3, 0xC0, 0x00, 
+	0x74, 0xA4, 0xE0, 0x00, 0x86, 0xA3, 0xE0, 0x00, 
+	0x86, 0xA3, 0xE0, 0x00, 0x86, 0xA3, 0xE0, 0x00, 
+	0x86, 0xA3, 0xE0, 0x00, 0x86, 0xA3, 0xC0, 0x00, 
+	0xDE, 0xAF, 0xC0, 0x00, 0x48, 0xB0, 0xC0, 0x00, 
+	0x84, 0xB0, 0xC0, 0x00, 0xF4, 0xB0, 0xC0, 0x00, 
+	0x76, 0xB1, 0xE0, 0x00, 0xE4, 0xB2, 0xE0, 0x00, 
+	0x8A, 0xB2, 0xE0, 0x00, 0xF4, 0xB3, 0xE0, 0x00, 
+	0x7C, 0xB3, 0xE0, 0x00, 0xC6, 0xAA, 0xC0, 0x00, 
+	0x36, 0xAB, 0xC0, 0x00, 0x90, 0xAB, 0xC0, 0x00, 
+	0xC2, 0xAB, 0xC0, 0x00, 0xEA, 0xAA, 0xC0, 0x00, 
+	0x80, 0xA3, 0xC0, 0x00, 0x80, 0xA3, 0x00, 0x3F, 
+	0x00, 0x7F, 0x00, 0x5E, 0x30, 0x00, 0x28, 0x00, 
+	0x43, 0x00, 0xB6, 0xA6, 0xB6, 0xA6, 0x1C, 0xA5, 
+	0x14, 0xA5, 0x46, 0xA5, 0x46, 0xA5, 0x62, 0xA5, 
+	0xB6, 0xA6, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, 
+	0x00, 0x00, 0x00, 0x08, 0x00, 0x20, 0x00, 0x08, 
+	0x00, 0x80, 0x00, 0x08, 0x00, 0x01, 0x00, 0x10, 
+	0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 
+	0x14, 0x00, 0x0E, 0x10, 0x0C, 0x0C, 0x0A, 0x0A, 
+	0x0A, 0x0A, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 
+	0x08, 0x08, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,  
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 
+	0x06, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,  
+	0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 
+	0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 
+	0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 
+	0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 
+	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 
+	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 
+	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 
+	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 
+	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 
+	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 
+	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 
+	0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x98, 0x07, 0x7E, 0xCA, 0x58, 0x07, 
+	0xF8, 0xB8, 0x58, 0x07, 0xFE, 0xB7, 0x58, 0x07, 
+	0x68, 0xB9, 0x58, 0x07, 0xD0, 0xB8, 0x98, 0x07, 
+	0x5A, 0xC7, 0x98, 0x07, 0x52, 0xC7, 0x78, 0x07, 
+	0xC2, 0xC1, 0x58, 0x07, 0x30, 0xB9, 0x98, 0x07, 
+	0x38, 0xCA, 0x78, 0x07, 0x96, 0xC2, 0x58, 0x07, 
+	0x6A, 0xC7, 0x58, 0x07, 0xE0, 0xB8, 0x58, 0x07, 
+	0x1E, 0xB9, 0x58, 0x07, 0xE2, 0xB9, 0x98, 0x07, 
+	0xAE, 0xCB, 0x98, 0x07, 0x8E, 0xC7, 0x78, 0x07, 
+	0x56, 0xC2, 0xB8, 0x07, 0x14, 0xCC, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0xA2, 0xBA, 0x16, 0xC1, 
+	0xCA, 0xC1, 0xD6, 0xC6, 0x8A, 0xBD, 0xC2, 0xBD, 
+	0xE0, 0xBD, 0x6A, 0xBE, 0x8E, 0xBE, 0xAA, 0xBE, 
+	0x22, 0xBF, 0x22, 0xBF, 0x56, 0xBE, 0xC8, 0xBF, 
+	0x10, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 
+	0x00, 0x0C, 0x01, 0x0F, 0xFF, 0xFE, 0x00, 0x58, 
+	0x00, 0x0E, 0xFF, 0xFE, 0x0E, 0x00, 0x00, 0x70, 
+	0x40, 0x80, 0x00, 0x5E, 0xA0, 0xC0, 0xDF, 0xFF, 
+	0x00, 0x18, 0x00, 0xE0, 0x00, 0x78, 0x00, 0x50, 
+	0x00, 0x60, 0x00, 0x70, 0x00, 0x0C, 0x06, 0x00, 
+	0x00, 0x00, 0x84, 0xE3, 0xE6, 0x07, 0xF4, 0x07, 
+	0x08, 0x00, 0x00, 0x00, 0x8A, 0xE3, 0xEA, 0x07, 
+	0xF4, 0x07, 0x06, 0x00, 0x40, 0x00, 0x00, 0x0A, 
+	0xE6, 0x07, 0xEE, 0x07, 0x08, 0x00, 0x40, 0x00, 
+	0x06, 0x0A, 0xEA, 0x07, 0xEE, 0x07, 0x00, 0x00, 
+	0xE2, 0xC1, 0x8B, 0xD4, 0xFF, 0xFF, 0xD7, 0xD1, 
+	0xD9, 0xC5, 0xD4, 0xC3, 0x3B, 0x59, 0x34, 0x09, 
+	0xFC, 0x05, 0x6C, 0x09, 0xD8, 0x06, 0x06, 0x04, 
+	0xBA, 0xEA, 0x30, 0x09, 0x48, 0x04, 0x80, 0x08, 
+	0x06, 0x00, 0x0A, 0x06, 0x0E, 0x0C, 0xBA, 0xCE, 
+	0x2E, 0xE0, 0x56, 0xE0, 0x50, 0xE1, 0x66, 0xE2, 
+	0xEC, 0xE2, 0x4C, 0xE3, 0xFE, 0xE3, 0xBA, 0xCE, 
+	0x80, 0xE4, 0x10, 0xE4, 0x14, 0xE0, 0x1C, 0xE4, 
+	0x1C, 0xE4, 0x46, 0xE5, 0x50, 0xE5, 0x5A, 0xE5, 
+	0xBA, 0xCE, 0xA6, 0xDC, 0xBA, 0xCE, 0x44, 0xDA, 
+	0xE6, 0xDF, 0x70, 0xDA, 0xDE, 0xDE, 0xB0, 0xCE, 
+	0x16, 0xDB, 0x3A, 0xDD, 0xB8, 0xDD, 0x34, 0xDE, 
+	0x58, 0xDE, 0x16, 0xDB, 0xDA, 0xDC, 0x08, 0xCF, 
+	0xB0, 0xCE, 0xA8, 0xD9, 0x8A, 0xD9, 0x44, 0xD9, 
+	0xB0, 0xCE, 0xEA, 0xDE, 0xB0, 0xCE, 0x72, 0x06, 
+	0xF6, 0xD2, 0x08, 0x07, 0x72, 0x06, 0x54, 0xD2, 
+	0xF4, 0x01, 0x72, 0x06, 0x34, 0xD2, 0x08, 0x07, 
+	0x7C, 0x06, 0x5A, 0xDC, 0x04, 0x00, 0x7C, 0x06, 
+	0x78, 0xD2, 0x00, 0x00, 0x7C, 0x06, 0xCC, 0xDE, 
+	0xFA, 0x00, 0x86, 0x06, 0xAC, 0xD1, 0x05, 0x00, 
+	0x90, 0x06, 0x1C, 0xDF, 0x28, 0x00, 0x90, 0x06, 
+	0x50, 0xD3, 0x04, 0x01, 0x90, 0x06, 0x00, 0x00, 
+	0x02, 0x00, 0x90, 0x06, 0x80, 0xD2, 0xBC, 0x02, 
+	0x9A, 0x06, 0x06, 0xD3, 0xDC, 0x05, 0x9A, 0x06, 
+	0xAA, 0xD2, 0x64, 0x00, 0x9A, 0x06, 0x0A, 0xD3, 
+	0x14, 0x00, 0x9A, 0x06, 0xE2, 0xE0, 0x40, 0x06, 
+	0x9A, 0x06, 0x12, 0xD3, 0x64, 0x00, 0x7C, 0x06, 
+	0x16, 0xDC, 0x04, 0x00, 0x7C, 0x06, 0xE6, 0xDA,  
+	0x16, 0x00, 0x7C, 0x06, 0xFA, 0xDB, 0x05, 0x00, 
+	0x7C, 0x06, 0x00, 0xDD, 0x14, 0x00, 0x9A, 0x06, 
+	0x7C, 0xD3, 0x14, 0x00, 0x9A, 0x06, 0x38, 0xD4, 
+	0x02, 0x00, 0x7C, 0x06, 0x0C, 0xE0, 0x19, 0x00, 
+	0x00, 0x00, 0x0A, 0x07, 0x0E, 0x07, 0x04, 0x07, 
+	0xD8, 0x06, 0x00, 0x07, 0xF0, 0x06, 0xEE, 0x06, 
+	0xEC, 0x06, 0x0C, 0x07, 0xE6, 0x06, 0x18, 0x07, 
+	0x92, 0x09, 0x94, 0x09, 0x96, 0x09, 0x98, 0x09, 
+	0x00, 0x50, 0xCC, 0x00, 0x03, 0x00, 0x00, 0x84, 
+	0x00, 0xA8, 0x00, 0xA0, 0x00, 0x20, 0x00, 0x80, 
+	0x00, 0x40, 0x00, 0x08, 0x00, 0x40, 0x00, 0x80, 
+	0x00, 0x40, 0x00, 0x10, 0x82, 0xEC, 0x48, 0xEB, 
+	0x62, 0xEB, 0x7C, 0xEB, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x09, 0x00, 0x09, 0x00, 0xEA, 0xEB, 
+	0x52, 0xEB, 0x68, 0xEB, 0x82, 0xEB, 0x40, 0x01, 
+	0x42, 0x01, 0x42, 0x01, 0x42, 0x01, 0x00, 0x00, 
+	0x7F, 0x00, 0xA0, 0x00, 0xFF, 0x00, 0x10, 0x02, 
+	0x1F, 0x02, 0x30, 0x02, 0x3F, 0x02, 0x50, 0x02, 
+	0x5F, 0x02, 0x70, 0x02, 0x7F, 0x02, 0x90, 0x02, 
+	0x9F, 0x02, 0xB0, 0x02, 0xBF, 0x02, 0xD0, 0x02, 
+	0xDF, 0x02, 0xE1, 0x02, 0xFF, 0x02, 0x01, 0x03, 
+	0x7F, 0x03, 0x81, 0x03, 0x8F, 0x03, 0x91, 0x03, 
+	0x9F, 0x03, 0xA1, 0x03, 0xAF, 0x03, 0xB1, 0x03, 
+	0xBF, 0x03, 0xC1, 0x03, 0xCF, 0x03, 0xE1, 0x03, 
+	0xFF, 0x03, 0xC0, 0x07, 0xFF, 0x07, 0x00, 0x0C, 
+	0xFF, 0x0F, 0x00, 0x30, 0xFF, 0x37, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xBC, 0xFE, 0x07, 0x00, 0x5E, 0x02, 
+	0x00, 0x01, 0xFF, 0xBA, 0x80, 0xBA, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x0C, 0x01, 0x0A, 0x01, 
+	0x0E, 0x01, 0x10, 0x01, 0x14, 0x01, 0x00, 0x00, 
+	0x12, 0x01, 0x00, 0xF8, 0x16, 0x01, 0x00, 0xFF, 
+	0x00, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x1C, 0x01, 
+	0x82, 0x01, 0x66, 0x96, 0x66, 0x96, 0x55, 0x55, 
+	0x00, 0x00, 0x82, 0x01, 0x2A, 0x8A, 0x2A, 0x8A, 
+	0x18, 0xC9, 0x18, 0xC9, 0x86, 0x01, 0xAA, 0xA2, 
+	0x1E, 0xA0, 0x55, 0x55, 0x1E, 0x54, 0x8A, 0x01, 
+	0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 
+	0x8C, 0x01, 0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, 
+	0x00, 0x00, 0x8E, 0x01, 0x00, 0x50, 0x00, 0x00, 
+	0x00, 0xA8, 0x00, 0x00, 0x90, 0x01, 0x00, 0x50, 
+	0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x92, 0x01, 
+	0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 
+	0x94, 0x01, 0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, 
+	0x00, 0x00, 0x96, 0x01, 0x00, 0x50, 0x00, 0x00, 
+	0x00, 0xA8, 0x00, 0x00, 0x98, 0x01, 0x00, 0x50, 
+	0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x9A, 0x01, 
+	0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 
+	0x9C, 0x01, 0x55, 0x55, 0xC0, 0x7F, 0xAA, 0xAA, 
+	0xC0, 0x7F, 0x00, 0x00, 0xA2, 0x01, 0xA4, 0x01, 
+	0xA8, 0x01, 0xAA, 0x01, 0xAE, 0x01, 0xB0, 0x01, 
+	0xB2, 0x01, 0x80, 0x01, 0x00, 0x00, 0x88, 0x01, 
+	0x00, 0xFF, 0x9E, 0x01, 0xFF, 0x00, 0xA0, 0x01, 
+	0x00, 0x80, 0xAC, 0x01, 0x00, 0x80, 0x00, 0x00, 
+	0xA6, 0x01, 0x00, 0x80, 0x00, 0x00, 0x80, 0x01, 
+	0xBC, 0x01, 0x00, 0x88, 0x00, 0x06, 0x00, 0xC8, 
+	0x00, 0x00, 0x00, 0x80, 0x30, 0x00, 0x00, 0x00, 
+	0x00, 0x80, 0x02, 0x00, 0x44, 0x00, 0x92, 0xEA, 
+	0x48, 0x00, 0x98, 0xEA, 0x50, 0x00, 0x9E, 0xEA, 
+	0x60, 0x00, 0xA4, 0xEA, 0x78, 0x00, 0xAA, 0xEA, 
+	0x0A, 0xE8, 0x18, 0xE7, 0x3C, 0xEA, 0x2A, 0xE7, 
+	0x14, 0x55, 0xA0, 0x01, 0xEC, 0xE6, 0xD0, 0xE9, 
+	0x46, 0xE7, 0xA0, 0xE7, 0x00, 0xE7, 0x58, 0xE8, 
+	0x00, 0x00, 0x1E, 0x00, 0x46, 0xE7, 0x92, 0xE7, 
+	0x00, 0x41, 0x01, 0x41, 0xB6, 0xE7, 0x73, 0xEA, 
+	0x18, 0xE7, 0x48, 0xEA, 0xEC, 0xE6, 0x04, 0xEA, 
+	0x56, 0xE7, 0x62, 0xE7, 0xB6, 0xE7, 0x6E, 0xEA, 
+	0x62, 0xE8, 0x00, 0x00, 0x36, 0xE8, 0xEC, 0xE6, 
+	0xFA, 0xE9, 0x56, 0xE7, 0x62, 0xE7, 0x36, 0xE8, 
+	0x62, 0xE8, 0x00, 0x00, 0xEC, 0xE6, 0xF0, 0xE9, 
+	0x0C, 0xE7, 0x4A, 0xE7, 0x62, 0xE7, 0x36, 0xE8, 
+	0xEC, 0xE6, 0xFA, 0xE9, 0x56, 0xE7, 0x62, 0xE7, 
+	0x36, 0xE8, 0x62, 0xE8, 0x00, 0x20, 0x2A, 0xE7, 
+	0x14, 0x55, 0xA0, 0x01, 0x18, 0xE7, 0x50, 0xEA, 
+	0xEC, 0xE6, 0xD0, 0xE9, 0x58, 0xE8, 0x50, 0x55, 
+	0x0C, 0x00, 0x46, 0xE7, 0x92, 0xE7, 0x00, 0x01, 
+	0x00, 0x00, 0xB6, 0xE7, 0x75, 0xEA, 0x00, 0xE7, 
+	0x58, 0xE8, 0x55, 0x55, 0x0C, 0x00, 0x56, 0xE7, 
+	0xA0, 0xE7, 0x00, 0xE7, 0x58, 0xE8, 0xFF, 0xFF, 
+	0x08, 0x00, 0x58, 0xE8, 0x02, 0x10, 0x06, 0x00, 
+	0x46, 0xE7, 0x92, 0xE7, 0x00, 0x01, 0x01, 0x01, 
+	0xB6, 0xE7, 0x80, 0xEA, 0x00, 0xE7, 0x58, 0xE8, 
+	0x00, 0xC0, 0x08, 0x00, 0x58, 0xE8, 0xFF, 0xFF, 
+	0x0A, 0x00, 0x58, 0xE8, 0xFF, 0xFF, 0x0C, 0x00, 
+	0x58, 0xE8, 0x0D, 0x10, 0x06, 0x00, 0x46, 0xE7, 
+	0x92, 0xE7, 0x00, 0x01, 0x01, 0x01, 0xB6, 0xE7, 
+	0x74, 0xEA, 0x62, 0xE8, 0x08, 0x20, 0x00, 0xE7, 
+	0x52, 0xE8, 0x82, 0x01, 0x02, 0xC9, 0x46, 0xE7, 
+	0xB6, 0xE7, 0x80, 0xEA, 0x62, 0xE8, 0x34, 0x20, 
+	0x00, 0xE7, 0x58, 0xE8, 0x00, 0x10, 0x06, 0x00, 
+	0x46, 0xE7, 0xC6, 0xE8, 0xB6, 0xE7, 0x78, 0xEA, 
+	0x52, 0xE8, 0x9C, 0x01, 0x40, 0x00, 0x18, 0xE7, 
+	0x50, 0xEA, 0x2A, 0xE7, 0xFF, 0x00, 0x80, 0x07, 
+	0x26, 0xE9, 0x03, 0x00, 0x66, 0xE9, 0x74, 0xE9, 
+	0x12, 0xEA, 0x38, 0xE9, 0x00, 0x00, 0x74, 0xE9, 
+	0x1C, 0xEA, 0x38, 0xE9, 0x04, 0x00, 0x74, 0xE9, 
+	0x24, 0xEA, 0x38, 0xE9, 0x07, 0x00, 0x74, 0xE9, 
+	0x2C, 0xEA, 0x26, 0xE9, 0x01, 0x00, 0x74, 0xE9, 
+	0x34, 0xEA, 0x38, 0xE9, 0x02, 0x00, 0x74, 0xE9, 
+	0x34, 0xEA, 0x38, 0xE9, 0x06, 0x00, 0x74, 0xE9, 
+	0x34, 0xEA, 0x38, 0xE9, 0x05, 0x00, 0x74, 0xE9, 
+	0x34, 0xEA, 0x26, 0xE9, 0x01, 0x00, 0x4A, 0xE9, 
+	0x26, 0xE9, 0x03, 0x00, 0x58, 0xE9, 0x62, 0xE7, 
+	0xE6, 0xE8, 0xD8, 0xE9, 0x01, 0x00, 0xE6, 0xE8, 
+	0x25, 0xEA, 0x02, 0x00, 0xE6, 0xE8, 0x2F, 0xEA, 
+	0x06, 0x00, 0xE6, 0xE8, 0x3A, 0xEA, 0x05, 0x00, 
+	0xB6, 0xE7, 0x74, 0xEA, 0x36, 0xE8, 0xEC, 0xE6, 
+	0xD0, 0xE9, 0x56, 0xE7, 0xC6, 0xE8, 0x0C, 0xE7, 
+	0x92, 0xE7, 0x00, 0x01, 0x00, 0x80, 0xB6, 0xE7, 
+	0x78, 0xEA, 0x00, 0xE7, 0xFE, 0xE8, 0x52, 0xE8, 
+	0x80, 0x01, 0x41, 0x8E, 0x4A, 0xE7, 0x92, 0xE7, 
+	0x00, 0x01, 0x01, 0x1B, 0x06, 0xE9, 0xE4, 0xFF, 
+	0xB6, 0xE7, 0x7C, 0xEA, 0xBE, 0xE8, 0x18, 0xE7, 
+	0x56, 0xEA, 0x0C, 0xE7, 0x6A, 0xE8, 0x3C, 0xE7, 
+	0x00, 0xE0, 0xC6, 0xE8, 0xB6, 0xE7, 0x86, 0xEA, 
+	0x3C, 0xE7, 0x00, 0xE8, 0x62, 0xE7, 0xB6, 0xE7, 
+	0x85, 0xEA, 0x3C, 0xE7, 0x00, 0x08, 0xC6, 0xE8, 
+	0xB6, 0xE7, 0x86, 0xEA, 0x3C, 0xE7, 0x00, 0xF8, 
+	0x62, 0xE7, 0xB6, 0xE7, 0x85, 0xEA, 0x52, 0xE8, 
+	0x80, 0x01, 0x00, 0x02, 0x3C, 0xE7, 0x00, 0xE0, 
+	0x62, 0xE7, 0xB6, 0xE7, 0x85, 0xEA, 0x52, 0xE8, 
+	0x84, 0x01, 0x00, 0x00, 0x62, 0xE8, 0x34, 0x00, 
+	0x3C, 0xE7, 0x00, 0x00, 0xC6, 0xE8, 0x62, 0xE8, 
+	0x34, 0x60, 0x0E, 0xE9, 0x52, 0xE8, 0x84, 0x01, 
+	0x00, 0x00, 0xB6, 0xE7, 0x86, 0xEA, 0x52, 0xE8, 
+	0x82, 0x01, 0x00, 0xC8, 0x3C, 0xE7, 0x00, 0xE0, 
+	0xC6, 0xE8, 0x3C, 0xE7, 0x00, 0x10, 0xC6, 0xE8, 
+	0x62, 0xE8, 0x34, 0x60, 0x52, 0xE8, 0x80, 0x01, 
+	0x00, 0x06, 0x3C, 0xE7, 0x10, 0x00, 0x78, 0xE8, 
+	0x36, 0xE8, 0x52, 0xE8, 0x84, 0x01, 0x00, 0x00, 
+	0x62, 0xE8, 0x34, 0x00, 0xEC, 0xE6, 0xD0, 0xE9, 
+	0x18, 0xE7, 0x5C, 0xEA, 0xD0, 0xE8, 0x92, 0xE9, 
+	0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0xF0, 
+	0x06, 0x00, 0x00, 0xC7, 0xA0, 0xE7, 0xDC, 0xE8, 
+	0x00, 0xE0, 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 
+	0x40, 0xD0, 0x06, 0x00, 0x00, 0xE0, 0xA0, 0xE7, 
+	0xDC, 0xE8, 0x00, 0xC0, 0x00, 0xE7, 0x0C, 0xE7, 
+	0x70, 0xE7, 0x40, 0x90, 0x06, 0x00, 0x00, 0xA0, 
+	0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x80, 0x00, 0xE7, 
+	0x0C, 0xE7, 0x70, 0xE7, 0x40, 0x50, 0x06, 0x00, 
+	0x00, 0x60, 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x40, 
+	0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0x10, 
+	0x06, 0x00, 0x00, 0x20, 0xA0, 0xE7, 0xDC, 0xE8,  
+	0x00, 0x00, 0xD0, 0xE8, 0x92, 0xE9, 0x00, 0xE7,  
+	0x0C, 0xE7, 0x70, 0xE7, 0x40, 0xD0, 0x06, 0x00, 
+	0x00, 0xA6, 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0xC0, 
+	0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0x90, 
+	0x06, 0x00, 0x00, 0xC0, 0xA0, 0xE7, 0xDC, 0xE8, 
+	0x00, 0x80, 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 
+	0x40, 0x50, 0x06, 0x00, 0x00, 0x40, 0xA0, 0xE7, 
+	0xDC, 0xE8, 0x00, 0x40, 0x00, 0xE7, 0x0C, 0xE7, 
+	0x70, 0xE7, 0x40, 0x70, 0x06, 0x00, 0x00, 0x60, 
+	0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x60, 0x7E, 0xE9, 
+	0x90, 0xE9, 0x18, 0xE7, 0x62, 0xEA, 0xEC, 0xE6, 
+	0xD0, 0xE9, 0xA4, 0xE8, 0x55, 0x55, 0x16, 0x00, 
+	0x46, 0xE7, 0x92, 0xE7, 0x00, 0x00, 0x00, 0x00, 
+	0xB6, 0xE7, 0x8B, 0xEA, 0x0A, 0xE8, 0x18, 0xE7, 
+	0x62, 0xEA, 0x58, 0xE8, 0x55, 0x55, 0x16, 0x00, 
+	0x00, 0xE7, 0x46, 0xE7, 0xA0, 0xE7, 0x2A, 0xE7, 
+	0xFF, 0x00, 0x00, 0x08, 0x2A, 0xE7, 0xFF, 0x00, 
+	0x00, 0x0C, 0x2A, 0xE7, 0xFF, 0x00, 0x00, 0x10,  
+	0x2A, 0xE7, 0xFF, 0x00, 0x00, 0x14, 0x2A, 0xE7, 
+	0xFF, 0x00, 0x00, 0x18, 0x2A, 0xE7, 0xFF, 0x00, 
+	0x00, 0x1C, 0x2A, 0xE7, 0xFF, 0x00, 0x00, 0x20, 
+	0x2A, 0xE7, 0xFF, 0x00, 0x00, 0x24, 0x2A, 0xE7, 
+	0xFF, 0x00, 0x00, 0x28, 0x2A, 0xE7, 0xFF, 0x00, 
+	0x00, 0x2C, 0xD2, 0xE7, 0x00, 0xE7, 0x0C, 0xE7, 
+	0x70, 0xE7, 0x40, 0x30, 0x06, 0x00, 0x00, 0x01, 
+	0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x20, 0x00, 0xE7, 
+	0x0C, 0xE7, 0x70, 0xE7, 0x40, 0x70, 0x06, 0x00, 
+	0x00, 0x43, 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x60, 
+	0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0xB0, 
+	0x06, 0x00, 0x00, 0x85, 0xA0, 0xE7, 0xDC, 0xE8, 
+	0x00, 0xA0, 0xD8, 0xE8, 0x00, 0x01, 0x03, 0x01, 
+	0x01, 0x01, 0x00, 0x00, 0x00, 0x81, 0x1A, 0x00, 
+	0x40, 0x10, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 
+	0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x72, 0x82, 
+	0x4A, 0xA9, 0xA5, 0x5A, 0xDA, 0xE7, 0x03, 0x09, 
+	0x11, 0x9D, 0x00, 0x00, 0x00, 0x81, 0x04, 0x00, 
+	0xD8, 0x90, 0x00, 0x10, 0x00, 0x00, 0x00, 0x81, 
+	0x04, 0x00, 0xD8, 0x90, 0xD8, 0xB4, 0x00, 0x00, 
+	0x00, 0x81, 0x08, 0x00, 0xD8, 0x90, 0x46, 0x16, 
+	0x00, 0x40, 0xD8, 0xB4, 0x08, 0x00, 0x00, 0x00, 
+	0x00, 0x80, 0x13, 0x00, 0x40, 0x10, 0x16, 0x00, 
+	0x00, 0x00, 0x00, 0x80, 0x10, 0x00, 0x15, 0x00, 
+	0x00, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x15, 0x00, 
+	0x00, 0x00, 0x00, 0x81, 0x0F, 0x00, 0x06, 0x00, 
+	0x00, 0x00, 0x00, 0x80, 0x12, 0x00, 0x0A, 0x80, 
+	0x40, 0x9E, 0x00, 0xC8, 0x00, 0x00, 0x5E, 0x80, 
+	0x0F, 0x00, 0x06, 0x80, 0x40, 0xFE, 0x00, 0xCC, 
+	0x00, 0x00, 0x04, 0x80, 0x40, 0x8E, 0x00, 0xC9, 
+	0x04, 0x80, 0x00, 0x06, 0x00, 0xCC, 0x04, 0x80, 
+	0x40, 0x0A, 0x00, 0xC8, 0x0A, 0x80, 0x40, 0x8A, 
+	0x00, 0xC8, 0x00, 0x00, 0x5E, 0x80, 0x0F, 0x00, 
+	0x0A, 0x08, 0x80, 0x1C, 0x0A, 0x00, 0x1C, 0x1A, 
+	0x00, 0x80, 0x1C, 0x0C, 0x00, 0x80, 0x1C, 0x1A, 
+	0x00, 0x80, 0x1A, 0x0E, 0x80, 0x1C, 0x04, 0x00, 
+	0x00, 0x80, 0x80, 0x02, 0x02, 0x00, 0x00, 0x80, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x80, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 
+	0x40, 0x00, 0x00, 0x00, 0x58, 0x07, 0x0C, 0xB8, 
+	0x16, 0xE0, 0xE2, 0x08, 0xEC, 0x08, 0xF6, 0x08, 
+	0x16, 0xE0, 0x00, 0x09, 0x0A, 0x09, 0x00, 0x00, 
+	0x00, 0x00, 0xE2, 0x08, 0x00, 0x00, 0xEC, 0x08, 
+	0xF6, 0x08, 0x00, 0x09, 0x00, 0x00, 0xB8, 0x07, 
+	0xCA, 0xCB, 0x80, 0x02, 0xB8, 0x07, 0xE8, 0xCB, 
+	0x84, 0xFF, 0xB8, 0x07, 0x0A, 0xCC, 0xB8, 0x07, 
+	0x84, 0xCC, 0x6E, 0xCD, 0x62, 0xCD, 0x88, 0xCD, 
+	0x90, 0xCE, 0x84, 0xCD, 0x92, 0xCE, 0x92, 0xCE, 
+	0x92, 0xCE, 0x8C, 0xCD, 0x96, 0xCD, 0x38, 0xCE, 
+	0x82, 0xCE, 0x92, 0xCE, 0x92, 0xCE, 0x92, 0xCE, 
+	0x92, 0xCE, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x08, 0x00, 0x08, 0x01, 0x05, 0x08, 
+	0x08, 0x08, 0x03, 0x08, 0x03, 0x03, 0x03, 0x03, 
+	0x00, 0x00, 0x04, 0x02, 0x04, 0x04, 0x00, 0x04, 
+	0x0A, 0x08, 0x00, 0x00, 0x10, 0x0C, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x18, 0x00, 0x1A, 0x00, 0x00, 
+	0x04, 0x41, 0x06, 0x0B, 0x08, 0xC2, 0x00, 0xE6, 
+	0x00, 0xE7, 0x04, 0x06, 0x04, 0x07, 0x04, 0x03, 
+	0x06, 0x04, 0x04, 0x05, 0x04, 0x88, 0x04, 0xCF, 
+	0x04, 0xCD, 0x03, 0x00, 0x05, 0x00, 0x1C, 0x00, 
+	0x00, 0x0C, 0x00, 0x80, 0xD2, 0xD8, 0xDA, 0xD8, 
+	0x1E, 0xD9, 0xDE, 0xD8, 0xEA, 0xD8, 0xF0, 0xD8, 
+	0x14, 0xD9, 0xE4, 0xD8, 0x32, 0xD9, 0x00, 0x06, 
+	0x00, 0x00, 0x03, 0x07, 0x0A, 0x0E, 0x0F, 0x14, 
+	0x26, 0x2A, 0x52, 0x42, 0x50, 0x48, 0x5D, 0x4D, 
+	0x62, 0x62, 0x6D, 0x57, 0x46, 0x39, 0x1A, 0x1D, 
+	0x7C, 0x76, 0x1F, 0x23, 0x15, 0x1D, 0x74, 0x6F, 
+	0x84, 0x7C, 0x8B, 0x82, 0x92, 0x89, 0x00, 0x00, 
+	0x32, 0x2F, 0x3F, 0x34, 0x32, 0x01, 0x01, 0x57, 
+	0x32, 0x11, 0x81, 0x51, 0x02, 0x56, 0x03, 0x55, 
+	0x54, 0x11, 0x56, 0x81, 0x55, 0x02, 0x54, 0x02, 
+	0x56, 0x81, 0x01, 0x76, 0x02, 0x34, 0x02, 0x55, 
+	0x81, 0x54, 0x02, 0x58, 0x02, 0x55, 0x81, 0x54, 
+	0x02, 0x58, 0x11, 0x12, 0x02, 0x52, 0x58, 0x83, 
+	0x52, 0x05, 0x83, 0x04, 0x02, 0x58, 0x08, 0x55, 
+	0x58, 0x83, 0x55, 0x02, 0x81, 0x02, 0x05, 0x58, 
+	0x03, 0x52, 0x5C, 0x15, 0x53, 0x5B, 0x52, 0x87, 
+	0x11, 0x03, 0x41, 0x51, 0x78, 0x51, 0x34, 0x11, 
+	0x81, 0x11, 0x20, 0x31, 0x54, 0x57, 0x01, 0x53, 
+	0x5A, 0x12, 0x81, 0x51, 0x20, 0x31, 0x5B, 0x57, 
+	0x01, 0x5A, 0x01, 0x11, 0x51, 0x11, 0x31, 0x81, 
+	0x57, 0x20, 0x15, 0x01, 0x13, 0x01, 0x11, 0x01, 
+	0x11, 0x11, 0x81, 0x51, 0x05, 0x58, 0x02, 0x52, 
+	0x5B, 0x54, 0x5D, 0x81, 0x52, 0x05, 0x54, 0x02, 
+	0x58, 0x81, 0x50, 0x02, 0x13, 0x03, 0x58, 0x81, 
+	0x50, 0x02, 0x11, 0x03, 0x81, 0x54, 0x72, 0x5D, 
+	0x50, 0x03, 0x13, 0x03, 0x13, 0x01, 0x40, 0x54, 
+	0x0E, 0x00, 0x20, 0x06, 0x56, 0x06, 0x0C, 0xDA, 
+	0x24, 0x00, 0x02, 0x10, 0x16, 0x00, 0x02, 0x00, 
+	0x01, 0x04, 0x08, 0x07, 0x0C, 0xDA, 0x20, 0x00, 
+	0x03, 0x10, 0x12, 0x00, 0x03, 0x00, 0x4E, 0xD9, 
+	0x14, 0x8E, 0x20, 0x00, 0x04, 0x10, 0x12, 0x00, 
+	0x04, 0x00, 0xD2, 0xCE, 0x20, 0x00, 0x05, 0xE0, 
+	0x12, 0x00, 0x05, 0x00, 0xD2, 0xCE, 0x20, 0x00, 
+	0x06, 0xE0, 0x12, 0x00, 0x06, 0x00, 0xE8, 0xDD, 
+	0x12, 0x00, 0x01, 0xE0, 0x6C, 0x09, 0xCC, 0x06, 
+	0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x30, 0x06, 
+	0x42, 0xDC, 0xF0, 0x05, 0x00, 0xE0, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0xE2, 0x05, 0x08, 0x00, 
+	0x26, 0xFF, 0xDC, 0x05, 0x00, 0x00, 0x30, 0x06, 
+	0xF8, 0xDB, 0x1E, 0x00, 0x01, 0xE0, 0x10, 0x00, 
+	0x11, 0x30, 0x0C, 0x04, 0x01, 0x00, 0x0E, 0x04, 
+	0x02, 0x00, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 
+	0x30, 0x06, 0x32, 0xDD, 0x12, 0x00, 0x01, 0xE0, 
+	0x04, 0x00, 0x13, 0x30, 0x74, 0xDE, 0x3E, 0x00, 
+	0x00, 0xE0, 0x00, 0xC0, 0x00, 0x00, 0x02, 0x00, 
+	0x30, 0x00, 0x20, 0x50, 0x23, 0x0C, 0xFC, 0x05, 
+	0x52, 0x06, 0x56, 0x06, 0x00, 0x00, 0x00, 0x81, 
+	0x16, 0x00, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0x00, 
+	0x10, 0x00, 0x08, 0x00, 0x2A, 0x40, 0x2A, 0x04, 
+	0x56, 0x06, 0x26, 0x00, 0x19, 0xED, 0x2B, 0x06, 
+	0x72, 0x09, 0x22, 0x00, 0x24, 0x00, 0x2F, 0xED, 
+	0x23, 0x0C, 0xFC, 0x05, 0x28, 0x08, 0x34, 0x09, 
+	0x29, 0x08, 0x58, 0x07, 0x78, 0x07, 0x98, 0x07, 
+	0x23, 0x00, 0x2A, 0x00, 0x3D, 0xED, 0x06, 0x04, 
+	0xF0, 0x06, 0x07, 0x04, 0xEE, 0x06, 0x24, 0x00, 
+	0xD2, 0xCE, 0x34, 0x00, 0x00, 0xE0, 0x00, 0xC0, 
+	0x00, 0x00, 0x10, 0x00, 0x26, 0x00, 0x25, 0x40, 
+	0xD2, 0xCE, 0x20, 0x00, 0x00, 0xE0, 0x00, 0xC0, 
+	0x00, 0x00, 0x10, 0x00, 0x12, 0x00, 0x26, 0x40, 
+	0xD2, 0xCE, 0x1A, 0x00, 0x00, 0xE0, 0x0C, 0x00, 
+	0x27, 0x60, 0x0A, 0x08, 0xE6, 0x06, 0xD2, 0xCE, 
+	0x24, 0x00, 0x00, 0xE0, 0x16, 0x00, 0x28, 0x60, 
+	0x30, 0x04, 0x06, 0x07, 0x52, 0xCF, 0x00, 0x81, 
+	0x30, 0x00, 0x00, 0xE0, 0x22, 0x00, 0x29, 0x60, 
+	0x2D, 0x08, 0x1C, 0x07, 0x2E, 0x08, 0x22, 0x07, 
+	0x00, 0x00, 0x08, 0x02, 0x06, 0x01, 0x14, 0x06, 
+	0x18, 0x08, 0x20, 0x0C, 0x26, 0x0E, 0x30, 0x0F, 
+	0x34, 0x11, 0x3E, 0x12, 0x42, 0x14, 0x46, 0x16, 
+	0x1C, 0x0A, 0x4A, 0x18, 0x13, 0x03, 0x11, 0x83, 
+	0x01, 0x11, 0x11, 0x81, 0x12, 0x81, 0x13, 0x01, 
+	0x52, 0x83, 0x81, 0x85, 0x85, 0x11, 0x12, 0x81, 
+	0x12, 0x81, 0x19, 0x81, 0x60, 0x85, 0x00, 0xC0, 
+	0x00, 0x00, 0x08, 0x00, 0x6C, 0x09, 0x00, 0x00, 
+	0x30, 0x06, 0x08, 0xE5, 0x54, 0x06, 0x50, 0x06, 
+	0x38, 0x02, 0x21, 0x04, 0x1E, 0x09, 0x0B, 0x06, 
+	0xD8, 0x06, 0x02, 0x08, 0xDC, 0x06, 0x00, 0xC0, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0x41, 0x00, 0x41, 0x00, 
+	0x14, 0xAE, 0x00, 0x00, 0x00, 0x81, 0x09, 0x04, 
+	0x0C, 0x07, 0x41, 0x00, 0x41, 0x00, 0x14, 0x02, 
+	0x00, 0x00, 0x00, 0x81, 0x0B, 0x06, 0xD8, 0x06, 
+	0x2C, 0x06, 0x76, 0x09, 0x22, 0x14, 0x3A, 0x09, 
+	0x41, 0x00, 0x41, 0x00, 0x54, 0x02, 0x00, 0x00, 
+	0x00, 0x81, 0xD8, 0x06, 0x00, 0x84, 0x00, 0x48, 
+	0xFC, 0xFF, 0x09, 0x00, 0x00, 0xC0, 0x00, 0x00, 
+	0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0xB8, 0xFF, 0x20, 0x00, 
+	0x43, 0x28, 0x31, 0x29, 0x38, 0x39, 0x2D, 0x33, 
+	0x39, 0x38, 0x39, 0x2C, 0x2D, 0x30, 0x38, 0x39, 
+	0x54, 0x20, 0x78, 0x65, 0x73, 0x61, 0x49, 0x20, 
+	0x73, 0x6E, 0x72, 0x74, 0x6D, 0x75, 0x6E, 0x65, 
+	0x73, 0x74, 0x28, 0x0A, 0x29, 0x43, 0x39, 0x31, 
+	0x33, 0x38, 0x34, 0x2C, 0x35, 0x2C, 0x36, 0x2C, 
+	0x49, 0x20, 0x4D, 0x42, 0x43, 0x20, 0x72, 0x6F, 
+	0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xF8, 0xFF, 0x01, 0x00, 0x34, 0x90, 
+	0x00, 0x00, 0xFA, 0xFF, 0x01, 0x00, 0xB8, 0xFF, 
+	0x00, 0x00, 0xFC, 0xFF, 0x02, 0x00, 0x80, 0x00, 
+	0x3E, 0xA0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00  
+};
+#endif /* CONFIG_SKTR */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/Config.in linux/drivers/net/wan/Config.in
--- v2.3.20/linux/drivers/net/wan/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/Config.in	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,64 @@
+#
+# wan devices configuration
+#
+
+mainmenu_option next_comment
+comment 'Wan interfaces'
+
+bool 'Wan interfaces support' CONFIG_WAN
+if [ "$CONFIG_WAN" = "y" ]; then
+
+	# There is no way to detect a comtrol sv11 - force it modular for now.
+	
+	dep_tristate 'Comtrol Hostess SV-11 support' CONFIG_HOSTESS_SV11 m
+
+	# The COSA/SRP driver has not been tested as non-modular yet.
+
+	dep_tristate 'COSA/SRP sync serial boards support' CONFIG_COSA m
+
+	# There is no way to detect a Sealevel board. Force it modular
+
+	dep_tristate 'Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m
+
+	tristate 'Frame relay DLCI support' CONFIG_DLCI
+	if [ "$CONFIG_DLCI" != "n" ]; then
+	   int 'Max open DLCI' CONFIG_DLCI_COUNT 24
+	   int 'Max DLCI per device' CONFIG_DLCI_MAX 8
+	   dep_tristate '  SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI
+	fi
+
+	# Wan router core.
+
+	if [ "$CONFIG_WAN_ROUTER" != "n" ]; then
+	   bool 'WAN router drivers' CONFIG_WAN_ROUTER_DRIVERS
+	   if [ "$CONFIG_WAN_ROUTER_DRIVERS" = "y" ]; then
+	      dep_tristate '  Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_ROUTER_DRIVERS
+	      if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then
+		 int 'Maximum number of cards' CONFIG_WANPIPE_CARDS 1
+		 bool '    WANPIPE X.25 support' CONFIG_WANPIPE_X25
+		 bool '    WANPIPE Frame Relay support' CONFIG_WANPIPE_FR
+		 bool '    WANPIPE PPP support' CONFIG_WANPIPE_PPP
+	      fi
+	      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+		 dep_tristate '  Cyclom 2X(tm) cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_ROUTER_DRIVERS
+		 if [ "$CONFIG_CYCLADES_SYNC" != "n" ]; then
+		    bool '    Cyclom 2X X.25 support' CONFIG_CYCLOMX_X25
+		 fi
+	      fi
+	   fi
+	fi
+
+	# X.25 network drivers
+
+	if [ "$CONFIG_X25" != "n" ]; then
+	   if [ "$CONFIG_LAPB" != "n" ]; then
+	      dep_tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER $CONFIG_LAPB
+	      dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB
+	   fi
+	fi
+
+	tristate 'SBNI12-xx support' CONFIG_SBNI
+fi
+
+endmenu
+
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/Makefile linux/drivers/net/wan/Makefile
--- v2.3.20/linux/drivers/net/wan/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/Makefile	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,181 @@
+# File: drivers/net/wan/Makefile
+#
+# Makefile for the Linux network (wan) device drivers.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now inherited from the
+# parent makefile.
+#
+
+SUB_DIRS     := 
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+L_TARGET := wan.a
+L_OBJS   :=
+M_OBJS   :=
+
+# Need these to keep track of whether the 82530 or SYNCPPP
+# modules should really go in the kernel or a module.
+CONFIG_85230_BUILTIN :=
+CONFIG_85230_MODULE  :=
+CONFIG_SYNCPPP_BUILTIN :=
+CONFIG_SYNCPPP_MODULE  :=
+
+ifeq ($(CONFIG_HOSTESS_SV11),y)
+L_OBJS += hostess_sv11.o
+CONFIG_85230_BUILTIN = y
+CONFIG_SYNCPPP_BUILTIN = y
+else
+  ifeq ($(CONFIG_HOSTESS_SV11),m)
+  CONFIG_85230_MODULE = y
+  CONFIG_SYNCPPP_MODULE = y
+  M_OBJS += hostess_sv11.o
+  endif
+endif
+
+ifeq ($(CONFIG_SEALEVEL_4021),y)
+L_OBJS += sealevel.o
+CONFIG_85230_BUILTIN = y
+CONFIG_SYNCPPP_BUILTIN = y
+else
+  ifeq ($(CONFIG_SEALEVEL_4021),m)
+  CONFIG_85230_MODULE = y
+  CONFIG_SYNCPPP_MODULE = y
+  M_OBJS += sealevel.o
+  endif
+endif
+
+ifeq ($(CONFIG_COSA),y)
+L_OBJS += cosa.o
+CONFIG_SYNCPPP_BUILTIN = y
+else
+  ifeq ($(CONFIG_COSA),m)
+  CONFIG_SYNCPPP_MODULE = y
+  M_OBJS += cosa.o
+  endif
+endif
+
+# If anything built-in uses syncppp, then build it into the kernel also.
+# If not, but a module uses it, build as a module.
+
+ifdef CONFIG_SYNCPPP_BUILTIN
+LX_OBJS += syncppp.o
+else
+  ifdef CONFIG_SYNCPPP_MODULE
+  MX_OBJS += syncppp.o
+  endif
+endif
+
+# If anything built-in uses Z85230, then build it into the kernel also.
+# If not, but a module uses it, build as a module.
+
+ifdef CONFIG_85230_BUILTIN
+LX_OBJS += z85230.o
+else
+  ifdef CONFIG_85230_MODULE
+  MX_OBJS += z85230.o
+  endif
+endif
+
+ifeq ($(CONFIG_DLCI),y)
+L_OBJS += dlci.o 
+else
+  ifeq ($(CONFIG_DLCI),m)
+  M_OBJS += dlci.o
+  endif
+endif
+
+ifeq ($(CONFIG_SDLA),y)
+  L_OBJS += sdla.o
+else
+  ifeq ($(CONFIG_SDLA),m)
+  M_OBJS += sdla.o
+endif
+
+ifeq ($(CONFIG_VENDOR_SANGOMA),y)
+  LX_OBJS += sdladrv.o
+  L_OBJS += sdlamain.o
+  ifeq ($(CONFIG_WANPIPE_X25),y)
+    L_OBJS += sdla_x25.o
+  endif
+  ifeq ($(CONFIG_WANPIPE_FR),y)
+    L_OBJS += sdla_fr.o
+  endif
+  ifeq ($(CONFIG_WANPIPE_PPP),y)
+    L_OBJS += sdla_ppp.o
+  endif
+endif
+
+endif
+
+ifeq ($(CONFIG_VENDOR_SANGOMA),m)
+  MX_OBJS += sdladrv.o
+  M_OBJS += wanpipe.o
+  WANPIPE_OBJS = sdlamain.o
+  ifeq ($(CONFIG_WANPIPE_X25),y)
+    WANPIPE_OBJS += sdla_x25.o
+  endif
+  ifeq ($(CONFIG_WANPIPE_FR),y)
+    WANPIPE_OBJS += sdla_fr.o
+  endif
+  ifeq ($(CONFIG_WANPIPE_PPP),y)
+    WANPIPE_OBJS += sdla_ppp.o
+  endif
+endif
+
+ifeq ($(CONFIG_CYCLADES_SYNC),y)
+  LX_OBJS += cycx_drv.o
+  L_OBJS += cycx_main.o
+  ifeq ($(CONFIG_CYCLOMX_X25),y)
+    L_OBJS += cycx_x25.o
+  endif
+endif
+
+ifeq ($(CONFIG_CYCLADES_SYNC),m)
+  MX_OBJS += cycx_drv.o
+  M_OBJS += cyclomx.o
+  CYCLOMX_OBJS = cycx_main.o
+  ifeq ($(CONFIG_CYCLOMX_X25),y)
+    CYCLOMX_OBJS += cycx_x25.o
+  endif
+endif
+
+ifeq ($(CONFIG_X25_ASY),y)
+L_OBJS += x25_asy.o
+else
+  ifeq ($(CONFIG_X25_ASY),m)
+  M_OBJS += x25_asy.o
+  endif
+endif
+
+ifeq ($(CONFIG_LAPBETHER),y)
+L_OBJS += lapbether.o
+else
+  ifeq ($(CONFIG_LAPBETHER),m)
+  M_OBJS += lapbether.o
+  endif
+endif
+
+ifeq ($(CONFIG_SBNI),y)
+L_OBJS += sbni.o
+else
+  ifeq ($(CONFIG_SBNI),m)
+  M_OBJS += sbni.o
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
+
+clean:
+	rm -f core *.o *.a *.s
+
+wanpipe.o: $(WANPIPE_OBJS)
+	ld -r -o $@ $(WANPIPE_OBJS)
+
+cyclomx.o: $(CYCLOMX_OBJS)
+	ld -r -o $@ $(CYCLOMX_OBJS)
+
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/cosa.c linux/drivers/net/wan/cosa.c
--- v2.3.20/linux/drivers/net/wan/cosa.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/cosa.c	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,2038 @@
+/* $Id: cosa.c,v 1.26 1999/07/09 15:02:37 kas Exp $ */
+
+/*
+ *  Copyright (C) 1995-1997  Jan "Yenya" Kasprzak <kas@fi.muni.cz>
+ *
+ *  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.
+ */
+
+/*
+ * The driver for the SRP and COSA synchronous serial cards.
+ *
+ * HARDWARE INFO
+ *
+ * Both cards are developed at the Institute of Computer Science,
+ * Masaryk University (http://www.ics.muni.cz/). The hardware is
+ * developed by Jiri Novotny <novotny@ics.muni.cz>. More information
+ * and the photo of both cards is available at
+ * http://www.pavoucek.cz/cosa.html. The card documentation, firmwares
+ * and other goods can be downloaded from ftp://ftp.ics.muni.cz/pub/cosa/.
+ * For Linux-specific utilities, see below in the "Software info" section.
+ * If you want to order the card, contact Jiri Novotny.
+ *
+ * The SRP (serial port?, the Czech word "srp" means "sickle") card
+ * is a 2-port intelligent (with its own 8-bit CPU) synchronous serial card
+ * with V.24 interfaces up to 80kb/s each.
+ *
+ * The COSA (communication serial adapter?, the Czech word "kosa" means
+ * "scythe") is a next-generation sync/async board with two interfaces
+ * - currently any of V.24, X.21, V.35 and V.36 can be selected.
+ * It has a 16-bit SAB80166 CPU and can do up to 10 Mb/s per channel.
+ * The 8-channels version is in development.
+ *
+ * Both types have downloadable firmware and communicate via ISA DMA.
+ * COSA can be also a bus-mastering device.
+ *
+ * SOFTWARE INFO
+ *
+ * The homepage of the Linux driver is at http://www.fi.muni.cz/~kas/cosa/.
+ * The CVS tree of Linux driver can be viewed there, as well as the
+ * firmware binaries and user-space utilities for downloading the firmware
+ * into the card and setting up the card.
+ *
+ * The Linux driver (unlike the present *BSD drivers :-) can work even
+ * for the COSA and SRP in one computer and allows each channel to work
+ * in one of the three modes (character device, Cisco HDLC, Sync PPP).
+ *
+ * AUTHOR
+ *
+ * The Linux driver was written by Jan "Yenya" Kasprzak <kas@fi.muni.cz>.
+ *
+ * You can mail me bugfixes and even success reports. I am especially
+ * interested in the SMP and/or muliti-channel success/failure reports
+ * (I wonder if I did the locking properly :-).
+ *
+ * THE AUTHOR USED THE FOLLOWING SOURCES WHEN PROGRAMMING THE DRIVER
+ *
+ * The COSA/SRP NetBSD driver by Zdenek Salvet and Ivos Cernohlavek
+ * The skeleton.c by Donald Becker
+ * The SDL Riscom/N2 driver by Mike Natale
+ * The Comtrol Hostess SV11 driver by Alan Cox
+ * The Sync PPP/Cisco HDLC layer (syncppp.c) ported to Linux by Alan Cox
+ */
+/*
+ *     5/25/1999 : Marcelo Tosatti <marcelo@conectiva.com.br>
+ *             fixed a deadlock in cosa_sppp_open
+ */
+
+/* ---------- Headers, macros, data structures ---------- */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+
+#undef COSA_SLOW_IO	/* for testing purposes only */
+#undef REALLY_SLOW_IO
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/byteorder.h>
+
+#include "syncppp.h"
+#include "cosa.h"
+
+/* Linux version stuff */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+typedef struct wait_queue *wait_queue_head_t;
+#define DECLARE_WAITQUEUE(wait, current) \
+	struct wait_queue wait = { current, NULL }
+#endif
+
+/* Maximum length of the identification string. */
+#define COSA_MAX_ID_STRING	128
+
+/* Maximum length of the channel name */
+#define COSA_MAX_NAME		(sizeof("cosaXXXcXXX")+1)
+
+/* Per-channel data structure */
+
+struct channel_data {
+	int usage;	/* Usage count; >0 for chrdev, -1 for netdev */
+	int num;	/* Number of the channel */
+	struct cosa_data *cosa;	/* Pointer to the per-card structure */
+	int txsize;	/* Size of transmitted data */
+	char *txbuf;	/* Transmit buffer */
+	char name[COSA_MAX_NAME];	/* channel name */
+
+	/* The HW layer interface */
+	/* routine called from the RX interrupt */
+	char *(*setup_rx)(struct channel_data *channel, int size);
+	/* routine called when the RX is done (from the EOT interrupt) */
+	int (*rx_done)(struct channel_data *channel);
+	/* routine called when the TX is done (from the EOT interrupt) */
+	int (*tx_done)(struct channel_data *channel, int size);
+
+	/* Character device parts */
+	struct semaphore rsem, wsem;
+	char *rxdata;
+	int rxsize;
+	wait_queue_head_t txwaitq; 
+	wait_queue_head_t rxwaitq;
+	int tx_status, rx_status;
+
+	/* SPPP/HDLC device parts */
+	struct ppp_device pppdev;
+	struct sk_buff *rx_skb, *tx_skb;
+	struct net_device_stats stats;
+};
+
+struct cosa_data {
+	int num;			/* Card number */
+	char name[COSA_MAX_NAME];	/* Card name - e.g "cosa0" */
+	unsigned int datareg, statusreg;	/* I/O ports */
+	unsigned short irq, dma;	/* IRQ and DMA number */
+	unsigned short startaddr;	/* Firmware start address */
+	unsigned short busmaster;	/* Use busmastering? */
+	int nchannels;			/* # of channels on this card */
+	int driver_status;		/* For communicating with firware */
+	int firmware_status;		/* Downloaded, reseted, etc. */
+	int rxbitmap, txbitmap;		/* Bitmap of channels who are willing to send/receive data */
+	int rxtx;			/* RX or TX in progress? */
+	int enabled;
+	int usage;				/* usage count */
+	int txchan, txsize, rxsize;
+	struct channel_data *rxchan;
+	char *bouncebuf;
+	char *txbuf, *rxbuf;
+	struct channel_data *chan;
+	spinlock_t lock;	/* For exclusive operations on this structure */
+	char id_string[COSA_MAX_ID_STRING];	/* ROM monitor ID string */
+	char *type;				/* card type */
+};
+
+/*
+ * Define this if you want all the possible ports to be autoprobed.
+ * It is here but it probably is not a good idea to use this.
+ */
+/* #define COSA_ISA_AUTOPROBE	1 */
+
+/*
+ * Character device major number. 117 was allocated for us.
+ * The value of 0 means to allocate a first free one.
+ */
+static int cosa_major = 117;
+
+/*
+ * Encoding of the minor numbers:
+ * The lowest CARD_MINOR_BITS bits means the channel on the single card,
+ * the highest bits means the card number.
+ */
+#define CARD_MINOR_BITS	4	/* How many bits in minor number are reserved
+				 * for the single card */
+/*
+ * The following depends on CARD_MINOR_BITS. Unfortunately, the "MODULE_STRING"
+ * macro doesn't like anything other than the raw number as an argument :-(
+ */
+#define MAX_CARDS	16
+/* #define MAX_CARDS	(1 << (8-CARD_MINOR_BITS)) */
+
+#define DRIVER_RX_READY		0x0001
+#define DRIVER_TX_READY		0x0002
+#define DRIVER_TXMAP_SHIFT	2
+#define DRIVER_TXMAP_MASK	0x0c	/* FIXME: 0xfc for 8-channel version */
+
+/*
+ * for cosa->rxtx - indicates whether either transmit or receive is
+ * in progress. These values are mean number of the bit.
+ */
+#define TXBIT 0
+#define RXBIT 1
+#define IRQBIT 2
+
+#define COSA_MTU 2000	/* FIXME: I don't know this exactly */
+
+#undef DEBUG_DATA 1	/* Dump the data read or written to the channel */
+#undef DEBUG_IRQS 1	/* Print the message when the IRQ is received */
+#undef DEBUG_IO 1	/* Dump the I/O traffic */
+
+/* Maybe the following should be allocated dynamically */
+static struct cosa_data cosa_cards[MAX_CARDS];
+static int nr_cards = 0;
+
+#ifdef COSA_ISA_AUTOPROBE
+static int io[MAX_CARDS+1]  = { 0x220, 0x228, 0x210, 0x218, 0, };
+/* NOTE: DMA is not autoprobed!!! */
+static int dma[MAX_CARDS+1] = { 1, 7, 1, 7, 1, 7, 1, 7, 0, };
+#else
+int io[MAX_CARDS+1]  = { 0, };
+int dma[MAX_CARDS+1] = { 0, };
+#endif
+/* IRQ can be safely autoprobed */
+static int irq[MAX_CARDS+1] = { -1, -1, -1, -1, -1, -1, 0, };
+
+#ifdef MODULE
+MODULE_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i");
+MODULE_PARM_DESC(io, "The I/O bases of the COSA or SRP cards");
+MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CARDS) "i");
+MODULE_PARM_DESC(irq, "The IRQ lines of the COSA or SRP cards");
+MODULE_PARM(dma, "1-" __MODULE_STRING(MAX_CARDS) "i");
+MODULE_PARM_DESC(dma, "The DMA channels of the COSA or SRP cards");
+
+MODULE_AUTHOR("Jan \"Yenya\" Kasprzak, <kas@fi.muni.cz>");
+MODULE_DESCRIPTION("Modular driver for the COSA or SRP synchronous card");
+#endif
+
+/* I use this mainly for testing purposes */
+#ifdef COSA_SLOW_IO
+#define cosa_outb outb_p
+#define cosa_outw outw_p
+#define cosa_inb  inb_p
+#define cosa_inw  inw_p
+#else
+#define cosa_outb outb
+#define cosa_outw outw
+#define cosa_inb  inb
+#define cosa_inw  inw
+#endif
+
+#define is_8bit(cosa)		(!(cosa->datareg & 0x08))
+
+#define cosa_getstatus(cosa)	(cosa_inb(cosa->statusreg))
+#define cosa_putstatus(cosa, stat)	(cosa_outb(stat, cosa->statusreg))
+#define cosa_getdata16(cosa)	(cosa_inw(cosa->datareg))
+#define cosa_getdata8(cosa)	(cosa_inb(cosa->datareg))
+#define cosa_putdata16(cosa, dt)	(cosa_outw(dt, cosa->datareg))
+#define cosa_putdata8(cosa, dt)	(cosa_outb(dt, cosa->datareg))
+
+/* Initialization stuff */
+static int cosa_probe(int ioaddr, int irq, int dma);
+
+/* HW interface */
+static void cosa_enable_rx(struct channel_data *chan);
+static void cosa_disable_rx(struct channel_data *chan);
+static int cosa_start_tx(struct channel_data *channel, char *buf, int size);
+static void cosa_kick(struct cosa_data *cosa);
+static int cosa_dma_able(struct channel_data *chan, char *buf, int data);
+
+/* SPPP/HDLC stuff */
+static void sppp_channel_init(struct channel_data *chan);
+static void sppp_channel_delete(struct channel_data *chan);
+static int cosa_sppp_open(struct net_device *d);
+static int cosa_sppp_close(struct net_device *d);
+static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *d);
+static char *sppp_setup_rx(struct channel_data *channel, int size);
+static int sppp_rx_done(struct channel_data *channel);
+static int sppp_tx_done(struct channel_data *channel, int size);
+static int cosa_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+static struct net_device_stats *cosa_net_stats(struct net_device *dev);
+
+/* Character device */
+static void chardev_channel_init(struct channel_data *chan);
+static char *chrdev_setup_rx(struct channel_data *channel, int size);
+static int chrdev_rx_done(struct channel_data *channel);
+static int chrdev_tx_done(struct channel_data *channel, int size);
+static long long cosa_lseek(struct file *file,
+	long long offset, int origin);
+static ssize_t cosa_read(struct file *file,
+	char *buf, size_t count, loff_t *ppos);
+static ssize_t cosa_write(struct file *file,
+	const char *buf, size_t count, loff_t *ppos);
+static unsigned int cosa_poll(struct file *file, poll_table *poll);
+static int cosa_open(struct inode *inode, struct file *file);
+static int cosa_release(struct inode *inode, struct file *file);
+static int cosa_chardev_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg);
+#ifdef COSA_FASYNC_WORKING
+static int cosa_fasync(struct inode *inode, struct file *file, int on);
+#endif
+
+static struct file_operations cosa_fops = {
+	cosa_lseek,
+	cosa_read,
+	cosa_write,
+	NULL,	/* readdir */
+	cosa_poll,
+	cosa_chardev_ioctl,
+	NULL,	/* mmap */
+	cosa_open,
+	NULL,	/* flush */
+	cosa_release,
+	NULL,	/* fsync */
+#ifdef COSA_FASYNC_WORKING
+	cosa_fasync,
+#else
+	NULL,
+#endif
+	NULL,	/* check media change */
+	NULL,	/* revalidate */
+	NULL	/* lock */
+};
+
+/* Ioctls */
+static int cosa_start(struct cosa_data *cosa, int address);
+static int cosa_reset(struct cosa_data *cosa);
+static int cosa_download(struct cosa_data *cosa, struct cosa_download *d);
+static int cosa_readmem(struct cosa_data *cosa, struct cosa_download *d);
+
+/* COSA/SRP ROM monitor */
+static int download(struct cosa_data *cosa, char *data, int addr, int len);
+static int startmicrocode(struct cosa_data *cosa, int address);
+static int readmem(struct cosa_data *cosa, char *data, int addr, int len);
+static int cosa_reset_and_read_id(struct cosa_data *cosa, char *id);
+
+/* Auxilliary functions */
+static int get_wait_data(struct cosa_data *cosa);
+static int put_wait_data(struct cosa_data *cosa, int data);
+static int puthexnumber(struct cosa_data *cosa, int number);
+static void put_driver_status(struct cosa_data *cosa);
+static void put_driver_status_nolock(struct cosa_data *cosa);
+
+/* Interrupt handling */
+static void cosa_interrupt(int irq, void *cosa, struct pt_regs *regs);
+
+/* I/O ops debugging */
+#ifdef DEBUG_IO
+static void debug_data_in(struct cosa_data *cosa, int data);
+static void debug_data_out(struct cosa_data *cosa, int data);
+static void debug_data_cmd(struct cosa_data *cosa, int data);
+static void debug_status_in(struct cosa_data *cosa, int status);
+static void debug_status_out(struct cosa_data *cosa, int status);
+#endif
+
+
+/* ---------- Initialization stuff ---------- */
+
+#ifdef MODULE
+int init_module(void)
+#else
+static int __init cosa_init(void)
+#endif
+{
+	int i;
+	printk(KERN_INFO "cosa v1.06 (c) 1997-8 Jan Kasprzak <kas@fi.muni.cz>\n");
+#ifdef __SMP__
+	printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n");
+#endif
+	if (cosa_major > 0) {
+		if (register_chrdev(cosa_major, "cosa", &cosa_fops)) {
+			printk(KERN_WARNING "cosa: unable to get major %d\n",
+				cosa_major);
+			return -EIO;
+		}
+	} else {
+		if (!(cosa_major=register_chrdev(0, "cosa", &cosa_fops))) {
+			printk(KERN_WARNING "cosa: unable to register chardev\n");
+			return -EIO;
+		}
+	}
+	for (i=0; i<MAX_CARDS; i++)
+		cosa_cards[i].num = -1;
+	for (i=0; io[i] != 0 && i < MAX_CARDS; i++)
+		cosa_probe(io[i], irq[i], dma[i]);
+	if (!nr_cards) {
+		printk(KERN_WARNING "cosa: no devices found.\n");
+		unregister_chrdev(cosa_major, "cosa");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+#ifdef MODULE
+void cleanup_module (void)
+{
+	struct cosa_data *cosa;
+	printk(KERN_INFO "Unloading the cosa module\n");
+
+	for (cosa=cosa_cards; nr_cards--; cosa++) {
+		int i;
+		/* Clean up the per-channel data */
+		for (i=0; i<cosa->nchannels; i++) {
+			/* Chardev driver has no alloc'd per-channel data */
+			sppp_channel_delete(cosa->chan+i);
+		}
+		/* Clean up the per-card data */
+		kfree(cosa->chan);
+		kfree(cosa->bouncebuf);
+		free_irq(cosa->irq, cosa);
+		free_dma(cosa->dma);
+		release_region(cosa->datareg,is_8bit(cosa)?2:4);
+	}
+	unregister_chrdev(cosa_major, "cosa");
+}
+#endif
+
+/*
+ * This function should register all the net devices needed for the
+ * single channel.
+ */
+static __inline__ void channel_init(struct channel_data *chan)
+{
+	sprintf(chan->name, "cosa%dc%d", chan->cosa->num, chan->num);
+
+	/* Initialize the chardev data structures */
+	chardev_channel_init(chan);
+
+	/* Register the sppp interface */
+	sppp_channel_init(chan);
+}
+	
+static int cosa_probe(int base, int irq, int dma)
+{
+	struct cosa_data *cosa = cosa_cards+nr_cards;
+	int i;
+
+	memset(cosa, 0, sizeof(struct cosa_data));
+
+	/* Checking validity of parameters: */
+	/* IRQ should be 2-7 or 10-15; negative IRQ means autoprobe */
+	if ((irq >= 0  && irq < 2) || irq > 15 || (irq < 10 && irq > 7)) {
+		printk (KERN_INFO "cosa_probe: invalid IRQ %d\n", irq);
+		return -1;
+	}
+	/* I/O address should be between 0x100 and 0x3ff and should be
+	 * multiple of 8. */
+	if (base < 0x100 || base > 0x3ff || base & 0x7) {
+		printk (KERN_INFO "cosa_probe: invalid I/O address 0x%x\n",
+			base);
+		return -1;
+	}
+	/* DMA should be 0,1 or 3-7 */
+	if (dma < 0 || dma == 4 || dma > 7) {
+		printk (KERN_INFO "cosa_probe: invalid DMA %d\n", dma);
+		return -1;
+	}
+	/* and finally, on 16-bit COSA DMA should be 4-7 and 
+	 * I/O base should not be multiple of 0x10 */
+	if (((base & 0x8) && dma < 4) || (!(base & 0x8) && dma > 3)) {
+		printk (KERN_INFO "cosa_probe: 8/16 bit base and DMA mismatch"
+			" (base=0x%x, dma=%d)\n", base, dma);
+		return -1;
+	}
+
+	cosa->dma = dma;
+	cosa->datareg = base;
+	cosa->statusreg = is_8bit(cosa)?base+1:base+2;
+	spin_lock_init(&cosa->lock);
+
+	if (check_region(base, is_8bit(cosa)?2:4))
+		return -1;
+	
+	if (cosa_reset_and_read_id(cosa, cosa->id_string) < 0) {
+		printk(KERN_DEBUG "cosa: probe at 0x%x failed.\n", base);
+		return -1;
+	}
+
+	/* Test the validity of identification string */
+	if (!strncmp(cosa->id_string, "SRP", 3))
+		cosa->type = "srp";
+	else if (!strncmp(cosa->id_string, "COSA", 4))
+		cosa->type = is_8bit(cosa)? "cosa8": "cosa16";
+	else {
+/* Print a warning only if we are not autoprobing */
+#ifndef COSA_ISA_AUTOPROBE
+		printk(KERN_INFO "cosa: valid signature not found at 0x%x.\n",
+			base);
+#endif
+		return -1;
+	}
+
+	/* Now do IRQ autoprobe */
+	if (irq < 0) {
+		unsigned long irqs;
+/*		printk(KERN_INFO "IRQ autoprobe\n"); */
+		sti();
+		irqs = probe_irq_on();
+		/* 
+		 * Enable interrupt on tx buffer empty (it sure is) 
+		 * really sure ?
+		 * FIXME: When this code is not used as module, we should
+		 * probably call udelay() instead of the interruptible sleep.
+		 */
+		current->state = TASK_INTERRUPTIBLE;
+		cosa_putstatus(cosa, SR_TX_INT_ENA);
+		schedule_timeout(30);
+		current->state = TASK_RUNNING;
+		irq = probe_irq_off(irqs);
+		/* Disable all IRQs from the card */
+		cosa_putstatus(cosa, 0);
+		/* Empty the received data register */
+		cosa_getdata8(cosa);
+
+		if (irq < 0) {
+			printk (KERN_INFO "cosa IRQ autoprobe: multiple interrupts obtained (%d, board at 0x%x)\n",
+				irq, cosa->datareg);
+			return -1;
+		}
+		if (irq == 0) {
+			printk (KERN_INFO "cosa IRQ autoprobe: no interrupt obtained (board at 0x%x)\n",
+				cosa->datareg);
+		/*	return -1; */
+		}
+	}
+
+	cosa->irq = irq;
+	cosa->num = nr_cards;
+	cosa->usage = 0;
+	cosa->nchannels = 2;	/* FIXME: how to determine this? */
+
+	request_region(base, is_8bit(cosa)?2:4, cosa->type);
+	if (request_irq(cosa->irq, cosa_interrupt, 0, cosa->type, cosa))
+		goto bad1;
+	if (request_dma(cosa->dma, cosa->type)) {
+		free_irq(cosa->irq, cosa);
+bad1:		release_region(cosa->datareg,is_8bit(cosa)?2:4);
+		printk(KERN_NOTICE "cosa%d: allocating resources failed\n",
+			cosa->num);
+		return -1;
+	}
+	
+	cosa->bouncebuf = kmalloc(COSA_MTU, GFP_KERNEL|GFP_DMA);
+	sprintf(cosa->name, "cosa%d", cosa->num);
+
+	/* Initialize the per-channel data */
+	cosa->chan = kmalloc(sizeof(struct channel_data)*cosa->nchannels,
+		GFP_KERNEL);
+	memset(cosa->chan, 0, sizeof(struct channel_data)*cosa->nchannels);
+	for (i=0; i<cosa->nchannels; i++) {
+		cosa->chan[i].cosa = cosa;
+		cosa->chan[i].num = i;
+		channel_init(cosa->chan+i);
+	}
+
+	printk (KERN_INFO "cosa%d: %s (%s at 0x%x irq %d dma %d), %d channels\n",
+		cosa->num, cosa->id_string, cosa->type,
+		cosa->datareg, cosa->irq, cosa->dma, cosa->nchannels);
+
+	return nr_cards++;
+}
+
+
+/*---------- SPPP/HDLC netdevice ---------- */
+
+static void sppp_channel_init(struct channel_data *chan)
+{
+	struct net_device *d;
+	sppp_attach(&chan->pppdev);
+	d=&chan->pppdev.dev;
+	d->name = chan->name;
+	d->base_addr = chan->cosa->datareg;
+	d->irq = chan->cosa->irq;
+	d->dma = chan->cosa->dma;
+	d->priv = chan;
+	d->init = NULL;
+	d->open = cosa_sppp_open;
+	d->stop = cosa_sppp_close;
+	d->hard_start_xmit = cosa_sppp_tx;
+	d->do_ioctl = cosa_sppp_ioctl;
+	d->get_stats = cosa_net_stats;
+	dev_init_buffers(d);
+	if (register_netdev(d) == -1) {
+		printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
+		sppp_detach(&chan->pppdev.dev);
+		return;
+	}
+}
+
+static void sppp_channel_delete(struct channel_data *chan)
+{
+	sppp_detach(&chan->pppdev.dev);
+	unregister_netdev(&chan->pppdev.dev);
+}
+
+
+static int cosa_sppp_open(struct net_device *d)
+{
+	struct channel_data *chan = d->priv;
+	int err, flags;
+
+	spin_lock_irqsave(&chan->cosa->lock, flags);
+	if (chan->usage != 0) {
+		printk(KERN_WARNING "%s: sppp_open called with usage count %d\n",
+			chan->name, chan->usage);
+		spin_unlock_irqrestore(&chan->cosa->lock, flags);
+		return -EBUSY;
+	}
+	chan->setup_rx = sppp_setup_rx;
+	chan->tx_done = sppp_tx_done;
+	chan->rx_done = sppp_rx_done;
+	chan->usage=-1;
+	chan->cosa->usage++;
+	MOD_INC_USE_COUNT;
+	spin_unlock_irqrestore(&chan->cosa->lock, flags);
+
+	err = sppp_open(d);
+	if (err) {
+		spin_lock_irqsave(&chan->cosa->lock, flags);
+		chan->usage=0;
+		chan->cosa->usage--;
+		MOD_DEC_USE_COUNT;
+		
+		spin_unlock_irqrestore(&chan->cosa->lock, flags);
+		return err;
+	}
+
+	d->tbusy = 0;
+	cosa_enable_rx(chan);
+	return 0;
+}
+
+static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct channel_data *chan = dev->priv;
+
+	if (dev->tbusy) { 
+		if (time_before(jiffies, dev->trans_start+2*HZ))
+			return 1;	/* Two seconds timeout */
+		if (test_bit(RXBIT, &chan->cosa->rxtx)) {
+			chan->stats.rx_errors++;
+			chan->stats.rx_missed_errors++;
+		} else {
+			chan->stats.tx_errors++;
+			chan->stats.tx_aborted_errors++;
+		}
+		cosa_kick(chan->cosa);
+		if (chan->tx_skb) {
+			dev_kfree_skb(chan->tx_skb);
+			chan->tx_skb = 0;
+		}
+		dev->tbusy = 0;
+	}
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+		printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
+		return 1;
+	}
+	
+	chan->tx_skb = skb;
+	dev->trans_start = jiffies;
+	cosa_start_tx(chan, skb->data, skb->len);
+	return 0;
+}
+
+static int cosa_sppp_close(struct net_device *d)
+{
+	struct channel_data *chan = d->priv;
+	int flags;
+
+	sppp_close(d);
+	d->tbusy = 1;
+	cosa_disable_rx(chan);
+	spin_lock_irqsave(&chan->cosa->lock, flags);
+	if (chan->rx_skb) {
+		kfree_skb(chan->rx_skb);
+		chan->rx_skb = 0;
+	}
+	if (chan->tx_skb) {
+		kfree_skb(chan->tx_skb);
+		chan->tx_skb = 0;
+	}
+	chan->usage=0;
+	chan->cosa->usage--;
+	MOD_DEC_USE_COUNT;
+	spin_unlock_irqrestore(&chan->cosa->lock, flags);
+	return 0;
+}
+
+static char *sppp_setup_rx(struct channel_data *chan, int size)
+{
+	/*
+	 * We can safely fall back to non-dma-able memory, because we have
+	 * the cosa->bouncebuf pre-allocated.
+	 */
+	if (chan->rx_skb)
+		kfree_skb(chan->rx_skb);
+	chan->rx_skb = dev_alloc_skb(size);
+	if (chan->rx_skb == NULL) {
+		printk(KERN_NOTICE "%s: Memory squeeze, dropping packet\n",
+			chan->name);
+		chan->stats.rx_dropped++;
+		return NULL;
+	}
+	chan->pppdev.dev.trans_start = jiffies;
+	return skb_put(chan->rx_skb, size);
+}
+
+static int sppp_rx_done(struct channel_data *chan)
+{
+	if (!chan->rx_skb) {
+		printk(KERN_WARNING "%s: rx_done with empty skb!\n",
+			chan->name);
+		chan->stats.rx_errors++;
+		chan->stats.rx_frame_errors++;
+		return 0;
+	}
+	chan->rx_skb->protocol = htons(ETH_P_WAN_PPP);
+	chan->rx_skb->dev = &chan->pppdev.dev;
+	chan->rx_skb->mac.raw = chan->rx_skb->data;
+	chan->stats.rx_packets++;
+	chan->stats.rx_bytes += chan->cosa->rxsize;
+	netif_rx(chan->rx_skb);
+	chan->rx_skb = 0;
+	chan->pppdev.dev.trans_start = jiffies;
+	return 0;
+}
+
+/* ARGSUSED */
+static int sppp_tx_done(struct channel_data *chan, int size)
+{
+	if (!chan->tx_skb) {
+		printk(KERN_WARNING "%s: tx_done with empty skb!\n",
+			chan->name);
+		chan->stats.tx_errors++;
+		chan->stats.tx_aborted_errors++;
+		return 1;
+	}
+	dev_kfree_skb(chan->tx_skb);
+	chan->tx_skb = 0;
+	chan->stats.tx_packets++;
+	chan->stats.tx_bytes += size;
+	chan->pppdev.dev.tbusy = 0;
+	mark_bh(NET_BH);
+	return 1;
+}
+
+static struct net_device_stats *cosa_net_stats(struct net_device *dev)
+{
+	struct channel_data *chan = dev->priv;
+	return &chan->stats;
+}
+
+
+/*---------- Character device ---------- */
+
+static void chardev_channel_init(struct channel_data *chan)
+{
+	init_MUTEX(&chan->rsem);
+	init_MUTEX(&chan->wsem);
+}
+
+static long long cosa_lseek(struct file * file,
+	long long offset, int origin)
+{
+	return -ESPIPE;
+}
+
+static ssize_t cosa_read(struct file *file,
+	char *buf, size_t count, loff_t *ppos)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int flags;
+	struct channel_data *chan = (struct channel_data *)file->private_data;
+	struct cosa_data *cosa = chan->cosa;
+	char *kbuf;
+
+	if (down_interruptible(&chan->rsem))
+		return -ERESTARTSYS;
+	
+	if ((chan->rxdata = kmalloc(COSA_MTU, GFP_DMA|GFP_KERNEL)) == NULL) {
+		printk(KERN_INFO "%s: cosa_read() - OOM\n", cosa->name);
+		up(&chan->rsem);
+		return -ENOMEM;
+	}
+
+	chan->rx_status = 0;
+	cosa_enable_rx(chan);
+	spin_lock_irqsave(&cosa->lock, flags);
+	add_wait_queue(&chan->rxwaitq, &wait);
+	while(!chan->rx_status) {
+		current->state = TASK_INTERRUPTIBLE;
+		spin_unlock_irqrestore(&cosa->lock, flags);
+		schedule();
+		spin_lock_irqsave(&cosa->lock, flags);
+		if (signal_pending(current) && chan->rx_status == 0) {
+			chan->rx_status = 1;
+			remove_wait_queue(&chan->rxwaitq, &wait);
+			current->state = TASK_RUNNING;
+			spin_unlock_irqrestore(&cosa->lock, flags);
+			up(&chan->rsem);
+			return -ERESTARTSYS;
+		}
+	}
+	remove_wait_queue(&chan->rxwaitq, &wait);
+	current->state = TASK_RUNNING;
+	kbuf = chan->rxdata;
+	count = chan->rxsize;
+	spin_unlock_irqrestore(&cosa->lock, flags);
+	up(&chan->rsem);
+
+	if (copy_to_user(buf, kbuf, count)) {
+		kfree(buf);
+		return -EFAULT;
+	}
+	kfree(kbuf);
+	return count;
+}
+
+static char *chrdev_setup_rx(struct channel_data *chan, int size)
+{
+	/* Expect size <= COSA_MTU */
+	chan->rxsize = size;
+	return chan->rxdata;
+}
+
+static int chrdev_rx_done(struct channel_data *chan)
+{
+	if (chan->rx_status) { /* Reader has died */
+		kfree(chan->rxdata);
+		up(&chan->wsem);
+	}
+	chan->rx_status = 1;
+	wake_up_interruptible(&chan->rxwaitq);
+	return 1;
+}
+
+
+static ssize_t cosa_write(struct file *file,
+	const char *buf, size_t count, loff_t *ppos)
+{
+	struct channel_data *chan = (struct channel_data *)file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
+	struct cosa_data *cosa = chan->cosa;
+	unsigned int flags;
+	char *kbuf;
+
+	if (down_interruptible(&chan->wsem))
+		return -ERESTARTSYS;
+
+	if (count > COSA_MTU)
+		count = COSA_MTU;
+	
+	/* Allocate the buffer */
+	if ((kbuf = kmalloc(count, GFP_KERNEL|GFP_DMA)) == NULL) {
+		printk(KERN_NOTICE "%s: cosa_write() OOM - dropping packet\n",
+			cosa->name);
+		up(&chan->wsem);
+		return -ENOMEM;
+	}
+	if (copy_from_user(kbuf, buf, count)) {
+		up(&chan->wsem);
+		kfree(kbuf);
+		return -EFAULT;
+	}
+	chan->tx_status=0;
+	cosa_start_tx(chan, kbuf, count);
+
+	spin_lock_irqsave(&cosa->lock, flags);
+	add_wait_queue(&chan->txwaitq, &wait);
+	while(!chan->tx_status) {
+		current->state = TASK_INTERRUPTIBLE;
+		spin_unlock_irqrestore(&cosa->lock, flags);
+		schedule();
+		spin_lock_irqsave(&cosa->lock, flags);
+		if (signal_pending(current) && chan->tx_status == 0) {
+			chan->tx_status = 1;
+			remove_wait_queue(&chan->txwaitq, &wait);
+			current->state = TASK_RUNNING;
+			chan->tx_status = 1;
+			spin_unlock_irqrestore(&cosa->lock, flags);
+			return -ERESTARTSYS;
+		}
+	}
+	remove_wait_queue(&chan->txwaitq, &wait);
+	current->state = TASK_RUNNING;
+	up(&chan->wsem);
+	spin_unlock_irqrestore(&cosa->lock, flags);
+	kfree(kbuf);
+	return count;
+}
+
+static int chrdev_tx_done(struct channel_data *chan, int size)
+{
+	if (chan->tx_status) { /* Writer was interrupted */
+		kfree(chan->txbuf);
+		up(&chan->wsem);
+	}
+	chan->tx_status = 1;
+	wake_up_interruptible(&chan->txwaitq);
+	return 1;
+}
+
+static unsigned int cosa_poll(struct file *file, poll_table *poll)
+{
+	printk(KERN_INFO "cosa_poll is here\n");
+	return 0;
+}
+
+static int cosa_open(struct inode *inode, struct file *file)
+{
+	struct cosa_data *cosa;
+	struct channel_data *chan;
+	unsigned long flags;
+	int n;
+
+	if ((n=MINOR(file->f_dentry->d_inode->i_rdev)>>CARD_MINOR_BITS)
+		>= nr_cards)
+		return -ENODEV;
+	cosa = cosa_cards+n;
+
+	if ((n=MINOR(file->f_dentry->d_inode->i_rdev)
+		& ((1<<CARD_MINOR_BITS)-1)) >= cosa->nchannels)
+		return -ENODEV;
+	chan = cosa->chan + n;
+	
+	file->private_data = chan;
+
+	spin_lock_irqsave(&cosa->lock, flags);
+
+	if (chan->usage < 0) { /* in netdev mode */
+		spin_unlock_irqrestore(&cosa->lock, flags);
+		return -EBUSY;
+	}
+	cosa->usage++;
+	chan->usage++;
+
+	chan->tx_done = chrdev_tx_done;
+	chan->setup_rx = chrdev_setup_rx;
+	chan->rx_done = chrdev_rx_done;
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+	spin_unlock_irqrestore(&cosa->lock, flags);
+	return 0;
+}
+
+static int cosa_release(struct inode *inode, struct file *file)
+{
+	struct channel_data *channel = (struct channel_data *)file->private_data;
+	struct cosa_data *cosa = channel->cosa;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cosa->lock, flags);
+	cosa->usage--;
+	channel->usage--;
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+	spin_unlock_irqrestore(&cosa->lock, flags);
+	return 0;
+}
+
+#ifdef COSA_FASYNC_WORKING
+static struct fasync_struct *fasync[256] = { NULL, };
+
+/* To be done ... */
+static int cosa_fasync(struct inode *inode, struct file *file, int on)
+{
+        int port = MINOR(inode->i_rdev);
+        int rv = fasync_helper(inode, file, on, &fasync[port]);
+        return rv < 0 ? rv : 0;
+}
+#endif
+
+
+/* ---------- Ioctls ---------- */
+
+/*
+ * Ioctl subroutines can safely be made inline, because they are called
+ * only from cosa_ioctl().
+ */
+static inline int cosa_reset(struct cosa_data *cosa)
+{
+	char idstring[COSA_MAX_ID_STRING];
+	if (cosa->usage > 1)
+		printk(KERN_INFO "cosa%d: WARNING: reset requested with cosa->usage > 1 (%d). Odd things may happen.\n",
+			cosa->num, cosa->usage);
+	if (cosa_reset_and_read_id(cosa, idstring) < 0) {
+		printk(KERN_NOTICE "cosa%d: reset failed\n", cosa->num);
+		return -EIO;
+	}
+	printk(KERN_INFO "cosa%d: resetting device: %s\n", cosa->num,
+		idstring);
+	return 0;
+}
+
+/* High-level function to download data into COSA memory. Calls download() */
+static inline int cosa_download(struct cosa_data *cosa, struct cosa_download *d)
+{
+	int i;
+	int addr, len;
+	char *code;
+
+	if (cosa->usage > 1)
+		printk(KERN_INFO "cosa%d: WARNING: download of microcode requested with cosa->usage > 1 (%d). Odd things may happen.\n",
+			cosa->num, cosa->usage);
+#if 0
+	if (cosa->status != CARD_STATUS_RESETED && cosa->status != CARD_STATUS_DOWNLOADED) {
+		printk(KERN_NOTICE "cosa%d: reset the card first (status %d).\n",
+			cosa->num, cosa->status);
+		return -EPERM;
+	}
+#endif
+	get_user_ret(addr, &(d->addr), -EFAULT);
+	get_user_ret(len, &(d->len), -EFAULT);
+	get_user_ret(code, &(d->code), -EFAULT);
+
+	if (d->addr < 0 || d->addr > COSA_MAX_FIRMWARE_SIZE)
+		return -EINVAL;
+	if (d->len < 0 || d->len > COSA_MAX_FIRMWARE_SIZE)
+		return -EINVAL;
+
+	if ((i=download(cosa, d->code, len, addr)) < 0) {
+		printk(KERN_NOTICE "cosa%d: microcode download failed: %d\n",
+			cosa->num, i);
+		return -EIO;
+	}
+	printk(KERN_INFO "cosa%d: downloading microcode - 0x%04x bytes at 0x%04x\n",
+		cosa->num, len, addr);
+	return 0;
+}
+
+/* High-level function to read COSA memory. Calls readmem() */
+static inline int cosa_readmem(struct cosa_data *cosa, struct cosa_download *d)
+{
+	int i;
+	int addr, len;
+	char *code;
+
+	if (cosa->usage > 1)
+		printk(KERN_INFO "cosa%d: WARNING: readmem requested with "
+			"cosa->usage > 1 (%d). Odd things may happen.\n",
+			cosa->num, cosa->usage);
+#if 0
+	if (cosa->status != CARD_STATUS_RESETED &&
+		cosa->status != CARD_STATUS_DOWNLOADED) {
+		printk(KERN_NOTICE "cosa%d: reset the card first (status %d).\n",
+			cosa->num, cosa->status);
+		return -EPERM;
+	}
+#endif
+	get_user_ret(addr, &(d->addr), -EFAULT);
+	get_user_ret(len, &(d->len), -EFAULT);
+	get_user_ret(code, &(d->code), -EFAULT);
+
+	if ((i=readmem(cosa, d->code, len, addr)) < 0) {
+		printk(KERN_NOTICE "cosa%d: reading memory failed: %d\n",
+			cosa->num, i);
+		return -EIO;
+	}
+	printk(KERN_INFO "cosa%d: reading card memory - 0x%04x bytes at 0x%04x\n",
+		cosa->num, len, addr);
+	return 0;
+}
+
+/* High-level function to start microcode. Calls startmicrocode(). */
+static inline int cosa_start(struct cosa_data *cosa, int address)
+{
+	int i;
+
+	if (cosa->usage > 1)
+		printk(KERN_INFO "cosa%d: WARNING: start microcode requested with cosa->usage > 1 (%d). Odd things may happen.\n",
+			cosa->num, cosa->usage);
+#if 0
+	if (cosa->status != CARD_STATUS_DOWNLOADED) {
+		printk(KERN_NOTICE "cosa%d: download the microcode first (status %d).\n",
+			cosa->num, cosa->status);
+		return -EPERM;
+	}
+#endif
+	if ((i=startmicrocode(cosa, address)) < 0) {
+		printk(KERN_NOTICE "cosa%d: start microcode at 0x%04x failed: %d\n",
+			cosa->num, address, i);
+		return -EIO;
+	}
+	printk(KERN_INFO "cosa%d: starting microcode at 0x%04x\n",
+		cosa->num, address);
+	cosa->startaddr = address;
+	return 0;
+}
+		
+/* Buffer of size at least COSA_MAX_ID_STRING is expected */
+static inline int cosa_getidstr(struct cosa_data *cosa, char *string)
+{
+	int l = strlen(cosa->id_string)+1;
+	copy_to_user_ret(string, cosa->id_string, l, -EFAULT);
+	return l;
+}
+
+/* Buffer of size at least COSA_MAX_ID_STRING is expected */
+static inline int cosa_gettype(struct cosa_data *cosa, char *string)
+{
+	int l = strlen(cosa->type)+1;
+	copy_to_user_ret(string, cosa->type, l, -EFAULT);
+	return l;
+}
+
+static int cosa_ioctl_common(struct cosa_data *cosa,
+	struct channel_data *channel, unsigned int cmd, unsigned long arg)
+{
+	switch(cmd) {
+	case COSAIORSET:	/* Reset the device */
+		if (!suser())
+			return -EACCES;
+		return cosa_reset(cosa);
+	case COSAIOSTRT:	/* Start the firmware */
+		if (!suser())
+			return -EACCES;
+		return cosa_start(cosa, arg);
+	case COSAIODOWNLD:	/* Download the firmware */
+		if (!suser())
+			return -EACCES;
+		return cosa_download(cosa, (struct cosa_download *)arg);
+	case COSAIORMEM:
+		if (!suser())
+			return -EACCES;
+		return cosa_readmem(cosa, (struct cosa_download *)arg);
+	case COSAIORTYPE:
+		return cosa_gettype(cosa, (char *)arg);
+	case COSAIORIDSTR:
+		return cosa_getidstr(cosa, (char *)arg);
+/*
+ * These two are _very_ugly_hack_(tm). Don't even look at this.
+ * Implementing this saved me few reboots after some process segfaulted
+ * inside this module.
+ */
+#ifdef MODULE
+#if 0
+	case COSAIOMINC:
+		MOD_INC_USE_COUNT;
+		return 0;
+	case COSAIOMDEC:
+		MOD_DEC_USE_COUNT;
+		return 0;
+#endif
+#endif
+	case COSAIONRCARDS:
+		return nr_cards;
+	case COSAIONRCHANS:
+		return cosa->nchannels;
+	case COSAIOBMSET:
+		if (!suser())
+			return -EACCES;
+		if (is_8bit(cosa))
+			return -EINVAL;
+		if (arg != COSA_BM_OFF && arg != COSA_BM_ON)
+			return -EINVAL;
+		cosa->busmaster = arg;
+		return 0;
+	case COSAIOBMGET:
+		return cosa->busmaster;
+	}
+	return -ENOIOCTLCMD;
+}
+
+static int cosa_sppp_ioctl(struct net_device *dev, struct ifreq *ifr,
+	int cmd)
+{
+	int rv;
+	struct channel_data *chan = (struct channel_data *)dev->priv;
+	rv = cosa_ioctl_common(chan->cosa, chan, cmd, (int)ifr->ifr_data);
+	if (rv == -ENOIOCTLCMD) {
+		return sppp_do_ioctl(dev, ifr, cmd);
+	}
+	return rv;
+}
+
+static int cosa_chardev_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	struct channel_data *channel = (struct channel_data *)file->private_data;
+	struct cosa_data *cosa = channel->cosa;
+	return cosa_ioctl_common(cosa, channel, cmd, arg);
+}
+
+
+/*---------- HW layer interface ---------- */
+
+/*
+ * The higher layer can bind itself to the HW layer by setting the callbacks
+ * in the channel_data structure and by using these routines.
+ */
+static void cosa_enable_rx(struct channel_data *chan)
+{
+	struct cosa_data *cosa = chan->cosa;
+
+	if (!test_and_set_bit(chan->num, &cosa->rxbitmap))
+		put_driver_status(cosa);
+}
+
+static void cosa_disable_rx(struct channel_data *chan)
+{
+	struct cosa_data *cosa = chan->cosa;
+
+	if (test_and_clear_bit(chan->num, &cosa->rxbitmap))
+		put_driver_status(cosa);
+}
+
+/*
+ * FIXME: This routine probably should check for cosa_start_tx() called when
+ * the previous transmit is still unfinished. In this case the non-zero
+ * return value should indicate to the caller that the queuing(sp?) up
+ * the transmit has failed.
+ */
+static int cosa_start_tx(struct channel_data *chan, char *buf, int len)
+{
+	struct cosa_data *cosa = chan->cosa;
+	int flags;
+#ifdef DEBUG_DATA
+	int i;
+
+	printk(KERN_INFO "cosa%dc%d: starting tx(0x%x)", chan->cosa->num,
+		chan->num, len);
+	for (i=0; i<len; i++)
+		printk(" %02x", buf[i]&0xff);
+	printk("\n");
+#endif
+	spin_lock_irqsave(&cosa->lock, flags);
+	chan->txbuf = buf;
+	chan->txsize = len;
+	if (len > COSA_MTU)
+		chan->txsize = COSA_MTU;
+	spin_unlock_irqrestore(&cosa->lock, flags);
+
+	/* Tell the firmware we are ready */
+	set_bit(chan->num, &cosa->txbitmap);
+	put_driver_status(cosa);
+
+	return 0;
+}
+
+static void put_driver_status(struct cosa_data *cosa)
+{
+	unsigned flags=0;
+	int status;
+
+	spin_lock_irqsave(&cosa->lock, flags);
+
+	status = (cosa->rxbitmap ? DRIVER_RX_READY : 0)
+		| (cosa->txbitmap ? DRIVER_TX_READY : 0)
+		| (cosa->txbitmap? ~(cosa->txbitmap<<DRIVER_TXMAP_SHIFT)
+			&DRIVER_TXMAP_MASK : 0);
+	if (!cosa->rxtx) {
+		if (cosa->rxbitmap|cosa->txbitmap) {
+			if (!cosa->enabled) {
+				cosa_putstatus(cosa, SR_RX_INT_ENA);
+#ifdef DEBUG_IO
+				debug_status_out(cosa, SR_RX_INT_ENA);
+#endif
+				cosa->enabled = 1;
+			}
+		} else if (cosa->enabled) {
+			cosa->enabled = 0;
+			cosa_putstatus(cosa, 0);
+#ifdef DEBUG_IO
+			debug_status_out(cosa, 0);
+#endif
+		}
+		cosa_putdata8(cosa, status);
+#ifdef DEBUG_IO
+		debug_data_cmd(cosa, status);
+#endif
+	}
+	spin_unlock_irqrestore(&cosa->lock, flags);
+}
+
+static void put_driver_status_nolock(struct cosa_data *cosa)
+{
+	int status;
+
+	status = (cosa->rxbitmap ? DRIVER_RX_READY : 0)
+		| (cosa->txbitmap ? DRIVER_TX_READY : 0)
+		| (cosa->txbitmap? ~(cosa->txbitmap<<DRIVER_TXMAP_SHIFT)
+			&DRIVER_TXMAP_MASK : 0);
+
+	if (cosa->rxbitmap|cosa->txbitmap) {
+		cosa_putstatus(cosa, SR_RX_INT_ENA);
+#ifdef DEBUG_IO
+		debug_status_out(cosa, SR_RX_INT_ENA);
+#endif
+		cosa->enabled = 1;
+	} else {
+		cosa_putstatus(cosa, 0);
+#ifdef DEBUG_IO
+		debug_status_out(cosa, 0);
+#endif
+		cosa->enabled = 0;
+	}
+	cosa_putdata8(cosa, status);
+#ifdef DEBUG_IO
+	debug_data_cmd(cosa, status);
+#endif
+}
+
+/*
+ * The "kickme" function: When the DMA times out, this is called to
+ * clean up the driver status.
+ * FIXME: Preliminary support, the interface is probably wrong.
+ */
+static void cosa_kick(struct cosa_data *cosa)
+{
+	unsigned flags, flags1;
+	char *s = "Unknown";
+
+	if (test_bit(RXBIT, &cosa->rxtx))
+		s = "RX";
+	if (test_bit(TXBIT, &cosa->rxtx))
+		s = "TX";
+
+	printk(KERN_INFO "%s: %s DMA timeout - restarting.\n", cosa->name, s); 
+	spin_lock_irqsave(&cosa->lock, flags);
+	cosa->rxtx = 0;
+
+	flags1 = claim_dma_lock();
+	disable_dma(cosa->dma);
+	clear_dma_ff(cosa->dma);
+	release_dma_lock(flags1);
+
+	/* FIXME: Anything else? */
+	udelay(100);
+	cosa_putstatus(cosa, 0);
+	udelay(100);
+	(void) cosa_getdata8(cosa);
+	udelay(100);
+	cosa_putdata8(cosa, 0);
+	udelay(100);
+	put_driver_status_nolock(cosa);
+	spin_unlock_irqrestore(&cosa->lock, flags);
+}
+
+/*
+ * Check if the whole buffer is DMA-able. It means it is below the 16M of
+ * physical memory and doesn't span the 64k boundary. For now it seems
+ * SKB's never do this, but we'll check this anyway.
+ */
+static int cosa_dma_able(struct channel_data *chan, char *buf, int len)
+{
+	static int count = 0;
+	unsigned long b = (unsigned long)buf;
+	if (b+len >= MAX_DMA_ADDRESS)
+		return 0;
+	if ((b^ (b+len)) & 0x10000) {
+		if (count++ < 5)
+			printk(KERN_INFO "%s: packet spanning a 64k boundary\n",
+				chan->name);
+		return 0;
+	}
+	return 1;
+}
+
+
+/* ---------- The SRP/COSA ROM monitor functions ---------- */
+
+/*
+ * Downloading SRP microcode: say "w" to SRP monitor, it answers by "w=",
+ * drivers need to say 4-digit hex number meaning start address of the microcode
+ * separated by a single space. Monitor replies by saying " =". Now driver
+ * has to write 4-digit hex number meaning the last byte address ended
+ * by a single space. Monitor has to reply with a space. Now the download
+ * begins. After the download monitor replies with "\r\n." (CR LF dot).
+ */
+static int download(struct cosa_data *cosa, char *microcode, int length, int address)
+{
+	int i;
+
+	if (put_wait_data(cosa, 'w') == -1) return -1;
+	if ((i=get_wait_data(cosa)) != 'w') { printk("dnld: 0x%04x\n",i); return -2;}
+	if (get_wait_data(cosa) != '=') return -3;
+
+	if (puthexnumber(cosa, address) < 0) return -4;
+	if (put_wait_data(cosa, ' ') == -1) return -10;
+	if (get_wait_data(cosa) != ' ') return -11;
+	if (get_wait_data(cosa) != '=') return -12;
+
+	if (puthexnumber(cosa, address+length-1) < 0) return -13;
+	if (put_wait_data(cosa, ' ') == -1) return -18;
+	if (get_wait_data(cosa) != ' ') return -19;
+
+	while (length--) {
+		char c;
+#ifndef SRP_DOWNLOAD_AT_BOOT
+		get_user_ret(c,microcode, -23);
+#else
+		c = *microcode;
+#endif
+		if (put_wait_data(cosa, c) == -1)
+			return -20;
+		microcode++;
+	}
+
+	if (get_wait_data(cosa) != '\r') return -21;
+	if (get_wait_data(cosa) != '\n') return -22;
+	if (get_wait_data(cosa) != '.') return -23;
+#if 0
+	printk(KERN_DEBUG "cosa%d: download completed.\n", cosa->num);
+#endif
+	return 0;
+}
+
+
+/*
+ * Starting microcode is done via the "g" command of the SRP monitor.
+ * The chat should be the following: "g" "g=" "<addr><CR>"
+ * "<CR><CR><LF><CR><LF>".
+ */
+static int startmicrocode(struct cosa_data *cosa, int address)
+{
+	if (put_wait_data(cosa, 'g') == -1) return -1;
+	if (get_wait_data(cosa) != 'g') return -2;
+	if (get_wait_data(cosa) != '=') return -3;
+
+	if (puthexnumber(cosa, address) < 0) return -4;
+	if (put_wait_data(cosa, '\r') == -1) return -5;
+	
+	if (get_wait_data(cosa) != '\r') return -6;
+	if (get_wait_data(cosa) != '\r') return -7;
+	if (get_wait_data(cosa) != '\n') return -8;
+	if (get_wait_data(cosa) != '\r') return -9;
+	if (get_wait_data(cosa) != '\n') return -10;
+#if 0
+	printk(KERN_DEBUG "cosa%d: microcode started\n", cosa->num);
+#endif
+	return 0;
+}
+
+/*
+ * Reading memory is done via the "r" command of the SRP monitor.
+ * The chat is the following "r" "r=" "<addr> " " =" "<last_byte> " " "
+ * Then driver can read the data and the conversation is finished
+ * by SRP monitor sending "<CR><LF>." (dot at the end).
+ *
+ * This routine is not needed during the normal operation and serves
+ * for debugging purposes only.
+ */
+static int readmem(struct cosa_data *cosa, char *microcode, int length, int address)
+{
+	if (put_wait_data(cosa, 'r') == -1) return -1;
+	if ((get_wait_data(cosa)) != 'r') return -2;
+	if ((get_wait_data(cosa)) != '=') return -3;
+
+	if (puthexnumber(cosa, address) < 0) return -4;
+	if (put_wait_data(cosa, ' ') == -1) return -5;
+	if (get_wait_data(cosa) != ' ') return -6;
+	if (get_wait_data(cosa) != '=') return -7;
+
+	if (puthexnumber(cosa, address+length-1) < 0) return -8;
+	if (put_wait_data(cosa, ' ') == -1) return -9;
+	if (get_wait_data(cosa) != ' ') return -10;
+
+	while (length--) {
+		char c;
+		int i;
+		if ((i=get_wait_data(cosa)) == -1) {
+			printk (KERN_INFO "cosa: 0x%04x bytes remaining\n",
+				length);
+			return -11;
+		}
+		c=i;
+#if 1
+		put_user_ret(c,microcode, -23);
+#else
+		*microcode = c;
+#endif
+		microcode++;
+	}
+
+	if (get_wait_data(cosa) != '\r') return -21;
+	if (get_wait_data(cosa) != '\n') return -22;
+	if (get_wait_data(cosa) != '.') return -23;
+#if 0
+	printk(KERN_DEBUG "cosa%d: readmem completed.\n", cosa->num);
+#endif
+	return 0;
+}
+
+/*
+ * This function resets the device and reads the initial prompt
+ * of the device's ROM monitor.
+ */
+static int cosa_reset_and_read_id(struct cosa_data *cosa, char *idstring)
+{
+	int i=0, id=0, prev=0, curr=0;
+
+	/* Reset the card ... */
+	cosa_putstatus(cosa, 0);
+	cosa_getdata8(cosa);
+	cosa_putstatus(cosa, SR_RST);
+#ifdef MODULE
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(HZ/2);
+	current->state = TASK_RUNNING;
+#else
+	udelay(5*100000);
+#endif
+	/* Disable all IRQs from the card */
+	cosa_putstatus(cosa, 0);
+
+	/*
+	 * Try to read the ID string. The card then prints out the
+	 * identification string ended by the "\n\x2e".
+	 *
+	 * The following loop is indexed through i (instead of id)
+	 * to avoid looping forever when for any reason
+	 * the port returns '\r', '\n' or '\x2e' permanently.
+	 */
+	for (i=0; i<COSA_MAX_ID_STRING-1; i++, prev=curr) {
+		if ((curr = get_wait_data(cosa)) == -1) {
+			return -1;
+		}
+		curr &= 0xff;
+		if (curr != '\r' && curr != '\n' && curr != 0x2e)
+			idstring[id++] = curr;
+		if (curr == 0x2e && prev == '\n')
+			break;
+	}
+	/* Perhaps we should fail when i==COSA_MAX_ID_STRING-1 ? */
+	idstring[id] = '\0';
+	return id;
+}
+
+
+/* ---------- Auxiliary routines for COSA/SRP monitor ---------- */
+
+/*
+ * This routine gets the data byte from the card waiting for the SR_RX_RDY
+ * bit to be set in a loop. It should be used in the exceptional cases
+ * only (for example when resetting the card or downloading the firmware.
+ */
+static int get_wait_data(struct cosa_data *cosa)
+{
+	int retries = 1000;
+
+	while (--retries) {
+		/* read data and return them */
+		if (cosa_getstatus(cosa) & SR_RX_RDY) {
+			short r;
+			r = cosa_getdata8(cosa);
+#if 0
+			printk(KERN_INFO "cosa: get_wait_data returning after %d retries\n", 999-retries);
+#endif
+			return r;
+		}
+		/* sleep if not ready to read */
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(1);
+	}
+	printk(KERN_INFO "cosa: timeout in get_wait_data (status 0x%x)\n",
+		cosa_getstatus(cosa));
+	return -1;
+}
+
+/*
+ * This routine puts the data byte to the card waiting for the SR_TX_RDY
+ * bit to be set in a loop. It should be used in the exceptional cases
+ * only (for example when resetting the card or downloading the firmware).
+ */
+static int put_wait_data(struct cosa_data *cosa, int data)
+{
+	int retries = 1000;
+	while (--retries) {
+		/* read data and return them */
+		if (cosa_getstatus(cosa) & SR_TX_RDY) {
+			cosa_putdata8(cosa, data);
+#if 0
+			printk(KERN_INFO "Putdata: %d retries\n", 999-retries);
+#endif
+			return 0;
+		}
+#if 0
+		/* sleep if not ready to read */
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(1);
+#endif
+	}
+	printk(KERN_INFO "cosa%d: timeout in put_wait_data (status 0x%x)\n",
+		cosa->num, cosa_getstatus(cosa));
+	return -1;
+}
+	
+/* 
+ * The following routine puts the hexadecimal number into the SRP monitor
+ * and verifies the proper echo of the sent bytes. Returns 0 on success,
+ * negative number on failure (-1,-3,-5,-7) means that put_wait_data() failed,
+ * (-2,-4,-6,-8) means that reading echo failed.
+ */
+static int puthexnumber(struct cosa_data *cosa, int number)
+{
+	char temp[5];
+	int i;
+
+	/* Well, I should probably replace this by something faster. */
+	sprintf(temp, "%04X", number);
+	for (i=0; i<4; i++) {
+		if (put_wait_data(cosa, temp[i]) == -1) {
+			printk(KERN_NOTICE "cosa%d: puthexnumber failed to write byte %d\n",
+				cosa->num, i);
+			return -1-2*i;
+		}
+		if (get_wait_data(cosa) != temp[i]) {
+			printk(KERN_NOTICE "cosa%d: puthexhumber failed to read echo of byte %d\n",
+				cosa->num, i);
+			return -2-2*i;
+		}
+	}
+	return 0;
+}
+
+
+/* ---------- Interrupt routines ---------- */
+
+/*
+ * There are three types of interrupt:
+ * At the beginning of transmit - this handled is in tx_interrupt(),
+ * at the beginning of receive - it is in rx_interrupt() and
+ * at the end of transmit/receive - it is the eot_interrupt() function.
+ * These functions are multiplexed by cosa_interrupt() according to the
+ * COSA status byte. I have moved the rx/tx/eot interrupt handling into
+ * separate functions to make it more readable. These functions are inline,
+ * so there should be no overhead of function call.
+ * 
+ * In the COSA bus-master mode, we need to tell the card the address of a
+ * buffer. Unfortunately, COSA may be too slow for us, so we must busy-wait.
+ * It's time to use the bottom half :-(
+ */
+
+/*
+ * Transmit interrupt routine - called when COSA is willing to obtain
+ * data from the OS. The most tricky part of the routine is selection
+ * of channel we (OS) want to send packet for. For SRP we should probably
+ * use the round-robin approach. The newer COSA firmwares have a simple
+ * flow-control - in the status word has bits 2 and 3 set to 1 means that the
+ * channel 0 or 1 doesn't want to receive data.
+ *
+ * It seems there is a bug in COSA firmware (need to trace it further):
+ * When the driver status says that the kernel has no more data for transmit
+ * (e.g. at the end of TX DMA) and then the kernel changes its mind
+ * (e.g. new packet is queued to hard_start_xmit()), the card issues
+ * the TX interrupt but does not mark the channel as ready-to-transmit.
+ * The fix seems to be to push the packet to COSA despite its request.
+ * We first try to obey the card's opinion, and then fall back to forced TX.
+ */
+static inline void tx_interrupt(struct cosa_data *cosa, int status)
+{
+	unsigned long flags, flags1;
+#ifdef DEBUG_IRQS
+	printk(KERN_INFO "cosa%d: SR_DOWN_REQUEST status=0x%04x\n",
+		cosa->num, status);
+#endif
+	spin_lock_irqsave(&cosa->lock, flags);
+	set_bit(TXBIT, &cosa->rxtx);
+	if (!test_bit(IRQBIT, &cosa->rxtx)) {
+		/* flow control, see the comment above */
+		int i=0;
+		if (!cosa->txbitmap) {
+			printk(KERN_WARNING "%s: No channel wants data "
+				"in TX IRQ. Expect DMA timeout.",
+				cosa->name);
+			put_driver_status_nolock(cosa);
+			clear_bit(TXBIT, &cosa->rxtx);
+			spin_unlock_irqrestore(&cosa->lock, flags);
+			return;
+		}
+		while(1) {
+			cosa->txchan++;
+			i++;
+			if (cosa->txchan >= cosa->nchannels)
+				cosa->txchan = 0;
+			if (!(cosa->txbitmap & (1<<cosa->txchan)))
+				continue;
+			if (~status & (1 << (cosa->txchan+DRIVER_TXMAP_SHIFT)))
+				break;
+			/* in second pass, accept first ready-to-TX channel */
+			if (i > cosa->nchannels) {
+				/* Can be safely ignored */
+				printk(KERN_DEBUG "%s: Forcing TX "
+					"to not-ready channel %d\n",
+					cosa->name, cosa->txchan);
+				break;
+			}
+		}
+
+		cosa->txsize = cosa->chan[cosa->txchan].txsize;
+		if (cosa_dma_able(cosa->chan+cosa->txchan,
+			cosa->chan[cosa->txchan].txbuf, cosa->txsize)) {
+			cosa->txbuf = cosa->chan[cosa->txchan].txbuf;
+		} else {
+			memcpy(cosa->bouncebuf, cosa->chan[cosa->txchan].txbuf,
+				cosa->txsize);
+			cosa->txbuf = cosa->bouncebuf;
+		}
+	}
+
+	if (is_8bit(cosa)) {
+		if (!test_bit(IRQBIT, &cosa->rxtx)) {
+			cosa_putstatus(cosa, SR_TX_INT_ENA);
+			cosa_putdata8(cosa, ((cosa->txchan << 5) & 0xe0)|
+				((cosa->txsize >> 8) & 0x1f));
+#ifdef DEBUG_IO
+			debug_status_out(cosa, SR_TX_INT_ENA);
+			debug_data_out(cosa, ((cosa->txchan << 5) & 0xe0)|
+                                ((cosa->txsize >> 8) & 0x1f));
+			debug_data_in(cosa, cosa_getdata8(cosa));
+#else
+			cosa_getdata8(cosa);
+#endif
+			set_bit(IRQBIT, &cosa->rxtx);
+			spin_unlock_irqrestore(&cosa->lock, flags);
+			return;
+		} else {
+			clear_bit(IRQBIT, &cosa->rxtx);
+			cosa_putstatus(cosa, 0);
+			cosa_putdata8(cosa, cosa->txsize&0xff);
+#ifdef DEBUG_IO
+			debug_status_out(cosa, 0);
+			debug_data_out(cosa, cosa->txsize&0xff);
+#endif
+		}
+	} else {
+		cosa_putstatus(cosa, SR_TX_INT_ENA);
+		cosa_putdata16(cosa, ((cosa->txchan<<13) & 0xe000)
+			| (cosa->txsize & 0x1fff));
+#ifdef DEBUG_IO
+		debug_status_out(cosa, SR_TX_INT_ENA);
+		debug_data_out(cosa, ((cosa->txchan<<13) & 0xe000)
+                        | (cosa->txsize & 0x1fff));
+		debug_data_in(cosa, cosa_getdata8(cosa));
+		debug_status_out(cosa, 0);
+#else
+		cosa_getdata8(cosa);
+#endif
+		cosa_putstatus(cosa, 0);
+	}
+
+	if (cosa->busmaster) {
+		unsigned long addr = virt_to_bus(cosa->txbuf);
+		int count=0;
+		printk(KERN_INFO "busmaster IRQ\n");
+		while (!(cosa_getstatus(cosa)&SR_TX_RDY)) {
+			count++;
+			udelay(10);
+			if (count > 1000) break;
+		}
+		printk(KERN_INFO "status %x\n", cosa_getstatus(cosa));
+		printk(KERN_INFO "ready after %d loops\n", count);
+		cosa_putdata16(cosa, (addr >> 16)&0xffff);
+
+		count = 0;
+		while (!(cosa_getstatus(cosa)&SR_TX_RDY)) {
+			count++;
+			if (count > 1000) break;
+			udelay(10);
+		}
+		printk(KERN_INFO "ready after %d loops\n", count);
+		cosa_putdata16(cosa, addr &0xffff);
+		flags1 = claim_dma_lock();
+		set_dma_mode(cosa->dma, DMA_MODE_CASCADE);
+		enable_dma(cosa->dma);
+		release_dma_lock(flags1);
+	} else {
+		/* start the DMA */
+		flags1 = claim_dma_lock();
+		disable_dma(cosa->dma);
+		clear_dma_ff(cosa->dma);
+		set_dma_mode(cosa->dma, DMA_MODE_WRITE);
+		set_dma_addr(cosa->dma, virt_to_bus(cosa->txbuf));
+		set_dma_count(cosa->dma, cosa->txsize);
+		enable_dma(cosa->dma);
+		release_dma_lock(flags1);
+	}
+	cosa_putstatus(cosa, SR_TX_DMA_ENA|SR_USR_INT_ENA);
+#ifdef DEBUG_IO
+	debug_status_out(cosa, SR_TX_DMA_ENA|SR_USR_INT_ENA);
+#endif
+	spin_unlock_irqrestore(&cosa->lock, flags);
+}
+
+static inline void rx_interrupt(struct cosa_data *cosa, int status)
+{
+	unsigned long flags;
+#ifdef DEBUG_IRQS
+	printk(KERN_INFO "cosa%d: SR_UP_REQUEST\n", cosa->num);
+#endif
+
+	spin_lock_irqsave(&cosa->lock, flags);
+	set_bit(RXBIT, &cosa->rxtx);
+
+	if (is_8bit(cosa)) {
+		if (!test_bit(IRQBIT, &cosa->rxtx)) {
+			set_bit(IRQBIT, &cosa->rxtx);
+			put_driver_status_nolock(cosa);
+			cosa->rxsize = cosa_getdata8(cosa) <<8;
+#ifdef DEBUG_IO
+			debug_data_in(cosa, cosa->rxsize >> 8);
+#endif
+			spin_unlock_irqrestore(&cosa->lock, flags);
+			return;
+		} else {
+			clear_bit(IRQBIT, &cosa->rxtx);
+			cosa->rxsize |= cosa_getdata8(cosa) & 0xff;
+#ifdef DEBUG_IO
+			debug_data_in(cosa, cosa->rxsize & 0xff);
+#endif
+#if 0
+			printk(KERN_INFO "cosa%d: receive rxsize = (0x%04x).\n",
+				cosa->num, cosa->rxsize);
+#endif
+		}
+	} else {
+		cosa->rxsize = cosa_getdata16(cosa);
+#ifdef DEBUG_IO
+		debug_data_in(cosa, cosa->rxsize);
+#endif
+#if 0
+		printk(KERN_INFO "cosa%d: receive rxsize = (0x%04x).\n",
+			cosa->num, cosa->rxsize);
+#endif
+	}
+	if (((cosa->rxsize & 0xe000) >> 13) >= cosa->nchannels) {
+		printk(KERN_WARNING "%s: rx for unknown channel (0x%04x)\n",
+			cosa->name, cosa->rxsize);
+		spin_unlock_irqrestore(&cosa->lock, flags);
+		goto reject;
+	}
+	cosa->rxchan = cosa->chan + ((cosa->rxsize & 0xe000) >> 13);
+	cosa->rxsize &= 0x1fff;
+	spin_unlock_irqrestore(&cosa->lock, flags);
+
+	cosa->rxbuf = NULL;
+	if (cosa->rxchan->setup_rx)
+		cosa->rxbuf = cosa->rxchan->setup_rx(cosa->rxchan, cosa->rxsize);
+
+	if (!cosa->rxbuf) {
+reject:		/* Reject the packet */
+		printk(KERN_INFO "cosa%d: rejecting packet on channel %d\n",
+			cosa->num, cosa->rxchan->num);
+		cosa->rxbuf = cosa->bouncebuf;
+	}
+
+	/* start the DMA */
+	flags = claim_dma_lock();
+	disable_dma(cosa->dma);
+	clear_dma_ff(cosa->dma);
+	set_dma_mode(cosa->dma, DMA_MODE_READ);
+	if (cosa_dma_able(cosa->rxchan, cosa->rxbuf, cosa->rxsize & 0x1fff)) {
+		set_dma_addr(cosa->dma, virt_to_bus(cosa->rxbuf));
+	} else {
+		set_dma_addr(cosa->dma, virt_to_bus(cosa->bouncebuf));
+	}
+	set_dma_count(cosa->dma, (cosa->rxsize&0x1fff));
+	enable_dma(cosa->dma);
+	release_dma_lock(flags);
+	spin_lock_irqsave(&cosa->lock, flags);
+	cosa_putstatus(cosa, SR_RX_DMA_ENA|SR_USR_INT_ENA);
+	if (!is_8bit(cosa) && (status & SR_TX_RDY))
+		cosa_putdata8(cosa, DRIVER_RX_READY);
+#ifdef DEBUG_IO
+	debug_status_out(cosa, SR_RX_DMA_ENA|SR_USR_INT_ENA);
+	if (!is_8bit(cosa) && (status & SR_TX_RDY))
+		debug_data_cmd(cosa, DRIVER_RX_READY);
+#endif
+	spin_unlock_irqrestore(&cosa->lock, flags);
+}
+
+static void inline eot_interrupt(struct cosa_data *cosa, int status)
+{
+	unsigned long flags, flags1;
+	spin_lock_irqsave(&cosa->lock, flags);
+	flags1 = claim_dma_lock();
+	disable_dma(cosa->dma);
+	clear_dma_ff(cosa->dma);
+	release_dma_lock(flags1);
+	if (test_bit(TXBIT, &cosa->rxtx)) {
+		struct channel_data *chan = cosa->chan+cosa->txchan;
+		if (chan->tx_done)
+			if (chan->tx_done(chan, cosa->txsize))
+				clear_bit(chan->num, &cosa->txbitmap);
+	} else if (test_bit(RXBIT, &cosa->rxtx)) {
+#ifdef DEBUG_DATA
+	{
+		int i;
+		printk(KERN_INFO "cosa%dc%d: done rx(0x%x)", cosa->num, 
+			cosa->rxchan->num, cosa->rxsize);
+		for (i=0; i<cosa->rxsize; i++)
+			printk (" %02x", cosa->rxbuf[i]&0xff);
+		printk("\n");
+	}
+#endif
+		/* Packet for unknown channel? */
+		if (cosa->rxbuf == cosa->bouncebuf)
+			goto out;
+		if (!cosa_dma_able(cosa->rxchan, cosa->rxbuf, cosa->rxsize))
+			memcpy(cosa->rxbuf, cosa->bouncebuf, cosa->rxsize);
+		if (cosa->rxchan->rx_done)
+			if (cosa->rxchan->rx_done(cosa->rxchan))
+				clear_bit(cosa->rxchan->num, &cosa->rxbitmap);
+	} else {
+		printk(KERN_NOTICE "cosa%d: unexpected EOT interrupt\n",
+			cosa->num);
+	}
+	/*
+	 * Clear the RXBIT, TXBIT and IRQBIT (the latest should be
+	 * cleared anyway). We should do it as soon as possible
+	 * so that we can tell the COSA we are done and to give it a time
+	 * for recovery.
+	 */
+out:
+	cosa->rxtx = 0;
+	put_driver_status_nolock(cosa);
+	spin_unlock_irqrestore(&cosa->lock, flags);
+}
+
+static void cosa_interrupt(int irq, void *cosa_, struct pt_regs *regs)
+{
+	unsigned status;
+	int count = 0;
+	struct cosa_data *cosa = cosa_;
+again:
+	status = cosa_getstatus(cosa);
+#ifdef DEBUG_IRQS
+	printk(KERN_INFO "cosa%d: got IRQ, status 0x%02x\n", cosa->num,
+		status & 0xff);
+#endif
+#ifdef DEBUG_IO
+	debug_status_in(cosa, status);
+#endif
+	switch (status & SR_CMD_FROM_SRP_MASK) {
+	case SR_DOWN_REQUEST:
+		tx_interrupt(cosa, status);
+		break;
+	case SR_UP_REQUEST:
+		rx_interrupt(cosa, status);
+		break;
+	case SR_END_OF_TRANSFER:
+		eot_interrupt(cosa, status);
+		break;
+	default:
+		/* We may be too fast for SRP. Try to wait a bit more. */
+		if (count++ < 100) {
+			udelay(100);
+			goto again;
+		}
+		printk(KERN_INFO "cosa%d: unknown status 0x%02x in IRQ after %d retries\n",
+			cosa->num, status & 0xff, count);
+	}
+#ifdef DEBUG_IRQS
+	if (count)
+		printk(KERN_INFO "%s: %d-times got unknown status in IRQ\n",
+			cosa->name, count);
+	else
+		printk(KERN_INFO "%s: returning from IRQ\n", cosa->name);
+#endif
+}
+
+
+/* ---------- I/O debugging routines ---------- */
+/*
+ * These routines can be used to monitor COSA/SRP I/O and to printk()
+ * the data being transfered on the data and status I/O port in a
+ * readable way.
+ */
+
+#ifdef DEBUG_IO
+static void debug_status_in(struct cosa_data *cosa, int status)
+{
+	char *s;
+	switch(status & SR_CMD_FROM_SRP_MASK) {
+	case SR_UP_REQUEST:
+		s = "RX_REQ";
+		break;
+	case SR_DOWN_REQUEST:
+		s = "TX_REQ";
+		break;
+	case SR_END_OF_TRANSFER:
+		s = "ET_REQ";
+		break;
+	default:
+		s = "NO_REQ";
+		break;
+	}
+	printk(KERN_INFO "%s: IO: status -> 0x%02x (%s%s%s%s)\n",
+		cosa->name,
+		status,
+		status & SR_USR_RQ ? "USR_RQ|":"",
+		status & SR_TX_RDY ? "TX_RDY|":"",
+		status & SR_RX_RDY ? "RX_RDY|":"",
+		s);
+}
+
+static void debug_status_out(struct cosa_data *cosa, int status)
+{
+	printk(KERN_INFO "%s: IO: status <- 0x%02x (%s%s%s%s%s%s)\n",
+		cosa->name,
+		status,
+		status & SR_RX_DMA_ENA  ? "RXDMA|":"!rxdma|",
+		status & SR_TX_DMA_ENA  ? "TXDMA|":"!txdma|",
+		status & SR_RST         ? "RESET|":"",
+		status & SR_USR_INT_ENA ? "USRINT|":"!usrint|",
+		status & SR_TX_INT_ENA  ? "TXINT|":"!txint|",
+		status & SR_RX_INT_ENA  ? "RXINT":"!rxint");
+}
+
+static void debug_data_in(struct cosa_data *cosa, int data)
+{
+	printk(KERN_INFO "%s: IO: data -> 0x%04x\n", cosa->name, data);
+}
+
+static void debug_data_out(struct cosa_data *cosa, int data)
+{
+	printk(KERN_INFO "%s: IO: data <- 0x%04x\n", cosa->name, data);
+}
+
+static void debug_data_cmd(struct cosa_data *cosa, int data)
+{
+	printk(KERN_INFO "%s: IO: data <- 0x%04x (%s|%s)\n",
+		cosa->name, data,
+		data & SR_RDY_RCV ? "RX_RDY" : "!rx_rdy",
+		data & SR_RDY_SND ? "TX_RDY" : "!tx_rdy");
+}
+#endif
+
+/* EOF -- this file has not been truncated */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/cosa.h linux/drivers/net/wan/cosa.h
--- v2.3.20/linux/drivers/net/wan/cosa.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/cosa.h	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,111 @@
+/* $Id: cosa.h,v 1.6 1999/01/06 14:02:44 kas Exp $ */
+
+/*
+ *  Copyright (C) 1995-1997  Jan "Yenya" Kasprzak <kas@fi.muni.cz>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef COSA_H__
+#define COSA_H__
+
+#include <linux/ioctl.h>
+
+#ifdef __KERNEL__
+/* status register - output bits */
+#define SR_RX_DMA_ENA   0x04    /* receiver DMA enable bit */
+#define SR_TX_DMA_ENA   0x08    /* transmitter DMA enable bit */
+#define SR_RST          0x10    /* SRP reset */
+#define SR_USR_INT_ENA  0x20    /* user interrupt enable bit */
+#define SR_TX_INT_ENA   0x40    /* transmitter interrupt enable bit */
+#define SR_RX_INT_ENA   0x80    /* receiver interrupt enable bit */
+
+/* status register - input bits */
+#define SR_USR_RQ       0x20    /* user interupt request pending */
+#define SR_TX_RDY       0x40    /* transmitter empty (ready) */
+#define SR_RX_RDY       0x80    /* receiver data ready */
+
+#define SR_UP_REQUEST   0x02    /* request from SRP to transfer data
+                                   up to PC */
+#define SR_DOWN_REQUEST 0x01    /* SRP is able to transfer data down
+                                   from PC to SRP */
+#define SR_END_OF_TRANSFER      0x03    /* SRP signalize end of
+                                           transfer (up or down) */
+
+#define SR_CMD_FROM_SRP_MASK    0x03    /* mask to get SRP command */
+
+/* bits in driver status byte definitions : */
+#define SR_RDY_RCV      0x01    /* ready to receive packet */
+#define SR_RDY_SND      0x02    /* ready to send packet */
+#define SR_CMD_PND      0x04    /* command pending */ /* not currently used */
+
+/* ???? */
+#define SR_PKT_UP       0x01    /* transfer of packet up in progress */
+#define SR_PKT_DOWN     0x02    /* transfer of packet down in progress */
+
+#endif /* __KERNEL__ */
+
+#define SR_LOAD_ADDR    0x4400  /* SRP microcode load address */
+#define SR_START_ADDR   0x4400  /* SRP microcode start address */
+
+#define COSA_LOAD_ADDR    0x400  /* SRP microcode load address */
+#define COSA_MAX_FIRMWARE_SIZE	0x10000
+
+/* ioctls */
+struct cosa_download {
+	int addr, len;
+	char *code;
+};
+
+/* Reset the device */
+#define COSAIORSET	_IO('C',0xf0)
+
+/* Start microcode at given address */
+#define COSAIOSTRT	_IOW('C',0xf1,sizeof(int))
+
+/* Read the block from the device memory */
+#define COSAIORMEM	_IOR('C',0xf2,sizeof(struct cosa_download *))
+
+/* Write the block to the device memory (i.e. download the microcode) */
+#define COSAIODOWNLD	_IOW('C',0xf2,sizeof(struct cosa_download *))
+
+/* Read the device type (one of "srp", "cosa", and "cosa8" for now) */
+#define COSAIORTYPE	_IOR('C',0xf3,sizeof(char *))
+
+/* Read the device identification string */
+#define COSAIORIDSTR	_IOR('C',0xf4,sizeof(char *))
+/* Maximum length of the identification string. */
+#define COSA_MAX_ID_STRING 128
+
+/* Increment/decrement the module usage count :-) */
+/* #define COSAIOMINC	_IO('C',0xf5) */
+/* #define COSAIOMDEC	_IO('C',0xf6) */
+
+/* Get the total number of cards installed */
+#define COSAIONRCARDS	_IO('C',0xf7)
+
+/* Get the number of channels on this card */
+#define COSAIONRCHANS	_IO('C',0xf8)
+
+/* Set the driver for the bus-master operations */
+#define COSAIOBMSET	_IOW('C', 0xf9, sizeof(unsigned short))
+
+#define COSA_BM_OFF	0	/* Bus-mastering off - use ISA DMA (default) */
+#define COSA_BM_ON	1	/* Bus-mastering on - faster but untested */
+
+/* Gets the busmaster status */
+#define COSAIOBMGET	_IO('C', 0xfa)
+
+#endif /* !COSA_H__ */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/cycx_drv.c linux/drivers/net/wan/cycx_drv.c
--- v2.3.20/linux/drivers/net/wan/cycx_drv.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/cycx_drv.c	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,660 @@
+/*
+* cycx_drv.c	cycx Support Module.
+*
+*		This module is a library of common hardware-specific
+*		functions used by all Cyclades sync and some async (8x & 16x)
+*		drivers.
+*
+* Copyright:	(c) 1998, 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+*
+* Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+*
+* Based on sdladrv.c by Gene Kozin <genek@compuserve.com>
+*
+*		This program is free software; you can redistribute it and/or
+*		modify it under the terms of the GNU General Public License
+*		as published by the Free Software Foundation; either version
+*		2 of the License, or (at your option) any later version.
+* ============================================================================
+* 1999/05/28    acme		cycx_intack & cycx_intde gone for good
+* 1999/05/18	acme		lots of unlogged work, submitting to Linus...
+* 1999/01/03	acme		more judicious use of data types
+* 1999/01/03	acme		judicious use of data types :>
+*				cycx_inten trying to reset pending interrupts
+*				from cyclom 2x - I think this isn't the way to
+*				go, but for now...
+* 1999/01/02	acme		cycx_intack ok, I think there's nothing to do
+*				to ack an int in cycx_drv.c, only handle it in
+*				cyx_isr (or in the other protocols: cyp_isr,
+*				cyf_isr, when they get implemented.
+* Dec 31, 1998	Arnaldo         cycx_data_boot & cycx_code_boot fixed, crossing
+*				fingers to see x25_configure in cycx_x25.c
+*				work... :)
+* Dec 26, 1998	Arnaldo         load implementation fixed, seems to work! :)
+*				cycx_2x_dpmbase_options with all the possible
+*				DPM addresses (20).
+*				cycx_intr implemented (test this!)
+*				general code cleanup
+* Dec  8, 1998	Ivan Passos	Cyclom-2X firmware load implementation.
+* Aug  8, 1998	Arnaldo		Initial version.
+*/
+
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#else
+#define EXPORT_SYMBOL(function)
+#endif
+#include <linux/kernel.h>	/* printk(), and other useful stuff */
+#include <linux/stddef.h>	/* offsetof(), etc. */
+#include <linux/errno.h>	/* return codes */
+#include <linux/sched.h>	/* for jiffies, HZ, etc. */
+#include <linux/cycx_drv.h>	/* API definitions */
+#include <linux/cycx_cfm.h>	/* CYCX firmware module definitions */
+#include <linux/delay.h>	/* udelay */
+#include <asm/io.h>		/* for inb(), outb(), etc. */
+
+#define	MOD_VERSION	0
+#define	MOD_RELEASE	2
+
+#ifdef MODULE
+MODULE_AUTHOR("Arnaldo Carvalho de Melo");
+MODULE_DESCRIPTION("Cyclades Sync Cards Driver.");
+#endif
+
+/* Function Prototypes */
+/* Module entry points. These are called by the OS and must be public. */
+int init_module (void);
+void cleanup_module (void);
+
+/* Hardware-specific functions */
+static int cycx_detect (cycxhw_t *hw);
+static int cycx_load (cycxhw_t *hw, cfm_t *cfm, u32 len);
+static int cycx_init (cycxhw_t *hw);
+static int cycx_reset (cycxhw_t *hw);
+static void cycx_bootcfg (cycxhw_t *hw);
+
+static int init_cycx_2x (cycxhw_t *hw);
+static int reset_cycx_2x (u32 addr);
+static int detect_cycx_2x (u32 addr);
+
+/* Miscellaneous functions */
+static void delay_cycx (int sec);
+static int get_option_index (u32 *optlist, u32 optval);
+static u16 checksum (u8 *buf, u32 len);
+
+#define wait_cyc(addr) cycx_exec(addr + CMD_OFFSET)
+
+/* Global Data
+ * Note: All data must be explicitly initialized!!! */
+
+/* private data */
+static char modname[] = "cycx_drv";
+static char fullname[] = "Cyclom X Support Module";
+static char copyright[]	= "(c) 1998, 1999 Arnaldo Carvalho de Melo";
+
+/* Hardware configuration options.
+ * These are arrays of configuration options used by verification routines.
+ * The first element of each array is its size (i.e. number of options).
+ */
+static u32 cycx_2x_dpmbase_options[] =
+{
+	20,
+	0xA0000, 0xA4000, 0xA8000, 0xAC000, 0xB0000, 0xB4000, 0xB8000,
+	0xBC000, 0xC0000, 0xC4000, 0xC8000, 0xCC000, 0xD0000, 0xD4000,
+	0xD8000, 0xDC000, 0xE0000, 0xE4000, 0xE8000, 0xEC000
+};
+
+static u32 cycx_2x_irq_options[]  = { 7, 3, 5, 9, 10, 11, 12, 15 };
+
+/* Kernel Loadable Module Entry Points */
+/* Module 'insert' entry point.
+ * o print announcement
+ * o initialize static data
+ *
+ * Return:	0	Ok
+ *		< 0	error.
+ * Context:	process */
+#ifdef MODULE
+int init_module (void)
+{
+	printk(KERN_INFO "%s v%u.%u %s\n",
+		fullname, MOD_VERSION, MOD_RELEASE, copyright);
+	return 0;
+}
+/* Module 'remove' entry point.
+ * o release all remaining system resources */
+void cleanup_module (void)
+{
+}
+#endif
+/* Kernel APIs */
+/* Set up adapter.
+ * o detect adapter type
+ * o verify hardware configuration options
+ * o check for hardware conflicts
+ * o set up adapter shared memory
+ * o test adapter memory
+ * o load firmware
+ * Return:	0	ok.
+ *		< 0	error */
+EXPORT_SYMBOL(cycx_setup);
+int cycx_setup (cycxhw_t *hw, void *cfm, u32 len)
+{
+	u32 *irq_opt = NULL;	/* IRQ options */
+	u32 *dpmbase_opt = NULL;/* DPM window base options */
+	int err = 0;
+
+	if (cycx_detect(hw)) {
+		printk(KERN_ERR "%s: adapter Cyclom %uX not found at "
+				"address 0x%lX!\n",
+			modname, hw->type, (unsigned long) hw->dpmbase);
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO "%s: found Cyclom %uX card at address 0x%lx.\n",
+			 modname, hw->type, (unsigned long) hw->dpmbase);
+
+	switch (hw->type) {
+		case CYCX_2X:
+			irq_opt	= cycx_2x_irq_options;
+			dpmbase_opt = cycx_2x_dpmbase_options;
+			break;
+		default:
+			printk(KERN_ERR "%s: unknown card.\n", modname);
+			return -EINVAL;
+	}
+
+	/* Verify IRQ configuration options */
+	if (!get_option_index(irq_opt, hw->irq)) {
+		printk (KERN_ERR "%s: IRQ %d is illegal!\n", modname, hw->irq);
+		return -EINVAL;
+	} 
+
+	/* Setup adapter dual-port memory window and test memory */
+	if (!hw->dpmbase) {
+		printk(KERN_ERR "%s: you must specify the dpm address!\n",
+				modname);
+ 		return -EINVAL;
+	}
+	else if (!get_option_index(dpmbase_opt, hw->dpmbase)) {
+		printk(KERN_ERR "%s: memory address 0x%lX is illegal!\n",
+				modname, (unsigned long) hw->dpmbase);
+		return -EINVAL;
+	}
+
+	hw->dpmsize = CYCX_WINDOWSIZE;
+	/* FIXME! Is this the only amount ever available? */
+	hw->memory = 0x40000;
+
+	cycx_init(hw);
+
+	printk(KERN_INFO "%s: dual-port memory window is set at 0x%lX.\n",
+			 modname, (unsigned long) hw->dpmbase);
+	printk(KERN_INFO "%s: found %luK bytes of on-board memory.\n",
+			 modname, (unsigned long) hw->memory / 1024);
+
+	/* Load firmware. If loader fails then shut down adapter */
+	err = cycx_load(hw, cfm, len);
+	if (err) cycx_down(hw);		/* shutdown adapter */
+	return err;
+} 
+
+/* Shut down CYCX: disable shared memory access and interrupts, stop CPU,etc.*/ 
+EXPORT_SYMBOL(cycx_down);
+int cycx_down (cycxhw_t *hw)
+{
+	return 0; /* FIXME: anything needed here? */
+}
+
+/* Enable interrupt generation.  */
+EXPORT_SYMBOL(cycx_inten);
+int cycx_inten (cycxhw_t *hw)
+{
+	switch (hw->type) {
+		case CYCX_2X: writeb (0, hw->dpmbase); break;
+		default: return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Generate an interrupt to adapter's CPU. */
+EXPORT_SYMBOL(cycx_intr);
+int cycx_intr (cycxhw_t *hw)
+{
+	switch (hw->type) {
+		case CYCX_2X:
+			writew(0, hw->dpmbase + GEN_CYCX_INTR);
+			return 0;
+		default: return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Execute Adapter Command.
+ * o Set exec flag.
+ * o Busy-wait until flag is reset. */
+EXPORT_SYMBOL(cycx_exec);
+int cycx_exec (u32 addr)
+{
+	u16 i = 0;
+	/* wait till addr content is zeroed */
+
+	while (readw(addr) != 0) {
+		udelay(1000);
+		if (++i > 50) return -1;
+	}
+
+	return 0;
+}
+
+/* Read absolute adapter memory.
+ * Transfer data from adapter's memory to data buffer. */
+EXPORT_SYMBOL(cycx_peek);
+int cycx_peek (cycxhw_t *hw, u32 addr, void *buf, u32 len)
+{
+	if (len == 1)	*(u8*)buf = readb (hw->dpmbase + addr);
+	else 		memcpy_fromio(buf, hw->dpmbase + addr, len);
+
+	return 0;
+}
+
+/* Write Absolute Adapter Memory.
+ * Transfer data from data buffer to adapter's memory. */
+EXPORT_SYMBOL(cycx_poke);
+int cycx_poke (cycxhw_t *hw, u32 addr, void *buf, u32 len)
+{
+	if (len == 1) writeb (*(u8*)buf, hw->dpmbase + addr);
+	else	      memcpy_toio(hw->dpmbase + addr, buf, len);
+
+	return 0;
+}
+
+/* Hardware-Specific Functions */
+/* Detect adapter type.
+ * o if adapter type is specified then call detection routine for that adapter
+ *   type.  Otherwise call detection routines for every adapter types until
+ *   adapter is detected.
+ *
+ * Notes:
+ * 1) Detection tests are destructive! Adapter will be left in shutdown state
+ *    after the test. */
+static int cycx_detect (cycxhw_t *hw)
+{
+	int err = 0;
+
+	if (!hw->dpmbase) return -EFAULT;
+
+	switch (hw->type) {
+		case CYCX_2X:
+			if (!detect_cycx_2x(hw->dpmbase)) err = -ENODEV;
+			break;
+		default:
+			if (detect_cycx_2x(hw->dpmbase)) hw->type = CYCX_2X;
+			else err = -ENODEV;
+	}
+
+	return err;
+}
+
+/* Load Aux Routines */
+/* Reset board hardware.
+   return 1 if memory exists at addr and 0 if not. */
+static int memory_exists(u32 addr)
+{
+	int timeout = 0;
+
+	for (; timeout < 3 ; timeout++) {
+		writew (TEST_PATTERN, addr + 0x10);
+
+		if (readw (addr + 0x10) == TEST_PATTERN)
+			if (readw (addr + 0x10) == TEST_PATTERN) return 1;
+
+		delay_cycx(1);
+	}
+
+	return 0;
+}
+
+/* Reset board hardware. */
+static int cycx_reset(cycxhw_t *hw)
+{
+	/* Reset board */
+	switch (hw->type) {
+		case CYCX_2X: return reset_cycx_2x(hw->dpmbase);
+	}
+
+	return -EINVAL;
+}
+
+/* Load reset code. */
+static void reset_load(u32 addr, u8 *buffer, u32 cnt)
+{
+	u32 pt_code = addr + RESET_OFFSET;
+	u16 i, j;
+
+	for ( i = 0 ; i < cnt ; i++) {
+		for (j = 0 ; j < 50 ; j++); /* Delay - FIXME busy waiting... */
+		writeb(*buffer++, pt_code++);
+	}
+}
+
+/* Load buffer using boot interface.
+ * o copy data from buffer to Cyclom-X memory
+ * o wait for reset code to copy it to right portion of memory */
+static int buffer_load(u32 addr, u8 *buffer, u32 cnt)
+{
+	memcpy_toio(addr + DATA_OFFSET, buffer, cnt);
+	writew(GEN_BOOT_DAT, addr + CMD_OFFSET);
+	return wait_cyc(addr);
+}
+
+/* Set up entry point and kick start Cyclom-X CPU. */
+static void cycx_start (u32 addr)
+{
+	/* put in 0x30 offset the jump instruction to the code entry point */
+	writeb(0xea, addr + 0x30);
+	writeb(0x00, addr + 0x31);
+	writeb(0xc4, addr + 0x32);
+	writeb(0x00, addr + 0x33);
+	writeb(0x00, addr + 0x34);
+
+	/* cmd to start executing code */
+	writew(GEN_START, addr + CMD_OFFSET);
+}         
+
+/* Load and boot reset code. */
+static void cycx_reset_boot(u32 addr, u8 *code, u32 len)
+{
+	u32 pt_start = addr + START_OFFSET;
+
+        writeb(0xea, pt_start++); /* jmp to f000:3f00 */
+        writeb(0x00, pt_start++);
+        writeb(0xfc, pt_start++);
+        writeb(0x00, pt_start++);
+        writeb(0xf0, pt_start);
+	reset_load(addr, code, len);
+
+	/* 80186 was in hold, go */
+	writeb(0, addr + START_CPU);
+	delay_cycx(1);
+}
+
+/* Load data.bin file through boot (reset) interface. */
+static int cycx_data_boot(u32 addr, u8 *code, u32 len)
+{
+	u32 pt_boot_cmd = addr + CMD_OFFSET;
+	u32 i;
+
+	/* boot buffer lenght */
+	writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16));
+	writew(GEN_DEFPAR, pt_boot_cmd);
+
+	if (wait_cyc(addr) < 0) return 2;
+
+	writew(0, pt_boot_cmd + sizeof(u16));
+	writew(0x4000, pt_boot_cmd + 2 * sizeof(u16));
+	writew(GEN_SET_SEG, pt_boot_cmd);
+
+	if (wait_cyc(addr) < 0) return 2;
+
+	for (i = 0 ; i < len ; i += CFM_LOAD_BUFSZ)
+		if (buffer_load(addr, code + i,
+				MIN(CFM_LOAD_BUFSZ, (len - i))) < 0) {
+			printk(KERN_ERR "%s: Error !!\n", modname);
+			return 4;
+		}
+
+	return 0;
+}
+
+
+/* Load code.bin file through boot (reset) interface. */
+static int cycx_code_boot(u32 addr, u8 *code, u32 len)
+{
+	u32 pt_boot_cmd = addr + CMD_OFFSET;
+	u32 i;
+
+	/* boot buffer lenght */
+	writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16));
+	writew(GEN_DEFPAR, pt_boot_cmd);
+
+	if (wait_cyc(addr) == -1) return 2;
+
+	writew(0x0000, pt_boot_cmd + sizeof(u16));
+	writew(0xc400, pt_boot_cmd + 2 * sizeof(u16));
+	writew(GEN_SET_SEG, pt_boot_cmd);
+
+	if (wait_cyc(addr) == -1) return 1;
+
+	for (i = 0 ; i < len ; i += CFM_LOAD_BUFSZ)
+		if (buffer_load(addr, code + i,MIN(CFM_LOAD_BUFSZ,(len - i)))) {
+			printk(KERN_ERR "%s: Error !!\n", modname);
+			return 4;
+		}
+
+	return 0;
+}
+
+/* Initialize CYCX hardware: setup memory window, IRQ, etc. */
+static int cycx_init (cycxhw_t *hw)
+{
+	switch (hw->type) {
+		case CYCX_2X: return init_cycx_2x(hw);
+	}
+
+	return -EINVAL;
+}
+
+/* Load adapter from the memory image of the CYCX firmware module. 
+ * o verify firmware integrity and compatibility
+ * o start adapter up */
+static int cycx_load (cycxhw_t *hw, cfm_t *cfm, u32 len)
+{
+	int i, j, status;
+	cycx_header_t *img_hdr;
+	u8 *reset_image,
+	   *data_image,
+	   *code_image;
+	u32 pt_cycld = hw->dpmbase + 0x400;
+	u16 cksum;
+
+	/* Announce */
+	printk(KERN_INFO "%s: firmware signature=\"%s\"\n",
+			 modname, cfm->signature); 
+
+	/* Verify firmware signature */
+	if (strcmp(cfm->signature, CFM_SIGNATURE)) {
+		printk(KERN_ERR "%s:cycx_load: not Cyclom-2X firmware!\n",
+				modname);
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO "%s: firmware version=%u\n", modname, cfm->version);
+
+	/* Verify firmware module format version */
+	if (cfm->version != CFM_VERSION) {
+		printk(KERN_ERR "%s:cycx_load: firmware format %u rejected! "
+				"Expecting %u.\n",
+				modname, cfm->version, CFM_VERSION);
+		return -EINVAL;
+	}
+
+	/* Verify firmware module length and checksum */
+	cksum = checksum((u8*)&cfm->info, sizeof(cfm_info_t) +
+					      cfm->info.codesize);
+/*
+        FIXME cfm->info.codesize is off by 2
+	if (((len - sizeof(cfm_t) - 1) != cfm->info.codesize) ||
+*/
+	if (cksum != cfm->checksum) {
+		printk(KERN_ERR "%s:cycx_load: firmware corrupted!\n", modname);
+		printk(KERN_ERR " cdsize = 0x%x (expected 0x%lx)\n",
+                       len - sizeof(cfm_t) - 1, cfm->info.codesize);
+                printk(KERN_ERR " chksum = 0x%x (expected 0x%x)\n",
+                       cksum, cfm->checksum);
+		return -EINVAL;
+	}
+
+	/* If everything is ok, set reset, data and code pointers */
+
+	img_hdr = (cycx_header_t*)(((u8*) cfm) + sizeof(cfm_t) - 1);
+#ifdef FIRMWARE_DEBUG
+	printk(KERN_INFO "%s:cycx_load: image sizes\n", modname);
+	printk(KERN_INFO " reset=%lu\n", img_hdr->reset_size);
+	printk(KERN_INFO "  data=%lu\n", img_hdr->data_size);
+	printk(KERN_INFO "  code=%lu\n", img_hdr->code_size);
+#endif
+	reset_image = ((u8 *) img_hdr) + sizeof(cycx_header_t);
+	data_image = reset_image + img_hdr->reset_size;
+	code_image = data_image + img_hdr->data_size;
+
+	/*---- Start load ----*/
+        /* Announce */
+	printk(KERN_INFO "%s: loading firmware %s (ID=%u)...\n", modname,
+		(cfm->descr[0] != '\0') ? cfm->descr : "unknown firmware",
+		cfm->info.codeid);
+
+	for (i = 0 ; i < 5 ; i++) {
+		/* Reset Cyclom hardware */
+		if ((status = cycx_reset(hw)) != 0) {
+			printk(KERN_ERR "%s: dpm problem or board not "
+					"found (%d).\n", modname, status);
+			return -EINVAL;
+		}
+
+		/* Load reset.bin */
+                cycx_reset_boot(hw->dpmbase, reset_image, img_hdr->reset_size);
+		/* reset is waiting for boot */
+		writew(GEN_POWER_ON, pt_cycld);
+		delay_cycx(1);
+
+		for (j = 0 ; j < 3 ; j++)
+			if (!readw(pt_cycld)) goto reset_loaded;
+			else delay_cycx(1);
+	}
+
+	printk(KERN_ERR "%s: reset not started.\n", modname);
+	return -EINVAL;
+reset_loaded:
+	/* Load data.bin */
+	if((status = cycx_data_boot(hw->dpmbase, data_image, 
+		                    img_hdr->data_size)) != 0) {
+		printk(KERN_ERR "%s: cannot load data file (%d).\n",
+				modname, status);
+		return -EINVAL;
+	}
+
+	/* Load code.bin */
+	if((status = cycx_code_boot(hw->dpmbase, code_image, 
+		                    img_hdr->code_size)) != 0) {
+		printk(KERN_ERR "%s: cannot load code file (%d).\n",
+				modname, status);
+		return -EINVAL;
+	}
+
+	/* Prepare boot-time configuration data */
+	cycx_bootcfg(hw);
+
+	/* kick-off CPU */
+	cycx_start(hw->dpmbase);
+
+	/* Arthur Ganzert's tip: wait a while after the firmware loading...
+	   seg abr 26 17:17:12 EST 1999 - acme */
+	delay_cycx(7);
+	printk(KERN_INFO "%s: firmware loaded!\n", modname);
+
+	/* enable interrupts */
+        if (cycx_inten(hw)) {
+		printk(KERN_ERR "%s: adapter hardware failure!\n", modname);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/* Prepare boot-time firmware configuration data.
+ * o initialize configuration data area
+   From async.doc - V_3.4.0 - 07/18/1994
+   - As of now, only static buffers are available to the user.
+     So, the bit VD_RXDIRC must be set in 'valid'. That means that user
+     wants to use the static transmission and reception buffers. */
+static void cycx_bootcfg (cycxhw_t *hw)
+{
+	/* use fixed buffers */
+	writeb(FIXED_BUFFERS, hw->dpmbase + CONF_OFFSET); 
+}
+
+/* Initialize CYCX_2X adapter. */
+static int init_cycx_2x (cycxhw_t *hw)
+{
+	if (!detect_cycx_2x(hw->dpmbase)) return -ENODEV;
+	return 0;
+}
+
+/* Detect Cyclom 2x adapter.
+ *	Following tests are used to detect Cyclom 2x adapter:
+ *       to be completed based on the tests done below
+ *	Return 1 if detected o.k. or 0 if failed.
+ *	Note:	This test is destructive! Adapter will be left in shutdown
+ *		state after the test. */
+static int detect_cycx_2x (u32 addr)
+{
+	printk(KERN_INFO "%s: looking for a cyclom 2x at 0x%lX...\n",
+			 modname, (unsigned long) addr);
+
+	reset_cycx_2x(addr);
+	return memory_exists(addr);
+}
+
+/* Miscellaneous */
+/* Get option's index into the options list.
+ *	Return option's index (1 .. N) or zero if option is invalid. */
+static int get_option_index (u32 *optlist, u32 optval)
+{
+	int i = 1;
+	for (; i <= optlist[0]; ++i) if (optlist[i] == optval) return i;
+	return 0;
+}
+
+/* Reset adapter's CPU. */
+static int reset_cycx_2x (u32 addr)
+{
+	writeb (0, addr + RST_ENABLE);  delay_cycx (2);
+	writeb (0, addr + RST_DISABLE); delay_cycx (2);
+	return memory_exists(addr) ? 0 : 1;
+}
+
+/* Delay */
+static void delay_cycx (int sec)
+{
+/* acme
+   Thu dez 31 21:45:16 EDT 1998
+   FIXME I'll keep this comment here just in case, as of now I don't
+   know it all the contexts where this routine is used are interruptible... */
+
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(sec*HZ);
+}
+
+/* Calculate 16-bit CRC using CCITT polynomial. */
+static u16 checksum (u8 *buf, u32 len)
+{
+	u16 crc = 0;
+	u16 mask, flag;
+
+	for (; len; --len, ++buf)
+		for (mask = 0x80; mask; mask >>= 1) {
+			flag = (crc & 0x8000);
+			crc <<= 1;
+			crc |= ((*buf & mask) ? 1 : 0);
+			if (flag) crc ^= 0x1021;
+		}
+
+	return crc;
+}
+/* End */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/cycx_main.c linux/drivers/net/wan/cycx_main.c
--- v2.3.20/linux/drivers/net/wan/cycx_main.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/cycx_main.c	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,379 @@
+/*
+* cycx_main.c	Cyclades Cyclom X Multiprotocol WAN Link Driver. Main module.
+*
+* Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+*
+* Copyright:	(c) 1998, 1999 Arnaldo Carvalho de Melo
+*
+* Based on sdlamain.c by Gene Kozin <genek@compuserve.com> &
+*			 Jaspreet Singh	<jaspreet@sangoma.com>
+*
+*		This program is free software; you can redistribute it and/or
+*		modify it under the terms of the GNU General Public License
+*		as published by the Free Software Foundation; either version
+*		2 of the License, or (at your option) any later version.
+* ============================================================================
+* 1999/08/09	acme		removed references to enable_tx_int
+*				use spinlocks instead of cli/sti in
+*				cyclomx_set_state
+* 1999/05/19	acme		works directly linked into the kernel
+*				init_waitqueue_head for 2.3.* kernel
+* 1999/05/18	acme		major cleanup (polling not needed), etc
+* 1998/08/28	acme		minor cleanup (ioctls for firmware deleted)
+*				queue_task activated
+* 1998/08/08	acme		Initial version.
+*/
+
+#include <linux/config.h>	/* OS configuration options */
+#include <linux/stddef.h>	/* offsetof(), etc. */
+#include <linux/errno.h>	/* return codes */
+#include <linux/string.h>	/* inline memset(), etc. */
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
+#include <linux/kernel.h>	/* printk(), and other useful stuff */
+#include <linux/module.h>	/* support for loadable modules */
+#include <linux/ioport.h>	/* request_region(), release_region() */
+#include <linux/tqueue.h>	/* for kernel task queues */
+#include <linux/wanrouter.h>	/* WAN router definitions */
+#include <linux/cyclomx.h>	/* cyclomx common user API definitions */
+#include <asm/uaccess.h>	/* kernel <-> user copy */
+#include <linux/init.h>         /* __init (when not using as a module) */
+
+#ifdef MODULE
+MODULE_AUTHOR("Arnaldo Carvalho de Melo");
+MODULE_DESCRIPTION("Cyclades Sync Cards Driver.");
+#endif
+
+/* Defines & Macros */
+
+#define	DRV_VERSION	0		/* version number */
+#define	DRV_RELEASE	4		/* release (minor version) number */
+#define	MAX_CARDS	1		/* max number of adapters */
+
+#ifndef	CONFIG_CYCLOMX_CARDS		/* configurable option */
+#define	CONFIG_CYCLOMX_CARDS 1
+#endif
+
+/* Function Prototypes */
+
+/* Module entry points */
+int init_module (void);
+void cleanup_module (void);
+
+/* WAN link driver entry points */
+static int setup (wan_device_t *wandev, wandev_conf_t *conf);
+static int shutdown (wan_device_t *wandev);
+static int ioctl (wan_device_t *wandev, unsigned cmd, unsigned long arg);
+
+/* Miscellaneous functions */
+static void cycx_isr (int irq, void *dev_id, struct pt_regs *regs);
+
+/* Global Data
+ * Note: All data must be explicitly initialized!!!
+ */
+
+/* private data */
+static char drvname[]	= "cyclomx";
+static char fullname[]	= "CYCLOM X(tm) Multiprotocol Driver";
+static char copyright[]	= "(c) 1998, 1999 Arnaldo Carvalho de Melo";
+static int ncards = CONFIG_CYCLOMX_CARDS;
+static cycx_t *card_array = NULL;	/* adapter data space */
+
+/* Kernel Loadable Module Entry Points */
+
+/*
+ * Module 'insert' entry point.
+ * o print announcement
+ * o allocate adapter data space
+ * o initialize static data
+ * o register all cards with WAN router
+ * o calibrate CYCX shared memory access delay.
+ *
+ * Return:	0	Ok
+ *		< 0	error.
+ * Context:	process
+ */
+#ifdef MODULE
+int init_module (void)
+#else
+int __init cyclomx_init (void)
+#endif
+{
+	int cnt, err = 0;
+
+	printk(KERN_INFO "%s v%u.%u %s\n",
+		fullname, DRV_VERSION, DRV_RELEASE, copyright);
+
+	/* Verify number of cards and allocate adapter data space */
+	ncards = min(ncards, MAX_CARDS);
+	ncards = max(ncards, 1);
+	card_array = kmalloc(sizeof(cycx_t) * ncards, GFP_KERNEL);
+
+	if (card_array == NULL) return -ENOMEM;
+
+	memset(card_array, 0, sizeof(cycx_t) * ncards);
+
+	/* Register adapters with WAN router */
+	for (cnt = 0; cnt < ncards; ++cnt) {
+		cycx_t *card = &card_array[cnt];
+		wan_device_t *wandev = &card->wandev;
+
+		sprintf(card->devname, "%s%d", drvname, cnt + 1);
+		wandev->magic    = ROUTER_MAGIC;
+		wandev->name     = card->devname;
+		wandev->private  = card;
+		wandev->setup    = &setup;
+		wandev->shutdown = &shutdown;
+		wandev->ioctl    = &ioctl;
+		err = register_wan_device(wandev);
+
+		if (err) {
+			printk(KERN_ERR
+				"%s: %s registration failed with error %d!\n",
+				drvname, card->devname, err);
+			break;
+		}
+	}
+
+	if (cnt) ncards = cnt;	/* adjust actual number of cards */
+	else {
+		kfree(card_array);
+		err = -ENODEV;
+	}
+
+	return err;
+}
+
+/*
+ * Module 'remove' entry point.
+ * o unregister all adapters from the WAN router
+ * o release all remaining system resources
+ */
+#ifdef MODULE
+void cleanup_module (void)
+{
+	int i = 0;
+
+	for (; i < ncards; ++i) {
+		cycx_t *card = &card_array[i];
+		unregister_wan_device(card->devname);
+	}
+
+	kfree(card_array);
+}
+#endif
+/* WAN Device Driver Entry Points */
+/*
+ * Setup/confugure WAN link driver.
+ * o check adapter state
+ * o make sure firmware is present in configuration
+ * o allocate interrupt vector
+ * o setup CYCLOM X hardware
+ * o call appropriate routine to perform protocol-specific initialization
+ * o mark I/O region as used
+ *
+ * This function is called when router handles ROUTER_SETUP IOCTL. The
+ * configuration structure is in kernel memory (including extended data, if
+ * any).
+ */
+static int setup (wan_device_t *wandev, wandev_conf_t *conf)
+{
+	cycx_t *card;
+	int err = 0;
+	int irq;
+
+	/* Sanity checks */
+	if (!wandev || !wandev->private || !conf) return -EFAULT;
+
+	card = wandev->private;
+
+	if (wandev->state != WAN_UNCONFIGURED) return -EBUSY;
+
+	if (!conf->data_size || (conf->data == NULL)) {
+		printk(KERN_ERR "%s: firmware not found in configuration "
+				"data!\n", wandev->name);
+		return -EINVAL;
+	}
+
+	if (conf->irq <= 0) {
+		printk(KERN_ERR "%s: can't configure without IRQ!\n",
+				wandev->name);
+		return -EINVAL;
+	}
+
+	/* Allocate IRQ */
+	irq = conf->irq == 2 ? 9 : conf->irq;	/* IRQ2 -> IRQ9 */
+
+	if (request_irq(irq, cycx_isr, 0, wandev->name, card)) {
+		printk(KERN_ERR "%s: can't reserve IRQ %d!\n",
+				wandev->name, irq);
+		return -EINVAL;
+	}
+
+	/* Configure hardware, load firmware, etc. */
+	memset(&card->hw, 0, sizeof(cycxhw_t));
+	card->hw.irq = (conf->irq == 9) ? 2 : conf->irq;
+	card->hw.dpmbase = conf->maddr;
+	card->hw.dpmsize = CYCX_WINDOWSIZE;
+	card->hw.type = conf->hw_opt[0];
+	card->hw.fwid = CFID_X25_2X;
+	card->lock = SPIN_LOCK_UNLOCKED;
+#if LINUX_VERSION_CODE >= 0x020300
+	init_waitqueue_head(&card->wait_stats);
+#else
+	card->wait_stats = NULL;
+#endif
+	err = cycx_setup(&card->hw, conf->data, conf->data_size);
+
+	if (err) {
+		free_irq(irq, card);
+		return err;
+	}
+
+	/* Intialize WAN device data space */
+	wandev->irq       = irq;
+	wandev->dma       = wandev->ioport = 0;
+	wandev->maddr     = (unsigned long*)card->hw.dpmbase;
+	wandev->msize     = card->hw.dpmsize;
+	wandev->hw_opt[0] = card->hw.type;
+	wandev->hw_opt[1] = card->hw.pclk;
+	wandev->hw_opt[2] = card->hw.memory;
+	wandev->hw_opt[3] = card->hw.fwid;
+
+	/* Protocol-specific initialization */
+	switch (card->hw.fwid) {
+#ifdef CONFIG_CYCLOMX_X25
+		case CFID_X25_2X: err = cyx_init(card, conf); break;
+#endif
+		default:
+			printk(KERN_ERR "%s: this firmware is not supported!\n",
+					wandev->name);
+			err = -EINVAL;
+	}
+
+	if (err) {
+		cycx_down(&card->hw);
+		free_irq(irq, card);
+		return err;
+	}
+
+	return 0;
+}
+
+/*
+ * Shut down WAN link driver. 
+ * o shut down adapter hardware
+ * o release system resources.
+ *
+ * This function is called by the router when device is being unregistered or
+ * when it handles ROUTER_DOWN IOCTL.
+ */
+static int shutdown (wan_device_t *wandev)
+{
+	cycx_t *card;
+
+	/* sanity checks */
+	if (!wandev || !wandev->private) return -EFAULT;
+
+	if (wandev->state == WAN_UNCONFIGURED) return 0;
+
+	card = wandev->private;
+	wandev->state = WAN_UNCONFIGURED;
+	cycx_down(&card->hw);
+	printk(KERN_INFO "%s: irq %d being freed!\n", wandev->name,wandev->irq);
+	free_irq(wandev->irq, card);
+	return 0;
+}
+
+/*
+ * Driver I/O control. 
+ * o verify arguments
+ * o perform requested action
+ *
+ * This function is called when router handles one of the reserved user
+ * IOCTLs.  Note that 'arg' stil points to user address space.
+ */
+static int ioctl (wan_device_t *wandev, unsigned cmd, unsigned long arg)
+{
+	return -EINVAL;
+}
+
+/* Miscellaneous */
+/*
+ * CYCX Interrupt Service Routine.
+ * o acknowledge CYCX hardware interrupt.
+ * o call protocol-specific interrupt service routine, if any.
+ */
+static void cycx_isr (int irq, void *dev_id, struct pt_regs *regs)
+{
+#define	card	((cycx_t*)dev_id)
+	if (!card || card->wandev.state == WAN_UNCONFIGURED)
+		return;
+
+	if (card->in_isr) {
+		printk(KERN_WARNING "%s: interrupt re-entrancy on IRQ %d!\n",
+				    card->devname, card->wandev.irq);
+		return;
+	}
+
+	if (card->isr)
+		card->isr(card);
+#undef	card
+}
+
+/*
+ * This routine is called by the protocol-specific modules when network
+ * interface is being open.  The only reason we need this, is because we
+ * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's
+ * defined more than once into the same kernel module.
+ */
+void cyclomx_open (cycx_t *card)
+{
+	++card->open_cnt;
+	MOD_INC_USE_COUNT;
+}
+
+/*
+ * This routine is called by the protocol-specific modules when network
+ * interface is being closed.  The only reason we need this, is because we
+ * have to call MOD_DEC_USE_COUNT, but cannot include 'module.h' where it's
+ * defined more than once into the same kernel module.
+ */
+void cyclomx_close (cycx_t *card)
+{
+	--card->open_cnt;
+	MOD_DEC_USE_COUNT;
+}
+
+/* Set WAN device state.  */
+void cyclomx_set_state (cycx_t *card, int state)
+{
+	unsigned long host_cpu_flags;
+
+	spin_lock_irqsave(&card->lock, host_cpu_flags);
+
+	if (card->wandev.state != state) {
+		switch (state) {
+			case WAN_CONNECTED:
+				printk (KERN_INFO "%s: link connected!\n",
+						  card->devname);
+				break;
+
+			case WAN_CONNECTING:
+				printk (KERN_INFO "%s: link connecting...\n",
+						  card->devname);
+				break;
+
+			case WAN_DISCONNECTED:
+				printk (KERN_INFO "%s: link disconnected!\n",
+						  card->devname);
+				break;
+		}
+
+		card->wandev.state = state;
+	}
+
+	card->state_tick = jiffies;
+	spin_unlock_irqrestore(&card->lock, host_cpu_flags);
+}
+
+/* End */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/cycx_x25.c linux/drivers/net/wan/cycx_x25.c
--- v2.3.20/linux/drivers/net/wan/cycx_x25.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/cycx_x25.c	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,1488 @@
+/*
+* cycx_x25.c	CYCLOM X Multiprotocol WAN Link Driver.  X.25 module.
+*
+* Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+* Copyright:	(c) 1998, 1999 Arnaldo Carvalho de Melo
+*
+* Based on sdla_x25.c by Gene Kozin <genek@compuserve.com>
+*
+*		This program is free software; you can redistribute it and/or
+*		modify it under the terms of the GNU General Public License
+*		as published by the Free Software Foundation; either version
+*		2 of the License, or (at your option) any later version.
+* ============================================================================
+* 1999/08/10	acme		serialized access to the card thru a spinlock
+*				in x25_exec
+* 1999/08/09	acme		removed per channel spinlocks
+*				removed references to enable_tx_int
+* 1999/05/28	acme		fixed nibble_to_byte, ackvc now properly treated
+*				if_send simplified
+* 1999/05/25	acme		fixed t1, t2, t21 & t23 configuration
+*				use spinlocks instead of cli/sti in some points
+* 1999/05/24	acme		finished the x25_get_stat function
+* 1999/05/23	acme		dev->type = ARPHRD_X25 (tcpdump only works,
+*				AFAIT, with ARPHRD_ETHER). This seems to be
+*				needed to use socket(AF_X25)...
+*				Now the config file must specify a peer media
+*				address for svc channes over a crossover cable.
+*				Removed hold_timeout from x25_channel_t,
+*				not used.
+*				A little enhancement in the DEBUG processing
+* 1999/05/22	acme		go to DISCONNECTED in disconnect_confirm_intr,
+*				instead of chan_disc.
+* 1999/05/16	marcelo		fixed timer initialization in SVCs
+* 1999/01/05	acme		x25_configure now get (most of) all
+*				parameters...
+* 1999/01/05	acme		pktlen now (correctly) uses log2 (value
+*				configured)
+* 1999/01/03	acme		judicious use of data types (u8, u16, u32, etc)
+* 1999/01/03	acme		cyx_isr: reset dpmbase to acknowledge
+*				indication (interrupt from cyclom 2x)
+* 1999/01/02	acme		cyx_isr: first hackings...
+* 1999/01/0203  acme 		when initializing an array don't give less
+*				elements than declared...
+* 				example: char send_cmd[6] = "?\xFF\x10";
+*          			you'll gonna lose a couple hours, 'cause your
+*				brain won't admit that there's an error in the
+*				above declaration...  the side effect is that
+*				memset is put into the unresolved symbols
+*				instead of using the inline memset functions...
+* 1999/01/02    acme 		began chan_connect, chan_send, x25_send
+* Dec 31, 1998	Arnaldo		x25_configure
+*				this code can be compiled as non module
+* Dec 27, 1998	Arnaldo		code cleanup
+*				IPX code wiped out! let's decrease code
+*				complexity for now, remember: I'm learning! :)
+*                               bps_to_speed_code OK
+* Dec 26, 1998	Arnaldo		Minimal debug code cleanup
+* Aug 08, 1998	Arnaldo		Initial version.
+*/
+#define CYCLOMX_X25_DEBUG 1
+
+#include <linux/version.h>
+#include <linux/kernel.h>	/* printk(), and other useful stuff */
+#include <linux/stddef.h>	/* offsetof(), etc. */
+#include <linux/errno.h>	/* return codes */
+#include <linux/string.h>	/* inline memset(), etc. */
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
+#include <linux/wanrouter.h>	/* WAN router definitions */
+#include <asm/byteorder.h>	/* htons(), etc. */
+#include <linux/if_arp.h>       /* ARPHRD_X25 */
+#include <linux/cyclomx.h>	/* CYCLOM X common user API definitions */
+#include <linux/cycx_x25.h>	/* X.25 firmware API definitions */
+
+/* Defines & Macros */
+#define MAX_CMD_RETRY	5
+#define X25_CHAN_MTU	2048	/* unfragmented logical channel MTU */
+
+/* Data Structures */
+/* This is an extention of the 'struct net_device' we create for each network
+   interface to keep the rest of X.25 channel-specific data. */
+typedef struct x25_channel {
+	char name[WAN_IFNAME_SZ+1];	/* interface name, ASCIIZ */
+	char addr[WAN_ADDRESS_SZ+1];	/* media address, ASCIIZ */
+	char *local_addr;		/* local media address, ASCIIZ -
+					   svc thru crossover cable */
+	s16 lcn;			/* logical channel number/conn.req.key*/
+	u8 link;
+	struct timer_list timer;	/* timer used for svc channel disc. */
+	u16 protocol;			/* ethertype, 0 - multiplexed */
+	u8 svc;				/* 0 - permanent, 1 - switched */
+	u8 state;			/* channel state */
+	u8 drop_sequence;		/* mark sequence for dropping */
+	u32 idle_tmout;			/* sec, before disconnecting */
+	struct sk_buff *rx_skb;		/* receive socket buffer */
+	cycx_t *card;			/* -> owner */
+	struct enet_statistics ifstats;	/* interface statistics */
+} x25_channel_t;
+
+/* Function Prototypes */
+/* WAN link driver entry points. These are called by the WAN router module. */
+static int update (wan_device_t *wandev),
+	   new_if (wan_device_t *wandev, struct net_device *dev,wanif_conf_t *conf),
+	   del_if (wan_device_t *wandev, struct net_device *dev);
+
+/* Network device interface */
+static int if_init (struct net_device *dev),
+	   if_open (struct net_device *dev),
+	   if_close (struct net_device *dev),
+	   if_header (struct sk_buff *skb, struct net_device *dev,
+		      u16 type, void *daddr, void *saddr, unsigned len),
+	   if_rebuild_hdr (struct sk_buff *skb),
+	   if_send (struct sk_buff *skb, struct net_device *dev);
+
+static struct net_device_stats * if_stats (struct net_device *dev);
+
+/* Interrupt handlers */
+static void cyx_isr (cycx_t *card),
+	    tx_intr (cycx_t *card, TX25Cmd *cmd),
+	    rx_intr (cycx_t *card, TX25Cmd *cmd),
+	    log_intr (cycx_t *card, TX25Cmd *cmd),
+	    stat_intr (cycx_t *card, TX25Cmd *cmd),
+	    connect_confirm_intr (cycx_t *card, TX25Cmd *cmd),
+	    disconnect_confirm_intr (cycx_t *card, TX25Cmd *cmd),
+	    connect_intr (cycx_t *card, TX25Cmd *cmd),
+	    disconnect_intr (cycx_t *card, TX25Cmd *cmd),
+	    spur_intr (cycx_t *card, TX25Cmd *cmd);
+
+/* X.25 firmware interface functions */
+static int x25_configure (cycx_t *card, TX25Config *conf),
+	   x25_get_stats (cycx_t *card),
+	   x25_send (cycx_t *card, u8 link, u8 lcn, u8 bitm, int len,void *buf),
+	   x25_connect_response (cycx_t *card, x25_channel_t *chan),
+	   x25_disconnect_response (cycx_t *card, u8 link, u8 lcn);
+
+/* Miscellaneous functions */
+static int chan_connect (struct net_device *dev),
+	   chan_send (struct net_device *dev, struct sk_buff *skb);
+
+static void set_chan_state (struct net_device *dev, u8 state),
+	    nibble_to_byte (u8 *s, u8 *d, u8 len, u8 nibble),
+	    reset_timer (struct net_device *dev),
+	    chan_disc (struct net_device *dev),
+	    chan_timer (unsigned long d);
+
+static u8 bps_to_speed_code (u32 bps);
+static u8 log2 (u32 n);
+
+static unsigned dec_to_uint (u8 *str, int len);
+
+static struct net_device *get_dev_by_lcn (wan_device_t *wandev, s16 lcn);
+static struct net_device *get_dev_by_dte_addr (wan_device_t *wandev, char *dte);
+
+#ifdef CYCLOMX_X25_DEBUG
+static void hex_dump(char *msg, unsigned char *p, int len);
+static void x25_dump_config(TX25Config *conf);
+static void x25_dump_stats(TX25Stats *stats);
+static void x25_dump_devs(wan_device_t *wandev);
+#define dprintk(format, a...) printk(format, ##a)
+#else
+#define hex_dump(msg, p, len)
+#define x25_dump_config(conf)
+#define x25_dump_stats(stats)
+#define x25_dump_devs(wandev)
+#define dprintk(format, a...)
+#endif
+/* Public Functions */
+
+/* X.25 Protocol Initialization routine.
+ *
+ * This routine is called by the main CYCLOM X module during setup.  At this
+ * point adapter is completely initialized and X.25 firmware is running.
+ *  o read firmware version (to make sure it's alive)
+ *  o configure adapter
+ *  o initialize protocol-specific fields of the adapter data space.
+ *
+ * Return:	0	o.k.
+ *		< 0	failure.  */
+int cyx_init (cycx_t *card, wandev_conf_t *conf)
+{
+	TX25Config cfg;
+
+	/* Verify configuration ID */
+	if (conf->config_id != WANCONFIG_X25) {
+		printk(KERN_INFO "%s: invalid configuration ID %u!\n",
+				 card->devname, conf->config_id);
+		return -EINVAL;
+	}
+
+	/* Initialize protocol-specific fields */
+	card->mbox  = card->hw.dpmbase + X25_MBOX_OFFS;
+	card->u.x.connection_keys = 0;
+	card->u.x.lock = SPIN_LOCK_UNLOCKED;
+
+	/* Configure adapter. Here we set resonable defaults, then parse
+	 * device configuration structure and set configuration options.
+	 * Most configuration options are verified and corrected (if
+	 * necessary) since we can't rely on the adapter to do so and don't
+	 * want it to fail either. */
+	memset(&cfg, 0, sizeof(cfg));
+	cfg.link = 0;
+	cfg.clock = conf->clocking == WANOPT_EXTERNAL ? 8 : 55;
+	cfg.speed = bps_to_speed_code(conf->bps);
+	cfg.n3win = 7;
+	cfg.n2win = 2;
+	cfg.n2 = 5;
+	cfg.nvc = 1;
+	cfg.npvc = 1;
+	cfg.flags = 0x02; /* default = V35 */
+	cfg.t1 = 10;   /* line carrier timeout */
+	cfg.t2 = 29;   /* tx timeout */
+	cfg.t21 = 180; /* CALL timeout */
+	cfg.t23 = 180; /* CLEAR timeout */
+
+	/* adjust MTU */
+	if (!conf->mtu || conf->mtu >= 512)
+		card->wandev.mtu = 512;
+	else if (conf->mtu >= 256)
+		card->wandev.mtu = 256;
+	else if (conf->mtu >= 128)
+		card->wandev.mtu = 128;
+	else
+		card->wandev.mtu = 64;
+
+	cfg.pktlen = log2(card->wandev.mtu);
+
+	if (conf->station == WANOPT_DTE) {
+		cfg.locaddr = 3; /* DTE */
+		cfg.remaddr = 1; /* DCE */
+	} else {
+		cfg.locaddr = 1; /* DCE */
+		cfg.remaddr = 3; /* DTE */
+	}
+
+        if (conf->interface == WANOPT_RS232)
+	        cfg.flags = 0;      /* FIXME just reset the 2nd bit */
+
+	if (conf->u.x25.hi_pvc) {
+		card->u.x.hi_pvc = min(conf->u.x25.hi_pvc, 4095);
+		card->u.x.lo_pvc = min(conf->u.x25.lo_pvc, card->u.x.hi_pvc);
+	}
+
+	if (conf->u.x25.hi_svc) {
+		card->u.x.hi_svc = min(conf->u.x25.hi_svc, 4095);
+		card->u.x.lo_svc = min(conf->u.x25.lo_svc, card->u.x.hi_svc);
+	}
+
+	if (card->u.x.lo_pvc == 255)
+		cfg.npvc = 0;
+	else
+		cfg.npvc = card->u.x.hi_pvc - card->u.x.lo_pvc + 1;
+
+	cfg.nvc = card->u.x.hi_svc - card->u.x.lo_svc + 1 + cfg.npvc;
+
+	if (conf->u.x25.hdlc_window)
+		cfg.n2win = min(conf->u.x25.hdlc_window, 7);
+
+	if (conf->u.x25.pkt_window)
+		cfg.n3win = min(conf->u.x25.pkt_window, 7);
+
+	if (conf->u.x25.t1)
+		cfg.t1 = min(conf->u.x25.t1, 30);
+
+	if (conf->u.x25.t2)
+		cfg.t2 = min(conf->u.x25.t2, 30);
+
+	if (conf->u.x25.t11_t21)
+		cfg.t21 = min(conf->u.x25.t11_t21, 30);
+
+	if (conf->u.x25.t13_t23)
+		cfg.t23 = min(conf->u.x25.t13_t23, 30);
+
+	if (conf->u.x25.n2)
+		cfg.n2 = min(conf->u.x25.n2, 30);
+
+	/* initialize adapter */
+	if (x25_configure(card, &cfg))
+		return -EIO;
+
+	/* Initialize protocol-specific fields of adapter data space */
+	card->wandev.bps	= conf->bps;
+	card->wandev.interface	= conf->interface;
+	card->wandev.clocking	= conf->clocking;
+	card->wandev.station	= conf->station;
+	card->isr		= &cyx_isr;
+	card->exec		= NULL;
+	card->wandev.update	= &update;
+	card->wandev.new_if	= &new_if;
+	card->wandev.del_if	= &del_if;
+	card->wandev.state	= WAN_DISCONNECTED;
+	return 0;
+}
+
+/* WAN Device Driver Entry Points */
+/* Update device status & statistics. */
+static int update (wan_device_t *wandev)
+{
+	/* sanity checks */
+	if (!wandev || !wandev->private)
+		return -EFAULT;
+
+	if (wandev->state == WAN_UNCONFIGURED)
+		return -ENODEV;
+
+	x25_get_stats(wandev->private);
+	return 0;
+}
+
+/* Create new logical channel.
+ * This routine is called by the router when ROUTER_IFNEW IOCTL is being
+ * handled.
+ * o parse media- and hardware-specific configuration
+ * o make sure that a new channel can be created
+ * o allocate resources, if necessary
+ * o prepare network device structure for registaration.
+ *
+ * Return:	0	o.k.
+ *		< 0	failure (channel will not be created) */
+static int new_if (wan_device_t *wandev, struct net_device *dev, wanif_conf_t *conf)
+{
+	cycx_t *card = wandev->private;
+	x25_channel_t *chan;
+	int err = 0;
+
+	if (conf->name[0] == '\0' || strlen(conf->name) > WAN_IFNAME_SZ) {
+		printk(KERN_INFO "%s: invalid interface name!\n",card->devname);
+		return -EINVAL;
+	}
+
+	/* allocate and initialize private data */
+	if ((chan = kmalloc(sizeof(x25_channel_t), GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+
+	memset(chan, 0, sizeof(x25_channel_t));
+	strcpy(chan->name, conf->name);
+	chan->card = card;
+	chan->link = conf->port;
+	chan->protocol = ETH_P_IP;
+	chan->rx_skb = NULL;
+	/* only used in svc connected thru crossover cable */
+	chan->local_addr = NULL;
+
+	if (conf->addr[0] == '@') {	/* SVC */
+		int len = strlen(conf->local_addr);
+
+		if (len) {
+			if (len > WAN_ADDRESS_SZ) {
+				printk(KERN_ERR "%s: %s local addr too long!\n",
+						wandev->name, chan->name);
+				kfree(chan);
+				return -EINVAL;
+			} else {
+				chan->local_addr = kmalloc(len + 1, GFP_KERNEL);
+
+				if (!chan->local_addr) {
+					kfree(chan);
+					return ENOMEM;
+				}
+			}
+
+                	strncpy(chan->local_addr, conf->local_addr,
+				WAN_ADDRESS_SZ);
+		}
+
+                chan->svc = 1;
+                strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ);
+		init_timer(&chan->timer);
+		chan->timer.function = chan_timer;
+		chan->timer.data = (unsigned long) dev;
+
+                /* Set channel timeouts (default if not specified) */
+                chan->idle_tmout = conf->idle_timeout ? conf->idle_timeout : 90;
+        } else if (is_digit(conf->addr[0])) {	/* PVC */
+		s16 lcn = dec_to_uint(conf->addr, 0);
+
+		if (lcn >= card->u.x.lo_pvc && lcn <= card->u.x.hi_pvc)
+			chan->lcn = lcn;
+		else {
+			printk(KERN_ERR
+				"%s: PVC %u is out of range on interface %s!\n",
+				wandev->name, lcn, chan->name);
+			err = -EINVAL;
+		}
+	} else {
+		printk(KERN_ERR "%s: invalid media address on interface %s!\n",
+				wandev->name, chan->name);
+		err = -EINVAL;
+	}
+
+	if (err) {
+		if (chan->local_addr)
+			kfree(chan->local_addr);
+
+		kfree(chan);
+		return err;
+	}
+
+	/* prepare network device data space for registration */
+	dev->name = chan->name;
+	dev->init = &if_init;
+	dev->priv = chan;
+	return 0;
+}
+
+/* Delete logical channel. */
+static int del_if (wan_device_t *wandev, struct net_device *dev)
+{
+	if (!dev) {
+		printk(KERN_ERR "cycx_x25:del_if:dev == NULL!\n");
+		return 0;
+	}
+
+	if (dev->priv) {
+		x25_channel_t *chan = dev->priv;
+
+		if (chan->svc) {
+			if (chan->local_addr)
+				kfree(chan->local_addr);
+
+			if (chan->state == WAN_CONNECTED)
+				del_timer(&chan->timer);
+		}
+
+		kfree(chan);
+		dev->priv = NULL;
+	}
+
+	return 0;
+}
+
+/* Network Device Interface */
+/* Initialize Linux network interface.
+ *
+ * This routine is called only once for each interface, during Linux network
+ * interface registration.  Returning anything but zero will fail interface
+ * registration. */
+static int if_init (struct net_device *dev)
+{
+	x25_channel_t *chan = dev->priv;
+	cycx_t *card = chan->card;
+	wan_device_t *wandev = &card->wandev;
+
+	/* Initialize device driver entry points */
+	dev->open = &if_open;
+	dev->stop = &if_close;
+	dev->hard_header = &if_header;
+	dev->rebuild_header = &if_rebuild_hdr;
+	dev->hard_start_xmit = &if_send;
+	dev->get_stats = &if_stats;
+
+	/* Initialize media-specific parameters */
+	dev->mtu = X25_CHAN_MTU;
+	dev->type = ARPHRD_X25;		/* ARP h/w type */
+	dev->hard_header_len = 0;	/* media header length */
+	dev->addr_len = 0;		/* hardware address length */
+
+	if (!chan->svc)
+		*(u16*)dev->dev_addr = htons(chan->lcn);
+
+	/* Initialize hardware parameters (just for reference) */
+	dev->irq = wandev->irq;
+	dev->dma = wandev->dma;
+	dev->base_addr = wandev->ioport;
+	dev->mem_start = (unsigned long)wandev->maddr;
+	dev->mem_end = (unsigned long)(wandev->maddr + wandev->msize - 1);
+	dev->flags |= IFF_NOARP;
+
+        /* Set transmit buffer queue length */
+        dev->tx_queue_len = 10;
+
+	/* Initialize socket buffers */
+	dev_init_buffers(dev);
+	set_chan_state(dev, WAN_DISCONNECTED);
+	return 0;
+}
+
+/* Open network interface.
+ * o prevent module from unloading by incrementing use count
+ * o if link is disconnected then initiate connection
+ *
+ * Return 0 if O.k. or errno.  */
+static int if_open (struct net_device *dev)
+{
+	x25_channel_t *chan = dev->priv;
+	cycx_t *card = chan->card;
+
+	if (dev->start)
+		return -EBUSY; /* only one open is allowed */ 
+
+	dev->interrupt = 0;
+	dev->tbusy = 0;
+	dev->start = 1;
+	cyclomx_open(card);
+
+	return 0;
+}
+
+/* Close network interface.
+ * o reset flags.
+ * o if there's no more open channels then disconnect physical link. */
+static int if_close (struct net_device *dev)
+{
+	x25_channel_t *chan = dev->priv;
+	cycx_t *card = chan->card;
+
+	dev->start = 0;
+
+	if (chan->state == WAN_CONNECTED || chan->state == WAN_CONNECTING)
+		chan_disc(dev);
+		
+	cyclomx_close(card);
+	return 0;
+}
+
+/* Build media header.
+ * o encapsulate packet according to encapsulation type.
+ *
+ * The trick here is to put packet type (Ethertype) into 'protocol' field of
+ * the socket buffer, so that we don't forget it.  If encapsulation fails,
+ * set skb->protocol to 0 and discard packet later.
+ *
+ * Return:	media header length. */
+static int if_header (struct sk_buff *skb, struct net_device *dev,
+		      u16 type, void *daddr, void *saddr, unsigned len)
+{
+	skb->protocol = type;
+	return dev->hard_header_len;
+}
+
+/* * Re-build media header.
+ * Return:	1	physical address resolved.
+ *		0	physical address not resolved */
+static int if_rebuild_hdr (struct sk_buff *skb)
+{
+	return 1;
+}
+
+/* Send a packet on a network interface.
+ * o set tbusy flag (marks start of the transmission).
+ * o check link state. If link is not up, then drop the packet.
+ * o check channel status. If it's down then initiate a call.
+ * o pass a packet to corresponding WAN device.
+ * o free socket buffer
+ *
+ * Return:	0	complete (socket buffer must be freed)
+ *		non-0	packet may be re-transmitted (tbusy must be set)
+ *
+ * Notes:
+ * 1. This routine is called either by the protocol stack or by the "net
+ *    bottom half" (with interrupts enabled).
+ * 2. Setting tbusy flag will inhibit further transmit requests from the
+ *    protocol stack and can be used for flow control with protocol layer. */
+static int if_send (struct sk_buff *skb, struct net_device *dev)
+{
+	x25_channel_t *chan = dev->priv;
+	cycx_t *card = chan->card;
+
+	if (dev->tbusy) {
+		++chan->ifstats.rx_dropped;	
+		return -EBUSY;	
+	}
+
+	if (!chan->svc)
+		chan->protocol = skb->protocol;
+
+	if (card->wandev.state != WAN_CONNECTED)
+		++chan->ifstats.tx_dropped;
+        else if (chan->svc && chan->protocol &&
+		 chan->protocol != skb->protocol) {
+                printk(KERN_INFO
+                        "%s: unsupported Ethertype 0x%04X on interface %s!\n",
+                        card->devname, skb->protocol, dev->name);
+                ++chan->ifstats.tx_errors;
+        } else switch (chan->state) {
+		case WAN_DISCONNECTED:
+			if (chan_connect(dev)) {
+				dev->tbusy = 1;
+				return -EBUSY;
+			}
+			/* fall thru */
+		case WAN_CONNECTED:
+			reset_timer(dev);
+			dev->trans_start = jiffies;
+			dev->tbusy = 1;
+
+			if (chan_send(dev, skb)) {
+				return -EBUSY;
+			}
+			break;
+		default:
+			++chan->ifstats.tx_dropped;	
+			++card->wandev.stats.tx_dropped;
+	}
+
+	dev_kfree_skb(skb);
+	return 0;
+}
+
+/* Get Ethernet-style interface statistics.
+ * Return a pointer to struct net_device_stats */
+static struct net_device_stats *if_stats (struct net_device *dev)
+{
+        x25_channel_t *chan = dev->priv;
+
+	return chan ? &chan->ifstats : NULL;
+}
+
+/* Interrupt Handlers */
+/* X.25 Interrupt Service Routine. */
+static void cyx_isr (cycx_t *card)
+{
+	TX25Cmd cmd;
+	u16 z = 0;
+
+	card->in_isr = 1;
+	card->buff_int_mode_unbusy = 0;
+	cycx_peek(&card->hw, X25_RXMBOX_OFFS, &cmd, sizeof(cmd));
+
+	switch (cmd.command) {
+		case X25_DATA_INDICATION:
+			rx_intr(card, &cmd);
+			break;
+		case X25_ACK_FROM_VC:
+			tx_intr(card, &cmd);
+			break;
+		case X25_LOG: 
+			log_intr(card, &cmd);
+			break;
+		case X25_STATISTIC: 
+			stat_intr(card, &cmd);
+			break;
+		case X25_CONNECT_CONFIRM:
+			connect_confirm_intr(card, &cmd);
+			break;
+		case X25_CONNECT_INDICATION:
+			connect_intr(card, &cmd);
+			break;
+		case X25_DISCONNECT_INDICATION:
+			disconnect_intr(card, &cmd);
+			break;
+		case X25_DISCONNECT_CONFIRM:
+			disconnect_confirm_intr(card, &cmd);
+			break;
+		case X25_LINE_ON:
+			cyclomx_set_state(card, WAN_CONNECTED);
+			break;
+		case X25_LINE_OFF:
+			cyclomx_set_state(card, WAN_DISCONNECTED);
+			break;
+		default: 
+			spur_intr(card, &cmd); /* unwanted interrupt */
+	}
+
+	cycx_poke(&card->hw, 0, &z, sizeof(z));
+	cycx_poke(&card->hw, X25_RXMBOX_OFFS, &z, sizeof(z));
+	card->in_isr = 0;
+
+	if (card->buff_int_mode_unbusy)
+		mark_bh(NET_BH);
+}
+
+/* Transmit interrupt handler.
+ *	o Release socket buffer
+ *	o Clear 'tbusy' flag */
+static void tx_intr (cycx_t *card, TX25Cmd *cmd)
+{
+	struct net_device *dev;
+	wan_device_t *wandev = &card->wandev;
+	u8 lcn;
+
+	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
+
+	/* unbusy device and then dev_tint(); */
+	if ((dev = get_dev_by_lcn (wandev, lcn)) != NULL) {
+		card->buff_int_mode_unbusy = 1;
+		dev->tbusy = 0;
+	} else
+		printk(KERN_ERR "%s:ackvc for inexistent lcn %d\n",
+				 card->devname, lcn);
+}
+
+/* Receive interrupt handler.
+ * This routine handles fragmented IP packets using M-bit according to the
+ * RFC1356.
+ * o map ligical channel number to network interface.
+ * o allocate socket buffer or append received packet to the existing one.
+ * o if M-bit is reset (i.e. it's the last packet in a sequence) then 
+ *   decapsulate packet and pass socket buffer to the protocol stack.
+ *
+ * Notes:
+ * 1. When allocating a socket buffer, if M-bit is set then more data is
+ *    comming and we have to allocate buffer for the maximum IP packet size
+ *    expected on this channel.
+ * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no
+ *    socket buffers available) the whole packet sequence must be discarded. */
+static void rx_intr (cycx_t *card, TX25Cmd *cmd)
+{
+	wan_device_t *wandev = &card->wandev;
+	struct net_device *dev;
+	x25_channel_t *chan;
+	struct sk_buff *skb;
+	u8 bitm, lcn;
+	int pktlen = cmd->len - 5;
+
+	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
+	cycx_peek(&card->hw, cmd->buf + 4, &bitm, sizeof(bitm));
+	bitm &= 0x10;
+
+	if ((dev = get_dev_by_lcn(wandev, lcn)) == NULL) {
+		/* Invalid channel, discard packet */
+		printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n",
+				 card->devname, lcn);
+		return;
+	}
+
+	chan = dev->priv;
+	reset_timer(dev);
+
+	if (chan->drop_sequence) {
+		if (!bitm)
+			chan->drop_sequence = 0;
+		else
+			return;
+	}
+
+	if ((skb = chan->rx_skb) == NULL) {
+		/* Allocate new socket buffer */
+		int bufsize = bitm ? dev->mtu : pktlen;
+
+		if ((skb = dev_alloc_skb(bufsize +
+					 dev->hard_header_len)) == NULL) {
+			printk(KERN_INFO "%s: no socket buffers available!\n",
+					 card->devname);
+			chan->drop_sequence = 1;
+			++chan->ifstats.rx_dropped;
+			return;
+		}
+
+		skb->dev = dev;
+		skb->protocol = htons(chan->protocol);
+		chan->rx_skb = skb;
+	}
+
+	if (skb_tailroom(skb) < pktlen) {
+		/* No room for the packet. Call off the whole thing! */
+		dev_kfree_skb(skb);
+		chan->rx_skb = NULL;
+
+		if (bitm)
+			chan->drop_sequence = 1;
+
+		printk(KERN_INFO "%s: unexpectedly long packet sequence "
+			"on interface %s!\n", card->devname, dev->name);
+		++chan->ifstats.rx_length_errors;
+		return;
+	}
+
+	/* Append packet to the socket buffer  */
+	cycx_peek(&card->hw, cmd->buf + 5, skb_put(skb, pktlen), pktlen);
+
+	if (bitm)
+		return; /* more data is coming */
+
+	dev->last_rx = jiffies;		/* timestamp */
+	chan->rx_skb = NULL;		/* dequeue packet */
+
+	skb->protocol = htons(ETH_P_IP);
+	skb->dev = dev;
+	skb->mac.raw = skb->data;
+	netif_rx(skb);
+	++chan->ifstats.rx_packets;
+	chan->ifstats.rx_bytes += skb->len;
+}
+
+/* Connect interrupt handler. */
+static void connect_intr (cycx_t *card, TX25Cmd *cmd)
+{
+	wan_device_t *wandev = &card->wandev;
+	struct net_device *dev = NULL;
+	x25_channel_t *chan;
+	u8 d[32],
+	   loc[24],
+	   rem[24];
+	u8 lcn, sizeloc, sizerem;
+
+	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
+	cycx_peek(&card->hw, cmd->buf + 5, &sizeloc, sizeof(sizeloc));
+	cycx_peek(&card->hw, cmd->buf + 6, d, cmd->len - 6);
+
+	sizerem = sizeloc >> 4;
+	sizeloc &= 0x0F;
+
+	loc[0] = rem[0] = '\0';
+
+	if (sizeloc)
+		nibble_to_byte(d, loc, sizeloc, 0);
+
+	if (sizerem)
+		nibble_to_byte(d + (sizeloc >> 1), rem, sizerem, sizeloc & 1);
+
+	dprintk(KERN_INFO "connect_intr:lcn=%d, local=%s, remote=%s\n",
+			  lcn, loc, rem);
+	if ((dev = get_dev_by_dte_addr(wandev, rem)) == NULL) {
+		/* Invalid channel, discard packet */
+		printk(KERN_INFO "%s: connect not expected: remote %s!\n",
+				 card->devname, rem);
+		return;
+	}
+
+	chan = dev->priv;
+	chan->lcn = lcn;
+	x25_connect_response(card, chan);
+	set_chan_state(dev, WAN_CONNECTED);
+}
+
+/* Connect confirm interrupt handler. */
+static void connect_confirm_intr (cycx_t *card, TX25Cmd *cmd)
+{
+	wan_device_t *wandev = &card->wandev;
+	struct net_device *dev;
+	x25_channel_t *chan;
+	u8 lcn, key;
+
+	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
+	cycx_peek(&card->hw, cmd->buf + 1, &key, sizeof(key));
+	dprintk(KERN_INFO "%s: connect_confirm_intr:lcn=%d, key=%d\n",
+			  card->devname, lcn, key);
+	if ((dev = get_dev_by_lcn(wandev, -key)) == NULL) {
+		/* Invalid channel, discard packet */
+		clear_bit(--key, (void*)&card->u.x.connection_keys);
+		printk(KERN_INFO "%s: connect confirm not expected: lcn %d, "
+				 "key=%d!\n", card->devname, lcn, key);
+		return;
+	}
+
+	clear_bit(--key, (void*)&card->u.x.connection_keys);
+	chan = dev->priv;
+	chan->lcn = lcn;
+	set_chan_state(dev, WAN_CONNECTED);
+}
+
+/* Disonnect confirm interrupt handler. */
+static void disconnect_confirm_intr (cycx_t *card, TX25Cmd *cmd)
+{
+	wan_device_t *wandev = &card->wandev;
+	struct net_device *dev;
+	u8 lcn;
+
+	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
+	dprintk(KERN_INFO "%s: disconnect_confirm_intr:lcn=%d\n",
+			  card->devname, lcn);
+	if ((dev = get_dev_by_lcn(wandev, lcn)) == NULL) {
+		/* Invalid channel, discard packet */
+		printk(KERN_INFO "%s:disconnect confirm not expected!:lcn %d\n",
+				 card->devname, lcn);
+		return;
+	}
+
+	set_chan_state(dev, WAN_DISCONNECTED);
+}
+
+/* disconnect interrupt handler. */
+static void disconnect_intr (cycx_t *card, TX25Cmd *cmd)
+{
+	wan_device_t *wandev = &card->wandev;
+	struct net_device *dev;
+	u8 lcn;
+
+	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
+	dprintk(KERN_INFO "disconnect_intr:lcn=%d\n", lcn);
+
+	if ((dev = get_dev_by_lcn(wandev, lcn)) != NULL) {
+		x25_channel_t *chan = dev->priv;
+
+		x25_disconnect_response(card, chan->link, lcn);
+		set_chan_state(dev, WAN_DISCONNECTED);
+	} else
+		x25_disconnect_response(card, 0, lcn);
+}
+
+/* LOG interrupt handler. */
+static void log_intr (cycx_t *card, TX25Cmd *cmd)
+{
+#if CYCLOMX_X25_DEBUG
+	char bf[20];
+	u16 size, toread, link, msg_code;
+	u8 code, routine;
+
+	cycx_peek(&card->hw, cmd->buf, &msg_code, sizeof(msg_code));
+	cycx_peek(&card->hw, cmd->buf + 2, &link, sizeof(link));
+	cycx_peek(&card->hw, cmd->buf + 4, &size, sizeof(size));
+	/* at most 20 bytes are available... thanx to Daniela :) */
+	toread = size < 20 ? size : 20;
+	cycx_peek(&card->hw, cmd->buf + 10, &bf, toread);
+	cycx_peek(&card->hw, cmd->buf + 10 + toread, &code, 1);
+	cycx_peek(&card->hw, cmd->buf + 10 + toread + 1, &routine, 1);
+
+	printk(KERN_INFO "cyx_isr: X25_LOG (0x4500) indic.:\n");
+	printk(KERN_INFO "cmd->buf=0x%X\n", cmd->buf);
+	printk(KERN_INFO "Log message code=0x%X\n", msg_code);
+	printk(KERN_INFO "Link=%d\n", link);
+	printk(KERN_INFO "log code=0x%X\n", code);
+	printk(KERN_INFO "log routine=0x%X\n", routine);
+	printk(KERN_INFO "Message size=%d\n", size);
+	hex_dump("Message", bf, toread);
+#endif
+}
+
+/* STATISTIC interrupt handler. */
+static void stat_intr (cycx_t *card, TX25Cmd *cmd)
+{
+	cycx_peek(&card->hw, cmd->buf, &card->u.x.stats,
+		  sizeof(card->u.x.stats));
+	hex_dump("stat_intr", (unsigned char*)&card->u.x.stats,
+		 sizeof(card->u.x.stats));
+	x25_dump_stats(&card->u.x.stats);
+	wake_up_interruptible(&card->wait_stats);
+}
+
+/* Spurious interrupt handler.
+ * o print a warning
+ * If number of spurious interrupts exceeded some limit, then ??? */
+static void spur_intr (cycx_t *card, TX25Cmd *cmd)
+{
+	printk(KERN_INFO "%s: spurious interrupt (0x%X)!\n",
+			 card->devname, cmd->command);
+}
+#ifdef CYCLOMX_X25_DEBUG
+static void hex_dump(char *msg, unsigned char *p, int len)
+{
+	unsigned char hex[1024],
+	    	* phex = hex;
+
+	if (len >= (sizeof(hex) / 2))
+		len = (sizeof(hex) / 2) - 1;
+
+	while (len--) {
+		sprintf(phex, "%02x", *p++);
+		phex += 2;
+	}
+
+	printk(KERN_INFO "%s: %s\n", msg, hex);
+}
+#endif
+/* CYCLOM X Firmware-Specific Functions */
+/* Exec x25 command. */
+static int x25_exec (cycx_t *card, int command, int link,
+		     void *d1, int len1, void *d2, int len2)
+{
+	TX25Cmd c;
+	unsigned long flags;
+	u32 addr = 0x1200 + 0x2E0 * link + 0x1E2;
+	u8 retry = MAX_CMD_RETRY;
+	int err = 0;
+
+	c.command = command;
+	c.link = link;
+	c.len = len1 + len2;
+
+	spin_lock_irqsave(&card->u.x.lock, flags);
+
+	/* write command */
+	cycx_poke(&card->hw, X25_MBOX_OFFS, &c, sizeof(c) - sizeof(c.buf));
+
+	/* write x25 data */
+	if (d1) {
+		cycx_poke(&card->hw, addr, d1, len1);
+
+		if (d2) {
+			if (len2 > 254) {
+				u32 addr1 = 0xA00 + 0x400 * link;
+
+				cycx_poke(&card->hw, addr + len1, d2, 249);
+				cycx_poke(&card->hw, addr1, ((u8*) d2) + 249,
+					  len2 - 249);
+			} else
+				cycx_poke(&card->hw, addr + len1, d2, len2);
+		}
+	}
+
+	/* generate interruption, executing command */
+	cycx_intr(&card->hw);
+
+	/* wait till card->mbox == 0 */
+	do {
+		err = cycx_exec(card->mbox);
+	} while (retry-- && err);
+
+	spin_unlock_irqrestore(&card->u.x.lock, flags);
+
+	return err;
+}
+
+/* Configure adapter. */
+static int x25_configure (cycx_t *card, TX25Config *conf)
+{
+	struct {
+		u16 nlinks;
+		TX25Config conf[2];
+	} x25_cmd_conf;
+
+	memset (&x25_cmd_conf, 0, sizeof(x25_cmd_conf));
+	x25_cmd_conf.nlinks = 2;
+	x25_cmd_conf.conf[0] = *conf;
+	/* FIXME: we need to find a way in the wanrouter framework
+		  to configure the second link, for now lets use it
+		  with the same config from the first link, fixing
+		  the interface type to RS232, the speed in 38400 and
+		  the clock to external */
+	x25_cmd_conf.conf[1] = *conf;
+	x25_cmd_conf.conf[1].link = 1;
+	x25_cmd_conf.conf[1].speed = 5; /* 38400 */
+	x25_cmd_conf.conf[1].clock = 8;
+	x25_cmd_conf.conf[1].flags = 0; /* default = RS232 */
+
+	x25_dump_config(&x25_cmd_conf.conf[0]);
+	x25_dump_config(&x25_cmd_conf.conf[1]);
+
+	return x25_exec(card, X25_CONFIG, 0,
+			&x25_cmd_conf, sizeof(x25_cmd_conf), NULL, 0);
+}
+
+/* Get protocol statistics. */
+static int x25_get_stats (cycx_t *card)
+{
+	/* the firmware expects 20 in the size field!!!
+	   thanx to Daniela */
+	int err = x25_exec(card, X25_STATISTIC, 0, NULL, 20, NULL, 0);
+
+	if (err)
+		return err;
+
+	interruptible_sleep_on(&card->wait_stats);
+
+	if (signal_pending(current))
+		return -EINTR;
+
+	card->wandev.stats.rx_packets = card->u.x.stats.n2_rx_frames;
+	card->wandev.stats.rx_over_errors = card->u.x.stats.rx_over_errors;
+	card->wandev.stats.rx_crc_errors = card->u.x.stats.rx_crc_errors;
+	card->wandev.stats.rx_length_errors = 0; /* not available from fw */
+	card->wandev.stats.rx_frame_errors = 0; /* not available from fw */
+	card->wandev.stats.rx_missed_errors = card->u.x.stats.rx_aborts;
+	card->wandev.stats.rx_dropped = 0; /* not available from fw */
+	card->wandev.stats.rx_errors = 0; /* not available from fw */
+	card->wandev.stats.tx_packets = card->u.x.stats.n2_tx_frames;
+	card->wandev.stats.tx_aborted_errors = card->u.x.stats.tx_aborts;
+	card->wandev.stats.tx_dropped = 0; /* not available from fw */
+	card->wandev.stats.collisions = 0; /* not available from fw */
+	card->wandev.stats.tx_errors = 0; /* not available from fw */
+
+	x25_dump_devs(&card->wandev);
+	return 0;
+}
+
+/* return the number of nibbles */
+static int byte_to_nibble(u8 *s, u8 *d, char *nibble)
+{
+        int i = 0;
+
+        if (*nibble && *s) {
+                d[i] |= *s++ - '0';
+                *nibble = 0;
+                ++i;
+        }
+
+        while (*s) {
+                d[i] = (*s - '0') << 4;
+                if (*(s + 1))
+			d[i] |= *(s + 1) - '0';
+                else {
+                        *nibble = 1;
+                        break;
+                }
+                ++i;
+                s += 2;
+        }
+
+        return i;
+}
+
+static void nibble_to_byte(u8 *s, u8 *d, u8 len, u8 nibble)
+{
+	if (nibble) {
+		*d++ = '0' + (*s++ & 0x0F);
+		--len;
+	}
+
+	while (len) {
+		*d++ = '0' + (*s >> 4);
+
+		if (--len) {
+			*d++ = '0' + (*s & 0x0F);
+			--len;
+		} else break;
+		
+		++s;
+	}
+
+	*d = '\0';
+}
+
+/* Place X.25 call. */
+static int x25_place_call (cycx_t *card, x25_channel_t *chan)
+{
+	int err = 0,
+	    len;
+	char d[64],
+	     nibble = 0,
+	     mylen = chan->local_addr ? strlen(chan->local_addr) : 0,
+	     remotelen = strlen(chan->addr);
+	u8 key;
+
+	if (card->u.x.connection_keys == ~0UL) {
+		printk(KERN_INFO "%s: too many simultaneous connection "
+				 "requests!\n", card->devname);
+		return -EAGAIN;
+	}
+
+	key = ffz(card->u.x.connection_keys);
+	set_bit(key, (void*)&card->u.x.connection_keys);
+	++key;
+	dprintk(KERN_INFO "%s:x25_place_call:key=%d\n", card->devname, key);
+	memset(d, 0, sizeof(d));
+	d[1] = key; /* user key */
+	d[2] = 0x10;
+	d[4] = 0x0B;
+
+	len = byte_to_nibble(chan->addr, d + 6, &nibble);
+
+	if (chan->local_addr)
+		len += byte_to_nibble(chan->local_addr, d + 6 + len, &nibble);
+
+	if (nibble)
+		++len;
+
+	d[5] = mylen << 4 | remotelen;
+	d[6 + len + 1] = 0xCC; /* TCP/IP over X.25, thanx to Daniela :) */
+	
+	if ((err = x25_exec(card, X25_CONNECT_REQUEST, chan->link,
+			    &d, 7 + len + 1, NULL, 0)) != 0)
+		clear_bit(--key, (void*)&card->u.x.connection_keys);
+	else {
+                chan->lcn = -key;
+                chan->protocol = ETH_P_IP;
+        }
+
+        return err;
+}
+
+/* Place X.25 CONNECT RESPONSE. */
+static int x25_connect_response (cycx_t *card, x25_channel_t *chan)
+{
+	u8 d[8];
+
+	memset(d, 0, sizeof(d));
+	d[0] = d[3] = chan->lcn;
+	d[2] = 0x10;
+	d[4] = 0x0F;
+	d[7] = 0xCC; /* TCP/IP over X.25, thanx Daniela */
+
+	return x25_exec(card, X25_CONNECT_RESPONSE, chan->link, &d, 8, NULL, 0);
+}
+
+/* Place X.25 DISCONNECT RESPONSE.  */
+static int x25_disconnect_response (cycx_t *card, u8 link, u8 lcn)
+{
+	char d[5];
+
+	memset(d, 0, sizeof(d));
+	d[0] = d[3] = lcn;
+	d[2] = 0x10;
+	d[4] = 0x17;
+	return x25_exec(card, X25_DISCONNECT_RESPONSE, link, &d, 5, NULL, 0);
+}
+
+/* Clear X.25 call.  */
+static int x25_clear_call (cycx_t *card, u8 link, u8 lcn, u8 cause, u8 diagn)
+{
+	u8 d[7];
+
+	memset(d, 0, sizeof(d));
+	d[0] = d[3] = lcn;
+	d[2] = 0x10;
+	d[4] = 0x13;
+	d[5] = cause;
+	d[6] = diagn;
+
+	return x25_exec(card, X25_DISCONNECT_REQUEST, link, d, 7, NULL, 0);
+}
+
+/* Send X.25 data packet. */
+static int x25_send (cycx_t *card, u8 link, u8 lcn, u8 bitm, int len, void *buf)
+{
+	u8 d[] = "?\xFF\x10??"; 
+
+	d[0] = d[3] = lcn;
+	d[4] = bitm;
+
+	return x25_exec(card, X25_DATA_REQUEST, link, &d, 5, buf, len);
+}
+
+/* Miscellaneous */
+/* Find network device by its channel number.  */
+static struct net_device *get_dev_by_lcn (wan_device_t *wandev, s16 lcn)
+{
+	struct net_device *dev = wandev->dev;
+
+	for (; dev; dev = dev->slave)
+		if (((x25_channel_t*)dev->priv)->lcn == lcn)
+			break;
+	return dev;
+}
+
+/* Find network device by its remote dte address. */
+static struct net_device *get_dev_by_dte_addr (wan_device_t *wandev, char *dte)
+{
+	struct net_device *dev = wandev->dev;
+
+	for (; dev; dev = dev->slave)
+		if (!strcmp (((x25_channel_t*)dev->priv)->addr, dte))
+			break;
+	return dev;
+}
+
+/* Initiate connection on the logical channel.
+ * o for PVC we just get channel configuration
+ * o for SVCs place an X.25 call
+ *
+ * Return:	0	connected
+ *		>0	connection in progress
+ *		<0	failure */
+static int chan_connect (struct net_device *dev)
+{
+	x25_channel_t *chan = dev->priv;
+	cycx_t *card = chan->card;
+
+	if (chan->svc) {
+                if (!chan->addr[0])
+			return -EINVAL; /* no destination address */
+                dprintk(KERN_INFO "%s: placing X.25 call to %s...\n",
+				  card->devname, chan->addr);
+                if (x25_place_call(card, chan))
+			return -EIO;
+                set_chan_state(dev, WAN_CONNECTING);
+                return 1;
+        } else 
+		set_chan_state(dev, WAN_CONNECTED);
+
+	return 0;
+}
+
+/* Disconnect logical channel.
+ * o if SVC then clear X.25 call */
+static void chan_disc (struct net_device *dev)
+{
+	x25_channel_t *chan = dev->priv;
+
+	if (chan->svc) {
+		x25_clear_call(chan->card, chan->link, chan->lcn, 0, 0);
+		set_chan_state(dev, WAN_DISCONNECTING);
+	} else
+		set_chan_state(dev, WAN_DISCONNECTED);
+}
+
+/* Called by kernel timer */
+static void chan_timer (unsigned long d)
+{
+	struct net_device *dev = (struct net_device*) d;
+	x25_channel_t *chan = dev->priv;
+	
+	switch (chan->state) {
+		case WAN_CONNECTED:
+			chan_disc(dev);
+			break;
+		default:
+			printk (KERN_ERR "%s: chan_timer for svc (%s) not "
+					 "connected!\n",
+					 chan->card->devname, dev->name);
+	}
+}
+
+/* Set logical channel state. */
+static void set_chan_state (struct net_device *dev, u8 state)
+{
+	x25_channel_t *chan = dev->priv;
+	cycx_t *card = chan->card;
+	u32 flags = 0;
+
+	spin_lock_irqsave(&card->lock, flags);
+
+	if (chan->state != state) {
+		if (chan->svc && chan->state == WAN_CONNECTED)
+			del_timer(&chan->timer);
+	
+		switch (state) {
+			case WAN_CONNECTED:
+				printk (KERN_INFO "%s: interface %s "
+						  "connected!\n",
+						  card->devname, dev->name);
+				*(u16*)dev->dev_addr = htons(chan->lcn);
+				dev->tbusy = 0;
+				reset_timer(dev);
+				break;
+
+			case WAN_CONNECTING:
+				printk (KERN_INFO "%s: interface %s "
+						  "connecting...\n",
+						  card->devname, dev->name);
+				break;
+
+			case WAN_DISCONNECTING:
+				printk (KERN_INFO "%s: interface %s "
+						  "disconnecting...\n",
+						  card->devname, dev->name);
+				break;
+
+			case WAN_DISCONNECTED:
+				printk (KERN_INFO "%s: interface %s "
+						  "disconnected!\n",
+						  card->devname, dev->name);
+				if (chan->svc) {
+					*(unsigned short*)dev->dev_addr = 0;
+					chan->lcn = 0;
+                                }
+				dev->tbusy = 0;
+				break;
+		}
+
+		chan->state = state;
+	}
+
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+/* Send packet on a logical channel.
+ *	When this function is called, tx_skb field of the channel data space
+ *	points to the transmit socket buffer.  When transmission is complete,
+ *	release socket buffer and reset 'tbusy' flag.
+ *
+ * Return:	0	- transmission complete
+ *		1	- busy
+ *
+ * Notes:
+ * 1. If packet length is greater than MTU for this channel, we'll fragment
+ *    the packet into 'complete sequence' using M-bit.
+ * 2. When transmission is complete, an event notification should be issued
+ *    to the router.  */
+static int chan_send (struct net_device *dev, struct sk_buff *skb)
+{
+	x25_channel_t *chan = dev->priv;
+	cycx_t *card = chan->card;
+	int bitm = 0;		/* final packet */
+	unsigned len = skb->len;
+
+	if (skb->len > card->wandev.mtu) {
+		len = card->wandev.mtu;
+		bitm = 0x10;		/* set M-bit (more data) */
+	}
+
+	if (x25_send(card, chan->link, chan->lcn, bitm, len, skb->data))
+		return 1;
+		
+	if (bitm) {
+		skb_pull(skb, len);
+		return 1;
+	}
+
+	++chan->ifstats.tx_packets;
+	chan->ifstats.tx_bytes += len;
+	return 0;
+}
+
+/* Convert line speed in bps to a number used by cyclom 2x code. */
+static u8 bps_to_speed_code (u32 bps)
+{
+	u8 number = 0; /* defaults to the lowest (1200) speed ;> */
+
+	     if (bps >= 512000) number = 8;
+	else if (bps >= 256000) number = 7;
+	else if (bps >= 64000)  number = 6;
+	else if (bps >= 38400)  number = 5;
+	else if (bps >= 19200)  number = 4;
+	else if (bps >= 9600)   number = 3;
+	else if (bps >= 4800)   number = 2;
+	else if (bps >= 2400)   number = 1;
+
+	return number;
+}
+
+/* log base 2 */
+static u8 log2 (u32 n)
+{
+        u8 log = 0;
+
+        if (!n)
+		return 0;
+
+        while (n > 1) {
+                n >>= 1;
+                ++log;
+        }
+
+        return log;
+}
+
+/* Convert decimal string to unsigned integer.
+ * If len != 0 then only 'len' characters of the string are converted. */
+static unsigned dec_to_uint (u8 *str, int len)
+{
+	unsigned val = 0;
+
+	if (!len)
+		len = strlen(str);
+
+	for (; len && is_digit(*str); ++str, --len)
+		val = (val * 10) + (*str - (unsigned)'0');
+
+	return val;
+}
+
+static void reset_timer(struct net_device *dev)
+{
+	x25_channel_t *chan = dev->priv;
+
+	if (!chan->svc)
+		return;
+
+	del_timer(&chan->timer);
+	chan->timer.expires = jiffies + chan->idle_tmout * HZ;
+	add_timer(&chan->timer);
+}
+#ifdef CYCLOMX_X25_DEBUG
+static void x25_dump_config(TX25Config *conf)
+{
+	printk (KERN_INFO "x25 configuration\n");
+	printk (KERN_INFO "-----------------\n");
+        printk (KERN_INFO "link number=%d\n", conf->link);
+        printk (KERN_INFO "line speed=%d\n", conf->speed);
+        printk (KERN_INFO "clock=%sternal\n", conf->clock == 8 ? "Ex" : "In");
+        printk (KERN_INFO "# level 2 retransm.=%d\n", conf->n2);
+        printk (KERN_INFO "level 2 window=%d\n", conf->n2win);
+        printk (KERN_INFO "level 3 window=%d\n", conf->n3win);
+        printk (KERN_INFO "# logical channels=%d\n", conf->nvc);
+        printk (KERN_INFO "level 3 pkt len=%d\n", conf->pktlen);
+	printk (KERN_INFO "my address=%d\n", conf->locaddr);
+        printk (KERN_INFO "remote address=%d\n", conf->remaddr);
+        printk (KERN_INFO "t1=%d seconds\n", conf->t1);
+        printk (KERN_INFO "t2=%d seconds\n", conf->t2);
+        printk (KERN_INFO "t21=%d seconds\n", conf->t21);
+        printk (KERN_INFO "# PVCs=%d\n", conf->npvc);
+	printk (KERN_INFO "t23=%d seconds\n", conf->t23);
+        printk (KERN_INFO "flags=0x%x\n", conf->flags);
+}
+
+static void x25_dump_stats(TX25Stats *stats)
+{
+	printk (KERN_INFO "x25 statistics\n");
+	printk (KERN_INFO "--------------\n");
+        printk (KERN_INFO "rx_crc_errors=%d\n", stats->rx_crc_errors);
+        printk (KERN_INFO "rx_over_errors=%d\n", stats->rx_over_errors);
+        printk (KERN_INFO "n2_tx_frames=%d\n", stats->n2_tx_frames);
+        printk (KERN_INFO "n2_rx_frames=%d\n", stats->n2_rx_frames);
+        printk (KERN_INFO "tx_timeouts=%d\n", stats->tx_timeouts);
+        printk (KERN_INFO "rx_timeouts=%d\n", stats->rx_timeouts);
+        printk (KERN_INFO "n3_tx_packets=%d\n", stats->n3_tx_packets);
+        printk (KERN_INFO "n3_rx_packets=%d\n", stats->n3_rx_packets);
+        printk (KERN_INFO "tx_aborts=%d\n", stats->tx_aborts);
+        printk (KERN_INFO "rx_aborts=%d\n", stats->rx_aborts);
+}
+
+static void x25_dump_devs(wan_device_t *wandev)
+{
+	struct net_device *dev = wandev->dev;
+
+	printk (KERN_INFO "x25 dev states\n");
+	printk (KERN_INFO "name: addr:           tbusy:\n");
+	printk (KERN_INFO "----------------------------\n");
+
+	for (; dev; dev = dev->slave) {
+		x25_channel_t *chan = dev->priv;
+
+		printk (KERN_INFO "%-5.5s %-15.15s   %ld\n",
+				  chan->name, chan->addr, dev->tbusy);
+	}
+}
+
+#endif /* CYCLOMX_X25_DEBUG */
+/* End */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/dlci.c linux/drivers/net/wan/dlci.c
--- v2.3.20/linux/drivers/net/wan/dlci.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/dlci.c	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,634 @@
+/*
+ * DLCI		Implementation of Frame Relay protocol for Linux, according to
+ *		RFC 1490.  This generic device provides en/decapsulation for an
+ *		underlying hardware driver.  Routes & IPs are assigned to these
+ *		interfaces.  Requires 'dlcicfg' program to create usable 
+ *		interfaces, the initial one, 'dlci' is for IOCTL use only.
+ *
+ * Version:	@(#)dlci.c	0.35	4 Jan 1997
+ *
+ * Author:	Mike McLagan <mike.mclagan@linux.org>
+ *
+ * Changes:
+ *
+ *		0.15	Mike Mclagan	Packet freeing, bug in kmalloc call
+ *					DLCI_RET handling
+ *		0.20	Mike McLagan	More conservative on which packets
+ *					are returned for retry and whic are
+ *					are dropped.  If DLCI_RET_DROP is
+ *					returned from the FRAD, the packet is
+ *				 	sent back to Linux for re-transmission
+ *		0.25	Mike McLagan	Converted to use SIOC IOCTL calls
+ *		0.30	Jim Freeman	Fixed to allow IPX traffic
+ *		0.35	Michael Elizabeth	Fixed incorrect memcpy_fromfs
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h> /* for CONFIG_DLCI_COUNT */
+#include <linux/module.h>
+
+#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/init.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/if_frad.h>
+
+#include <net/sock.h>
+
+static const char *devname = "dlci";
+static const char *version = "DLCI driver v0.35, 4 Jan 1997, mike.mclagan@linux.org";
+
+static struct net_device *open_dev[CONFIG_DLCI_COUNT];
+
+static char *basename[16];
+
+int dlci_init(struct net_device *dev);
+
+/* allow FRAD's to register their name as a valid FRAD */
+int register_frad(const char *name)
+{
+	int i;
+
+	if (!name)
+		return(-EINVAL);
+
+	for (i=0;i<sizeof(basename) / sizeof(char *);i++)
+	{
+		if (!basename[i])
+			break;
+
+		/* take care of multiple registrations */
+		if (strcmp(basename[i], name) == 0)
+			return(0);
+	}
+
+	if (i == sizeof(basename) / sizeof(char *))
+		return(-EMLINK);
+
+	basename[i] = kmalloc(strlen(name) + 1, GFP_KERNEL);
+	if (!basename[i])
+		return(-ENOMEM);
+
+	strcpy(basename[i], name);
+
+	return(0);
+}
+
+int unregister_frad(const char *name)
+{
+	int i;
+
+	if (!name)
+		return(-EINVAL);
+
+	for (i=0;i<sizeof(basename) / sizeof(char *);i++)
+		if (basename[i] && (strcmp(basename[i], name) == 0))
+			break;
+
+	if (i == sizeof(basename) / sizeof(char *))
+		return(-EINVAL);
+
+	kfree(basename[i]);
+	basename[i] = NULL;
+
+	return(0);
+}
+
+/* 
+ * these encapsulate the RFC 1490 requirements as well as 
+ * deal with packet transmission and reception, working with
+ * the upper network layers 
+ */
+
+static int dlci_header(struct sk_buff *skb, struct net_device *dev, 
+                           unsigned short type, void *daddr, void *saddr, 
+                           unsigned len)
+{
+	struct frhdr		hdr;
+	struct dlci_local	*dlp;
+	unsigned int		hlen;
+	char			*dest;
+
+	dlp = dev->priv;
+
+	hdr.control = FRAD_I_UI;
+	switch(type)
+	{
+		case ETH_P_IP:
+			hdr.IP_NLPID = FRAD_P_IP;
+			hlen = sizeof(hdr.control) + sizeof(hdr.IP_NLPID);
+			break;
+
+		/* feel free to add other types, if necessary */
+
+		default:
+			hdr.pad = FRAD_P_PADDING;
+			hdr.NLPID = FRAD_P_SNAP;
+			memset(hdr.OUI, 0, sizeof(hdr.OUI));
+			hdr.PID = htons(type);
+			hlen = sizeof(hdr);
+			break;
+	}
+
+	dest = skb_push(skb, hlen);
+	if (!dest)
+		return(0);
+
+	memcpy(dest, &hdr, hlen);
+
+	return(hlen);
+}
+
+static void dlci_receive(struct sk_buff *skb, struct net_device *dev)
+{
+	struct dlci_local *dlp;
+	struct frhdr		*hdr;
+	int					process, header;
+
+	dlp = dev->priv;
+	hdr = (struct frhdr *) skb->data;
+	process = 0;
+	header = 0;
+	skb->dev = dev;
+
+	if (hdr->control != FRAD_I_UI)
+	{
+		printk(KERN_NOTICE "%s: Invalid header flag 0x%02X.\n", dev->name, hdr->control);
+		dlp->stats.rx_errors++;
+	}
+	else
+		switch(hdr->IP_NLPID)
+		{
+			case FRAD_P_PADDING:
+				if (hdr->NLPID != FRAD_P_SNAP)
+				{
+					printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->NLPID);
+					dlp->stats.rx_errors++;
+					break;
+				}
+	 
+				if (hdr->OUI[0] + hdr->OUI[1] + hdr->OUI[2] != 0)
+				{
+					printk(KERN_NOTICE "%s: Unsupported organizationally unique identifier 0x%02X-%02X-%02X.\n", dev->name, hdr->OUI[0], hdr->OUI[1], hdr->OUI[2]);
+					dlp->stats.rx_errors++;
+					break;
+				}
+
+				/* at this point, it's an EtherType frame */
+				header = sizeof(struct frhdr);
+				/* Already in network order ! */
+				skb->protocol = hdr->PID;
+				process = 1;
+				break;
+
+			case FRAD_P_IP:
+				header = sizeof(hdr->control) + sizeof(hdr->IP_NLPID);
+				skb->protocol = htons(ETH_P_IP);
+				process = 1;
+				break;
+
+			case FRAD_P_SNAP:
+			case FRAD_P_Q933:
+			case FRAD_P_CLNP:
+				printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->pad);
+				dlp->stats.rx_errors++;
+				break;
+
+			default:
+				printk(KERN_NOTICE "%s: Invalid pad byte 0x%02X.\n", dev->name, hdr->pad);
+				dlp->stats.rx_errors++;
+				break;				
+		}
+
+	if (process)
+	{
+		/* we've set up the protocol, so discard the header */
+		skb->mac.raw = skb->data; 
+		skb_pull(skb, header);
+		netif_rx(skb);
+		dlp->stats.rx_packets++;
+	}
+	else
+		dev_kfree_skb(skb);
+}
+
+static int dlci_transmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct dlci_local *dlp;
+	int					ret;
+
+	ret = 0;
+
+	if (!skb || !dev)
+		return(0);
+
+	if (dev->tbusy)
+		return(1);
+
+	dlp = dev->priv;
+
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
+		printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
+	else
+	{
+		ret = dlp->slave->hard_start_xmit(skb, dlp->slave);
+		switch (ret)
+		{
+			case DLCI_RET_OK:
+				dlp->stats.tx_packets++;
+				ret = 0;
+				break;
+
+			case DLCI_RET_ERR:
+				dlp->stats.tx_errors++;
+				ret = 0;
+				break;
+
+			case DLCI_RET_DROP:
+				dlp->stats.tx_dropped++;
+				ret = 1;
+				break;
+		}
+
+		/* Alan Cox recommends always returning 0, and always freeing the packet */
+		/* experience suggest a slightly more conservative approach */
+
+		if (!ret)
+			dev_kfree_skb(skb);
+
+		dev->tbusy = 0;
+	}
+
+	return(ret);
+}
+
+int dlci_config(struct net_device *dev, struct dlci_conf *conf, int get)
+{
+	struct dlci_conf	config;
+	struct dlci_local	*dlp;
+	struct frad_local	*flp;
+	int			err;
+
+	dlp = dev->priv;
+
+	flp = dlp->slave->priv;
+
+	if (!get)
+	{
+		if(copy_from_user(&config, conf, sizeof(struct dlci_conf)))
+			return -EFAULT;
+		if (config.flags & ~DLCI_VALID_FLAGS)
+			return(-EINVAL);
+		memcpy(&dlp->config, &config, sizeof(struct dlci_conf));
+		dlp->configured = 1;
+	}
+
+	err = (*flp->dlci_conf)(dlp->slave, dev, get);
+	if (err)
+		return(err);
+
+	if (get)
+	{
+		if(copy_to_user(conf, &dlp->config, sizeof(struct dlci_conf)))
+			return -EFAULT;
+	}
+
+	return(0);
+}
+
+int dlci_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct dlci_local *dlp;
+
+	if (!capable(CAP_NET_ADMIN))
+		return(-EPERM);
+
+	dlp = dev->priv;
+
+	switch(cmd)
+	{
+		case DLCI_GET_SLAVE:
+			if (!*(short *)(dev->dev_addr))
+				return(-EINVAL);
+
+			strncpy(ifr->ifr_slave, dlp->slave->name, sizeof(ifr->ifr_slave));
+			break;
+
+		case DLCI_GET_CONF:
+		case DLCI_SET_CONF:
+			if (!*(short *)(dev->dev_addr))
+				return(-EINVAL);
+
+			return(dlci_config(dev, (struct dlci_conf *) ifr->ifr_data, cmd == DLCI_GET_CONF));
+			break;
+
+		default: 
+			return(-EOPNOTSUPP);
+	}
+	return(0);
+}
+
+static int dlci_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct dlci_local *dlp;
+
+	dlp = dev->priv;
+
+	return((*dlp->slave->change_mtu)(dlp->slave, new_mtu));
+}
+
+static int dlci_open(struct net_device *dev)
+{
+	struct dlci_local	*dlp;
+	struct frad_local	*flp;
+	int			err;
+
+	dlp = dev->priv;
+
+	if (!*(short *)(dev->dev_addr))
+		return(-EINVAL);
+
+	if (!dlp->slave->start)
+		return(-ENOTCONN);
+
+	dev->flags = 0;
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	flp = dlp->slave->priv;
+	err = (*flp->activate)(dlp->slave, dev);
+	if (err)
+		return(err);
+
+	return 0;
+}
+
+static int dlci_close(struct net_device *dev)
+{
+	struct dlci_local	*dlp;
+	struct frad_local	*flp;
+	int			err;
+
+	dlp = dev->priv;
+
+	flp = dlp->slave->priv;
+	err = (*flp->deactivate)(dlp->slave, dev);
+
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	return 0;
+}
+
+static struct net_device_stats *dlci_get_stats(struct net_device *dev)
+{
+	struct dlci_local *dlp;
+
+	dlp = dev->priv;
+
+	return(&dlp->stats);
+}
+
+int dlci_add(struct dlci_add *dlci)
+{
+	struct net_device		*master, *slave;
+	struct dlci_local	*dlp;
+	struct frad_local	*flp;
+	int			err, i;
+	char			buf[10];
+
+	/* validate slave device */
+	slave = __dev_get_by_name(dlci->devname);
+	if (!slave)
+		return(-ENODEV);
+
+	if (slave->type != ARPHRD_FRAD)
+		return(-EINVAL);
+
+	/* check for registration */
+	for (i=0;i<sizeof(basename) / sizeof(char *); i++)
+		if ((basename[i]) && 
+			 (strncmp(dlci->devname, basename[i], strlen(basename[i])) == 0) && 
+			 (strlen(dlci->devname) > strlen(basename[i])))
+			break;
+
+	if (i == sizeof(basename) / sizeof(char *))
+		return(-EINVAL);
+
+	/* check for too many open devices : should this be dynamic ? */
+	for(i=0;i<CONFIG_DLCI_COUNT;i++)
+		if (!open_dev[i])
+			break;
+
+	if (i == CONFIG_DLCI_COUNT)
+		return(-ENOSPC);  /*  #### Alan: Comments on this?? */
+
+	/* create device name */
+	sprintf(buf, "%s%02i", devname, i);
+
+	master = kmalloc(sizeof(*master), GFP_KERNEL);
+	if (!master)
+		return(-ENOMEM);
+
+	memset(master, 0, sizeof(*master));
+	master->name = kmalloc(strlen(buf) + 1, GFP_KERNEL);
+
+	if (!master->name)
+	{
+		kfree(master);
+		return(-ENOMEM);
+	}
+
+	strcpy(master->name, buf);
+	master->init = dlci_init;
+	master->flags = 0;
+
+	err = register_netdev(master);
+	if (err < 0)
+	{
+		kfree(master->name);
+		kfree(master);
+		return(err);
+	}
+
+	*(short *)(master->dev_addr) = dlci->dlci;
+
+	dlp = (struct dlci_local *) master->priv;
+	dlp->slave = slave;
+
+	flp = slave->priv;
+	err = flp ? (*flp->assoc)(slave, master) : -EINVAL;
+	if (err < 0)
+	{
+		unregister_netdev(master);
+		kfree(master->priv);
+		kfree(master->name);
+		kfree(master);
+		return(err);
+	}
+
+	strcpy(dlci->devname, buf);
+	open_dev[i] = master;
+	MOD_INC_USE_COUNT;
+	return(0);
+}
+
+int dlci_del(struct dlci_add *dlci)
+{
+	struct dlci_local	*dlp;
+	struct frad_local	*flp;
+	struct net_device		*master, *slave;
+	int			i, err;
+
+	/* validate slave device */
+	master = __dev_get_by_name(dlci->devname);
+	if (!master)
+		return(-ENODEV);
+
+	if (master->start)
+		return(-EBUSY);
+
+	dlp = master->priv;
+	slave = dlp->slave;
+	flp = slave->priv;
+
+	err = (*flp->deassoc)(slave, master);
+	if (err)
+		return(err);
+
+	unregister_netdev(master);
+
+	for(i=0;i<CONFIG_DLCI_COUNT;i++)
+		if (master == open_dev[i])
+			break;
+
+	if (i<CONFIG_DLCI_COUNT)
+		open_dev[i] = NULL;
+
+	kfree(master->priv);
+	kfree(master->name);
+	kfree(master);
+
+	MOD_DEC_USE_COUNT;
+
+	return(0);
+}
+
+int dlci_ioctl(unsigned int cmd, void *arg)
+{
+	struct dlci_add add;
+	int err;
+	
+	if (!capable(CAP_NET_ADMIN))
+		return(-EPERM);
+
+	if(copy_from_user(&add, arg, sizeof(struct dlci_add)))
+		return -EFAULT;
+
+	switch (cmd)
+	{
+		case SIOCADDDLCI:
+			err = dlci_add(&add);
+
+			if (!err)
+				if(copy_to_user(arg, &add, sizeof(struct dlci_add)))
+					return -EFAULT;
+			break;
+
+		case SIOCDELDLCI:
+			err = dlci_del(&add);
+			break;
+
+		default:
+			err = -EINVAL;
+	}
+
+	return(err);
+}
+
+int dlci_init(struct net_device *dev)
+{
+	struct dlci_local *dlp;
+
+	dev->priv = kmalloc(sizeof(struct dlci_local), GFP_KERNEL);
+	if (!dev->priv)
+		return(-ENOMEM);
+
+	memset(dev->priv, 0, sizeof(struct dlci_local));
+	dlp = dev->priv;
+
+	dev->flags		= 0;
+	dev->open		= dlci_open;
+	dev->stop		= dlci_close;
+	dev->do_ioctl		= dlci_dev_ioctl;
+	dev->hard_start_xmit	= dlci_transmit;
+	dev->hard_header	= dlci_header;
+	dev->get_stats		= dlci_get_stats;
+	dev->change_mtu		= dlci_change_mtu;
+
+	dlp->receive		= dlci_receive;
+
+	dev->type		= ARPHRD_DLCI;
+	dev->hard_header_len	= sizeof(struct frhdr);
+	dev->addr_len		= sizeof(short);
+	memset(dev->dev_addr, 0, sizeof(dev->dev_addr));
+
+	dev_init_buffers(dev);
+	
+	return(0);
+}
+
+int __init dlci_setup(void)
+{
+	int i;
+
+	printk("%s.\n", version);
+	
+	for(i=0;i<CONFIG_DLCI_COUNT;i++)
+		open_dev[i] = NULL;
+
+	for(i=0;i<sizeof(basename) / sizeof(char *);i++)
+		basename[i] = NULL;
+
+	return(0);
+}
+
+#ifdef MODULE
+
+extern int (*dlci_ioctl_hook)(unsigned int, void *);
+
+int init_module(void)
+{
+	dlci_ioctl_hook = dlci_ioctl;
+
+	return(dlci_setup());
+}
+
+void cleanup_module(void)
+{
+	dlci_ioctl_hook = NULL;
+}
+#endif /* MODULE */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/hostess_sv11.c linux/drivers/net/wan/hostess_sv11.c
--- v2.3.20/linux/drivers/net/wan/hostess_sv11.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/hostess_sv11.c	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,434 @@
+#define LINUX_21
+
+/*
+ *	Comtrol SV11 card driver
+ *
+ *	This is a slightly odd Z85230 synchronous driver. All you need to
+ *	know basically is
+ *
+ *	Its a genuine Z85230
+ *
+ *	It supports DMA using two DMA channels in SYNC mode. The driver doesn't
+ *	use these facilities
+ *	
+ *	The control port is at io+1, the data at io+3 and turning off the DMA
+ *	is done by writing 0 to io+4
+ *
+ *	The hardware does the bus handling to avoid the need for delays between
+ *	touching control registers.
+ *
+ *	Port B isnt wired (why - beats me)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <net/arp.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/byteorder.h>
+#include "syncppp.h"
+#include "z85230.h"
+
+static int dma;
+
+struct sv11_device
+{
+	struct z8530_dev sync;
+	struct ppp_device netdev;
+	char name[16];
+};
+
+/*
+ *	Network driver support routines
+ */
+
+/*
+ *	Frame receive. Simple for our card as we do sync ppp and there
+ *	is no funny garbage involved
+ */
+ 
+static void hostess_input(struct z8530_channel *c, struct sk_buff *skb)
+{
+	/* Drop the CRC - its not a good idea to try and negotiate it ;) */
+	skb_trim(skb, skb->len-2);
+	skb->protocol=htons(ETH_P_WAN_PPP);
+	skb->mac.raw=skb->data;
+	skb->dev=c->netdevice;
+	/*
+	 *	Send it to the PPP layer. We dont have time to process
+	 *	it right now.
+	 */
+	netif_rx(skb);
+}
+ 
+/*
+ *	We've been placed in the UP state
+ */ 
+ 
+static int hostess_open(struct net_device *d)
+{
+	struct sv11_device *sv11=d->priv;
+	int err = -1;
+	
+	/*
+	 *	Link layer up
+	 */
+	switch(dma)
+	{
+		case 0:
+			err=z8530_sync_open(d, &sv11->sync.chanA);
+			break;
+		case 1:
+			err=z8530_sync_dma_open(d, &sv11->sync.chanA);
+			break;
+		case 2:
+			err=z8530_sync_txdma_open(d, &sv11->sync.chanA);
+			break;
+	}
+	
+	if(err)
+		return err;
+	/*
+	 *	Begin PPP
+	 */
+	err=sppp_open(d);
+	if(err)
+	{
+		switch(dma)
+		{
+			case 0:
+				z8530_sync_close(d, &sv11->sync.chanA);
+				break;
+			case 1:
+				z8530_sync_dma_close(d, &sv11->sync.chanA);
+				break;
+			case 2:
+				z8530_sync_txdma_close(d, &sv11->sync.chanA);
+				break;
+		}				
+		return err;
+	}
+	sv11->sync.chanA.rx_function=hostess_input;
+	
+	/*
+	 *	Go go go
+	 */
+	d->tbusy=0;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int hostess_close(struct net_device *d)
+{
+	struct sv11_device *sv11=d->priv;
+	/*
+	 *	Discard new frames
+	 */
+	sv11->sync.chanA.rx_function=z8530_null_rx;
+	/*
+	 *	PPP off
+	 */
+	sppp_close(d);
+	/*
+	 *	Link layer down
+	 */
+	d->tbusy=1;
+	
+	switch(dma)
+	{
+		case 0:
+			z8530_sync_close(d, &sv11->sync.chanA);
+			break;
+		case 1:
+			z8530_sync_dma_close(d, &sv11->sync.chanA);
+			break;
+		case 2:
+			z8530_sync_txdma_close(d, &sv11->sync.chanA);
+			break;
+	}
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int hostess_ioctl(struct net_device *d, struct ifreq *ifr, int cmd)
+{
+	/* struct sv11_device *sv11=d->priv;
+	   z8530_ioctl(d,&sv11->sync.chanA,ifr,cmd) */
+	return sppp_do_ioctl(d, ifr,cmd);
+}
+
+static struct enet_statistics *hostess_get_stats(struct net_device *d)
+{
+	struct sv11_device *sv11=d->priv;
+	if(sv11)
+		return z8530_get_stats(&sv11->sync.chanA);
+	else
+		return NULL;
+}
+
+/*
+ *	Passed PPP frames, fire them downwind.
+ */
+ 
+static int hostess_queue_xmit(struct sk_buff *skb, struct net_device *d)
+{
+	struct sv11_device *sv11=d->priv;
+	return z8530_queue_xmit(&sv11->sync.chanA, skb);
+}
+
+#ifdef LINUX_21
+static int hostess_neigh_setup(struct neighbour *n)
+{
+	if (n->nud_state == NUD_NONE) {
+		n->ops = &arp_broken_ops;
+		n->output = n->ops->output;
+	}
+	return 0;
+}
+
+static int hostess_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p)
+{
+	if (p->tbl->family == AF_INET) {
+		p->neigh_setup = hostess_neigh_setup;
+		p->ucast_probes = 0;
+		p->mcast_probes = 0;
+	}
+	return 0;
+}
+
+#else
+
+static int return_0(struct net_device *d)
+{
+	return 0;
+}
+
+#endif
+
+/*
+ *	Description block for a Comtrol Hostess SV11 card
+ */
+ 
+static struct sv11_device *sv11_init(int iobase, int irq)
+{
+	struct z8530_dev *dev;
+	struct sv11_device *sv;
+	int i;
+	unsigned long flags;
+	
+	/*
+	 *	Get the needed I/O space
+	 */
+	 
+	if(check_region(iobase, 8))
+	{	
+		printk(KERN_WARNING "hostess: I/O 0x%X already in use.\n", iobase);
+		return NULL;
+	}
+	request_region(iobase, 8, "Comtrol SV11");
+	
+	sv=(struct sv11_device *)kmalloc(sizeof(struct sv11_device), GFP_KERNEL);
+	if(!sv)
+		goto fail3;
+			
+	memset(sv, 0, sizeof(*sv));
+	
+	dev=&sv->sync;
+	
+	/*
+	 *	Stuff in the I/O addressing
+	 */
+	 
+	dev->active = 0;
+	
+	dev->chanA.ctrlio=iobase+1;
+	dev->chanA.dataio=iobase+3;
+	dev->chanB.ctrlio=-1;
+	dev->chanB.dataio=-1;
+	dev->chanA.irqs=&z8530_nop;
+	dev->chanB.irqs=&z8530_nop;
+	
+	outb(0, iobase+4);		/* DMA off */
+	
+	/* We want a fast IRQ for this device. Actually we'd like an even faster
+	   IRQ ;) - This is one driver RtLinux is made for */
+	   
+	if(request_irq(irq, &z8530_interrupt, SA_INTERRUPT, "Hostess SV/11", dev)<0)
+	{
+		printk(KERN_WARNING "hostess: IRQ %d already in use.\n", irq);
+		goto fail2;
+	}
+	
+	dev->irq=irq;
+	dev->chanA.private=sv;
+	dev->chanA.netdevice=&sv->netdev.dev;
+	dev->chanA.dev=dev;
+	dev->chanB.dev=dev;
+	dev->name=sv->name;
+	
+	if(dma)
+	{
+		/*
+		 *	You can have DMA off or 1 and 3 thats the lot
+		 *	on the Comtrol.
+		 */
+		dev->chanA.txdma=3;
+		dev->chanA.rxdma=1;
+		outb(0x03|0x08, iobase+4);		/* DMA on */
+		if(request_dma(dev->chanA.txdma, "Hostess SV/11 (TX)")!=0)
+			goto fail;
+			
+		if(dma==1)
+		{
+			if(request_dma(dev->chanA.rxdma, "Hostess SV/11 (RX)")!=0)
+				goto dmafail;
+		}
+	}
+	save_flags(flags);
+	cli();
+	
+	/*
+	 *	Begin normal initialise
+	 */
+	 
+	if(z8530_init(dev)!=0)
+	{
+		printk(KERN_ERR "Z8530 series device not found.\n");
+		goto dmafail2;
+	}
+	z8530_channel_load(&dev->chanB, z8530_dead_port);
+	if(dev->type==Z85C30)
+		z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream);
+	else
+		z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream_85230);
+	
+	restore_flags(flags);
+
+
+	/*
+	 *	Now we can take the IRQ
+	 */
+	
+	for(i=0;i<999;i++)
+	{
+		sprintf(sv->name,"hdlc%d", i);
+		if(dev_get(sv->name)==0)
+		{
+			struct net_device *d=dev->chanA.netdevice;
+	
+			/* 
+			 *	Initialise the PPP components
+			 */
+			sppp_attach(&sv->netdev);
+			
+			/*
+			 *	Local fields
+			 */	
+			sprintf(sv->name,"hdlc%d", i);
+			
+			d->name = sv->name;
+			d->base_addr = iobase;
+			d->irq = irq;
+			d->priv = sv;
+			d->init = NULL;
+			
+			d->open = hostess_open;
+			d->stop = hostess_close;
+			d->hard_start_xmit = hostess_queue_xmit;
+			d->get_stats = hostess_get_stats;
+			d->set_multicast_list = NULL;
+			d->do_ioctl = hostess_ioctl;
+#ifdef LINUX_21			
+			d->neigh_setup = hostess_neigh_setup_dev;
+			dev_init_buffers(d);
+#else
+			d->init = return_0;
+#endif
+			d->set_mac_address = NULL;
+			
+			if(register_netdev(d)==-1)
+			{
+				printk(KERN_ERR "%s: unable to register device.\n",
+					sv->name);
+				goto fail;
+			}				
+
+			z8530_describe(dev, "I/O", iobase);
+			dev->active=1;
+		 	return sv;	
+		}
+	}
+dmafail2:
+	if(dma==1)
+		free_dma(dev->chanA.rxdma);
+dmafail:
+	if(dma)
+		free_dma(dev->chanA.txdma);
+fail:
+	free_irq(irq, dev);
+fail2:
+	kfree(sv);
+fail3:
+	release_region(iobase,8);
+	return NULL;
+}
+
+static void sv11_shutdown(struct sv11_device *dev)
+{
+	sppp_detach(&dev->netdev.dev);
+	z8530_shutdown(&dev->sync);
+	unregister_netdev(&dev->netdev.dev);
+	free_irq(dev->sync.irq, dev);
+	if(dma)
+	{
+		if(dma==1)
+			free_dma(dev->sync.chanA.rxdma);
+		free_dma(dev->sync.chanA.txdma);
+	}
+	release_region(dev->sync.chanA.ctrlio-1, 8);
+}
+
+#ifdef MODULE
+
+static int io=0x200;
+static int irq=9;
+
+#ifdef LINUX_21
+MODULE_PARM(io,"i");
+MODULE_PARM_DESC(io, "The I/O base of the Comtrol Hostess SV11 card");
+MODULE_PARM(dma,"i");
+MODULE_PARM_DESC(dma, "Set this to 1 to use DMA1/DMA3 for TX/RX");
+MODULE_PARM(irq,"i");
+MODULE_PARM_DESC(irq, "The interrupt line setting for the Comtrol Hostess SV11 card");
+
+MODULE_AUTHOR("Bulding Number Three Ltd");
+MODULE_DESCRIPTION("Modular driver for the Comtrol Hostess SV11");
+#endif
+
+static struct sv11_device *sv11_unit;
+
+int init_module(void)
+{
+	printk(KERN_INFO "SV-11 Z85230 Synchronous Driver v 0.02.\n");
+	printk(KERN_INFO "(c) Copyright 1998, Building Number Three Ltd.\n");	
+	if((sv11_unit=sv11_init(io,irq))==NULL)
+		return -ENODEV;
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	if(sv11_unit)
+		sv11_shutdown(sv11_unit);
+}
+
+#endif
+
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/lapbether.c linux/drivers/net/wan/lapbether.c
--- v2.3.20/linux/drivers/net/wan/lapbether.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/lapbether.c	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,571 @@
+/*
+ *	"LAPB via ethernet" driver release 001
+ *
+ *	This code REQUIRES 2.1.15 or higher/ NET3.038
+ *
+ *	This module:
+ *		This module 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 is a "pseudo" network driver to allow LAPB over Ethernet.
+ *
+ *	This driver can use any ethernet destination address, and can be 
+ *	limited to accept frames from one dedicated ethernet card only.
+ *
+ *	History
+ *	LAPBETH 001	Jonathan Naylor		Cloned from bpqether.c
+ */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/net.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/notifier.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/netfilter.h>
+#include <linux/module.h>
+#include <linux/lapb.h>
+#include <linux/init.h>
+
+static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
+
+static int lapbeth_rcv(struct sk_buff *, struct net_device *, struct packet_type *);
+static int lapbeth_device_event(struct notifier_block *, unsigned long, void *);
+
+static struct packet_type lapbeth_packet_type = {
+	0,		/* ntohs(ETH_P_DEC),*/
+	0,		/* copy */
+	lapbeth_rcv,
+	NULL,
+	NULL,
+};
+
+static struct notifier_block lapbeth_dev_notifier = {
+	lapbeth_device_event,
+	0
+};
+
+
+#define MAXLAPBDEV 100
+
+static struct lapbethdev {
+	struct lapbethdev *next;
+	char   ethname[14];		/* ether device name */
+	struct net_device *ethdev;		/* link to ethernet device */
+	struct net_device axdev;		/* lapbeth device (lapb#) */
+	struct net_device_stats stats;	/* some statistics */
+} *lapbeth_devices = NULL;
+
+
+/* ------------------------------------------------------------------------ */
+
+
+/*
+ *	Get the ethernet device for a LAPB device
+ */
+static __inline__ struct net_device *lapbeth_get_ether_dev(struct net_device *dev)
+{
+	struct lapbethdev *lapbeth;
+	
+	lapbeth = (struct lapbethdev *)dev->priv;
+
+	return (lapbeth != NULL) ? lapbeth->ethdev : NULL;
+}
+
+/*
+ *	Get the LAPB device for the ethernet device
+ */
+static __inline__ struct net_device *lapbeth_get_x25_dev(struct net_device *dev)
+{
+	struct lapbethdev *lapbeth;
+
+	for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth->next)
+		if (lapbeth->ethdev == dev)
+			return &lapbeth->axdev;
+
+	return NULL;
+}
+
+static __inline__ int dev_is_ethdev(struct net_device *dev)
+{
+	return (
+			dev->type == ARPHRD_ETHER
+			&& strncmp(dev->name, "dummy", 5)
+	);
+}
+
+/*
+ *	Sanity check: remove all devices that ceased to exists and
+ *	return '1' if the given LAPB device was affected.
+ */
+static int lapbeth_check_devices(struct net_device *dev)
+{
+	struct lapbethdev *lapbeth, *lapbeth_prev;
+	int result = 0;
+	unsigned long flags;
+	
+	save_flags(flags);
+	cli();
+
+	lapbeth_prev = NULL;
+
+	for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth->next) {
+		if (!dev_get(lapbeth->ethname)) {
+			if (lapbeth_prev)
+				lapbeth_prev->next = lapbeth->next;
+			else
+				lapbeth_devices = lapbeth->next;
+				
+			if (&lapbeth->axdev == dev)
+				result = 1;
+
+			unregister_netdev(&lapbeth->axdev);
+			kfree(lapbeth);
+		}
+
+		lapbeth_prev = lapbeth;
+	}
+	
+	restore_flags(flags);
+	
+	return result;
+}
+
+
+/* ------------------------------------------------------------------------ */
+
+
+/*
+ *	Receive a LAPB frame via an ethernet interface.
+ */
+static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype)
+{
+	int len, err;
+	struct lapbethdev *lapbeth;
+
+	skb->sk = NULL;		/* Initially we don't know who it's for */
+	
+	dev = lapbeth_get_x25_dev(dev);
+
+	if (dev == NULL || dev->start == 0) {
+		kfree_skb(skb);
+		return 0;
+	}
+
+	lapbeth = (struct lapbethdev *)dev->priv;
+
+	lapbeth->stats.rx_packets++;
+
+	len = skb->data[0] + skb->data[1] * 256;
+
+	skb_pull(skb, 2);	/* Remove the length bytes */
+	skb_trim(skb, len);	/* Set the length of the data */
+
+	if ((err = lapb_data_received(lapbeth, skb)) != LAPB_OK) {
+		kfree_skb(skb);
+		printk(KERN_DEBUG "lapbether: lapb_data_received err - %d\n", err);
+	}
+
+	return 0;
+}
+
+static void lapbeth_data_indication(void *token, struct sk_buff *skb)
+{
+	struct lapbethdev *lapbeth = (struct lapbethdev *)token;
+	unsigned char *ptr;
+
+	ptr  = skb_push(skb, 1);
+	*ptr = 0x00;
+
+	skb->dev      = &lapbeth->axdev;
+	skb->protocol = htons(ETH_P_X25);
+	skb->mac.raw  = skb->data;
+	skb->pkt_type = PACKET_HOST;
+
+	netif_rx(skb);
+}
+
+/*
+ * 	Send a LAPB frame via an ethernet interface
+ */
+static int lapbeth_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct lapbethdev *lapbeth;
+	int err;
+	
+	lapbeth = (struct lapbethdev *)dev->priv;
+
+	/*
+	 * Just to be *really* sure not to send anything if the interface
+	 * is down, the ethernet device may have gone.
+	 */
+	if (!dev->start) {
+		lapbeth_check_devices(dev);
+		kfree_skb(skb);
+		return -ENODEV;
+	}
+
+	switch (skb->data[0]) {
+		case 0x00:
+			break;
+		case 0x01:
+			if ((err = lapb_connect_request(lapbeth)) != LAPB_OK)
+				printk(KERN_ERR "lapbeth: lapb_connect_request error - %d\n", err);
+			kfree_skb(skb);
+			return 0;
+		case 0x02:
+			if ((err = lapb_disconnect_request(lapbeth)) != LAPB_OK)
+				printk(KERN_ERR "lapbeth: lapb_disconnect_request err - %d\n", err);
+			kfree_skb(skb);
+			return 0;
+		default:
+			kfree_skb(skb);
+			return 0;
+	}
+
+	skb_pull(skb, 1);
+
+	if ((err = lapb_data_request(lapbeth, skb)) != LAPB_OK) {
+		printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err);
+		kfree_skb(skb);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+	
+static void lapbeth_data_transmit(void *token, struct sk_buff *skb)
+{
+	struct lapbethdev *lapbeth = (struct lapbethdev *)token;
+	unsigned char *ptr;
+	struct net_device *dev;
+	int size;
+
+	skb->protocol = htons(ETH_P_X25);
+
+	size = skb->len;
+
+	ptr = skb_push(skb, 2);
+
+	*ptr++ = size % 256;
+	*ptr++ = size / 256;
+
+	lapbeth->stats.tx_packets++;
+
+	skb->dev = dev = lapbeth->ethdev;
+
+	dev->hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0);
+
+	dev_queue_xmit(skb);
+}
+
+static void lapbeth_connected(void *token, int reason)
+{
+	struct lapbethdev *lapbeth = (struct lapbethdev *)token;
+	struct sk_buff *skb;
+	unsigned char *ptr;
+
+	if ((skb = dev_alloc_skb(1)) == NULL) {
+		printk(KERN_ERR "lapbeth: out of memory\n");
+		return;
+	}
+
+	ptr  = skb_put(skb, 1);
+	*ptr = 0x01;
+
+	skb->dev      = &lapbeth->axdev;
+	skb->protocol = htons(ETH_P_X25);
+	skb->mac.raw  = skb->data;
+	skb->pkt_type = PACKET_HOST;
+
+	netif_rx(skb);
+}
+
+static void lapbeth_disconnected(void *token, int reason)
+{
+	struct lapbethdev *lapbeth = (struct lapbethdev *)token;
+	struct sk_buff *skb;
+	unsigned char *ptr;
+
+	if ((skb = dev_alloc_skb(1)) == NULL) {
+		printk(KERN_ERR "lapbeth: out of memory\n");
+		return;
+	}
+
+	ptr  = skb_put(skb, 1);
+	*ptr = 0x02;
+
+	skb->dev      = &lapbeth->axdev;
+	skb->protocol = htons(ETH_P_X25);
+	skb->mac.raw  = skb->data;
+	skb->pkt_type = PACKET_HOST;
+
+	netif_rx(skb);
+}
+
+/*
+ *	Statistics
+ */
+static struct net_device_stats *lapbeth_get_stats(struct net_device *dev)
+{
+	struct lapbethdev *lapbeth;
+
+	lapbeth = (struct lapbethdev *)dev->priv;
+
+	return &lapbeth->stats;
+}
+
+/*
+ *	Set AX.25 callsign
+ */
+static int lapbeth_set_mac_address(struct net_device *dev, void *addr)
+{
+    struct sockaddr *sa = (struct sockaddr *)addr;
+
+    memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
+
+    return 0;
+}
+
+static int lapbeth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	return -EINVAL;
+}
+
+/*
+ * open/close a device
+ */
+static int lapbeth_open(struct net_device *dev)
+{
+	struct lapb_register_struct lapbeth_callbacks;
+	struct lapbethdev *lapbeth;
+	int err;
+
+	if (lapbeth_check_devices(dev))
+		return -ENODEV;		/* oops, it's gone */
+	
+	dev->tbusy = 0;
+	dev->start = 1;
+
+	lapbeth = (struct lapbethdev *)dev->priv;
+
+	lapbeth_callbacks.connect_confirmation    = lapbeth_connected;
+	lapbeth_callbacks.connect_indication      = lapbeth_connected;
+	lapbeth_callbacks.disconnect_confirmation = lapbeth_disconnected;
+	lapbeth_callbacks.disconnect_indication   = lapbeth_disconnected;
+	lapbeth_callbacks.data_indication         = lapbeth_data_indication;
+	lapbeth_callbacks.data_transmit           = lapbeth_data_transmit;
+
+	if ((err = lapb_register(lapbeth, &lapbeth_callbacks)) != LAPB_OK) {
+		printk(KERN_ERR "lapbeth: lapb_register error - %d\n", err);
+		dev->tbusy = 1;
+		dev->start = 0;
+		return -ENODEV;
+	}
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+static int lapbeth_close(struct net_device *dev)
+{
+	struct lapbethdev *lapbeth;
+	int err;
+
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	lapbeth = (struct lapbethdev *)dev->priv;
+
+	if ((err = lapb_unregister(lapbeth)) != LAPB_OK)
+		printk(KERN_ERR "lapbeth: lapb_unregister error - %d\n", err);
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static int lapbeth_dev_init(struct net_device *dev)
+{
+	return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+/*
+ *	Setup a new device.
+ */
+static int lapbeth_new_device(struct net_device *dev)
+{
+	int k;
+	unsigned char *buf;
+	struct lapbethdev *lapbeth, *lapbeth2;
+	
+	if ((lapbeth = kmalloc(sizeof(struct lapbethdev), GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+		
+	memset(lapbeth, 0, sizeof(struct lapbethdev));
+	
+	lapbeth->ethdev = dev;
+
+	lapbeth->ethname[sizeof(lapbeth->ethname)-1] = '\0';
+	strncpy(lapbeth->ethname, dev->name, sizeof(lapbeth->ethname)-1);
+
+	dev = &lapbeth->axdev;
+	buf = kmalloc(14, GFP_KERNEL);
+
+	for (k = 0; k < MAXLAPBDEV; k++) {
+		struct net_device *odev;
+
+		sprintf(buf, "lapb%d", k);
+
+		if ((odev = __dev_get_by_name(buf)) == NULL || lapbeth_check_devices(odev))
+			break;
+	}
+
+	if (k == MAXLAPBDEV) {
+		kfree(lapbeth);
+		return -ENODEV;
+	}
+	
+	dev->priv = (void *)lapbeth;	/* pointer back */
+	dev->name = buf;
+	dev->init = lapbeth_dev_init;
+
+	if (register_netdev(dev) != 0) {
+		kfree(lapbeth);
+                return -EIO;
+        }
+
+	dev_init_buffers(dev);
+
+	dev->hard_start_xmit = lapbeth_xmit;
+	dev->open	     = lapbeth_open;
+	dev->stop	     = lapbeth_close;
+	dev->set_mac_address = lapbeth_set_mac_address;
+	dev->get_stats	     = lapbeth_get_stats;
+	dev->do_ioctl	     = lapbeth_ioctl;
+
+	dev->flags      = 0;
+
+	dev->type            = ARPHRD_X25;
+	dev->hard_header_len = 3;
+	dev->mtu             = 1000;
+	dev->addr_len        = 0;
+
+	cli();
+
+	if (lapbeth_devices == NULL) {
+		lapbeth_devices = lapbeth;
+	} else {
+		for (lapbeth2 = lapbeth_devices; lapbeth2->next != NULL; lapbeth2 = lapbeth2->next);
+		lapbeth2->next = lapbeth;
+	}
+	
+	sti();
+
+	return 0;
+}
+
+
+/*
+ *	Handle device status changes.
+ */
+static int lapbeth_device_event(struct notifier_block *this,unsigned long event, void *ptr)
+{
+	struct net_device *dev = (struct net_device *)ptr;
+	
+	if (!dev_is_ethdev(dev))
+		return NOTIFY_DONE;
+
+	lapbeth_check_devices(NULL);
+
+	switch (event) {
+		case NETDEV_UP:		/* new ethernet device -> new LAPB interface */
+			if (lapbeth_get_x25_dev(dev) == NULL)
+				lapbeth_new_device(dev);
+			break;
+
+		case NETDEV_DOWN:	/* ethernet device closed -> close LAPB interface */
+			if ((dev = lapbeth_get_x25_dev(dev)) != NULL)
+				dev_close(dev);
+			break;
+
+		default:
+			break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+
+/* ------------------------------------------------------------------------ */
+
+/*
+ * Initialize driver. To be called from af_ax25 if not compiled as a
+ * module
+ */
+int lapbeth_init(void)
+{
+	struct net_device *dev;
+
+	lapbeth_packet_type.type  = htons(ETH_P_DEC);
+	dev_add_pack(&lapbeth_packet_type);
+
+	register_netdevice_notifier(&lapbeth_dev_notifier);
+
+	printk(KERN_INFO "LAPB Ethernet driver version 0.01\n");
+
+	read_lock_bh(&dev_base_lock);
+	for (dev = dev_base; dev != NULL; dev = dev->next) {
+		if (dev_is_ethdev(dev)) {
+			read_unlock_bh(&dev_base_lock);
+			lapbeth_new_device(dev);
+			read_lock_bh(&dev_base_lock);
+		}
+	}
+	read_unlock_bh(&dev_base_lock);
+
+	return 0;
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");
+MODULE_DESCRIPTION("The unofficial LAPB over Ethernet driver");
+
+int init_module(void)
+{
+	return lapbeth_init();
+}
+
+void cleanup_module(void)
+{
+	struct lapbethdev *lapbeth;
+
+	dev_remove_pack(&lapbeth_packet_type);
+
+	unregister_netdevice_notifier(&lapbeth_dev_notifier);
+
+	for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth->next)
+		unregister_netdev(&lapbeth->axdev);
+}
+#endif
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/sbni.c linux/drivers/net/wan/sbni.c
--- v2.3.20/linux/drivers/net/wan/sbni.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/sbni.c	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,1533 @@
+/*
+ * Driver for Granch SBNI-12 leased line network adapters.
+ * 
+ * Copyright 1997 - 1999, Granch ltd.
+ * Written 1999 by Yaroslav Polyakov (xenon@granch.ru).
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License, incorporated herein by reference.
+ * 
+ *   // Whole developers team:
+ *   //   Yaroslav Polyakov (xenon@granch.ru)
+ *   //      - main developer of this version
+ *   //   Alexey Zverev (zverev@granch.ru)
+ *   //      - previous SBNI driver for linux
+ *   //   Alexey Chirkov (chirkov@granch.ru)
+ *   //      - all the hardware work and consulting
+ *   //   Max Khon (max@iclub.nsu.ru)
+ *   //      - first SBNI driver for linux
+ *   // --------------------------------------------
+ *   // also I thank: 
+ *   //   Max Krasnyansky (max@uznet.net)
+ *   //      - for bug hunting and many ideas
+ *   //   Alan Cox (Alan.Cox@linux.org)
+ *   //	     - for consulting in some hardcore questions
+ *   //   Donald Becker (becker@cesdis.gsfc.nasa.gov)
+ *   //      - for pretty nice skeleton 
+ * 
+ *   More info and useful utilities to work w/ SBNI you can find at 
+ *   http://www.granch.ru.
+ *
+ *  3.0.0 = Initial Revision, Yaroslav Polyakov (24 Feb 1999)
+ *        - added pre-calculation for CRC, fixed bug with "len-2" frames, 
+ *        - removed outbound fragmentation (MTU=1000), written CRC-calculation 
+ *        - on asm, added work with hard_headers and now we have our own cache 
+ *        - for them, optionally supported word-interchange on some chipsets,
+ *        - something else I cant remember ;) 
+ * 
+ *  3.0.1 = just fixed some bugs (14 apr 1999).
+ * 	  - fixed statistical tx bug 
+ *        - fixed wrong creation dates (1998 -> 1999) in driver source code ;)
+ * 	  - fixed source address bug.
+ *        - fixed permanent nirvana bug 
+ * 
+ *  3.1.0 = (Katyusha) (26 apr 1999)
+ *        - Added balancing feature
+ * 
+ *  3.1.1 = (Medea) (5 aug 1999)
+ *        - Fixed mac.raw bug
+ *	  - Thanks to tolix@olviko.ru and 
+ *        - to Barnaul Brewery, producers of my favorite beer "Medea".
+ *
+ *
+ */
+
+
+#undef GOODBUS16
+#define CRCASM
+#define KATYUSHA
+
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE >=0x020200
+#define v22
+#endif
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/fcntl.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#include <asm/io.h>
+#include <asm/types.h>
+#include <asm/byteorder.h>
+
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/timer.h>
+#include <linux/config.h>	/* for CONFIG_INET. do we need this?*/
+
+#include <net/arp.h>
+
+
+
+#ifdef v22
+#include <asm/uaccess.h>
+#include <linux/init.h>
+#endif
+
+#include "sbni.h"
+
+
+static const char *version = 
+"sbni.c: ver. 3.1.1 Medea 5 Aug 1999 Yaroslav Polyakov (xenon@granch.ru)\n";
+
+int sbni_probe(struct net_device *dev);
+static int  sbni_probe1(struct net_device *dev, int ioaddr);
+static int  sbni_open(struct net_device *dev);
+static int  sbni_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void sbni_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int  sbni_close(struct net_device *dev);
+static void sbni_drop_tx_queue(struct net_device *dev);
+static struct enet_statistics *sbni_get_stats(struct net_device *dev);
+void card_start(struct net_device *dev);
+static inline unsigned short sbni_recv(struct net_device *dev);
+void change_level(struct net_device *dev);
+static inline void sbni_xmit(struct net_device *dev);
+static inline void sbni_get_packet(struct net_device* dev);
+static void sbni_watchdog(unsigned long arg);
+static void set_multicast_list(struct net_device *dev);
+static int sbni_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+static int sbni_set_mac_address(struct net_device *dev, void *addr);
+unsigned long calc_crc(char *mem, int len, unsigned initial);
+void sbni_nirvana(struct net_device *dev);
+static int sbni_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
+		void *daddr, void *saddr, unsigned len);
+
+static int sbni_rebuild_header(struct sk_buff *skb);
+static int sbni_header_cache(struct neighbour *neigh, struct hh_cache *hh);
+
+static inline void sbni_outs(int port, void *data, int len);
+static inline void sbni_ins(int port, void *data, int len);
+
+
+
+#define SIZE_OF_TIMEOUT_RXL_TAB 4
+static u_char timeout_rxl_tab[] = {
+  0x03, 0x05, 0x08, 0x0b
+};
+
+static u_char rxl_tab[] = {
+  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 
+  0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f
+};
+
+/* A zero-terminated list of I/O addresses to be probed */
+static unsigned int netcard_portlist[] =  { 
+	0x210, 0x2c0, 0x2d0, 0x2f0, 0x220, 0x230, 0x240, 0x250, 
+	0x260, 0x290, 0x2a0, 0x2b0, 0x224, 0x234, 0x244, 0x254, 
+	0x264, 0x294, 0x2a4, 0x2b4, 0};
+
+static unsigned char magic_reply[] = {
+	0x5a,0x06,0x30,0x00,0x00,0x50,0x65,0x44,0x20
+};
+
+static int def_baud = DEF_RATE;
+static int def_rxl = DEF_RXL_DELTA;
+static long def_mac = 0;
+
+
+/*
+ * CRC-32 stuff
+ */
+
+#define CRC32(c,crc) (crc32tab[((size_t)(crc) ^ (c)) & 0xff] ^ (((crc) >> 8) & 0x00FFFFFF))
+/* CRC generator 0xEDB88320 */
+/* CRC remainder 0x2144DF1C */
+/* CRC initial value 0x00000000 */
+#define CRC32_REMAINDER 0x2144DF1C
+#define CRC32_INITIAL 0x00000000
+
+static unsigned long crc32tab[] = {
+	0xD202EF8D,  0xA505DF1B,  0x3C0C8EA1,  0x4B0BBE37,
+	0xD56F2B94,  0xA2681B02,  0x3B614AB8,  0x4C667A2E,
+	0xDCD967BF,  0xABDE5729,  0x32D70693,  0x45D03605,
+	0xDBB4A3A6,  0xACB39330,  0x35BAC28A,  0x42BDF21C,
+	0xCFB5FFE9,  0xB8B2CF7F,  0x21BB9EC5,  0x56BCAE53,
+	0xC8D83BF0,  0xBFDF0B66,  0x26D65ADC,  0x51D16A4A,
+	0xC16E77DB,  0xB669474D,  0x2F6016F7,  0x58672661,
+	0xC603B3C2,  0xB1048354,  0x280DD2EE,  0x5F0AE278,
+	0xE96CCF45,  0x9E6BFFD3,  0x0762AE69,  0x70659EFF,
+	0xEE010B5C,  0x99063BCA,  0x000F6A70,  0x77085AE6,
+	0xE7B74777,  0x90B077E1,  0x09B9265B,  0x7EBE16CD,
+	0xE0DA836E,  0x97DDB3F8,  0x0ED4E242,  0x79D3D2D4,
+	0xF4DBDF21,  0x83DCEFB7,  0x1AD5BE0D,  0x6DD28E9B,
+	0xF3B61B38,  0x84B12BAE,  0x1DB87A14,  0x6ABF4A82,
+	0xFA005713,  0x8D076785,  0x140E363F,  0x630906A9,
+	0xFD6D930A,  0x8A6AA39C,  0x1363F226,  0x6464C2B0,
+	0xA4DEAE1D,  0xD3D99E8B,  0x4AD0CF31,  0x3DD7FFA7,
+	0xA3B36A04,  0xD4B45A92,  0x4DBD0B28,  0x3ABA3BBE,
+	0xAA05262F,  0xDD0216B9,  0x440B4703,  0x330C7795,
+	0xAD68E236,  0xDA6FD2A0,  0x4366831A,  0x3461B38C,
+	0xB969BE79,  0xCE6E8EEF,  0x5767DF55,  0x2060EFC3,
+	0xBE047A60,  0xC9034AF6,  0x500A1B4C,  0x270D2BDA,
+	0xB7B2364B,  0xC0B506DD,  0x59BC5767,  0x2EBB67F1,
+	0xB0DFF252,  0xC7D8C2C4,  0x5ED1937E,  0x29D6A3E8,
+	0x9FB08ED5,  0xE8B7BE43,  0x71BEEFF9,  0x06B9DF6F,
+	0x98DD4ACC,  0xEFDA7A5A,  0x76D32BE0,  0x01D41B76,
+	0x916B06E7,  0xE66C3671,  0x7F6567CB,  0x0862575D,
+	0x9606C2FE,  0xE101F268,  0x7808A3D2,  0x0F0F9344,
+	0x82079EB1,  0xF500AE27,  0x6C09FF9D,  0x1B0ECF0B,
+	0x856A5AA8,  0xF26D6A3E,  0x6B643B84,  0x1C630B12,	
+	0x8CDC1683,  0xFBDB2615,  0x62D277AF,  0x15D54739,
+	0x8BB1D29A,  0xFCB6E20C,  0x65BFB3B6,  0x12B88320,
+	0x3FBA6CAD,  0x48BD5C3B,  0xD1B40D81,  0xA6B33D17,
+	0x38D7A8B4,  0x4FD09822,  0xD6D9C998,  0xA1DEF90E,
+	0x3161E49F,  0x4666D409,  0xDF6F85B3,  0xA868B525,
+	0x360C2086,  0x410B1010,  0xD80241AA,  0xAF05713C,
+	0x220D7CC9,  0x550A4C5F,  0xCC031DE5,  0xBB042D73,
+	0x2560B8D0,  0x52678846,  0xCB6ED9FC,  0xBC69E96A,
+	0x2CD6F4FB,  0x5BD1C46D,  0xC2D895D7,  0xB5DFA541,
+	0x2BBB30E2,  0x5CBC0074,  0xC5B551CE,  0xB2B26158,
+	0x04D44C65,  0x73D37CF3,  0xEADA2D49,  0x9DDD1DDF,
+	0x03B9887C,  0x74BEB8EA,  0xEDB7E950,  0x9AB0D9C6,
+	0x0A0FC457,  0x7D08F4C1,  0xE401A57B,  0x930695ED,
+	0x0D62004E,  0x7A6530D8,  0xE36C6162,  0x946B51F4,
+	0x19635C01,  0x6E646C97,  0xF76D3D2D,  0x806A0DBB,
+	0x1E0E9818,  0x6909A88E,  0xF000F934,  0x8707C9A2,
+	0x17B8D433,  0x60BFE4A5,  0xF9B6B51F,  0x8EB18589,
+	0x10D5102A,  0x67D220BC,  0xFEDB7106,  0x89DC4190,
+	0x49662D3D,  0x3E611DAB,  0xA7684C11,  0xD06F7C87,
+	0x4E0BE924,  0x390CD9B2,  0xA0058808,  0xD702B89E,
+	0x47BDA50F,  0x30BA9599,  0xA9B3C423,  0xDEB4F4B5,
+	0x40D06116,  0x37D75180,  0xAEDE003A,  0xD9D930AC,
+	0x54D13D59,  0x23D60DCF,  0xBADF5C75,  0xCDD86CE3,
+	0x53BCF940,  0x24BBC9D6,  0xBDB2986C,  0xCAB5A8FA,
+	0x5A0AB56B,  0x2D0D85FD,  0xB404D447,  0xC303E4D1,
+	0x5D677172,  0x2A6041E4,  0xB369105E,  0xC46E20C8,
+	0x72080DF5,  0x050F3D63,  0x9C066CD9,  0xEB015C4F,
+	0x7565C9EC,  0x0262F97A,  0x9B6BA8C0,  0xEC6C9856,
+	0x7CD385C7,  0x0BD4B551,  0x92DDE4EB,  0xE5DAD47D,
+	0x7BBE41DE,  0x0CB97148,  0x95B020F2,  0xE2B71064,
+	0x6FBF1D91,  0x18B82D07,  0x81B17CBD,  0xF6B64C2B,
+	0x68D2D988,  0x1FD5E91E,  0x86DCB8A4,  0xF1DB8832,
+	0x616495A3,  0x1663A535,  0x8F6AF48F,  0xF86DC419,
+	0x660951BA,  0x110E612C,  0x88073096,  0xFF000000
+};
+
+static inline void sbni_outs(int port, void *data, int len)
+{
+#ifdef GOODBUS16
+	outsw(port,data,len/2);
+	if(len & 1)
+		outb(((char*)data)[len - 1],port);
+#else
+	outsb(port,data,len);
+#endif
+}
+
+static inline void sbni_ins(int port, void *data, int len)
+{
+#ifdef GOODBUS16
+	insw(port,data,len/2);
+	if(len & 1)
+		((char*)data)[len - 1] = inb(port);
+#else
+	insb(port,data,len);
+#endif
+}
+
+
+static int sbni_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
+	   void *daddr, void *saddr, unsigned len)
+{
+	struct sbni_hard_header *hh = (struct sbni_hard_header *) 
+			skb_push(skb, sizeof(struct sbni_hard_header));
+  
+  
+	if(type!=ETH_P_802_3) 
+		hh->h_proto = htons(type);
+	else
+		hh->h_proto = htons(len);
+  
+	if(saddr)
+		memcpy(hh->h_source,saddr,dev->addr_len);
+	else
+		memcpy(hh->h_source,dev->dev_addr,dev->addr_len);
+
+	if(daddr)
+	{
+		memcpy(hh->h_dest,daddr,dev->addr_len);
+		return dev->hard_header_len;
+	} 
+	return -dev->hard_header_len;
+}
+
+
+int sbni_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+{
+	unsigned short type = hh->hh_type;
+	struct sbni_hard_header *sbni = (struct sbni_hard_header*)
+						(((u8*)hh->hh_data) - 8);
+	struct net_device *dev = neigh->dev;
+  
+  
+	if (type == __constant_htons(ETH_P_802_3))
+		return -1;
+  
+	sbni->h_proto = type;
+	memcpy(sbni->h_source, dev->dev_addr, dev->addr_len);
+	memcpy(sbni->h_dest, neigh->ha, dev->addr_len);
+	return 0;
+}
+
+static int sbni_rebuild_header(struct sk_buff *skb)
+{
+	struct sbni_hard_header *hh = (struct sbni_hard_header *)skb;
+	/*
+	 *	Only ARP/IP is currently supported
+	 */
+
+	/*
+	 *	Try to get ARP to resolve the header.
+	 */
+  
+#ifdef CONFIG_INET
+  	return arp_find((unsigned char*)hh->h_dest, skb)? 1 : 0;  
+#else
+	return 0;	
+#endif	
+}
+
+static void sbni_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr)
+{
+	memcpy(((u8*)hh->hh_data) + 2, haddr, dev->addr_len);
+}
+
+
+
+#ifdef HAVE_DEVLIST
+struct netdev_entry sbni_drv = {
+	"sbni", sbni_probe1, SBNI_IO_EXTENT, netcard_portlist 
+};
+
+#else
+
+int __init sbni_probe(struct net_device *dev)
+{
+	int i;
+	int base_addr = dev ? dev->base_addr : 0;
+	
+	DP( printk("%s: sbni_probe\n", dev->name); )
+
+	if(base_addr > 0x1ff)	/* Check a single specified location. */
+		return sbni_probe1(dev, base_addr);
+	else if(base_addr != 0)	/* Don't probe at all. */
+		return ENXIO;
+	for(i = 0; (base_addr = netcard_portlist[i]); i++)
+	{ 
+		if(!check_region(base_addr, SBNI_IO_EXTENT) && base_addr != 1)
+		{
+			/* Lock this address, or later we'll try it again */
+			netcard_portlist[i] = 1;
+			if(sbni_probe1(dev, base_addr) == 0)
+				return 0;
+		}
+	}
+	return ENODEV;
+}
+
+#endif /* have devlist*/
+
+/*
+ *	The actual probe. 
+ */
+
+/*
+	Valid combinations in CSR0 (for probing):
+
+	VALID_DECODER	0000,0011,1011,1010
+
+				    	; 0   ; -
+				TR_REQ	; 1   ; +
+			TR_RDY	    	; 2   ; -
+			TR_RDY	TR_REQ	; 3   ; +
+		BU_EMP		    	; 4   ; +
+		BU_EMP	     	TR_REQ	; 5   ; +
+		BU_EMP	TR_RDY	    	; 6   ; -
+		BU_EMP	TR_RDY	TR_REQ	; 7   ; +
+	RC_RDY 		     		; 8   ; +
+	RC_RDY			TR_REQ	; 9   ; +
+	RC_RDY		TR_RDY		; 10  ; -
+	RC_RDY		TR_RDY	TR_REQ	; 11  ; -
+	RC_RDY	BU_EMP			; 12  ; -
+	RC_RDY	BU_EMP		TR_REQ	; 13  ; -
+	RC_RDY	BU_EMP	TR_RDY		; 14  ; -
+	RC_RDY	BU_EMP	TR_RDY	TR_REQ	; 15  ; -
+*/
+#define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200)
+
+static int __init sbni_probe1(struct net_device *dev, int ioaddr)
+
+{
+	int autoirq = 0;
+	int bad_card = 0;
+	unsigned char csr0;
+	struct net_local* lp;
+	static int version_printed = 0;
+
+	DP( printk("%s: sbni_probe1 ioaddr=%d\n", dev->name, ioaddr); )
+       
+	if(check_region(ioaddr, SBNI_IO_EXTENT) < 0)
+		return -ENODEV;
+	if(version_printed++ == 0)
+		printk(version);
+     
+	/* check for valid combination in CSR0 */
+	csr0 = inb(ioaddr + CSR0);
+	if(csr0 == 0xff || csr0 == 0)
+		bad_card = 1;
+	else 
+	{
+		csr0 &= ~EN_INT;
+		if(csr0 & BU_EMP)
+			csr0 |= EN_INT;
+		if((VALID_DECODER & (1 << (csr0 >> 4))) == 0)
+			bad_card = 1;
+	}
+
+	if(bad_card)
+		return ENODEV;
+	else
+		outb(0, ioaddr + CSR0); 
+	if(dev->irq < 2)
+	{
+		DP( printk("%s: autoprobing\n", dev->name); );
+		autoirq_setup(5);
+		outb(EN_INT | TR_REQ, ioaddr + CSR0);
+		outb(PR_RES, ioaddr + CSR1);
+		autoirq = autoirq_report(5);
+
+		if(autoirq == 0)
+		{
+			printk("sbni probe at %#x failed to detect IRQ line\n", ioaddr);
+			return EAGAIN;
+		}
+	}
+	/* clear FIFO buffer */
+	outb(0, ioaddr + CSR0);
+   
+	if(autoirq)
+		dev->irq = autoirq;
+
+	{
+   		int irqval=request_irq(dev->irq, sbni_interrupt, 0, dev->name, dev);
+		if (irqval) 
+		{
+			printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval);
+			return EAGAIN;
+		}
+	}
+     
+	/* 
+	 *	Initialize the device structure. 
+	 */
+
+	dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+	if(dev->priv == NULL)
+	{
+		DP( printk("%s: cannot allocate memory\n", dev->name); )
+		return -ENOMEM;
+	}
+   
+	memset(dev->priv, 0, sizeof(struct net_local));
+	dev->base_addr = ioaddr;
+	request_region(ioaddr, SBNI_IO_EXTENT, "sbni");
+
+	/* 
+	 * generate Ethernet address (0x00ff01xxxxxx)
+	 */
+
+	*(u16*)dev->dev_addr = htons(0x00ff);
+	*(u32*)(dev->dev_addr+2) = htonl(((def_mac ? def_mac : (u32) dev->priv) & 0x00ffffff) | 0x01000000);
+   
+	lp = dev->priv;
+	if(def_rxl < 0)
+	{
+		/* autodetect receive level */
+		lp->rxl_curr = 0xf;
+		lp->rxl_delta = -1;
+	} else {
+		/* fixed receive level */
+		lp->rxl_curr = def_rxl & 0xf;
+		lp->rxl_delta = 0;
+	}
+	lp->csr1.rxl = rxl_tab[lp->rxl_curr];
+	lp->csr1.rate = def_baud & 3;
+	lp->frame_len = DEF_FRAME_LEN;
+	printk("%s: sbni adapter at %#lx, using %sIRQ %d, MAC: 00:ff:01:%x:%x:%x\n", 
+		dev->name, dev->base_addr, autoirq ? "auto":"assigned ", dev->irq,
+	       *(unsigned char*)(dev->dev_addr+3),
+	       *(unsigned char*)(dev->dev_addr+4),
+	       *(unsigned char*)(dev->dev_addr+5)
+	);
+
+	printk("%s: receive level: ", dev->name);
+	if(lp->rxl_delta == 0)
+		printk ("%#1x (fixed)", lp->rxl_curr); 
+	else
+		printk ("autodetect");
+	printk(", baud rate: %u\n", (unsigned)lp->csr1.rate);
+   
+	/*
+	 *	The SBNI-specific entries in the device structure. 
+	 */
+	dev->open = &sbni_open;
+	dev->hard_start_xmit = &sbni_start_xmit;
+	dev->stop = &sbni_close;
+	dev->get_stats = &sbni_get_stats;
+	dev->set_multicast_list = &set_multicast_list;
+	dev->set_mac_address = &sbni_set_mac_address;
+	dev->do_ioctl = &sbni_ioctl;
+   
+	/*
+	 *	Setup the generic properties 
+	 */
+
+	ether_setup(dev);
+   
+	dev->hard_header = sbni_header;
+	dev->hard_header_len = sizeof(struct sbni_hard_header);
+	dev->rebuild_header=sbni_rebuild_header;
+	dev->mtu = DEF_FRAME_LEN;
+
+	dev->hard_header_cache = sbni_header_cache;
+	dev->header_cache_update = sbni_header_cache_update;
+  
+	lp->m=dev;
+	lp->me=dev;
+	lp->next_lp=NULL;
+  
+	return 0;
+}
+
+/*
+ *	Open/initialize the board. 
+ */
+
+static int sbni_open(struct net_device *dev)
+{
+	struct net_local* lp = (struct net_local*)dev->priv;
+	struct timer_list* watchdog = &lp->watchdog;
+   
+      
+	DP( printk("%s: sbni_open\n", dev->name); )
+     
+	cli();
+	lp->currframe = NULL;
+   
+	card_start(dev);
+	dev->start = 1;
+	/* set timer  watchdog */
+	init_timer(watchdog);
+	watchdog->expires = jiffies + SBNI_TIMEOUT;
+	watchdog->data = (unsigned long)dev;
+	watchdog->function = sbni_watchdog;
+	add_timer(watchdog);
+	DP( printk("%s: sbni timer watchdog initialized\n", dev->name); );
+   
+	sti();
+   
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int sbni_close(struct net_device *dev)
+{
+	int ioaddr = dev->base_addr;
+	struct net_local* lp = (struct net_local*) dev->priv;
+	struct timer_list* watchdog = &lp->watchdog;
+
+   
+	DP( printk("%s: sbni_close\n", dev->name); )
+
+	cli();
+   
+	sbni_drop_tx_queue(dev);	
+   
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	del_timer(watchdog);
+
+	outb(0, ioaddr + CSR0);
+	sti();
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int sbni_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct net_local *lp = (struct net_local*)dev->priv;
+	struct sbni_hard_header *hh=(struct sbni_hard_header *)skb->data;
+  
+#ifdef KATYUSHA   
+	struct net_local *nl;
+	int stop;
+#endif
+  
+	DP( printk("%s: sbni_start_xmit In \n", dev->name); );
+  
+  
+	if(lp->me != dev)
+		panic("sbni: lp->me != dev !!!\nMail to developer (xenon@granch.ru) if you noticed this error\n");
+  
+	if(dev->interrupt)
+	{
+		DP( printk("sbni_xmit_start: interrupt\n"); )
+		/* May be unloading, don't stamp on */	
+		return 1;	/* the packet buffer this time      */
+	}
+  
+	hh->number = 1;
+	hh->reserv = 0;
+  
+	hh->packetlen =  (skb->len - sizeof (unsigned short) - 
+			(sizeof(struct sbni_hard_header) - SBNI_HH_SZ)) 
+			| PACKET_SEND_OK | PACKET_FIRST_FRAME;
+  
+	/* we should use hairy method to calculate crc because of extra bytes are 
+	  livin between hard header and data*/
+	hh->crc = calc_crc((void*)&hh->packetlen, SBNI_HH_SZ - sizeof(unsigned), CRC32_INITIAL);
+	hh->crc = calc_crc(skb->data + sizeof(struct sbni_hard_header),
+		       skb->len - sizeof(struct sbni_hard_header),
+		       hh->crc);
+  
+#ifdef KATYUSHA
+	/* looking for first idle device */
+	for (stop=0,nl=lp; nl && !stop; nl=nl->next_lp)
+	{
+		if((!nl->currframe) && (nl->carrier)) /* if idle */
+		{
+			skb->dev = lp->me;
+			nl->currframe = skb;
+			/* set request for transmit */
+			outb(inb(nl->me->base_addr + CSR0) | TR_REQ, 
+				nl->me->base_addr + CSR0);
+			stop=1;
+		}
+	}
+  
+	if(!stop) /* we havent found any idle.*/
+	{
+		skb_queue_tail(&lp->queue,skb);
+		outb(inb(dev->base_addr + CSR0) | TR_REQ, dev->base_addr + CSR0);
+      
+	}		
+#else 
+	if (lp->currframe || 1)
+	{
+		skb_queue_tail(&lp->queue,skb);
+		  
+	}
+	else
+	{
+		lp->currframe = skb;
+	}
+	/* set request for transmit */
+	outb(inb(dev->base_addr + CSR0) | TR_REQ, dev->base_addr + CSR0);
+#endif
+	return 0;
+}
+
+void card_start(struct net_device *dev)
+{
+	struct net_local *lp = (struct net_local*)dev->priv;
+   
+	DP( printk("%s: card_start\n",dev->name); )
+	lp->wait_frame_number = 0;
+	lp->inppos = lp->outpos = 0;
+	lp->eth_trans_buffer_len = 0;
+	lp->tr_err = TR_ERROR_COUNT;
+	lp->last_receive_OK = FALSE;
+	lp->tr_resend = FALSE;
+	lp->timer_ticks = CHANGE_LEVEL_START_TICKS;
+	lp->timeout_rxl = 0;
+
+	lp->waitack=0;
+	skb_queue_head_init(&lp->queue);
+	sbni_drop_tx_queue(dev);
+	dev->tbusy = 0;
+   
+	dev->interrupt = 0;
+	/* Reset the card and set start parameters */
+	outb(PR_RES | *(char*)&lp->csr1, dev->base_addr + CSR1);
+	outb(EN_INT, dev->base_addr + CSR0);
+}
+
+void sbni_nirvana(struct net_device *dev)
+{
+	sbni_outs(dev->base_addr+DAT,magic_reply,9);
+}
+
+static inline unsigned short sbni_recv(struct net_device *dev)
+{
+	struct net_local *lp = (struct net_local*)dev->priv;
+	unsigned long crc;
+	unsigned short packetlen = 0;
+	unsigned short packetinf, packetfirst, receiveframeresend;
+	unsigned char current_frame;
+	unsigned int i, j;
+	unsigned char delme,rcv_res=RCV_WR;
+  
+	lp->in_stats.all_rx_number++;
+  
+	if((delme=inb(dev->base_addr + DAT)) == SBNI_SIG)
+	{
+		crc = CRC32_INITIAL;
+		*(((unsigned char *)&packetlen) + 0) = inb(dev->base_addr + DAT);
+		crc = CRC32(*(((unsigned char *)&packetlen) + 0), crc);
+		*(((unsigned char *)&packetlen) + 1) = inb(dev->base_addr + DAT);
+		crc = CRC32(*(((unsigned char *)&packetlen) + 1), crc);
+		packetinf = packetlen & PACKET_INF_MASK;
+		packetfirst = packetlen & PACKET_FIRST_FRAME;
+		receiveframeresend = packetlen & RECEIVE_FRAME_RESEND;
+		packetlen = packetlen & PACKET_LEN_MASK;
+    
+    
+		if((packetlen <= SB_MAX_BUFFER_ARRAY - 3) && (packetlen >= 6))
+		{
+			/* read frame number */
+			current_frame = inb(dev->base_addr + DAT);
+			crc = CRC32(current_frame, crc);
+			/* read HandShake counter */
+			lp->HSCounter = inb(dev->base_addr + DAT);
+			crc = CRC32(lp->HSCounter, crc);
+			packetlen -= 2;
+      
+			sbni_ins(dev->base_addr + DAT, lp->eth_rcv_buffer + lp->inppos, packetlen);
+      
+			for(i = lp->inppos; i < (packetlen + lp->inppos); i++)
+			{
+				crc = CRC32(lp->eth_rcv_buffer[i], crc);
+			}
+      
+			if(crc == CRC32_REMAINDER)
+			{
+				if(packetlen > 4) 
+					rcv_res=RCV_OK;
+				else if(packetlen == 4) 
+					rcv_res=RCV_NO;
+      		
+				if(lp->waitack && packetinf == PACKET_RESEND)
+					lp->in_stats.resend_tx_number++;
+	
+	
+				switch(packetinf)
+				{
+				case PACKET_SEND_OK:
+				{
+					lp->tr_err = TR_ERROR_COUNT;
+					lp->tr_resend = FALSE;
+					/* if(lp->trans_frame_number){ */
+					lp->outpos += lp->realframelen;
+	      
+					/* SendComplete
+					 * not supported
+					 */
+					DP( printk("%s: sbni_recv SendComplete\n",dev->name); );
+					/*
+					 *	We sucessfully sent current packet
+					 */
+	      
+					if(lp->waitack)
+					{
+						dev_kfree_skb(lp->currframe);
+						lp->stats.tx_packets++;
+#ifdef KATYUSHA
+						lp->currframe=skb_dequeue(&(((struct net_local*) (lp->m->priv))->queue));
+#else
+						lp->currframe=skb_dequeue(&lp->queue);
+#endif		       
+						lp->in_stats.all_tx_number++;
+						lp->waitack=0;
+					}
+	      
+					/*
+	      				 * reset output active flags
+					 */
+					dev->tbusy = 0;
+					mark_bh(NET_BH);
+					/*} if */
+				}
+				case PACKET_RESEND:
+				{
+					if(lp->tr_err) /**/
+						lp->tr_err--;
+					if(lp->ok_curr < 0xffffffff)
+						lp->ok_curr++;
+					if(packetlen > 4 && !(lp->last_receive_OK && receiveframeresend))
+					{
+						if(packetfirst)
+						{
+							if(lp->wait_frame_number)
+							{
+								for(i = lp->inppos, j = 0; 
+									i < (lp->inppos + packetlen - 4); 
+									i++, j++)
+								lp->eth_rcv_buffer[j] = lp->eth_rcv_buffer[i];
+							}
+							lp->wait_frame_number = current_frame;
+							lp->inppos = 0;
+						}
+						if(current_frame == lp->wait_frame_number)
+						{
+							lp->inppos += (packetlen - 4);
+							if(lp->wait_frame_number == 1)
+		  					{
+								sbni_get_packet(dev);
+								lp->inppos = 0;
+							}
+							lp->wait_frame_number--;
+						}
+					}
+					lp->last_receive_OK = TRUE;
+					break;
+				}
+				default:
+					break;
+				}
+			}
+			else 
+			{
+				DP(printk("%s: bad CRC32\n",dev->name));
+				change_level(dev);
+			}
+		}
+		else 
+		{
+			DP(printk("%s: bad len\n ",dev->name));
+			change_level(dev);
+			lp->stats.rx_over_errors++;
+		}
+	}
+	else 
+	{
+		DP(printk("%s: bad sig\n",dev->name));
+		change_level(dev);
+	}
+	outb(inb(dev->base_addr + CSR0) ^ CT_ZER, dev->base_addr + CSR0);
+	return (rcv_res);
+}
+
+void change_level(struct net_device *dev)
+{
+	struct net_local *lp = (struct net_local*)dev->priv;
+
+	lp->in_stats.bad_rx_number++;
+	lp->stats.tx_errors++;
+	if(lp->rxl_delta == 0)
+		return;
+	/* 
+	 * set new rxl_delta value
+	 */
+	if(lp->rxl_curr == 0)
+		lp->rxl_delta = 1;
+	else if(lp->rxl_curr == 0xf)
+		lp->rxl_delta = -1;
+	else if(lp->ok_curr < lp->ok_prev)
+		lp->rxl_delta = -lp->rxl_delta;
+	/*
+	 * set new rxl_curr value
+	 */
+	lp->csr1.rxl = rxl_tab[lp->rxl_curr += lp->rxl_delta];
+	outb(*(char*)&lp->csr1, dev->base_addr + CSR1);
+  
+  
+	/*
+	 * update ok_prev/ok_curr counters
+	 */
+	lp->ok_prev = lp->ok_curr;
+	lp->ok_curr = 0;
+
+	DP( printk("%s: receive error, rxl_curr = %d, rxl_delta = %d\n",\
+		   dev->name,lp->rxl_curr, lp->rxl_delta); )
+     
+}
+
+static inline void sbni_xmit(struct net_device *dev)
+{
+	struct net_local* lp = (struct net_local *)dev->priv;
+	struct sk_buff *skb;
+ 
+	skb=lp->currframe;
+  
+	DP( printk("%s: sbni_xmit CSR0=%02x\n",dev->name, (unsigned char)inb(dev->base_addr + CSR0)); );
+	  
+	/* push signature*/  
+	outb(SBNI_SIG, dev->base_addr + DAT);
+	
+	/* push frame w/o crc [HAiRY]*/
+	sbni_outs(dev->base_addr + DAT,
+	      &((struct sbni_hard_header *)(skb->data))->packetlen,
+	      SBNI_HH_SZ - sizeof(unsigned)); 
+	
+	sbni_outs(dev->base_addr + DAT,
+	      skb->data + sizeof(struct sbni_hard_header),
+	      skb->len - sizeof(struct sbni_hard_header)); /* ÕÓÐÅÅÍ ÅÝÅ */
+
+	/* push crc */
+	sbni_outs(dev->base_addr + DAT, skb->data, sizeof(unsigned));
+	
+	lp->waitack=1;
+}
+
+/*
+ *	The typical workload of the driver:
+ *	Handle the ether interface interrupts. 
+ */
+static void sbni_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct net_local* lp;
+	u_char csr0;
+	unsigned short rcv_res = RCV_NO;
+  
+  
+	if(dev == NULL || dev->irq != irq)
+	{
+		printk("sbni: irq %d for unknown device\n", irq);
+		return;
+	}
+   
+	if(dev->interrupt)
+	{
+		printk("%s: Reentering the interrupt driver!\n", dev->name);
+		return;
+	}
+	dev->interrupt = 1;
+   
+	csr0 = inb(dev->base_addr + CSR0);
+	DP( printk("%s: entering interrupt handler, CSR0 = %02x\n", dev->name, csr0); )
+     
+	lp=dev->priv;
+  
+	if(!lp->carrier)
+		lp->carrier=1;
+  
+	/*
+	 * Disable adapter interrupts
+	 */
+	outb((csr0 & ~EN_INT) | TR_REQ, dev->base_addr + CSR0);
+	lp->timer_ticks = CHANGE_LEVEL_START_TICKS;
+	csr0 = inb(dev->base_addr + CSR0);
+   
+	if(csr0 & (TR_RDY | RC_RDY))
+	{
+		if(csr0 & RC_RDY)
+			rcv_res = sbni_recv(dev);
+	   
+		if((lp->currframe) && (rcv_res != RCV_WR))
+			sbni_xmit(dev);
+		else if (rcv_res == RCV_OK)
+			sbni_nirvana(dev);
+       
+		csr0 = inb(dev->base_addr + CSR0);
+		DP( printk("%s: CSR0 = %02x\n",dev->name, (u_int)csr0); );
+	}
+   
+  
+	DP( printk("%s: leaving interrupt handler, CSR0 = %02x\n",dev->name, csr0 | EN_INT); );
+     
+	/* here we should send pong */
+	outb(inb(dev->base_addr+CSR0) & ~TR_REQ, dev->base_addr + CSR0);
+	if(lp->currframe)
+		outb(inb(dev->base_addr+CSR0) | TR_REQ, dev->base_addr + CSR0);
+	else
+		csr0 = inb(dev->base_addr + CSR0);
+  
+	/*
+	 * Enable adapter interrupts
+	 */
+  
+	outb(csr0 | EN_INT, dev->base_addr + CSR0);
+	dev->interrupt = 0;
+}
+
+static struct enet_statistics *sbni_get_stats(struct net_device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	return &lp->stats;
+}
+
+static inline void sbni_get_packet(struct net_device* dev)
+{
+	struct net_local* lp = (struct net_local*)dev->priv;
+	struct sk_buff* skb;
+	unsigned char *rawp;
+    
+   
+     
+	skb = dev_alloc_skb(lp->inppos - ETH_HLEN + sizeof(struct sbni_hard_header));
+   
+	if(skb == NULL)
+	{
+		DP( printk("%s: Memory squeeze, dropping packet.\n", dev->name); )
+		lp->stats.rx_dropped++;
+		return;
+	} else {
+#ifdef KATYUSHA
+		skb->dev = lp->m;
+#else
+		skb->dev = dev;
+#endif      
+		memcpy((unsigned char*)skb_put(skb, lp->inppos + 8)+8,
+			lp->eth_rcv_buffer,
+			lp->inppos);
+      
+      
+		skb->mac.raw = skb->data + 8;
+    
+		if((*(char*)lp->eth_rcv_buffer) & 1)
+		{
+			if(memcmp(lp->eth_rcv_buffer,dev->broadcast, ETH_ALEN)==0)
+				skb->pkt_type=PACKET_BROADCAST;
+			else
+				skb->pkt_type=PACKET_MULTICAST;
+		}
+		else if(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))
+		{
+			if(memcmp(lp->eth_rcv_buffer,dev->dev_addr, ETH_ALEN))
+				skb->pkt_type=PACKET_OTHERHOST;
+		}
+      
+		if( htons(*((unsigned short*)(&lp->eth_rcv_buffer[2*ETH_ALEN]))) >= 1536)
+			skb->protocol =  *((unsigned short*)(&lp->eth_rcv_buffer[2*ETH_ALEN]));
+		else
+		{
+			rawp = (unsigned char*)(&lp->eth_rcv_buffer[2*ETH_ALEN]);
+			if (*(unsigned short *)rawp == 0xFFFF)
+				skb->protocol=htons(ETH_P_802_3);
+			else
+				skb->protocol=htons(ETH_P_802_2);
+		}
+            
+
+		skb_pull(skb,SBNI_HH_SZ);
+   
+		netif_rx(skb);
+		lp->stats.rx_packets++;
+	}
+	return;
+}
+
+static void sbni_watchdog(unsigned long arg)
+{
+	struct net_device* dev = (struct net_device*)arg;
+	struct net_local* lp = (struct net_local *)dev->priv;
+	u_char csr0;
+
+
+  
+	DP( printk("%s: watchdog start\n",dev->name); )	
+	/*
+	 * if no pong received and transmission is not in progress
+	 * then assume error
+	 */
+	cli();
+	csr0 = inb(dev->base_addr + CSR0);
+	if(csr0 & (RC_CHK | TR_REQ))
+	{
+		if(lp->timer_ticks)
+		{
+			if(csr0 & (RC_RDY | BU_EMP))
+			{
+				lp->timer_ticks--;
+			}
+		}
+		else 
+		{
+			if(lp->rxl_delta)
+			{
+				lp->ok_prev = lp->ok_curr;
+				lp->ok_curr = 0;
+				lp->rxl_curr = timeout_rxl_tab[lp->timeout_rxl];
+				lp->timeout_rxl++;
+				if(lp->timeout_rxl > SIZE_OF_TIMEOUT_RXL_TAB - 1)
+					lp->timeout_rxl = 0; 
+				lp->csr1.rxl = rxl_tab[lp->rxl_curr];
+				/*
+				 * update ok_prev/ok_curr counters
+				 */
+				lp->ok_prev = lp->ok_curr;
+				lp->ok_curr = 0;
+			}
+			if(lp->tr_err)
+				lp->tr_err--;
+			else 
+			{
+				/* Drop the queue of tx packets */
+				sbni_drop_tx_queue(dev);
+				lp->carrier=0;
+			}
+	     
+			/*
+			 * send pong
+			 */
+
+			csr0 = inb(dev->base_addr + CSR0);
+			outb(csr0 & ~TR_REQ, dev->base_addr + CSR0);
+			outb(*(char*)(&lp->csr1) | PR_RES, dev->base_addr + CSR1);
+			lp->in_stats.timeout_number++;
+		}
+	}
+	sti();
+	outb(csr0 | RC_CHK, dev->base_addr + CSR0);
+	if(dev->start)
+	{
+		struct timer_list* watchdog = &lp->watchdog; 
+		init_timer(watchdog);
+		watchdog->expires = jiffies + SBNI_TIMEOUT;
+		watchdog->data = arg;
+		watchdog->function = sbni_watchdog;
+		add_timer(watchdog);
+	}
+}
+
+static void sbni_drop_tx_queue(struct net_device *dev)
+{
+	struct net_local* lp = (struct net_local *)dev->priv,*nl;
+	struct sk_buff *tmp;
+   
+	/* first of all, we should try to gift our packets to another interface */
+  
+	nl=(struct net_local *)lp->m->priv;
+	if(nl==lp)
+		nl=lp->next_lp;
+  
+	if(nl)
+	{
+		/* we found device*/
+		if(lp->currframe)
+		{
+			if(!nl->currframe)
+			{
+				nl->currframe=lp->currframe;
+			}
+			else
+			{
+				skb_queue_head(&((struct net_local*)(lp->m->priv))->queue,lp->currframe);
+			}
+		}
+		lp->currframe=NULL;
+
+		if(!nl->currframe)
+			nl->currframe=skb_dequeue(&(((struct net_local*)(lp->m->priv))->queue));
+
+		/* set request for transmit */
+		outb(inb(nl->me->base_addr + CSR0) | TR_REQ,  nl->me->base_addr + CSR0);
+    
+	}
+	else
+	{
+		/* *sigh*, we should forget this packets */
+		nl=lp->m->priv;
+    
+		while((tmp = skb_dequeue(&nl->queue)) != NULL)
+		{
+			dev_kfree_skb(tmp);
+			lp->stats.tx_packets++;
+		}
+    
+		if (lp->currframe)
+		{
+			dev_kfree_skb(lp->currframe);
+			lp->currframe = NULL;
+			lp->stats.tx_packets++;
+		}
+	}
+	lp->waitack=0;
+  	dev->tbusy = 0;
+  
+	mark_bh(NET_BH);
+	DP( printk("%s: queue dropping stoped\n",dev->name); );	
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ * num_addrs == -1	Promiscuous mode, receive all packets
+ * num_addrs == 0	Normal mode, clear multicast list
+ * num_addrs > 0	Multicast mode, receive normal and MC packets,
+ *			and do best-effort filtering.
+ */
+ 
+static void set_multicast_list(struct net_device *dev)
+{
+	/*
+	 * always enabled promiscuous mode.
+	*/
+	return;
+}
+
+static int sbni_set_mac_address(struct net_device *dev, void *addr)
+{	
+	/* struct net_local *lp = (struct net_local *)dev->priv; */
+	struct sockaddr *saddr = addr;
+	
+	if(dev->start)
+	{
+		/* Only possible while card isn't started */
+		return -EBUSY;
+	}
+	memcpy(dev->dev_addr, saddr->sa_data, dev->addr_len);
+	return (0);
+}
+
+static int sbni_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct net_local* lp = (struct net_local *)dev->priv,*tlp; 
+	struct net_device *slave;
+	int error = 0;
+	char tmpstr[6];
+  
+  
+	switch(cmd)
+	{
+		case SIOCDEVGETINSTATS:
+		{
+			struct sbni_in_stats *in_stats = (struct sbni_in_stats *)ifr->ifr_data;
+			DP( printk("%s: SIOCDEVGETINSTATS %08x\n",dev->name,(unsigned)in_stats);)
+			if(copy_to_user((void *)in_stats, (void *)(&(lp->in_stats)), sizeof(struct sbni_in_stats)))
+				return -EFAULT;
+			break;
+		}
+		case SIOCDEVRESINSTATS:
+		{
+			DP( printk("%s: SIOCDEVRESINSTATS\n",dev->name); )
+			lp->in_stats.all_rx_number = 0;
+			lp->in_stats.bad_rx_number = 0;
+			lp->in_stats.timeout_number = 0;
+			lp->in_stats.all_tx_number = 0;
+			lp->in_stats.resend_tx_number = 0;
+			break;
+		}
+		case SIOCDEVGHWSTATE:
+		{
+			struct sbni_flags flags;
+			flags.rxl = lp->rxl_curr;
+			flags.rate = lp->csr1.rate;
+			flags.fixed_rxl = (lp->rxl_delta == 0);
+			flags.fixed_rate = 1;
+			ifr->ifr_data = *(caddr_t*)&flags;
+			DP( printk("%s: get flags (0x%02x)\n",dev->name, (unsigned char)ifr->ifr_data); )
+			break;
+		}
+		case SIOCDEVSHWSTATE:
+		{
+			struct sbni_flags flags;
+			DP( printk("%s: SIOCDEVSHWSTATE flags=0x%02x\n",dev->name, (unsigned char)ifr->ifr_data); )
+			/* root only */
+			if(!capable(CAP_NET_ADMIN))
+				return -EPERM;
+			flags = *(struct sbni_flags*)&ifr->ifr_data;
+			if(flags.fixed_rxl)
+			{
+				lp->rxl_delta = 0;
+				lp->rxl_curr = flags.rxl;
+			}
+			else
+			{
+				lp->rxl_delta = DEF_RXL_DELTA;
+				lp->rxl_curr = DEF_RXL;
+			}
+			lp->csr1.rxl = rxl_tab[lp->rxl_curr];
+			if(flags.fixed_rate)
+				lp->csr1.rate = flags.rate;
+			else
+				lp->csr1.rate = DEF_RATE;
+			/*
+			 * Don't be afraid...
+			 */
+			outb(*(char*)(&lp->csr1) | PR_RES, dev->base_addr + CSR1);
+
+			DP( printk("%s: set flags (0x%02x)\n receive level: %u, baud rate: %u\n",\
+				dev->name, (unsigned char)ifr->ifr_data, (unsigned)lp->rxl_curr, (unsigned)lp->csr1.rate); )
+			break;
+		}
+
+		case SIOCDEVENSLAVE:
+			if(!capable(CAP_NET_ADMIN))
+				return -EPERM;
+			if(copy_from_user( tmpstr, ifr->ifr_data, 6))
+				return -EFAULT;
+			slave=dev_get(tmpstr);
+			if(!(slave && slave->flags & IFF_UP && dev->flags & IFF_UP))
+			{
+				printk("%s: Both devices should be UP to enslave!\n",dev->name);
+				return -EINVAL;
+			}
+		
+			if(slave)
+			{
+				if(!((dev->flags & IFF_SLAVE) || (slave->flags & IFF_SLAVE)))
+				{
+					/* drop queue*/
+					sbni_drop_tx_queue(slave);
+					slave->flags |= IFF_SLAVE;
+					((struct net_local *)(slave->priv))->m=dev;
+					while(lp->next_lp)	//tail it after last slave
+						lp=lp->next_lp;
+					lp->next_lp=slave->priv;
+					lp=(struct net_local *)dev->priv;
+					dev->flags |= IFF_MASTER;
+					}
+				else
+				{
+					printk("%s: one of devices is already slave!\n",dev->name);
+					return -EBUSY;
+				}
+			}
+			else
+			{
+				printk("%s: can't find device %s to enslave\n",dev->name,ifr->ifr_data);
+				return -ENOENT;
+			}
+			break;    
+
+		case SIOCDEVEMANSIPATE:
+			if(!capable(CAP_NET_ADMIN))
+				return -EPERM;
+
+			if(dev->flags & IFF_SLAVE)
+			{
+				dev->flags &= ~IFF_SLAVE;
+				/* exclude us from masters slavelist*/
+				for(tlp=lp->m->priv;tlp->next_lp!=lp && tlp->next_lp;tlp=tlp->next_lp);
+				if(tlp->next_lp)
+				{
+					tlp->next_lp = lp->next_lp;
+					if(!((struct net_local *)lp->m->priv)->next_lp)
+					{
+						lp->m->flags &= ~IFF_MASTER;	
+					}
+					lp->next_lp=NULL;
+					lp->m=dev;     	
+				}
+				else
+				{
+					printk("%s: Ooops. drivers structure is mangled!\n",dev->name);
+					return -EIO;
+				}      
+			}
+			else
+			{
+				printk("%s: isn't slave device!\n",dev->name);
+				return -EINVAL;
+			}
+			break;    
+
+		default:
+			DP( printk("%s: invalid ioctl: 0x%x\n",dev->name, cmd); )
+			error = -EINVAL;
+	}
+	return (error);
+}
+
+
+
+#ifdef CRCASM
+
+unsigned long calc_crc(char *mem, int len, unsigned initial)
+{
+   
+	__asm__ (
+		"xorl %%eax,%%eax\n\t"
+		"1:\n\t"
+		"lodsb\n\t"
+		"xorb %%dl,%%al\n\t"
+		"shrl $8,%%edx\n\t"
+		"xorl (%%edi,%%eax,4),%%edx\n\t"
+		"loop 1b\n\t"
+		"movl %%edx,%%eax"
+		: 
+		: "S" (mem), "D" (&crc32tab[0]), "c" (len), "d" (initial)
+		: "eax", "edx", "ecx"
+	);
+	/* return crc; */
+}
+
+#else
+
+unsigned long calc_crc(char *mem, int len, unsigned initial)
+{
+	unsigned crc;
+	crc = initial;
+   
+	for(;len;mem++,len--)
+	{
+		crc = CRC32(*mem, crc);
+	}
+	return(crc);
+}
+#endif /* CRCASM */
+#ifdef MODULE
+
+static int io[SBNI_MAX_NUM_CARDS] = { 0 };
+static int irq[SBNI_MAX_NUM_CARDS] = { 0 };
+static int rxl[SBNI_MAX_NUM_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
+static int baud[SBNI_MAX_NUM_CARDS] = { 0 };
+static long mac[SBNI_MAX_NUM_CARDS] = { 0 };
+
+#ifdef v22
+MODULE_PARM(io, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
+MODULE_PARM(rxl, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
+MODULE_PARM(baud, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
+MODULE_PARM(mac, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
+#endif
+
+
+static int sbniautodetect = -1;
+
+static struct net_device dev_sbni[SBNI_MAX_NUM_CARDS] = {
+	{
+		"sbni0",
+		0, 0, 0, 0,		/* memory */
+		0, 0,			/* base, irq */
+		0, 0, 0, NULL, sbni_probe 
+	},
+	{
+		"sbni1",
+		0, 0, 0, 0,		/* memory */
+		0, 0,			/* base, irq */
+		0, 0, 0, NULL, sbni_probe 
+	},
+	{
+		"sbni2",
+		0, 0, 0, 0,		/* memory */
+		0, 0,			/* base, irq */
+		0, 0, 0, NULL, sbni_probe 
+	},
+	{
+		"sbni3",
+		0, 0, 0, 0,		/* memory */
+		0, 0,			/* base, irq */
+		0, 0, 0, NULL, sbni_probe 
+	},
+	{
+		"sbni4",
+		0, 0, 0, 0,		/* memory */
+		0, 0,			/* base, irq */
+		0, 0, 0, NULL, sbni_probe 
+	},
+	{
+		"sbni5",
+		0, 0, 0, 0,		/* memory */
+		0, 0,			/* base, irq */
+		0, 0, 0, NULL, sbni_probe 
+	},
+	{
+		"sbni6",
+		0, 0, 0, 0,		/* memory */
+		0, 0,			/* base, irq */
+		0, 0, 0, NULL, sbni_probe 
+	},
+	{
+		"sbni7",
+		0, 0, 0, 0,		/* memory */
+		0, 0,			/* base, irq */
+		0, 0, 0, NULL, sbni_probe 
+	}
+};
+
+int init_module(void)
+{
+	int devices = 0;
+	int installed = 0;
+	int i;
+
+	/* My simple plug for this huge init_module. "XenON */
+      
+	if(sbniautodetect != -1)
+	{
+		/* Autodetect mode */
+		printk("sbni: Autodetect mode (not recommended!) ...\n");
+		if(!sbniautodetect)
+			sbniautodetect=SBNI_MAX_NUM_CARDS;
+		printk("Trying to find %d SBNI cards...\n", sbniautodetect);
+		if(sbniautodetect > SBNI_MAX_NUM_CARDS)
+		{
+			sbniautodetect = SBNI_MAX_NUM_CARDS;
+			printk("sbni: You want to detect too many cards. Truncated to %d\n", SBNI_MAX_NUM_CARDS);
+		}
+		for(i = 0; i < sbniautodetect; i++)
+		{
+			if(!register_netdev(&dev_sbni[i]))
+				installed++;
+		}
+		if(installed)
+			return 0;
+		else
+		    return -EIO;
+	}
+	
+	/* Manual mode */
+	for(i = 0; i < SBNI_MAX_NUM_CARDS; i++)
+	{
+		if((io[i] != 0) || (irq[i] != 0))
+			devices++;
+	}
+	for(i = 0; i < devices; i++)
+	{
+		dev_sbni[i].irq = irq[i];
+		dev_sbni[i].base_addr = io[i];
+		def_rxl = rxl[i];
+		def_baud = baud[i];
+		def_mac = mac[i];
+		if(register_netdev(&dev_sbni[i]))
+			printk("sbni: card not found!\n");
+		else
+			installed++;
+	}
+	if(installed)
+		return 0;
+	else
+		return -EIO;
+}
+
+void cleanup_module(void)
+{
+	int i;
+	for(i = 0; i < 4; i++)
+	{
+		if(dev_sbni[i].priv)
+		{
+			free_irq(dev_sbni[i].irq, &dev_sbni[i]);
+			release_region(dev_sbni[i].base_addr, SBNI_IO_EXTENT);
+			unregister_netdev(&dev_sbni[i]);
+			kfree(dev_sbni[i].priv);
+			dev_sbni[i].priv = NULL;
+		}
+	}
+}
+#endif /* MODULE */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/sbni.h linux/drivers/net/wan/sbni.h
--- v2.3.20/linux/drivers/net/wan/sbni.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/sbni.h	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,194 @@
+/*
+ * sbni.h - header file for sbni linux device driver
+ *
+ * Copyright (C) 1999 Granch ltd., Yaroslav Polyakov (xenon@granch.ru).
+ *
+ */
+
+/*
+ * SBNI12 definitions
+ *
+ * Revision 2.0.0  1997/08/27
+ * Initial revision
+ *
+ * Revision 2.1.0  1999/04/26
+ * dev_priv structure changed to support balancing and some other features.
+ *
+ */
+
+#ifndef __SBNI_H
+#define __SBNI_H
+
+#define SBNI_DEBUG 0
+
+#if SBNI_DEBUG
+#define DP( A ) A
+#else
+#define DP( A )
+#endif
+
+typedef unsigned char BOOLEAN;
+
+#define TRUE 1
+#define FALSE 0
+
+#define	SBNI_IO_EXTENT	0x4
+#define SB_MAX_BUFFER_ARRAY 1023
+
+#define CSR0	0
+#define CSR1	1
+
+#define	DAT	2
+
+/* CSR0 mapping */
+#define BU_EMP	(1 << 1)	/* r z    */
+#define	RC_CHK	(1 << 2)	/* rw     */
+#define	CT_ZER	(1 << 3)	/*  w     */
+#define	TR_REQ	(1 << 4)	/* rwz*   */
+
+#define TR_RDY	(1 << 5)	/* r z    */
+#define EN_INT	(1 << 6)	/* rwz* */
+#define RC_RDY	(1 << 7)	/* r z    */
+
+/* CSR1 mapping */
+#define PR_RES	(1 << 7)	/*  w     */
+
+struct sbni_csr1 {
+	unsigned rxl:5;
+	unsigned rate:2;
+	unsigned:1;
+};
+
+#define DEF_RXL_DELTA	-1
+#define DEF_RXL		0xf
+#define DEF_RATE	0
+#define DEF_FRAME_LEN	(1023 - 14 - 9)
+
+#ifdef MODULE
+
+#define SBNI_MAX_NUM_CARDS 8
+#define SBNI_MAX_SLAVES 8
+
+
+#endif				/* MODULE */
+
+#define SBNI_SIG 0x5a
+
+#define	SB_ETHER_MIN_LEN 60
+
+#define SB_FILLING_CHAR (unsigned char)0x00
+#define TR_ERROR_COUNT 32
+#define CHANGE_LEVEL_START_TICKS 4
+#define SBNI_INTERNAL_QUEUE_SIZE 10	/* 100 ? */
+
+#define PACKET_FIRST_FRAME (unsigned short)0x8000
+#define RECEIVE_FRAME_RESEND (unsigned short)0x0800
+#define PACKET_RESEND 0x4000
+#define PACKET_SEND_OK 0x3000
+#define PACKET_LEN_MASK (unsigned short)0x03ff
+#define PACKET_INF_MASK (unsigned short)0x7000
+
+#define ETHER_ADDR_LEN 6
+
+#define SBNI_TIMEOUT HZ/10	/* ticks to wait for pong or packet */
+		/* sbni watchdog called SBNI_HZ times per sec. */
+
+struct sbni_in_stats {
+	unsigned int all_rx_number;
+	unsigned int bad_rx_number;
+	unsigned int timeout_number;
+	unsigned int all_tx_number;
+	unsigned int resend_tx_number;
+};
+
+
+/*
+ *    Board-specific info in dev->priv. 
+ */
+struct net_local {
+	struct enet_statistics stats;
+
+	struct timer_list watchdog;
+	unsigned int realframelen;	/* the current size of the SB-frame */
+	unsigned int eth_trans_buffer_len;	/* tx buffer length */
+	unsigned int outpos;
+	unsigned int inppos;
+	unsigned int frame_len;	/* The set SB-frame size */
+	unsigned int tr_err;
+	unsigned int timer_ticks;
+	BOOLEAN last_receive_OK;
+	BOOLEAN tr_resend;
+
+	unsigned char wait_frame_number;
+	unsigned char eth_trans_buffer[1520];	/* tx buffer */
+	unsigned char HSCounter;	/* Reserved field */
+	unsigned char eth_rcv_buffer[2600];	/* rx buffer */
+	struct sbni_csr1 csr1;
+	/* Internal Statistics */
+	struct sbni_in_stats in_stats;
+
+	int rxl_curr;		/* current receive level value [0..0xf] */
+	int rxl_delta;		/* receive level delta (+1, -1)
+				   rxl_delta == 0 - receive level
+				   autodetection
+				   disabled            */
+	unsigned int ok_curr;	/* current ok frames received           */
+	unsigned int ok_prev;	/* previous ok frames received          */
+	unsigned int timeout_rxl;
+
+	struct sk_buff_head queue;
+	struct sk_buff *currframe;
+	BOOLEAN waitack;
+
+	struct net_device *m;	/* master */
+	struct net_device *me;	/* me */
+	struct net_local *next_lp;	/* next lp */
+
+	int carrier;
+
+
+};
+
+
+struct sbni_hard_header {
+
+	/* internal sbni stuff */
+	unsigned int crc;	/* 4 */
+	unsigned short packetlen;	/* 2 */
+	unsigned char number;	/* 1 */
+	unsigned char reserv;	/* 1 */
+
+	/* 8 */
+
+	/* ethernet stuff */
+	unsigned char h_dest[ETH_ALEN];		/* destination eth addr */
+	unsigned char h_source[ETH_ALEN];	/* source ether addr    */
+	unsigned short h_proto;	/* packet type ID field */
+	/* +14 */
+	/* 22 */
+
+};
+
+#define SBNI_HH_SZ 22
+
+struct sbni_flags {
+	unsigned rxl:4;
+	unsigned rate:2;
+	unsigned fixed_rxl:1;
+	unsigned fixed_rate:1;
+};
+
+#define RCV_NO 0
+#define RCV_OK 1
+#define RCV_WR 2
+
+
+#define SIOCDEVGETINSTATS 	SIOCDEVPRIVATE
+#define SIOCDEVRESINSTATS 	SIOCDEVPRIVATE+1
+#define SIOCDEVGHWSTATE   	SIOCDEVPRIVATE+2
+#define SIOCDEVSHWSTATE   	SIOCDEVPRIVATE+3
+#define SIOCDEVENSLAVE  	SIOCDEVPRIVATE+4
+#define SIOCDEVEMANSIPATE  	SIOCDEVPRIVATE+5
+
+
+#endif				/* __SBNI_H */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/sdla.c linux/drivers/net/wan/sdla.c
--- v2.3.20/linux/drivers/net/wan/sdla.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/sdla.c	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,1696 @@
+/*
+ * SDLA		An implementation of a driver for the Sangoma S502/S508 series
+ *		multi-protocol PC interface card.  Initial offering is with 
+ *		the DLCI driver, providing Frame Relay support for linux.
+ *
+ *		Global definitions for the Frame relay interface.
+ *
+ * Version:	@(#)sdla.c   0.30	12 Sep 1996
+ *
+ * Credits:	Sangoma Technologies, for the use of 2 cards for an extended
+ *			period of time.
+ *		David Mandelstam <dm@sangoma.com> for getting me started on 
+ *			this project, and incentive to complete it.
+ *		Gene Kozen <74604.152@compuserve.com> for providing me with
+ *			important information about the cards.
+ *
+ * Author:	Mike McLagan <mike.mclagan@linux.org>
+ *
+ * Changes:
+ *		0.15	Mike McLagan	Improved error handling, packet dropping
+ *		0.20	Mike McLagan	New transmit/receive flags for config
+ *					If in FR mode, don't accept packets from
+ *					non DLCI devices.
+ *		0.25	Mike McLagan	Fixed problem with rejecting packets
+ *					from non DLCI devices.
+ *		0.30	Mike McLagan	Fixed kernel panic when used with modified
+ *					ifconfig
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h> /* for CONFIG_DLCI_MAX */
+#include <linux/module.h>
+
+#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/timer.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/if_frad.h>
+
+#include <linux/sdla.h>
+
+static const char* version = "SDLA driver v0.30, 12 Sep 1996, mike.mclagan@linux.org";
+
+static const char* devname = "sdla";
+
+static unsigned int valid_port[] __initdata = { 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390};
+
+static unsigned int valid_mem[]  __initdata = {
+				    0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, 
+                                    0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000,
+                                    0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000,
+                                    0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, 0xDE000,
+                                    0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000}; 
+
+/*********************************************************
+ *
+ * these are the core routines that access the card itself 
+ *
+ *********************************************************/
+
+#define SDLA_WINDOW(dev,addr) outb((((addr) >> 13) & 0x1F), (dev)->base_addr + SDLA_REG_Z80_WINDOW)
+
+static void sdla_read(struct net_device *dev, int addr, void *buf, short len)
+{
+	unsigned long flags;
+	char          *temp, *base;
+	int           offset, bytes;
+
+	temp = buf;
+	while(len)
+	{	
+		offset = addr & SDLA_ADDR_MASK;
+		bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;
+		base = (void *) (dev->mem_start + offset);
+
+		save_flags(flags);
+		cli();
+		SDLA_WINDOW(dev, addr);
+		memcpy(temp, base, bytes);
+		restore_flags(flags);
+
+		addr += bytes;
+		temp += bytes;
+		len  -= bytes;
+	}  
+}
+
+static void sdla_write(struct net_device *dev, int addr, void *buf, short len)
+{
+	unsigned long flags;
+	char          *temp, *base;
+	int           offset, bytes;
+
+	temp = buf;
+	while(len)
+	{
+		offset = addr & SDLA_ADDR_MASK;
+		bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;
+		base = (void *) (dev->mem_start + offset);
+		save_flags(flags);
+		cli();
+		SDLA_WINDOW(dev, addr);
+		memcpy(base, temp, bytes);
+		restore_flags(flags);
+		addr += bytes;
+		temp += bytes;
+		len  -= bytes;
+	}
+}
+
+static void sdla_clear(struct net_device *dev)
+{
+	unsigned long flags;
+	char          *base;
+	int           len, addr, bytes;
+
+	len = 65536;	
+	addr = 0;
+	bytes = SDLA_WINDOW_SIZE;
+	base = (void *) dev->mem_start;
+
+	save_flags(flags);
+	cli();
+	while(len)
+	{
+		SDLA_WINDOW(dev, addr);
+		memset(base, 0, bytes);
+
+		addr += bytes;
+		len  -= bytes;
+	}
+	restore_flags(flags);
+}
+
+static char sdla_byte(struct net_device *dev, int addr)
+{
+	unsigned long flags;
+	char          byte, *temp;
+
+	temp = (void *) (dev->mem_start + (addr & SDLA_ADDR_MASK));
+
+	save_flags(flags);
+	cli();
+	SDLA_WINDOW(dev, addr);
+	byte = *temp;
+	restore_flags(flags);
+
+	return(byte);
+}
+
+void sdla_stop(struct net_device *dev)
+{
+	struct frad_local *flp;
+
+	flp = dev->priv;
+	switch(flp->type)
+	{
+		case SDLA_S502A:
+			outb(SDLA_S502A_HALT, dev->base_addr + SDLA_REG_CONTROL);
+			flp->state = SDLA_HALT;
+			break;
+		case SDLA_S502E:
+			outb(SDLA_HALT, dev->base_addr + SDLA_REG_Z80_CONTROL);
+			outb(SDLA_S502E_ENABLE, dev->base_addr + SDLA_REG_CONTROL);
+			flp->state = SDLA_S502E_ENABLE;
+			break;
+		case SDLA_S507:
+			flp->state &= ~SDLA_CPUEN;
+			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+			break;
+		case SDLA_S508:
+			flp->state &= ~SDLA_CPUEN;
+			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+			break;
+	}
+}
+
+void sdla_start(struct net_device *dev)
+{
+	struct frad_local *flp;
+
+	flp = dev->priv;
+	switch(flp->type)
+	{
+		case SDLA_S502A:
+			outb(SDLA_S502A_NMI, dev->base_addr + SDLA_REG_CONTROL);
+			outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
+			flp->state = SDLA_S502A_START;
+			break;
+		case SDLA_S502E:
+			outb(SDLA_S502E_CPUEN, dev->base_addr + SDLA_REG_Z80_CONTROL);
+			outb(0x00, dev->base_addr + SDLA_REG_CONTROL);
+			flp->state = 0;
+			break;
+		case SDLA_S507:
+			flp->state |= SDLA_CPUEN;
+			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+			break;
+		case SDLA_S508:
+			flp->state |= SDLA_CPUEN;
+			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+			break;
+	}
+}
+
+/****************************************************
+ *
+ * this is used for the S502A/E cards to determine
+ * the speed of the onboard CPU.  Calibration is
+ * necessary for the Frame Relay code uploaded 
+ * later.  Incorrect results cause timing problems
+ * with link checks & status messages
+ *
+ ***************************************************/
+
+int sdla_z80_poll(struct net_device *dev, int z80_addr, int jiffs, char resp1, char resp2)
+{
+	unsigned long start, done, now;
+	char          resp, *temp;
+
+	start = now = jiffies;
+	done = jiffies + jiffs;
+
+	temp = (void *)dev->mem_start;
+	temp += z80_addr & SDLA_ADDR_MASK;
+	
+	resp = ~resp1;
+	while (time_before(jiffies, done) && (resp != resp1) && (!resp2 || (resp != resp2)))
+	{
+		if (jiffies != now)
+		{
+			SDLA_WINDOW(dev, z80_addr);
+			now = jiffies;
+			resp = *temp;
+		}
+	}
+	return(time_before(jiffies, done) ? jiffies - start : -1);
+}
+
+/* constants for Z80 CPU speed */
+#define Z80_READY 		'1'	/* Z80 is ready to begin */
+#define LOADER_READY 		'2'	/* driver is ready to begin */
+#define Z80_SCC_OK 		'3'	/* SCC is on board */
+#define Z80_SCC_BAD	 	'4'	/* SCC was not found */
+
+static int sdla_cpuspeed(struct net_device *dev, struct ifreq *ifr)
+{
+	int  jiffs;
+	char data;
+
+	sdla_start(dev);
+	if (sdla_z80_poll(dev, 0, 3*HZ, Z80_READY, 0) < 0)
+		return(-EIO);
+
+	data = LOADER_READY;
+	sdla_write(dev, 0, &data, 1);
+
+	if ((jiffs = sdla_z80_poll(dev, 0, 8*HZ, Z80_SCC_OK, Z80_SCC_BAD)) < 0)
+		return(-EIO);
+
+	sdla_stop(dev);
+	sdla_read(dev, 0, &data, 1);
+
+	if (data == Z80_SCC_BAD)
+	{
+		printk("%s: SCC bad\n", dev->name);
+		return(-EIO);
+	}
+
+	if (data != Z80_SCC_OK)
+		return(-EINVAL);
+
+	if (jiffs < 165)
+		ifr->ifr_mtu = SDLA_CPU_16M;
+	else if (jiffs < 220)
+		ifr->ifr_mtu = SDLA_CPU_10M;
+	else if (jiffs < 258)
+		ifr->ifr_mtu = SDLA_CPU_8M;
+	else if (jiffs < 357)
+		ifr->ifr_mtu = SDLA_CPU_7M;
+	else if (jiffs < 467)
+		ifr->ifr_mtu = SDLA_CPU_5M;
+	else
+		ifr->ifr_mtu = SDLA_CPU_3M;
+ 
+	return(0);
+}
+
+/************************************************
+ *
+ *  Direct interaction with the Frame Relay code 
+ *  starts here.
+ *
+ ************************************************/
+
+struct _dlci_stat 
+{
+	short dlci		__attribute__((packed));
+	char  flags		__attribute__((packed));
+};
+
+struct _frad_stat 
+{
+	char    flags;
+	struct _dlci_stat dlcis[SDLA_MAX_DLCI];
+};
+
+static void sdla_errors(struct net_device *dev, int cmd, int dlci, int ret, int len, void *data) 
+{
+	struct _dlci_stat *pstatus;
+	short             *pdlci;
+	int               i;
+	char              *state, line[30];
+
+	switch (ret)
+	{
+		case SDLA_RET_MODEM:
+			state = data;
+			if (*state & SDLA_MODEM_DCD_LOW)
+				printk(KERN_INFO "%s: Modem DCD unexpectedly low!\n", dev->name);
+			if (*state & SDLA_MODEM_CTS_LOW)
+				printk(KERN_INFO "%s: Modem CTS unexpectedly low!\n", dev->name);
+			/* I should probably do something about this! */
+			break;
+
+		case SDLA_RET_CHANNEL_OFF:
+			printk(KERN_INFO "%s: Channel became inoperative!\n", dev->name);
+			/* same here */
+			break;
+
+		case SDLA_RET_CHANNEL_ON:
+			printk(KERN_INFO "%s: Channel became operative!\n", dev->name);
+			/* same here */
+			break;
+
+		case SDLA_RET_DLCI_STATUS:
+			printk(KERN_INFO "%s: Status change reported by Access Node.\n", dev->name);
+			len /= sizeof(struct _dlci_stat);
+			for(pstatus = data, i=0;i < len;i++,pstatus++)
+			{
+				if (pstatus->flags & SDLA_DLCI_NEW)
+					state = "new";
+				else if (pstatus->flags & SDLA_DLCI_DELETED)
+					state = "deleted";
+				else if (pstatus->flags & SDLA_DLCI_ACTIVE)
+					state = "active";
+				else
+				{
+					sprintf(line, "unknown status: %02X", pstatus->flags);
+					state = line;
+				}
+				printk(KERN_INFO "%s: DLCI %i: %s.\n", dev->name, pstatus->dlci, state);
+				/* same here */
+			}
+			break;
+
+		case SDLA_RET_DLCI_UNKNOWN:
+			printk(KERN_INFO "%s: Received unknown DLCIs:", dev->name);
+			len /= sizeof(short);
+			for(pdlci = data,i=0;i < len;i++,pdlci++)
+				printk(" %i", *pdlci);
+			printk("\n");
+			break;
+
+		case SDLA_RET_TIMEOUT:
+			printk(KERN_ERR "%s: Command timed out!\n", dev->name);
+			break;
+
+		case SDLA_RET_BUF_OVERSIZE:
+			printk(KERN_INFO "%s: Bc/CIR overflow, acceptable size is %i\n", dev->name, len);
+			break;
+
+		case SDLA_RET_BUF_TOO_BIG:
+			printk(KERN_INFO "%s: Buffer size over specified max of %i\n", dev->name, len);
+			break;
+
+		case SDLA_RET_CHANNEL_INACTIVE:
+		case SDLA_RET_DLCI_INACTIVE:
+		case SDLA_RET_CIR_OVERFLOW:
+		case SDLA_RET_NO_BUFS:
+			if (cmd == SDLA_INFORMATION_WRITE)
+				break;
+
+		default: 
+			printk(KERN_DEBUG "%s: Cmd 0x%2.2X generated return code 0x%2.2X\n", dev->name, cmd, ret);
+			/* Further processing could be done here */
+			break;
+	}
+}
+
+static int sdla_cmd(struct net_device *dev, int cmd, short dlci, short flags, 
+                        void *inbuf, short inlen, void *outbuf, short *outlen)
+{
+	static struct _frad_stat status;
+	struct frad_local        *flp;
+	struct sdla_cmd          *cmd_buf;
+	unsigned long            pflags;
+	int                      jiffs, ret, waiting, len;
+	long                     window;
+
+	flp = dev->priv;
+	window = flp->type == SDLA_S508 ? SDLA_508_CMD_BUF : SDLA_502_CMD_BUF;
+	cmd_buf = (struct sdla_cmd *)(dev->mem_start + (window & SDLA_ADDR_MASK));
+	ret = 0;
+	len = 0;
+	jiffs = jiffies + HZ;  /* 1 second is plenty */
+	save_flags(pflags);
+	cli();
+	SDLA_WINDOW(dev, window);
+	cmd_buf->cmd = cmd;
+	cmd_buf->dlci = dlci;
+	cmd_buf->flags = flags;
+
+	if (inbuf)
+		memcpy(cmd_buf->data, inbuf, inlen);
+
+	cmd_buf->length = inlen;
+
+	cmd_buf->opp_flag = 1;
+	restore_flags(pflags);
+
+	waiting = 1;
+	len = 0;
+	while (waiting && time_before_eq(jiffies, jiffs))
+	{
+		if (waiting++ % 3) 
+		{
+			save_flags(pflags);
+			cli();
+			SDLA_WINDOW(dev, window);
+			waiting = ((volatile int)(cmd_buf->opp_flag));
+			restore_flags(pflags);
+		}
+	}
+	
+	if (!waiting)
+	{
+		save_flags(pflags);
+		cli();
+		SDLA_WINDOW(dev, window);
+		ret = cmd_buf->retval;
+		len = cmd_buf->length;
+		if (outbuf && outlen)
+		{
+			*outlen = *outlen >= len ? len : *outlen;
+
+			if (*outlen)
+				memcpy(outbuf, cmd_buf->data, *outlen);
+		}
+
+		/* This is a local copy that's used for error handling */
+		if (ret)
+			memcpy(&status, cmd_buf->data, len > sizeof(status) ? sizeof(status) : len);
+
+		restore_flags(pflags);
+	}
+	else
+		ret = SDLA_RET_TIMEOUT;
+
+	if (ret != SDLA_RET_OK)
+	   	sdla_errors(dev, cmd, dlci, ret, len, &status);
+
+	return(ret);
+}
+
+/***********************************************
+ *
+ * these functions are called by the DLCI driver 
+ *
+ ***********************************************/
+
+static int sdla_reconfig(struct net_device *dev);
+
+int sdla_activate(struct net_device *slave, struct net_device *master)
+{
+	struct frad_local *flp;
+	int i;
+
+	flp = slave->priv;
+
+	for(i=0;i<CONFIG_DLCI_MAX;i++)
+		if (flp->master[i] == master)
+			break;
+
+	if (i == CONFIG_DLCI_MAX)
+		return(-ENODEV);
+
+	flp->dlci[i] = abs(flp->dlci[i]);
+
+	if (slave->start && (flp->config.station == FRAD_STATION_NODE))
+		sdla_cmd(slave, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
+
+	return(0);
+}
+
+int sdla_deactivate(struct net_device *slave, struct net_device *master)
+{
+	struct frad_local *flp;
+	int               i;
+
+	flp = slave->priv;
+
+	for(i=0;i<CONFIG_DLCI_MAX;i++)
+		if (flp->master[i] == master)
+			break;
+
+	if (i == CONFIG_DLCI_MAX)
+		return(-ENODEV);
+
+	flp->dlci[i] = -abs(flp->dlci[i]);
+
+	if (slave->start && (flp->config.station == FRAD_STATION_NODE))
+		sdla_cmd(slave, SDLA_DEACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
+
+	return(0);
+}
+
+int sdla_assoc(struct net_device *slave, struct net_device *master)
+{
+	struct frad_local *flp;
+	int               i;
+
+	if (master->type != ARPHRD_DLCI)
+		return(-EINVAL);
+
+	flp = slave->priv;
+
+	for(i=0;i<CONFIG_DLCI_MAX;i++)
+	{
+		if (!flp->master[i])
+			break;
+		if (abs(flp->dlci[i]) == *(short *)(master->dev_addr))
+			return(-EADDRINUSE);
+	} 
+
+	if (i == CONFIG_DLCI_MAX)
+		return(-EMLINK);  /* #### Alan: Comments on this ?? */
+
+	MOD_INC_USE_COUNT;
+
+	flp->master[i] = master;
+	flp->dlci[i] = -*(short *)(master->dev_addr);
+	master->mtu = slave->mtu;
+
+	if (slave->start) {
+		if (flp->config.station == FRAD_STATION_CPE)
+			sdla_reconfig(slave);
+		else
+			sdla_cmd(slave, SDLA_ADD_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
+	}
+
+	return(0);
+}
+
+int sdla_deassoc(struct net_device *slave, struct net_device *master)
+{
+	struct frad_local *flp;
+	int               i;
+
+	flp = slave->priv;
+
+	for(i=0;i<CONFIG_DLCI_MAX;i++)
+		if (flp->master[i] == master)
+			break;
+
+	if (i == CONFIG_DLCI_MAX)
+		return(-ENODEV);
+
+	flp->master[i] = NULL;
+	flp->dlci[i] = 0;
+
+	MOD_DEC_USE_COUNT;
+
+	if (slave->start) {
+		if (flp->config.station == FRAD_STATION_CPE)
+			sdla_reconfig(slave);
+		else
+			sdla_cmd(slave, SDLA_DELETE_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
+	}
+
+	return(0);
+}
+
+int sdla_dlci_conf(struct net_device *slave, struct net_device *master, int get)
+{
+	struct frad_local *flp;
+	struct dlci_local *dlp;
+	int               i;
+	short             len, ret;
+
+	flp = slave->priv;
+
+	for(i=0;i<CONFIG_DLCI_MAX;i++)
+		if (flp->master[i] == master)
+			break;
+
+	if (i == CONFIG_DLCI_MAX)
+		return(-ENODEV);
+
+	dlp = master->priv;
+
+	ret = SDLA_RET_OK;
+	len = sizeof(struct dlci_conf);
+	if (slave->start) {
+		if (get)
+			ret = sdla_cmd(slave, SDLA_READ_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,  
+			            NULL, 0, &dlp->config, &len);
+		else
+			ret = sdla_cmd(slave, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,  
+			            &dlp->config, sizeof(struct dlci_conf) - 4 * sizeof(short), NULL, NULL);
+	}
+
+	return(ret == SDLA_RET_OK ? 0 : -EIO);
+}
+
+/**************************
+ *
+ * now for the Linux driver 
+ *
+ **************************/
+
+/* NOTE: the DLCI driver deals with freeing the SKB!! */
+static int sdla_transmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct frad_local *flp;
+	int               ret, addr, accept;
+	short             size;
+	unsigned long     flags;
+	struct buf_entry  *pbuf;
+
+	flp = dev->priv;
+	ret = 0;
+	accept = 1;
+
+	if (dev->tbusy) 
+		return(1);
+
+	if (skb == NULL) 
+		return(0);
+
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
+		printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
+	else
+	{
+		/*
+		 * stupid GateD insists on setting up the multicast router thru us
+		 * and we're ill equipped to handle a non Frame Relay packet at this
+		 * time!
+		 */
+
+		accept = 1;
+		switch (dev->type)
+		{
+			case ARPHRD_FRAD:
+				if (skb->dev->type != ARPHRD_DLCI)
+				{
+					printk(KERN_WARNING "%s: Non DLCI device, type %i, tried to send on FRAD module.\n", dev->name, skb->dev->type);
+					accept = 0;
+				}
+				break;
+
+			default:
+				printk(KERN_WARNING "%s: unknown firmware type 0x%4.4X\n", dev->name, dev->type);
+				accept = 0;
+				break;
+		}
+
+		if (accept)
+		{
+			/* this is frame specific, but till there's a PPP module, it's the default */
+			switch (flp->type)
+			{
+				case SDLA_S502A:
+				case SDLA_S502E:
+					ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, skb->data, skb->len, NULL, NULL);
+					break;
+
+				case SDLA_S508:
+					size = sizeof(addr);
+					ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, NULL, skb->len, &addr, &size);
+					if (ret == SDLA_RET_OK)
+					{
+						save_flags(flags); 
+						cli();
+						SDLA_WINDOW(dev, addr);
+						pbuf = (void *)(((int) dev->mem_start) + (addr & SDLA_ADDR_MASK));
+
+						sdla_write(dev, pbuf->buf_addr, skb->data, skb->len);
+
+						SDLA_WINDOW(dev, addr);
+						pbuf->opp_flag = 1;
+						restore_flags(flags);
+					}
+					break;
+			}
+
+			switch (ret)
+			{
+				case SDLA_RET_OK:
+					flp->stats.tx_packets++;
+					ret = DLCI_RET_OK;
+					break;
+
+				case SDLA_RET_CIR_OVERFLOW:
+				case SDLA_RET_BUF_OVERSIZE:
+				case SDLA_RET_NO_BUFS:
+					flp->stats.tx_dropped++;
+					ret = DLCI_RET_DROP;
+					break;
+
+				default:
+					flp->stats.tx_errors++;
+					ret = DLCI_RET_ERR;
+					break;
+			}
+		}
+		dev->tbusy = 0;
+	}
+	return(ret);
+}
+
+static void sdla_receive(struct net_device *dev)
+{
+	struct net_device	  *master;
+	struct frad_local *flp;
+	struct dlci_local *dlp;
+	struct sk_buff	 *skb;
+
+	struct sdla_cmd	*cmd;
+	struct buf_info	*pbufi;
+	struct buf_entry  *pbuf;
+
+	unsigned long	  flags;
+	int               i, received, success, addr, buf_base, buf_top;
+	short             dlci, len, len2, split;
+
+	flp = dev->priv;
+	success = 1;
+	received = addr = buf_top = buf_base = 0;
+	len = dlci = 0;
+	skb = NULL;
+	master = NULL;
+	cmd = NULL;
+	pbufi = NULL;
+	pbuf = NULL;
+
+	save_flags(flags);
+	cli();
+
+	switch (flp->type)
+	{
+		case SDLA_S502A:
+		case SDLA_S502E:
+			cmd = (void *) (dev->mem_start + (SDLA_502_RCV_BUF & SDLA_ADDR_MASK));
+			SDLA_WINDOW(dev, SDLA_502_RCV_BUF);
+			success = cmd->opp_flag;
+			if (!success)
+				break;
+
+			dlci = cmd->dlci;
+			len = cmd->length;
+			break;
+
+		case SDLA_S508:
+			pbufi = (void *) (dev->mem_start + (SDLA_508_RXBUF_INFO & SDLA_ADDR_MASK));
+			SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
+			pbuf = (void *) (dev->mem_start + ((pbufi->rse_base + flp->buffer * sizeof(struct buf_entry)) & SDLA_ADDR_MASK));
+			success = pbuf->opp_flag;
+			if (!success)
+				break;
+
+			buf_top = pbufi->buf_top;
+			buf_base = pbufi->buf_base;
+			dlci = pbuf->dlci;
+			len = pbuf->length;
+			addr = pbuf->buf_addr;
+			break;
+	}
+
+	/* common code, find the DLCI and get the SKB */
+	if (success)
+	{
+		for (i=0;i<CONFIG_DLCI_MAX;i++)
+			if (flp->dlci[i] == dlci)
+				break;
+
+		if (i == CONFIG_DLCI_MAX)
+		{
+			printk(KERN_NOTICE "%s: Received packet from invalid DLCI %i, ignoring.", dev->name, dlci);
+			flp->stats.rx_errors++;
+			success = 0;
+		}
+	}
+
+	if (success)
+	{
+		master = flp->master[i];
+		skb = dev_alloc_skb(len + sizeof(struct frhdr));
+		if (skb == NULL) 
+		{
+			printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+			flp->stats.rx_dropped++; 
+			success = 0;
+		}
+		else
+			skb_reserve(skb, sizeof(struct frhdr));
+	}
+
+	/* pick up the data */
+	switch (flp->type)
+	{
+		case SDLA_S502A:
+		case SDLA_S502E:
+			if (success)
+				sdla_read(dev, SDLA_502_RCV_BUF + SDLA_502_DATA_OFS, skb_put(skb,len), len);
+
+			SDLA_WINDOW(dev, SDLA_502_RCV_BUF);
+			cmd->opp_flag = 0;
+			break;
+
+		case SDLA_S508:
+			if (success)
+			{
+				/* is this buffer split off the end of the internal ring buffer */
+				split = addr + len > buf_top + 1 ? len - (buf_top - addr + 1) : 0;
+				len2 = len - split;
+
+				sdla_read(dev, addr, skb_put(skb, len2), len2);
+				if (split)
+					sdla_read(dev, buf_base, skb_put(skb, split), split);
+			}
+
+			/* increment the buffer we're looking at */
+			SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
+			flp->buffer = (flp->buffer + 1) % pbufi->rse_num;
+			pbuf->opp_flag = 0;
+			break;
+	}
+
+	if (success)
+	{
+		flp->stats.rx_packets++;
+		dlp = master->priv;
+		(*dlp->receive)(skb, master);
+	}
+
+	restore_flags(flags);
+}
+
+static void sdla_isr(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct net_device     *dev;
+	struct frad_local *flp;
+	char              byte;
+
+	dev = dev_id;
+
+	if (dev == NULL)
+	{
+		printk(KERN_WARNING "sdla_isr(): irq %d for unknown device.\n", irq);
+		return;
+	}
+
+	flp = dev->priv;
+
+	if (!flp->initialized)
+	{
+		printk(KERN_WARNING "%s: irq %d for uninitialized device.\n", dev->name, irq);
+		return;
+	}
+
+	dev->interrupt = 1;
+	byte = sdla_byte(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE);
+	switch (byte)
+	{
+		case SDLA_INTR_RX:
+			sdla_receive(dev);
+			break;
+
+		/* the command will get an error return, which is processed above */
+		case SDLA_INTR_MODEM:
+		case SDLA_INTR_STATUS:
+			sdla_cmd(dev, SDLA_READ_DLC_STATUS, 0, 0, NULL, 0, NULL, NULL);
+			break;
+
+		case SDLA_INTR_TX:
+		case SDLA_INTR_COMPLETE:
+		case SDLA_INTR_TIMER:
+			printk(KERN_WARNING "%s: invalid irq flag 0x%02X.\n", dev->name, byte);
+			break;
+	}
+
+	/* the S502E requires a manual acknowledgement of the interrupt */ 
+	if (flp->type == SDLA_S502E)
+	{
+		flp->state &= ~SDLA_S502E_INTACK;
+		outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+		flp->state |= SDLA_S502E_INTACK;
+		outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+	}
+
+	/* this clears the byte, informing the Z80 we're done */
+	byte = 0;
+	sdla_write(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE, &byte, sizeof(byte));
+	dev->interrupt = 0;
+}
+
+static void sdla_poll(unsigned long device)
+{
+	struct net_device	  *dev;
+	struct frad_local *flp;
+
+	dev = (struct net_device *) device;
+	flp = dev->priv;
+
+	if (sdla_byte(dev, SDLA_502_RCV_BUF))
+		sdla_receive(dev);
+
+	flp->timer.expires = 1;
+	add_timer(&flp->timer);
+}
+
+static int sdla_close(struct net_device *dev)
+{
+	struct frad_local *flp;
+	struct intr_info  intr;
+	int               len, i;
+	short             dlcis[CONFIG_DLCI_MAX];
+
+	flp = dev->priv;
+
+	len = 0;
+	for(i=0;i<CONFIG_DLCI_MAX;i++)
+		if (flp->dlci[i])
+			dlcis[len++] = abs(flp->dlci[i]);
+	len *= 2;
+
+	if (flp->config.station == FRAD_STATION_NODE)
+	{
+		for(i=0;i<CONFIG_DLCI_MAX;i++)
+			if (flp->dlci[i] > 0) 
+				sdla_cmd(dev, SDLA_DEACTIVATE_DLCI, 0, 0, dlcis, len, NULL, NULL);
+		sdla_cmd(dev, SDLA_DELETE_DLCI, 0, 0, &flp->dlci[i], sizeof(flp->dlci[i]), NULL, NULL);
+	}
+
+	memset(&intr, 0, sizeof(intr));
+	/* let's start up the reception */
+	switch(flp->type)
+	{
+		case SDLA_S502A:
+			del_timer(&flp->timer); 
+			break;
+
+		case SDLA_S502E:
+			sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(char) + sizeof(short), NULL, NULL);
+			flp->state &= ~SDLA_S502E_INTACK;
+			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+			break;
+
+		case SDLA_S507:
+			break;
+
+		case SDLA_S508:
+			sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(struct intr_info), NULL, NULL);
+			flp->state &= ~SDLA_S508_INTEN;
+			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+			break;
+	}
+
+	sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
+
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	MOD_DEC_USE_COUNT;
+
+	return(0);
+}
+
+struct conf_data {
+	struct frad_conf config;
+	short            dlci[CONFIG_DLCI_MAX];
+};
+
+static int sdla_open(struct net_device *dev)
+{
+	struct frad_local *flp;
+	struct dlci_local *dlp;
+	struct conf_data  data;
+	struct intr_info  intr;
+	int               len, i;
+	char              byte;
+
+	flp = dev->priv;
+
+	if (!flp->initialized)
+		return(-EPERM);
+
+	if (!flp->configured)
+		return(-EPERM);
+
+	/* time to send in the configuration */
+	len = 0;
+	for(i=0;i<CONFIG_DLCI_MAX;i++)
+		if (flp->dlci[i])
+			data.dlci[len++] = abs(flp->dlci[i]);
+	len *= 2;
+
+	memcpy(&data.config, &flp->config, sizeof(struct frad_conf));
+	len += sizeof(struct frad_conf);
+
+	sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
+	sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, 0, 0, &data, len, NULL, NULL);
+
+	if (flp->type == SDLA_S508)
+		flp->buffer = 0;
+
+	sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
+
+	/* let's start up the reception */
+	memset(&intr, 0, sizeof(intr));
+	switch(flp->type)
+	{
+		case SDLA_S502A:
+			flp->timer.expires = 1;
+			add_timer(&flp->timer);
+			break;
+
+		case SDLA_S502E:
+			flp->state |= SDLA_S502E_ENABLE;
+			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+			flp->state |= SDLA_S502E_INTACK;
+			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+			byte = 0;
+			sdla_write(dev, SDLA_502_IRQ_INTERFACE, &byte, sizeof(byte));
+			intr.flags = SDLA_INTR_RX | SDLA_INTR_STATUS | SDLA_INTR_MODEM;
+			sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(char) + sizeof(short), NULL, NULL);
+			break;
+
+		case SDLA_S507:
+			break;
+
+		case SDLA_S508:
+			flp->state |= SDLA_S508_INTEN;
+			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+			byte = 0;
+			sdla_write(dev, SDLA_508_IRQ_INTERFACE, &byte, sizeof(byte));
+			intr.flags = SDLA_INTR_RX | SDLA_INTR_STATUS | SDLA_INTR_MODEM;
+			intr.irq = dev->irq;
+			sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(struct intr_info), NULL, NULL);
+			break;
+	}
+
+	if (flp->config.station == FRAD_STATION_CPE)
+	{
+		byte = SDLA_ICS_STATUS_ENQ;
+		sdla_cmd(dev, SDLA_ISSUE_IN_CHANNEL_SIGNAL, 0, 0, &byte, sizeof(byte), NULL, NULL);
+	}
+	else
+	{
+		sdla_cmd(dev, SDLA_ADD_DLCI, 0, 0, data.dlci, len - sizeof(struct frad_conf), NULL, NULL);
+		for(i=0;i<CONFIG_DLCI_MAX;i++)
+			if (flp->dlci[i] > 0)
+				sdla_cmd(dev, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], 2*sizeof(flp->dlci[i]), NULL, NULL);
+	}
+
+	/* configure any specific DLCI settings */
+	for(i=0;i<CONFIG_DLCI_MAX;i++)
+		if (flp->dlci[i])
+		{
+			dlp = flp->master[i]->priv;
+			if (dlp->configured)
+				sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0, &dlp->config, sizeof(struct dlci_conf), NULL, NULL);
+		}
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	MOD_INC_USE_COUNT;
+
+	return(0);
+}
+
+static int sdla_config(struct net_device *dev, struct frad_conf *conf, int get)
+{
+	struct frad_local *flp;
+	struct conf_data  data;
+	int               i;
+	short             size;
+
+	if (dev->type == 0xFFFF)
+		return(-EUNATCH);
+
+	flp = dev->priv;
+
+	if (!get)
+	{
+		if (dev->start)
+			return(-EBUSY);
+
+		if(copy_from_user(&data.config, conf, sizeof(struct frad_conf)))
+			return -EFAULT;
+
+		if (data.config.station & ~FRAD_STATION_NODE)
+			return(-EINVAL);
+
+		if (data.config.flags & ~FRAD_VALID_FLAGS)
+			return(-EINVAL);
+
+		if ((data.config.kbaud < 0) || 
+			 ((data.config.kbaud > 128) && (flp->type != SDLA_S508)))
+			return(-EINVAL);
+
+		if (data.config.clocking & ~(FRAD_CLOCK_INT | SDLA_S508_PORT_RS232))
+			return(-EINVAL);
+
+		if ((data.config.mtu < 0) || (data.config.mtu > SDLA_MAX_MTU))
+			return(-EINVAL);
+
+		if ((data.config.T391 < 5) || (data.config.T391 > 30))
+			return(-EINVAL);
+
+		if ((data.config.T392 < 5) || (data.config.T392 > 30))
+			return(-EINVAL);
+
+		if ((data.config.N391 < 1) || (data.config.N391 > 255))
+			return(-EINVAL);
+
+		if ((data.config.N392 < 1) || (data.config.N392 > 10))
+			return(-EINVAL);
+
+		if ((data.config.N393 < 1) || (data.config.N393 > 10))
+			return(-EINVAL);
+
+		memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
+		flp->config.flags |= SDLA_DIRECT_RECV;
+
+		if (flp->type == SDLA_S508)
+			flp->config.flags |= SDLA_TX70_RX30;
+
+		if (dev->mtu != flp->config.mtu)
+		{
+			/* this is required to change the MTU */
+			dev->mtu = flp->config.mtu;
+			for(i=0;i<CONFIG_DLCI_MAX;i++)
+				if (flp->master[i])
+					flp->master[i]->mtu = flp->config.mtu;
+		}
+
+		flp->config.mtu += sizeof(struct frhdr);
+
+		/* off to the races! */
+		if (!flp->configured)
+			sdla_start(dev);
+
+		flp->configured = 1;
+	}
+	else
+	{
+		/* no sense reading if the CPU isn't started */
+		if (dev->start)
+		{
+			size = sizeof(data);
+			if (sdla_cmd(dev, SDLA_READ_DLCI_CONFIGURATION, 0, 0, NULL, 0, &data, &size) != SDLA_RET_OK)
+				return(-EIO);
+		}
+		else
+			if (flp->configured)
+				memcpy(&data.config, &flp->config, sizeof(struct frad_conf));
+			else
+				memset(&data.config, 0, sizeof(struct frad_conf));
+
+		memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
+		data.config.flags &= FRAD_VALID_FLAGS;
+		data.config.mtu -= data.config.mtu > sizeof(struct frhdr) ? sizeof(struct frhdr) : data.config.mtu;
+		return copy_to_user(conf, &data.config, sizeof(struct frad_conf))?-EFAULT:0;
+	}
+
+	return(0);
+}
+
+static int sdla_xfer(struct net_device *dev, struct sdla_mem *info, int read)
+{
+	struct sdla_mem mem;
+	char	*temp;
+
+	if(copy_from_user(&mem, info, sizeof(mem)))
+		return -EFAULT;
+		
+	if (read)
+	{	
+		temp = kmalloc(mem.len, GFP_KERNEL);
+		if (!temp)
+			return(-ENOMEM);
+		sdla_read(dev, mem.addr, temp, mem.len);
+		if(copy_to_user(mem.data, temp, mem.len))
+			return -EFAULT;
+		kfree(temp);
+	}
+	else
+	{
+		temp = kmalloc(mem.len, GFP_KERNEL);
+		if (!temp)
+			return(-ENOMEM);
+		if(copy_from_user(temp, mem.data, mem.len))
+			return -EFAULT;
+		sdla_write(dev, mem.addr, temp, mem.len);
+		kfree(temp);
+	}
+	return(0);
+}
+
+static int sdla_reconfig(struct net_device *dev)
+{
+	struct frad_local *flp;
+	struct conf_data  data;
+	int               i, len;
+
+	flp = dev->priv;
+
+	len = 0;
+	for(i=0;i<CONFIG_DLCI_MAX;i++)
+		if (flp->dlci[i])
+			data.dlci[len++] = flp->dlci[i];
+	len *= 2;
+
+	memcpy(&data, &flp->config, sizeof(struct frad_conf));
+	len += sizeof(struct frad_conf);
+
+	sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
+	sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, 0, 0, &data, len, NULL, NULL);
+	sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
+
+	return(0);
+}
+
+static int sdla_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct frad_local *flp;
+
+	if(!suser())
+		return -EPERM;
+		
+	flp = dev->priv;
+
+	if (!flp->initialized)
+		return(-EINVAL);
+
+	switch (cmd)
+	{
+		case FRAD_GET_CONF:
+		case FRAD_SET_CONF:
+			return(sdla_config(dev, (struct frad_conf *)ifr->ifr_data, cmd == FRAD_GET_CONF));
+
+		case SDLA_IDENTIFY:
+			ifr->ifr_flags = flp->type;
+			break;
+
+		case SDLA_CPUSPEED:
+			return(sdla_cpuspeed(dev, ifr)); 
+
+/* ==========================================================
+NOTE:  This is rather a useless action right now, as the
+       current driver does not support protocols other than
+       FR.  However, Sangoma has modules for a number of
+       other protocols in the works.
+============================================================*/
+		case SDLA_PROTOCOL:
+			if (flp->configured)
+				return(-EALREADY);
+
+			switch (ifr->ifr_flags)
+			{
+				case ARPHRD_FRAD:
+					dev->type = ifr->ifr_flags;
+					break;
+				default:
+					return(-ENOPROTOOPT);
+			}
+			break;
+
+		case SDLA_CLEARMEM:
+			sdla_clear(dev);
+			break;
+
+		case SDLA_WRITEMEM:
+		case SDLA_READMEM:
+			return(sdla_xfer(dev, (struct sdla_mem *)ifr->ifr_data, cmd == SDLA_READMEM));
+
+		case SDLA_START:
+			sdla_start(dev);
+			break;
+
+		case SDLA_STOP:
+			sdla_stop(dev);
+			break;
+
+		default:
+			return(-EOPNOTSUPP);
+	}
+	return(0);
+}
+
+int sdla_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct frad_local *flp;
+
+	flp = dev->priv;
+
+	if (dev->start)
+		return(-EBUSY);
+
+	/* for now, you can't change the MTU! */
+	return(-EOPNOTSUPP);
+}
+
+int sdla_set_config(struct net_device *dev, struct ifmap *map)
+{
+	struct frad_local *flp;
+	int               i;
+	char              byte;
+
+	flp = dev->priv;
+
+	if (flp->initialized)
+		return(-EINVAL);
+
+	for(i=0;i < sizeof(valid_port) / sizeof (int) ; i++)
+		if (valid_port[i] == map->base_addr)
+			break;   
+
+	if (i == sizeof(valid_port) / sizeof(int))
+		return(-EINVAL);
+
+	dev->base_addr = map->base_addr;
+	request_region(dev->base_addr, SDLA_IO_EXTENTS, dev->name);
+
+	/* test for card types, S502A, S502E, S507, S508                 */
+	/* these tests shut down the card completely, so clear the state */
+	flp->type = SDLA_UNKNOWN;
+	flp->state = 0;
+   
+	for(i=1;i<SDLA_IO_EXTENTS;i++)
+		if (inb(dev->base_addr + i) != 0xFF)
+			break;
+
+	if (i == SDLA_IO_EXTENTS)
+	{   
+		outb(SDLA_HALT, dev->base_addr + SDLA_REG_Z80_CONTROL);
+		if ((inb(dev->base_addr + SDLA_S502_STS) & 0x0F) == 0x08)
+		{
+			outb(SDLA_S502E_INTACK, dev->base_addr + SDLA_REG_CONTROL);
+			if ((inb(dev->base_addr + SDLA_S502_STS) & 0x0F) == 0x0C)
+			{
+				outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
+				flp->type = SDLA_S502E;
+			}
+		}
+	}
+
+	if (flp->type == SDLA_UNKNOWN)
+	{
+		for(byte=inb(dev->base_addr),i=0;i<SDLA_IO_EXTENTS;i++)
+			if (inb(dev->base_addr + i) != byte)
+				break;
+
+		if (i == SDLA_IO_EXTENTS)
+		{
+			outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
+			if ((inb(dev->base_addr + SDLA_S502_STS) & 0x7E) == 0x30)
+			{
+				outb(SDLA_S507_ENABLE, dev->base_addr + SDLA_REG_CONTROL);
+				if ((inb(dev->base_addr + SDLA_S502_STS) & 0x7E) == 0x32)
+				{
+					outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
+					flp->type = SDLA_S507;
+				}
+			}
+		}
+	}
+
+	if (flp->type == SDLA_UNKNOWN)
+	{
+		outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
+		if ((inb(dev->base_addr + SDLA_S508_STS) & 0x3F) == 0x00)
+		{
+			outb(SDLA_S508_INTEN, dev->base_addr + SDLA_REG_CONTROL);
+			if ((inb(dev->base_addr + SDLA_S508_STS) & 0x3F) == 0x10)
+			{
+				outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
+				flp->type = SDLA_S508;
+			}
+		}
+	}
+
+	if (flp->type == SDLA_UNKNOWN)
+	{
+		outb(SDLA_S502A_HALT, dev->base_addr + SDLA_REG_CONTROL);
+		if (inb(dev->base_addr + SDLA_S502_STS) == 0x40)
+		{
+			outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
+			if (inb(dev->base_addr + SDLA_S502_STS) == 0x40)
+			{
+				outb(SDLA_S502A_INTEN, dev->base_addr + SDLA_REG_CONTROL);
+				if (inb(dev->base_addr + SDLA_S502_STS) == 0x44)
+				{
+					outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
+					flp->type = SDLA_S502A;
+				}
+			}
+		}
+	}
+
+	if (flp->type == SDLA_UNKNOWN)
+	{
+		printk(KERN_NOTICE "%s: Unknown card type\n", dev->name);
+		return(-ENODEV);
+	}
+
+	switch(dev->base_addr)
+	{
+		case 0x270:
+		case 0x280:
+		case 0x380: 
+		case 0x390:
+			if ((flp->type != SDLA_S508) && (flp->type != SDLA_S507))
+				return(-EINVAL);
+	}
+
+	switch (map->irq)
+	{
+		case 2:
+			if (flp->type != SDLA_S502E)
+				return(-EINVAL);
+			break;
+
+		case 10:
+		case 11:
+		case 12:
+		case 15:
+		case 4:
+			if ((flp->type != SDLA_S508) && (flp->type != SDLA_S507))
+				return(-EINVAL);
+
+		case 3:
+		case 5:
+		case 7:
+			if (flp->type == SDLA_S502A)
+				return(-EINVAL);
+			break;
+
+		default:
+			return(-EINVAL);
+	}
+	dev->irq = map->irq;
+
+	if (request_irq(dev->irq, &sdla_isr, 0, dev->name, dev)) 
+		return(-EAGAIN);
+
+	if (flp->type == SDLA_S507)
+	{
+		switch(dev->irq)
+		{
+			case 3:
+				flp->state = SDLA_S507_IRQ3;
+				break;
+			case 4:
+				flp->state = SDLA_S507_IRQ4;
+				break;
+			case 5:
+				flp->state = SDLA_S507_IRQ5;
+				break;
+			case 7:
+				flp->state = SDLA_S507_IRQ7;
+				break;
+			case 10:
+				flp->state = SDLA_S507_IRQ10;
+				break;
+			case 11:
+				flp->state = SDLA_S507_IRQ11;
+				break;
+			case 12:
+				flp->state = SDLA_S507_IRQ12;
+				break;
+			case 15:
+				flp->state = SDLA_S507_IRQ15;
+				break;
+		}
+	}
+
+	for(i=0;i < sizeof(valid_mem) / sizeof (int) ; i++)
+		if (valid_mem[i] == map->mem_start)
+			break;   
+
+	if (i == sizeof(valid_mem) / sizeof(int))
+	/*
+	 *	FIXME:
+	 *	BUG BUG BUG: MUST RELEASE THE IRQ WE ALLOCATED IN
+	 *	ALL THESE CASES
+	 *
+	 */
+		return(-EINVAL);
+
+	if ((flp->type == SDLA_S502A) && (((map->mem_start & 0xF000) >> 12) == 0x0E))
+		return(-EINVAL);
+
+	if ((flp->type != SDLA_S507) && ((map->mem_start >> 16) == 0x0B))
+		return(-EINVAL);
+
+	if ((flp->type == SDLA_S507) && ((map->mem_start >> 16) == 0x0D))
+		return(-EINVAL);
+
+	dev->mem_start = map->mem_start;
+	dev->mem_end = dev->mem_start + 0x2000;
+
+	byte = flp->type != SDLA_S508 ? SDLA_8K_WINDOW : 0;
+	byte |= (map->mem_start & 0xF000) >> (12 + (flp->type == SDLA_S508 ? 1 : 0));
+	switch(flp->type)
+	{
+		case SDLA_S502A:
+		case SDLA_S502E:
+			switch (map->mem_start >> 16)
+			{
+				case 0x0A:
+					byte |= SDLA_S502_SEG_A;
+					break;
+				case 0x0C:
+					byte |= SDLA_S502_SEG_C;
+					break;
+				case 0x0D:
+					byte |= SDLA_S502_SEG_D;
+					break;
+				case 0x0E:
+					byte |= SDLA_S502_SEG_E;
+					break;
+			}
+			break;
+		case SDLA_S507:
+			switch (map->mem_start >> 16)
+			{
+				case 0x0A:
+					byte |= SDLA_S507_SEG_A;
+					break;
+				case 0x0B:
+					byte |= SDLA_S507_SEG_B;
+					break;
+				case 0x0C:
+					byte |= SDLA_S507_SEG_C;
+					break;
+				case 0x0E:
+					byte |= SDLA_S507_SEG_E;
+					break;
+			}
+			break;
+		case SDLA_S508:
+			switch (map->mem_start >> 16)
+			{
+				case 0x0A:
+					byte |= SDLA_S508_SEG_A;
+					break;
+				case 0x0C:
+					byte |= SDLA_S508_SEG_C;
+					break;
+				case 0x0D:
+					byte |= SDLA_S508_SEG_D;
+					break;
+				case 0x0E:
+					byte |= SDLA_S508_SEG_E;
+					break;
+			}
+			break;
+	}
+
+	/* set the memory bits, and enable access */
+	outb(byte, dev->base_addr + SDLA_REG_PC_WINDOW);
+
+	switch(flp->type)
+	{
+		case SDLA_S502E:
+			flp->state = SDLA_S502E_ENABLE;
+			break;
+		case SDLA_S507:
+			flp->state |= SDLA_MEMEN;
+			break;
+		case SDLA_S508:
+			flp->state = SDLA_MEMEN;
+			break;
+	}
+	outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+
+	flp->initialized = 1;
+	return(0);
+}
+ 
+static struct net_device_stats *sdla_stats(struct net_device *dev)
+{
+	struct frad_local *flp;
+	flp = dev->priv;
+
+	return(&flp->stats);
+}
+
+int __init sdla_init(struct net_device *dev)
+{
+	struct frad_local *flp;
+
+	/* allocate the private data structure */
+	flp = kmalloc(sizeof(struct frad_local), GFP_KERNEL);
+	if (!flp)
+		return(-ENOMEM);
+
+	memset(flp, 0, sizeof(struct frad_local));
+	dev->priv = flp;
+
+	dev->flags		= 0;
+	dev->open		= sdla_open;
+	dev->stop		= sdla_close;
+	dev->do_ioctl		= sdla_ioctl;
+	dev->set_config		= sdla_set_config;
+	dev->get_stats		= sdla_stats;
+	dev->hard_start_xmit	= sdla_transmit;
+	dev->change_mtu		= sdla_change_mtu;
+
+	dev->type		= 0xFFFF;
+	dev->hard_header_len = 0;
+	dev->addr_len		= 0;
+	dev->mtu		= SDLA_MAX_MTU;
+
+	dev_init_buffers(dev);
+   
+	flp->activate		= sdla_activate;
+	flp->deactivate		= sdla_deactivate;
+	flp->assoc		= sdla_assoc;
+	flp->deassoc		= sdla_deassoc;
+	flp->dlci_conf		= sdla_dlci_conf;
+
+	init_timer(&flp->timer);
+	flp->timer.expires	= 1;
+	flp->timer.data		= (unsigned long) dev;
+	flp->timer.function	= sdla_poll;
+
+	return(0);
+}
+
+void __init sdla_setup(void)
+{
+	printk("%s.\n", version);
+	register_frad(devname);
+}
+
+#ifdef MODULE
+static struct net_device sdla0 = {"sdla0", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, sdla_init};
+
+int init_module(void)
+{
+	int result;
+
+	sdla_setup();
+	if ((result = register_netdev(&sdla0)) != 0)
+		return result;
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	unregister_netdev(&sdla0);
+	if (sdla0.priv)
+		kfree(sdla0.priv);
+	if (sdla0.irq)
+		free_irq(sdla0.irq, &sdla0);
+}
+#endif /* MODULE */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/sdla_fr.c linux/drivers/net/wan/sdla_fr.c
--- v2.3.20/linux/drivers/net/wan/sdla_fr.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/sdla_fr.c	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,3127 @@
+/*****************************************************************************
+* sdla_fr.c	WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module.
+*
+* Author(s):	Gene Kozin	
+*		Jaspreet Singh		<jaspreet@sangoma.com>
+*
+* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
+*
+*		This program is free software; you can redistribute it and/or
+*		modify it under the terms of the GNU General Public License
+*		as published by the Free Software Foundation; either version
+*		2 of the License, or (at your option) any later version.
+* ============================================================================
+* Nov 26, 1997	Jaspreet Singh	o Improved load sharing with multiple boards
+*				o Added Cli() to protect enabling of interrupts
+*				  while polling is called.
+* Nov 24, 1997	Jaspreet Singh	o Added counters to avoid enabling of interrupts
+*				  when they have been disabled by another
+*				  interface or routine (eg. wpf_poll).
+* Nov 06, 1997	Jaspreet Singh	o Added INTR_TEST_MODE to avoid polling	
+*				  routine disable interrupts during interrupt
+*				  testing.
+* Oct 20, 1997  Jaspreet Singh  o Added hooks in for Router UP time.
+* Oct 16, 1997  Jaspreet Singh  o The critical flag is used to maintain flow
+*                                 control by avoiding RACE conditions.  The
+*                                 cli() and restore_flags() are taken out.
+*                                 The fr_channel structure is appended for 
+*                                 Driver Statistics.
+* Oct 15, 1997  Farhan Thawar    o updated if_send() and receive for IPX
+* Aug 29, 1997  Farhan Thawar    o Removed most of the cli() and sti()
+*                                o Abstracted the UDP management stuff
+*                                o Now use tbusy and critical more intelligently
+* Jul 21, 1997  Jaspreet Singh	 o Can configure T391, T392, N391, N392 & N393
+*				   through router.conf.
+*				 o Protected calls to sdla_peek() by adDing 
+*				   save_flags(), cli() and restore_flags().
+*				 o Added error message for Inactive DLCIs in
+*				   fr_event() and update_chan_state().
+*				 o Fixed freeing up of buffers using kfree() 
+*			           when packets are received.
+* Jul 07, 1997	Jaspreet Singh	 o Added configurable TTL for UDP packets 
+*				 o Added ability to discard multicast and 
+*				   broadcast source addressed packets
+* Jun 27, 1997	Jaspreet Singh	 o Added FT1 monitor capabilities 
+*				   New case (0x44) statement in if_send routine *				   Added a global variable rCount to keep track
+*			 	   of FT1 status enabled on the board.
+* May 29, 1997	Jaspreet Singh	 o Fixed major Flow Control Problem
+*				   With multiple boards a problem was seen where
+*				   the second board always stopped transmitting
+*				   packet after running for a while. The code
+*				   got into a stage where the interrupts were
+*				   disabled and dev->tbusy was set to 1.
+*                  		   This caused the If_send() routine to get into*                                  the if clause for it(0,dev->tbusy) 
+*				   forever.
+*				   The code got into this stage due to an 
+*				   interrupt occurring within the if clause for 
+*				   set_bit(0,dev->tbusy).  Since an interrupt 
+*				   disables furhter transmit interrupt and 
+* 				   makes dev->tbusy = 0, this effect was undone *                                  by making dev->tbusy = 1 in the if clause.
+*				   The Fix checks to see if Transmit interrupts
+*				   are disabled then do not make dev->tbusy = 1
+* 	   			   Introduced a global variable: int_occur and
+*				   added tx_int_enabled in the wan_device 
+*				   structure.	
+* May 21, 1997  Jaspreet Singh   o Fixed UDP Management for multiple
+*                                  boards.
+*
+* Apr 25, 1997  Farhan Thawar    o added UDP Management stuff
+*                                o fixed bug in if_send() and tx_intr() to
+*                                  sleep and wakeup all devices
+* Mar 11, 1997  Farhan Thawar   Version 3.1.1
+*                                o fixed (+1) bug in fr508_rx_intr()
+*                                o changed if_send() to return 0 if
+*                                  wandev.critical() is true
+*                                o free socket buffer in if_send() if
+*                                  returning 0 
+*                                o added tx_intr() routine
+* Jan 30, 1997	Gene Kozin	Version 3.1.0
+*				 o implemented exec() entry point
+*				 o fixed a bug causing driver configured as
+*				   a FR switch to be stuck in WAN_
+*				   mode
+* Jan 02, 1997	Gene Kozin	Initial version.
+*****************************************************************************/
+
+#include <linux/kernel.h>	/* printk(), and other useful stuff */
+#include <linux/stddef.h>	/* offsetof(), etc. */
+#include <linux/errno.h>	/* return codes */
+#include <linux/string.h>	/* inline memset(), etc. */
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
+#include <linux/wanrouter.h>	/* WAN router definitions */
+#include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
+#include <linux/if_arp.h>	/* ARPHRD_* defines */
+#include <asm/byteorder.h>	/* htons(), etc. */
+#include <asm/io.h>		/* for inb(), outb(), etc. */
+#include <linux/time.h>		/* for do_gettimeofday */
+#define	_GNUC_
+#include <linux/sdla_fr.h>	/* frame relay firmware API definitions */
+#include <asm/uaccess.h>
+
+/****** Defines & Macros ****************************************************/
+
+#define	MAX_CMD_RETRY	10	/* max number of firmware retries */
+#define	FR_HEADER_LEN	8	/* max encapsulation header size */
+#define	FR_CHANNEL_MTU	1500	/* unfragmented logical channel MTU */
+
+/* Q.922 frame types */
+
+#define	Q922_UI		0x03	/* Unnumbered Info frame */
+#define	Q922_XID	0xAF	/* ??? */
+
+/* DLCI configured or not */
+
+#define DLCI_NOT_CONFIGURED	0x00
+#define DLCI_CONFIG_PENDING	0x01
+#define DLCI_CONFIGURED		0x02
+
+/* CIR enabled or not */
+
+#define CIR_ENABLED	0x00
+#define CIR_DISABLED	0x01
+
+/* Interrupt mode for DLCI = 0 */
+
+#define BUFFER_INTR_MODE	0x00
+#define DLCI_LIST_INTR_MODE	0x01
+
+/* Transmit Interrupt Status */
+
+#define DISABLED 		0x00
+#define WAITING_TO_BE_ENABLED	0x01
+
+/* For handle_IPXWAN() */
+
+#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b)))
+
+/****** Data Structures *****************************************************/
+
+/* This is an extention of the 'struct net_device' we create for each network
+ * interface to keep the rest of channel-specific data.
+ */
+typedef struct fr_channel {
+	char name[WAN_IFNAME_SZ + 1];	/* interface name, ASCIIZ */
+	unsigned dlci_configured;	/* check whether configured or not */
+	unsigned cir_status;	/* check whether CIR enabled or not */
+	unsigned dlci;		/* logical channel number */
+	unsigned cir;		/* committed information rate */
+	unsigned bc;		/* committed burst size */
+	unsigned be;		/* excess burst size */
+	unsigned mc;		/* multicast support on or off */
+	unsigned tx_int_status;	/* Transmit Interrupt Status */
+	unsigned short pkt_length;	/* Packet Length */
+	unsigned long router_start_time;	/* Router start time in seconds */
+	unsigned long tick_counter;	/* counter for transmit time out */
+	char dev_pending_devtint;	/* interface pending dev_tint() */
+	char state;		/* channel state */
+	void *dlci_int_interface;	/* pointer to the DLCI Interface */
+	unsigned long IB_addr;	/* physical address of Interface Byte */
+	unsigned long state_tick;	/* time of the last state change */
+	sdla_t *card;		/* -> owner */
+	struct net_device_stats ifstats;		/* interface statistics */
+	unsigned long if_send_entry;
+	unsigned long if_send_skb_null;
+	unsigned long if_send_broadcast;
+	unsigned long if_send_multicast;
+	unsigned long if_send_critical_ISR;
+	unsigned long if_send_critical_non_ISR;
+	unsigned long if_send_busy;
+	unsigned long if_send_busy_timeout;
+	unsigned long if_send_FPIPE_request;
+	unsigned long if_send_DRVSTATS_request;
+	unsigned long if_send_wan_disconnected;
+	unsigned long if_send_dlci_disconnected;
+	unsigned long if_send_no_bfrs;
+	unsigned long if_send_adptr_bfrs_full;
+	unsigned long if_send_bfrs_passed_to_adptr;
+	unsigned long rx_intr_no_socket;
+	unsigned long rx_intr_dev_not_started;
+	unsigned long rx_intr_FPIPE_request;
+	unsigned long rx_intr_DRVSTATS_request;
+	unsigned long rx_intr_bfr_not_passed_to_stack;
+	unsigned long rx_intr_bfr_passed_to_stack;
+	unsigned long UDP_FPIPE_mgmt_kmalloc_err;
+	unsigned long UDP_FPIPE_mgmt_direction_err;
+	unsigned long UDP_FPIPE_mgmt_adptr_type_err;
+	unsigned long UDP_FPIPE_mgmt_adptr_cmnd_OK;
+	unsigned long UDP_FPIPE_mgmt_adptr_cmnd_timeout;
+	unsigned long UDP_FPIPE_mgmt_adptr_send_passed;
+	unsigned long UDP_FPIPE_mgmt_adptr_send_failed;
+	unsigned long UDP_FPIPE_mgmt_not_passed_to_stack;
+	unsigned long UDP_FPIPE_mgmt_passed_to_stack;
+	unsigned long UDP_FPIPE_mgmt_no_socket;
+	unsigned long UDP_DRVSTATS_mgmt_kmalloc_err;
+	unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
+	unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
+	unsigned long UDP_DRVSTATS_mgmt_adptr_send_passed;
+	unsigned long UDP_DRVSTATS_mgmt_adptr_send_failed;
+	unsigned long UDP_DRVSTATS_mgmt_not_passed_to_stack;
+	unsigned long UDP_DRVSTATS_mgmt_passed_to_stack;
+	unsigned long UDP_DRVSTATS_mgmt_no_socket;
+	unsigned long router_up_time;
+} fr_channel_t;
+
+typedef struct dlci_status {
+	unsigned short dlci PACKED;
+	unsigned char state PACKED;
+} dlci_status_t;
+
+typedef struct dlci_IB_mapping {
+	unsigned short dlci PACKED;
+	unsigned long addr_value PACKED;
+} dlci_IB_mapping_t;
+
+/* This structure is used for DLCI list Tx interrupt mode.  It is used to
+   enable interrupt bit and set the packet length for transmission
+ */
+
+typedef struct fr_dlci_interface {
+	unsigned char gen_interrupt PACKED;
+	unsigned short packet_length PACKED;
+	unsigned char reserved PACKED;
+} fr_dlci_interface_t;
+
+static unsigned short num_frames;
+static unsigned long curr_trace_addr;
+static unsigned long start_trace_addr;
+static unsigned short available_buffer_space;
+static char TracingEnabled; /* variable for keeping track of enabling/disabling FT1 monitor status */
+static int rCount = 0;
+extern void disable_irq(unsigned int);
+extern void enable_irq(unsigned int);
+
+/* variable for keeping track of number of interrupts generated during 
+ * interrupt test routine 
+ */
+static int Intr_test_counter;
+
+/****** Function Prototypes *************************************************/
+
+/* WAN link driver entry points. These are called by the WAN router module. */
+static int update(wan_device_t * wandev);
+static int new_if(wan_device_t * wandev, struct net_device *dev,
+		  wanif_conf_t * conf);
+static int del_if(wan_device_t * wandev, struct net_device *dev);
+/* WANPIPE-specific entry points */
+static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data);
+/* Network device interface */
+static int if_init(struct net_device *dev);
+static int if_open(struct net_device *dev);
+static int if_close(struct net_device *dev);
+static int if_header(struct sk_buff *skb, struct net_device *dev,
+	    unsigned short type, void *daddr, void *saddr, unsigned len);
+static int if_rebuild_hdr(struct sk_buff *skb);
+static int if_send(struct sk_buff *skb, struct net_device *dev);
+static struct net_device_stats *if_stats(struct net_device *dev);
+/* Interrupt handlers */
+static void fr502_isr(sdla_t * card);
+static void fr508_isr(sdla_t * card);
+static void fr502_rx_intr(sdla_t * card);
+static void fr508_rx_intr(sdla_t * card);
+static void tx_intr(sdla_t * card);
+static void spur_intr(sdla_t * card);
+/* Background polling routines */
+static void wpf_poll(sdla_t * card);
+/* Frame relay firmware interface functions */
+static int fr_read_version(sdla_t * card, char *str);
+static int fr_configure(sdla_t * card, fr_conf_t * conf);
+static int fr_dlci_configure(sdla_t * card, fr_dlc_conf_t * conf, unsigned dlci);
+static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu);
+static int fr_comm_enable(sdla_t * card);
+static int fr_comm_disable(sdla_t * card);
+static int fr_get_err_stats(sdla_t * card);
+static int fr_get_stats(sdla_t * card);
+static int fr_add_dlci(sdla_t * card, int dlci, int num);
+static int fr_activate_dlci(sdla_t * card, int dlci, int num);
+static int fr_issue_isf(sdla_t * card, int isf);
+static int fr502_send(sdla_t * card, int dlci, int attr, int len, void *buf);
+static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf);
+/* Firmware asynchronous event handlers */
+static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox);
+static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox);
+static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox);
+/* Miscellaneous functions */
+static int update_chan_state(struct net_device *dev);
+static void set_chan_state(struct net_device *dev, int state);
+static struct net_device *find_channel(sdla_t * card, unsigned dlci);
+static int is_tx_ready(sdla_t * card, fr_channel_t * chan);
+static unsigned int dec_to_uint(unsigned char *str, int len);
+static int reply_udp(unsigned char *data, unsigned int mbox_len);
+static int intr_test(sdla_t * card);
+static void init_chan_statistics(fr_channel_t * chan);
+static void init_global_statistics(sdla_t * card);
+static void read_DLCI_IB_mapping(sdla_t * card, fr_channel_t * chan);
+/* Udp management functions */
+static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, int dlci, fr_channel_t * chan);
+static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, int dlci, fr_channel_t * chan);
+static int udp_pkt_type(struct sk_buff *skb, sdla_t * card);
+/* IPX functions */
+static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming);
+static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number);
+
+/****** Public Functions ****************************************************/
+
+/*============================================================================
+ * Frame relay protocol initialization routine.
+ *
+ * This routine is called by the main WANPIPE module during setup.  At this
+ * point adapter is completely initialized and firmware is running.
+ *  o read firmware version (to make sure it's alive)
+ *  o configure adapter
+ *  o initialize protocol-specific fields of the adapter data space.
+ *
+ * Return:	0	o.k.
+ *		< 0	failure.
+ */
+int wpf_init(sdla_t * card, wandev_conf_t * conf)
+{
+	union {
+		char str[80];
+		fr_conf_t cfg;
+	} u;
+	int i;
+	/* Verify configuration ID */
+	if (conf->config_id != WANCONFIG_FR) 
+	{
+		printk(KERN_INFO "%s: invalid configuration ID %u!\n",
+		       card->devname, conf->config_id);
+		return -EINVAL;
+	}
+	/* Initialize protocol-specific fields of adapter data space */
+	switch (card->hw.fwid) 
+	{
+		case SFID_FR502:
+			card->mbox = (void *) (card->hw.dpmbase + FR502_MBOX_OFFS);
+			card->rxmb = (void *) (card->hw.dpmbase + FR502_RXMB_OFFS);
+			card->flags = (void *) (card->hw.dpmbase + FR502_FLAG_OFFS);
+			card->isr = &fr502_isr;
+			break;
+		case SFID_FR508:
+			card->mbox = (void *) (card->hw.dpmbase + FR508_MBOX_OFFS);
+			card->flags = (void *) (card->hw.dpmbase + FR508_FLAG_OFFS);
+			card->isr = &fr508_isr;
+			break;
+		default:
+			return -EINVAL;
+	}
+	/* Read firmware version.  Note that when adapter initializes, it
+	 * clears the mailbox, so it may appear that the first command was
+	 * executed successfully when in fact it was merely erased. To work
+	 * around this, we execute the first command twice.
+	 */
+	if (fr_read_version(card, NULL) || fr_read_version(card, u.str))
+		return -EIO;
+	printk(KERN_INFO "%s: running frame relay firmware v%s\n",
+	       card->devname, u.str);
+	/* Adjust configuration */
+	conf->mtu = max(min(conf->mtu, 4080), FR_CHANNEL_MTU + FR_HEADER_LEN);
+	conf->bps = min(conf->bps, 2048000);
+	/* Configure adapter firmware */
+	memset(&u.cfg, 0, sizeof(u.cfg));
+	u.cfg.mtu = conf->mtu;
+	u.cfg.kbps = conf->bps / 1000;
+	u.cfg.cir_fwd = u.cfg.cir_bwd = 16;
+	u.cfg.bc_fwd = u.cfg.bc_bwd = 16;
+	if (conf->station == WANOPT_CPE) 
+	{
+		u.cfg.options = 0x0080;
+		printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname);
+	}
+	else
+	{
+		u.cfg.options = 0x0081;
+	}
+	switch (conf->u.fr.signalling) 
+	{
+		case WANOPT_FR_Q933:
+			u.cfg.options |= 0x0200;
+			break;
+		case WANOPT_FR_LMI:
+			u.cfg.options |= 0x0400;
+			break;
+	}
+	if (conf->station == WANOPT_CPE) 
+	{
+		u.cfg.options |= 0x8000;	/* auto config DLCI */
+		card->u.f.dlci_num = 0;
+	}
+	else
+	{
+		u.cfg.station = 1;	/* switch emulation mode */
+		/* For switch emulation we have to create a list of dlci(s)
+		 * that will be sent to be global SET_DLCI_CONFIGURATION 
+		 * command in fr_configure() routine. 
+		 */
+		card->u.f.dlci_num = min(max(conf->u.fr.dlci_num, 1), 100);
+		for (i = 0; i < card->u.f.dlci_num; i++) 
+		{
+			card->u.f.node_dlci[i] = (unsigned short)
+			    conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16;
+		}
+	}
+	if (conf->clocking == WANOPT_INTERNAL)
+		u.cfg.port |= 0x0001;
+	if (conf->interface == WANOPT_RS232)
+		u.cfg.port |= 0x0002;
+	if (conf->u.fr.t391)
+		u.cfg.t391 = min(conf->u.fr.t391, 30);
+	else
+		u.cfg.t391 = 5;
+	if (conf->u.fr.t392)
+		u.cfg.t392 = min(conf->u.fr.t392, 30);
+	else
+		u.cfg.t392 = 15;
+	if (conf->u.fr.n391)
+		u.cfg.n391 = min(conf->u.fr.n391, 255);
+	else
+		u.cfg.n391 = 2;
+	if (conf->u.fr.n392)
+		u.cfg.n392 = min(conf->u.fr.n392, 10);
+	else
+		u.cfg.n392 = 3;
+	if (conf->u.fr.n393)
+		u.cfg.n393 = min(conf->u.fr.n393, 10);
+	else
+		u.cfg.n393 = 4;
+	if (fr_configure(card, &u.cfg))
+		return -EIO;
+	if (card->hw.fwid == SFID_FR508) 
+	{
+		fr_buf_info_t *buf_info =
+		(void *) (card->hw.dpmbase + FR508_RXBC_OFFS);
+		card->rxmb = (void *) (buf_info->rse_next - FR_MB_VECTOR + card->hw.dpmbase);
+		card->u.f.rxmb_base = (void *) (buf_info->rse_base - FR_MB_VECTOR + card->hw.dpmbase);
+		card->u.f.rxmb_last = (void *) (buf_info->rse_base + (buf_info->rse_num - 1) * 
+				sizeof(fr_buf_ctl_t) - FR_MB_VECTOR + card->hw.dpmbase);
+		card->u.f.rx_base = buf_info->buf_base;
+		card->u.f.rx_top = buf_info->buf_top;
+	}
+	card->wandev.mtu = conf->mtu;
+	card->wandev.bps = conf->bps;
+	card->wandev.interface = conf->interface;
+	card->wandev.clocking = conf->clocking;
+	card->wandev.station = conf->station;
+	card->poll = &wpf_poll;
+	card->exec = &wpf_exec;
+	card->wandev.update = &update;
+	card->wandev.new_if = &new_if;
+	card->wandev.del_if = &del_if;
+	card->wandev.state = WAN_DISCONNECTED;
+	card->wandev.ttl = conf->ttl;
+	card->wandev.udp_port = conf->udp_port;
+	card->wandev.enable_tx_int = 0;
+	card->irq_dis_if_send_count = 0;
+	card->irq_dis_poll_count = 0;
+	card->wandev.enable_IPX = conf->enable_IPX;
+	if (conf->network_number)
+		card->wandev.network_number = conf->network_number;
+	else
+		card->wandev.network_number = 0xDEADBEEF;
+	/* Intialize global statistics for a card */
+	init_global_statistics(card);
+	TracingEnabled = 0;
+	return 0;
+}
+
+/******* WAN Device Driver Entry Points *************************************/
+
+/*============================================================================
+ * Update device status & statistics.
+ */
+
+static int update(wan_device_t * wandev)
+{
+	sdla_t *card;
+	/* sanity checks */
+	if ((wandev == NULL) || (wandev->private == NULL))
+		return -EFAULT;
+	if (wandev->state == WAN_UNCONFIGURED)
+		return -ENODEV;
+	if (test_and_set_bit(0, (void *) &wandev->critical))
+		return -EAGAIN;
+	card = wandev->private;
+	fr_get_err_stats(card);
+	fr_get_stats(card);
+	wandev->critical = 0;
+	return 0;
+}
+
+/*============================================================================
+ * Create new logical channel.
+ * This routine is called by the router when ROUTER_IFNEW IOCTL is being
+ * handled.
+ * o parse media- and hardware-specific configuration
+ * o make sure that a new channel can be created
+ * o allocate resources, if necessary
+ * o prepare network device structure for registaration.
+ *
+ * Return:	0	o.k.
+ *		< 0	failure (channel will not be created)
+ */
+
+static int new_if(wan_device_t * wandev, struct net_device *dev, wanif_conf_t * conf)
+{
+	sdla_t *card = wandev->private;
+	fr_channel_t *chan;
+	int err = 0;
+	if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) 
+	{
+		printk(KERN_INFO "%s: invalid interface name!\n",
+		       card->devname);
+		return -EINVAL;
+	}
+	/* allocate and initialize private data */
+	chan = kmalloc(sizeof(fr_channel_t), GFP_KERNEL);
+	if (chan == NULL)
+		return -ENOMEM;
+	memset(chan, 0, sizeof(fr_channel_t));
+	strcpy(chan->name, conf->name);
+	chan->card = card;
+	/* verify media address */
+	if (is_digit(conf->addr[0])) 
+	{
+		int dlci = dec_to_uint(conf->addr, 0);
+		if (dlci && (dlci <= 4095)) 
+		{
+			chan->dlci = dlci;
+		}
+		else
+		{
+			printk(KERN_ERR "%s: invalid DLCI %u on interface %s!\n",
+			       wandev->name, dlci, chan->name);
+			err = -EINVAL;
+		}
+	} 
+	else 
+	{
+		printk(KERN_ERR "%s: invalid media address on interface %s!\n",
+		       wandev->name, chan->name);
+		err = -EINVAL;
+	}
+	if (err) 
+	{
+		kfree(chan);
+		return err;
+	}
+	/* place cir,be,bc and other channel specific information into the
+	 * chan structure 
+	 */
+	if (conf->cir) 
+	{
+		chan->cir = max(1, min(conf->cir, 512));
+		chan->cir_status = CIR_ENABLED;
+		if (conf->bc)
+			chan->bc = max(1, min(conf->bc, 512));
+		if (conf->be)
+			chan->be = max(0, min(conf->be, 511));
+	}
+	else
+		chan->cir_status = CIR_DISABLED;
+	chan->mc = conf->mc;
+	chan->dlci_configured = DLCI_NOT_CONFIGURED;
+	chan->tx_int_status = DISABLED;
+	init_chan_statistics(chan);
+	/* prepare network device data space for registration */
+	dev->name = chan->name;
+	dev->init = &if_init;
+	dev->priv = chan;
+	return 0;
+}
+/*============================================================================
+ * Delete logical channel.
+ */
+static int del_if(wan_device_t * wandev, struct net_device *dev)
+{
+	if (dev->priv) 
+	{
+		kfree(dev->priv);
+		dev->priv = NULL;
+	}
+	return 0;
+}
+
+/****** WANPIPE-specific entry points ***************************************/
+
+/*============================================================================
+ * Execute adapter interface command.
+ */
+static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data)
+{
+	fr_mbox_t *mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err, len;
+	fr_cmd_t cmd;
+	if(copy_from_user((void *) &cmd, u_cmd, sizeof(cmd)))
+		return -EFAULT;		
+	/* execute command */
+	do 
+	{
+		memcpy(&mbox->cmd, &cmd, sizeof(cmd));
+		if (cmd.length)
+		{
+			if(copy_from_user((void *) &mbox->data, u_data, cmd.length))
+				return -EFAULT;
+		}
+		if (sdla_exec(mbox))
+			err = mbox->cmd.result;
+		else
+			return -EIO;
+	} 
+	while (err && retry-- && fr_event(card, err, mbox));
+
+	/* return result */
+
+	if(copy_to_user(u_cmd, (void *) &mbox->cmd, sizeof(fr_cmd_t)))
+		return -EFAULT;
+	len = mbox->cmd.length;
+	if (len && u_data && copy_to_user(u_data, (void *) &mbox->data, len))
+		return -EFAULT;
+	return 0;
+}
+
+/****** Network Device Interface ********************************************/
+/*============================================================================
+ * Initialize Linux network interface.
+ *
+ * This routine is called only once for each interface, during Linux network
+ * interface registration.  Returning anything but zero will fail interface
+ * registration.
+ */
+static int if_init(struct net_device *dev)
+{
+	fr_channel_t *chan = dev->priv;
+	sdla_t *card = chan->card;
+	wan_device_t *wandev = &card->wandev;
+
+	/* Initialize device driver entry points */
+	dev->open = &if_open;
+	dev->stop = &if_close;
+	dev->hard_header = &if_header;
+	dev->rebuild_header = &if_rebuild_hdr;
+	dev->hard_start_xmit = &if_send;
+	dev->get_stats = &if_stats;
+	/* Initialize media-specific parameters */
+	dev->type = ARPHRD_DLCI;			/* ARP h/w type */
+	dev->mtu = FR_CHANNEL_MTU;
+	dev->hard_header_len = FR_HEADER_LEN;		/* media header length */
+	dev->addr_len = 2;				/* hardware address length */
+	*(unsigned short *) dev->dev_addr = htons(chan->dlci);
+	/* Initialize hardware parameters (just for reference) */
+	dev->irq = wandev->irq;
+	dev->dma = wandev->dma;
+	dev->base_addr = wandev->ioport;
+	dev->mem_start = (unsigned long)wandev->maddr;
+	dev->mem_end = dev->mem_start + wandev->msize - 1;
+	/* Set transmit buffer queue length */
+	dev->tx_queue_len = 10;
+	/* Initialize socket buffers */
+	dev_init_buffers(dev);
+	set_chan_state(dev, WAN_DISCONNECTED);
+	return 0;
+}
+
+/*============================================================================
+ * Open network interface.
+ * o if this is the first open, then enable communications and interrupts.
+ * o prevent module from unloading by incrementing use count
+ *
+ * Return 0 if O.k. or errno.
+ */
+
+static int if_open(struct net_device *dev)
+{
+	fr_channel_t *chan = dev->priv;
+	sdla_t *card = chan->card;
+	struct net_device *dev2;
+	int err = 0;
+	fr508_flags_t *flags = card->flags;
+	struct timeval tv;
+	if (dev->start)
+		return -EBUSY;	/* only one open is allowed */
+	if (test_and_set_bit(0, (void *) &card->wandev.critical))
+		return -EAGAIN;
+	if (!card->open_cnt) 
+	{
+		Intr_test_counter = 0;
+		card->intr_mode = INTR_TEST_MODE;
+		err = intr_test(card);
+		if ((err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) {
+			printk(KERN_INFO
+			       "%s: Interrupt Test Failed, Counter: %i\n",
+			       card->devname, Intr_test_counter);
+			err = -EIO;
+			card->wandev.critical = 0;
+			return err;
+		}
+		printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n"
+		       ,card->devname, Intr_test_counter);
+		/* The following allocates and intializes a circular
+		 * link list of interfaces per card.
+		 */
+		card->devs_struct = kmalloc(sizeof(load_sharing_t), GFP_KERNEL);
+		if (card->devs_struct == NULL)
+			return -ENOMEM;
+		card->dev_to_devtint_next = card->devs_struct;
+		for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) {
+			(card->devs_struct)->dev_ptr = dev2;
+			if (dev2->slave == NULL)
+				(card->devs_struct)->next = card->dev_to_devtint_next;
+			else {
+				(card->devs_struct)->next = kmalloc(
+				     sizeof(load_sharing_t), GFP_KERNEL);
+				if ((card->devs_struct)->next == NULL)
+					return -ENOMEM;
+				card->devs_struct = (card->devs_struct)->next;
+			}
+		}
+		card->devs_struct = card->dev_to_devtint_next;
+		card->intr_mode = BUFFER_INTR_MODE;
+		/* 
+		   check all the interfaces for the device to see if CIR has
+		   been enabled for any DLCI(s). If so then use the DLCI list
+		   Interrupt mode for fr_set_intr_mode(), otherwise use the                     default global interrupt mode
+		 */
+		for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) {
+			if (((fr_channel_t *) dev2->priv)->cir_status
+			    == CIR_ENABLED) {
+				card->intr_mode = DLCI_LIST_INTR_MODE;
+				break;
+			}
+		}
+		/* 
+		   If you enable comms and then set ints, you get a Tx int as you
+		   perform the SET_INT_TRIGGERS command. So, we only set int
+		   triggers and then adjust the interrupt mask (to disable Tx ints)             before enabling comms. 
+		 */
+		if (card->intr_mode == BUFFER_INTR_MODE) {
+			if (fr_set_intr_mode(card, 0x03, card->wandev.mtu)) {
+				err = -EIO;
+				card->wandev.critical = 0;
+				return err;
+			}
+			printk(KERN_INFO
+			       "%s: Global Buffering Tx Interrupt Mode\n"
+			       ,card->devname);
+		} else if (card->intr_mode == DLCI_LIST_INTR_MODE) {
+			if (fr_set_intr_mode(card, 0x83, card->wandev.mtu)) {
+				err = -EIO;
+				card->wandev.critical = 0;
+				return err;
+			}
+			printk(KERN_INFO
+			       "%s: DLCI list Tx Interrupt Mode\n",
+			       card->devname);
+		}
+		flags->imask &= ~0x02;
+		if (fr_comm_enable(card)) {
+			err = -EIO;
+			card->wandev.critical = 0;
+			return err;
+		}
+		wanpipe_set_state(card, WAN_CONNECTED);
+		if (card->wandev.station == WANOPT_CPE) {
+			/* CPE: issue full status enquiry */
+			fr_issue_isf(card, FR_ISF_FSE);
+		} else {	/* FR switch: activate DLCI(s) */
+			/* For Switch emulation we have to ADD and ACTIVATE
+			 * the DLCI(s) that were configured with the SET_DLCI_
+			 * CONFIGURATION command. Add and Activate will fail if
+			 * DLCI specified is not included in the list.
+			 *
+			 * Also If_open is called once for each interface. But
+			 * it does not get in here for all the interface. So
+			 * we have to pass the entire list of DLCI(s) to add 
+			 * activate routines.  
+			 */
+			fr_add_dlci(card,
+			     card->u.f.node_dlci[0], card->u.f.dlci_num);
+			fr_activate_dlci(card,
+			     card->u.f.node_dlci[0], card->u.f.dlci_num);
+		}
+	}
+	dev->mtu = min(dev->mtu, card->wandev.mtu - FR_HEADER_LEN);
+	dev->interrupt = 0;
+	dev->tbusy = 0;
+	dev->start = 1;
+	wanpipe_open(card);
+	update_chan_state(dev);
+	do_gettimeofday(&tv);
+	chan->router_start_time = tv.tv_sec;
+	card->wandev.critical = 0;
+	return err;
+}
+
+/*============================================================================
+ * Close network interface.
+ * o if this is the last open, then disable communications and interrupts.
+ * o reset flags.
+ */
+
+static int if_close(struct net_device *dev)
+{
+	fr_channel_t *chan = dev->priv;
+	sdla_t *card = chan->card;
+	if (test_and_set_bit(0, (void *) &card->wandev.critical))
+		return -EAGAIN;
+	dev->start = 0;
+	wanpipe_close(card);
+	if (!card->open_cnt) 
+	{
+		wanpipe_set_state(card, WAN_DISCONNECTED);
+		fr_set_intr_mode(card, 0, 0);
+		fr_comm_disable(card);
+	}
+	card->wandev.critical = 0;
+	return 0;
+}
+
+/*============================================================================
+ * Build media header.
+ * o encapsulate packet according to encapsulation type.
+ *
+ * The trick here is to put packet type (Ethertype) into 'protocol' field of
+ * the socket buffer, so that we don't forget it.  If encapsulation fails,
+ * set skb->protocol to 0 and discard packet later.
+ *
+ * Return:	media header length.
+ */
+
+static int if_header(struct sk_buff *skb, struct net_device *dev,
+	     unsigned short type, void *daddr, void *saddr, unsigned len)
+{
+	int hdr_len = 0;
+	skb->protocol = type;
+	hdr_len = wanrouter_encapsulate(skb, dev);
+	if (hdr_len < 0) 
+	{
+		hdr_len = 0;
+		skb->protocol = 0;
+	}
+	skb_push(skb, 1);
+	skb->data[0] = Q922_UI;
+	++hdr_len;
+	return hdr_len;
+}
+
+/*============================================================================
+ * Re-build media header.
+ *
+ * Return:	1	physical address resolved.
+ *		0	physical address not resolved
+ */
+
+static int if_rebuild_hdr(struct sk_buff *skb)
+{
+	struct net_device *dev=skb->dev;
+	fr_channel_t *chan = dev->priv;
+	sdla_t *card = chan->card;
+	printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
+	       card->devname, dev->name);
+	return 1;
+}
+
+/*============================================================================
+ * Send a packet on a network interface.
+ * o set tbusy flag (marks start of the transmission) to block a timer-based
+ *   transmit from overlapping.
+ * o check link state. If link is not up, then drop the packet.
+ * o check channel status. If it's down then initiate a call.
+ * o pass a packet to corresponding WAN device.
+ * o free socket buffer
+ *
+ * Return:	0	complete (socket buffer must be freed)
+ *		non-0	packet may be re-transmitted (tbusy must be set)
+ *
+ * Notes:
+ * 1. This routine is called either by the protocol stack or by the "net
+ *    bottom half" (with interrupts enabled).
+ * 2. Setting tbusy flag will inhibit further transmit requests from the
+ *    protocol stack and can be used for flow control with protocol layer.
+ */
+
+static int if_send(struct sk_buff *skb, struct net_device *dev)
+{
+	fr_channel_t *chan = dev->priv;
+	sdla_t *card = chan->card;
+	int retry = 0, err;
+	unsigned char *sendpacket;
+	struct net_device *dev2;
+	unsigned long check_braddr, check_mcaddr;
+	fr508_flags_t *adptr_flags = card->flags;
+	int udp_type, send_data;
+	fr_dlci_interface_t *dlci_interface = chan->dlci_int_interface;
+	unsigned long host_cpu_flags;
+	++chan->if_send_entry;
+
+	if (dev->tbusy) 
+	{
+		/* If our device stays busy for at least 5 seconds then we will
+		 * kick start the device by making dev->tbusy = 0.  We expect
+		 * that our device never stays busy more than 5 seconds. So this                 * is only used as a last resort.
+		 */
+		++chan->if_send_busy;
+		++chan->ifstats.collisions;
+		if ((jiffies - chan->tick_counter) < (5 * HZ))
+			return 1;
+
+		printk(KERN_INFO "%s: Transmit timed out\n", chan->name);
+		++chan->if_send_busy_timeout;
+		/* unbusy all the interfaces on the card */
+		for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave)
+			dev2->tbusy = 0;
+	}
+	sendpacket = skb->data;
+	udp_type = udp_pkt_type(skb, card);
+	if (udp_type == UDP_DRVSTATS_TYPE) 
+	{
+		++chan->if_send_DRVSTATS_request;
+		process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev, 0,
+					chan);
+		dev_kfree_skb(skb);
+		return 0;
+	}
+	else if (udp_type == UDP_FPIPE_TYPE)
+		++chan->if_send_FPIPE_request;
+	/* retreive source address in two forms: broadcast & multicast */
+	check_braddr = sendpacket[17];
+	check_mcaddr = sendpacket[14];
+	check_braddr = check_braddr << 8;
+	check_mcaddr = check_mcaddr << 8;
+	check_braddr |= sendpacket[16];
+	check_mcaddr |= sendpacket[15];
+	check_braddr = check_braddr << 8;
+	check_mcaddr = check_mcaddr << 8;
+	check_braddr |= sendpacket[15];
+	check_mcaddr |= sendpacket[16];
+	check_braddr = check_braddr << 8;
+	check_mcaddr = check_mcaddr << 8;
+	check_braddr |= sendpacket[14];
+	check_mcaddr |= sendpacket[17];
+	/* if the Source Address is a Multicast address */
+	if ((chan->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001) &&
+	    (check_mcaddr <= 0xFFFFFFFE)) 
+	{
+		printk(KERN_INFO "%s: Multicast Src. Addr. silently discarded\n"
+		       ,card->devname);
+		dev_kfree_skb(skb);
+		++chan->ifstats.tx_dropped;
+		++chan->if_send_multicast;
+		return 0;
+	}
+	disable_irq(card->hw.irq);
+	++card->irq_dis_if_send_count;
+	if (test_and_set_bit(0, (void *) &card->wandev.critical)) 
+	{
+		if (card->wandev.critical == CRITICAL_IN_ISR) 
+		{
+			++chan->if_send_critical_ISR;
+			if (card->intr_mode == DLCI_LIST_INTR_MODE) 
+			{
+				/* The enable_tx_int flag is set here so that if
+				 * the critical flag is set due to an interrupt 
+				 * then we want to enable transmit interrupts 
+				 * again.
+				 */
+				card->wandev.enable_tx_int = 1;
+				/* Setting this flag to WAITING_TO_BE_ENABLED 
+				 * specifies that interrupt bit has to be 
+				 * enabled for that particular interface. 
+				 * (delayed interrupt)
+				 */
+				chan->tx_int_status = WAITING_TO_BE_ENABLED;
+				/* This is used for enabling dynamic calculation
+				 * of CIRs relative to the packet length.
+				 */
+				chan->pkt_length = skb->len;
+				dev->tbusy = 1;
+				chan->tick_counter = jiffies;
+			}
+			else
+			{
+				card->wandev.enable_tx_int = 1;
+				dev->tbusy = 1;
+				chan->tick_counter = jiffies;
+			}
+			save_flags(host_cpu_flags);
+			cli();
+			if ((!(--card->irq_dis_if_send_count)) &&
+			    (!card->irq_dis_poll_count))
+				enable_irq(card->hw.irq);
+			restore_flags(host_cpu_flags);
+			return 1;
+		}
+		++chan->if_send_critical_non_ISR;
+		++chan->ifstats.tx_dropped;
+		dev_kfree_skb(skb);
+		save_flags(host_cpu_flags);
+		cli();
+		if ((!(--card->irq_dis_if_send_count)) &&
+		    (!card->irq_dis_poll_count))
+			enable_irq(card->hw.irq);
+		restore_flags(host_cpu_flags);
+		return 0;
+	}
+	card->wandev.critical = 0x21;
+	if (udp_type == UDP_FPIPE_TYPE) 
+	{
+		err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb,
+					   dev, 0, chan);
+	}
+	else if (card->wandev.state != WAN_CONNECTED) 
+	{
+		++chan->if_send_wan_disconnected;
+		++chan->ifstats.tx_dropped;
+		++card->wandev.stats.tx_dropped;
+	}
+	else if (chan->state != WAN_CONNECTED) 
+	{
+		++chan->if_send_dlci_disconnected;
+		update_chan_state(dev);
+		++chan->ifstats.tx_dropped;
+		++card->wandev.stats.tx_dropped;
+	}
+	else if (!is_tx_ready(card, chan)) 
+	{
+		if (card->intr_mode == DLCI_LIST_INTR_MODE) 
+		{
+			dlci_interface->gen_interrupt |= 0x40;
+			dlci_interface->packet_length = skb->len;
+		}
+		dev->tbusy = 1;
+		chan->tick_counter = jiffies;
+		adptr_flags->imask |= 0x02;
+		++chan->if_send_no_bfrs;
+		retry = 1;
+	}
+	else
+	{
+		send_data = 1;
+		/* If it's an IPX packet */
+		if (sendpacket[1] == 0x00 &&
+		    sendpacket[2] == 0x80 &&
+		    sendpacket[6] == 0x81 &&
+		    sendpacket[7] == 0x37) 
+		{
+			if (card->wandev.enable_IPX) 
+			{
+				switch_net_numbers(sendpacket,
+					 card->wandev.network_number, 0);
+			} 
+			else 
+			{
+				/* increment some statistic here! */
+				send_data = 0;
+			}
+		}
+		if (send_data) 
+		{
+			err = (card->hw.fwid == SFID_FR508) ?
+			    fr508_send(card, chan->dlci, 0, skb->len, skb->data) :
+			    fr502_send(card, chan->dlci, 0, skb->len, skb->data);
+			if (err) 
+			{
+				if (card->intr_mode == DLCI_LIST_INTR_MODE) 
+				{
+					dlci_interface->gen_interrupt |= 0x40;
+					dlci_interface->packet_length = skb->len;
+				}
+				dev->tbusy = 1;
+				chan->tick_counter = jiffies;
+				adptr_flags->imask |= 0x02;
+				retry = 1;
+				++chan->if_send_adptr_bfrs_full;
+				++chan->ifstats.tx_errors;
+				++card->wandev.stats.tx_errors;
+			}
+			else 
+			{
+				++chan->if_send_bfrs_passed_to_adptr;
+				++chan->ifstats.tx_packets;
+				++card->wandev.stats.tx_packets;
+				chan->ifstats.tx_bytes += skb->len;
+				card->wandev.stats.tx_bytes += skb->len;
+			}
+		}
+	}
+	if (!retry)
+		dev_kfree_skb(skb);
+
+	card->wandev.critical = 0;
+	save_flags(host_cpu_flags);
+	cli();
+	if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count))
+		enable_irq(card->hw.irq);
+	restore_flags(host_cpu_flags);
+	return retry;
+}
+
+/*============================================================================
+ * Reply to UDP Management system.
+ * Return nothing.
+ */
+
+static int reply_udp(unsigned char *data, unsigned int mbox_len)
+{
+	unsigned short len, udp_length, temp, i, ip_length;
+	unsigned long sum;
+	/* Set length of packet */
+	len = mbox_len + 62;
+	/* fill in UDP reply */
+	data[38] = 0x02;
+	/* fill in UDP length */
+	udp_length = mbox_len + 40;
+	/* put it on an even boundary */
+	if (udp_length & 0x0001) 
+	{
+		udp_length += 1;
+		len += 1;
+	}
+	temp = (udp_length << 8) | (udp_length >> 8);
+	memcpy(&data[26], &temp, 2);
+	/* swap UDP ports */
+	memcpy(&temp, &data[22], 2);
+	memcpy(&data[22], &data[24], 2);
+	memcpy(&data[24], &temp, 2);
+	/* add UDP pseudo header */
+	temp = 0x1100;
+	memcpy(&data[udp_length + 22], &temp, 2);
+	temp = (udp_length << 8) | (udp_length >> 8);
+	memcpy(&data[udp_length + 24], &temp, 2);
+	/* calculate UDP checksum */
+	data[28] = data[29] = 0;
+	sum = 0;
+	for (i = 0; i < udp_length + 12; i += 2) 
+	{
+		memcpy(&temp, &data[14 + i], 2);
+		sum += (unsigned long) temp;
+	}
+	while (sum >> 16)
+		sum = (sum & 0xffffUL) + (sum >> 16);
+
+	temp = (unsigned short) sum;
+	temp = ~temp;
+	if (temp == 0)
+		temp = 0xffff;
+	memcpy(&data[28], &temp, 2);
+	/* fill in IP length */
+	ip_length = udp_length + 20;
+	temp = (ip_length << 8) | (ip_length >> 8);
+	memcpy(&data[4], &temp, 2);
+	/* swap IP addresses */
+	memcpy(&temp, &data[14], 2);
+	memcpy(&data[14], &data[18], 2);
+	memcpy(&data[18], &temp, 2);
+	memcpy(&temp, &data[16], 2);
+	memcpy(&data[16], &data[20], 2);
+	memcpy(&data[20], &temp, 2);
+	/* fill in IP checksum */
+	data[12] = data[13] = 0;
+	sum = 0;
+	for (i = 0; i < 20; i += 2) 
+	{
+		memcpy(&temp, &data[2 + i], 2);
+		sum += (unsigned long) temp;
+	}
+	while (sum >> 16)
+		sum = (sum & 0xffffUL) + (sum >> 16);
+	temp = (unsigned short) sum;
+	temp = ~temp;
+	if (temp == 0)
+		temp = 0xffff;
+	memcpy(&data[12], &temp, 2);
+	return len;
+}				/* reply_udp */
+/*
+   If incoming is 0 (outgoing)- if the net numbers is ours make it 0
+   if incoming is 1 - if the net number is 0 make it ours 
+ */
+
+static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming)
+{
+	unsigned long pnetwork_number;
+	pnetwork_number = (unsigned long) ((sendpacket[14] << 24) +
+			 (sendpacket[15] << 16) + (sendpacket[16] << 8) +
+					   sendpacket[17]);
+	if (!incoming) {
+		/* If the destination network number is ours, make it 0 */
+		if (pnetwork_number == network_number) {
+			sendpacket[14] = sendpacket[15] = sendpacket[16] =
+			    sendpacket[17] = 0x00;
+		}
+	} else {
+		/* If the incoming network is 0, make it ours */
+		if (pnetwork_number == 0) 
+		{
+			sendpacket[14] = (unsigned char) (network_number >> 24);
+			sendpacket[15] = (unsigned char) ((network_number &
+						      0x00FF0000) >> 16);
+			sendpacket[16] = (unsigned char) ((network_number &
+						       0x0000FF00) >> 8);
+			sendpacket[17] = (unsigned char) (network_number &
+							  0x000000FF);
+		}
+	}
+	pnetwork_number = (unsigned long) ((sendpacket[26] << 24) +
+			 (sendpacket[27] << 16) + (sendpacket[28] << 8) +
+					   sendpacket[29]);
+	if (!incoming) {
+		/* If the source network is ours, make it 0 */
+		if (pnetwork_number == network_number) 
+		{
+			sendpacket[26] = sendpacket[27] = sendpacket[28] =
+			    sendpacket[29] = 0x00;
+		}
+	} else {
+		/* If the source network is 0, make it ours */
+		if (pnetwork_number == 0) {
+			sendpacket[26] = (unsigned char) (network_number >> 24);
+			sendpacket[27] = (unsigned char) ((network_number &
+						      0x00FF0000) >> 16);
+			sendpacket[28] = (unsigned char) ((network_number &
+						       0x0000FF00) >> 8);
+			sendpacket[29] = (unsigned char) (network_number &
+							  0x000000FF);
+		}
+	}
+}				/* switch_net_numbers */
+
+/*============================================================================
+ * Get Ethernet-style interface statistics.
+ * Return a pointer to struct net_device_stats.
+ */
+
+static struct net_device_stats *if_stats(struct net_device *dev)
+{
+	fr_channel_t *chan = dev->priv;
+	if(chan==NULL)
+		return NULL;
+		
+	return &chan->ifstats;
+}
+
+/****** Interrupt Handlers **************************************************/
+/*============================================================================
+ * S502 frame relay interrupt service routine.
+ */
+
+static void fr502_isr(sdla_t * card)
+{
+	fr502_flags_t *flags = card->flags;
+	switch (flags->iflag) 
+	{
+		case 0x01:		/* receive interrupt */
+			fr502_rx_intr(card);
+			break;
+		case 0x02:		/* transmit interrupt */
+			flags->imask &= ~0x02;
+			tx_intr(card);
+			break;
+		default:
+			spur_intr(card);
+	}
+	flags->iflag = 0;
+}
+/*============================================================================
+ * S508 frame relay interrupt service routine.
+ */
+
+static void fr508_isr(sdla_t * card)
+{
+	fr508_flags_t *flags = card->flags;
+	fr_buf_ctl_t *bctl;
+	char *ptr = &flags->iflag;
+	struct net_device *dev = card->wandev.dev;
+	struct net_device *dev2;
+	int i;
+	unsigned long host_cpu_flags;
+	unsigned disable_tx_intr = 1;
+	fr_channel_t *chan;
+	fr_dlci_interface_t *dlci_interface;
+	/* This flag prevents nesting of interrupts.  See sdla_isr() routine
+	 * in sdlamain.c. 
+	 */
+	card->in_isr = 1;
+	++card->statistics.isr_entry;
+	if (test_and_set_bit(0, (void *) &card->wandev.critical)) 
+	{
+		printk(KERN_INFO "fr508_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, flags->iflag);
+		++card->statistics.isr_already_critical;
+		card->in_isr = 0;
+		return;
+	}
+	/* For all interrupts set the critical flag to CRITICAL_RX_INTR.
+	 * If the if_send routine is called with this flag set it will set
+	 * the enable transmit flag to 1. (for a delayed interrupt)
+	 */
+	card->wandev.critical = CRITICAL_IN_ISR;
+	card->dlci_int_mode_unbusy = 0;
+	card->buff_int_mode_unbusy = 0;
+	switch (flags->iflag) 
+	{
+		case 0x01:		/* receive interrupt */
+			++card->statistics.isr_rx;
+			fr508_rx_intr(card);
+			break;
+		case 0x02:		/* transmit interrupt */
+			++card->statistics.isr_tx;
+			bctl = (void *) (flags->tse_offs - FR_MB_VECTOR +
+				 card->hw.dpmbase);
+			bctl->flag = 0xA0;
+			if (card->intr_mode == DLCI_LIST_INTR_MODE) 
+			{
+				/* Find the structure and make it unbusy */
+				dev = find_channel(card, flags->dlci);
+				dev->tbusy = 0;
+				/* This is used to perform devtint at the
+				 * end of the isr 
+				 */
+				card->dlci_int_mode_unbusy = 1;
+				/* check to see if any other interfaces are
+				 * busy. If so then do not disable the tx
+				 * interrupts 
+				 */
+				for (dev2 = card->wandev.dev; dev2;
+					dev2 = dev2->slave) 
+				{
+					if (dev2->tbusy == 1) 
+					{
+						disable_tx_intr = 0;
+						break;
+					}
+				}
+				if (disable_tx_intr)
+					flags->imask &= ~0x02;
+			} 
+			else if (card->intr_mode == BUFFER_INTR_MODE) 
+			{
+				for (dev2 = card->wandev.dev; dev2;
+					dev2 = dev2->slave) 
+				{
+					if (!dev2 || !dev2->start) 
+					{
+						++card->statistics.tx_intr_dev_not_started;
+						continue;
+					}
+					if (dev2->tbusy) 
+					{
+						card->buff_int_mode_unbusy = 1;
+						((fr_channel_t *) dev2->priv)->dev_pending_devtint = 1;
+						dev2->tbusy = 0;
+					} 
+					else
+						((fr_channel_t *) dev2->priv)->dev_pending_devtint = 0;
+				}
+				flags->imask &= ~0x02;
+			}
+			break;
+		case 0x08:
+			Intr_test_counter++;
+			++card->statistics.isr_intr_test;
+			break;
+		default:
+			++card->statistics.isr_spurious;
+			spur_intr(card);
+			printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n",
+			       card->devname, flags->iflag);
+			printk(KERN_INFO "%s: ID Bytes = ", card->devname);
+			for (i = 0; i < 8; i++)
+				printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
+			printk(KERN_INFO "\n");
+			break;
+	}
+	card->wandev.critical = CRITICAL_INTR_HANDLED;
+	if (card->wandev.enable_tx_int) 
+	{
+		if (card->intr_mode == DLCI_LIST_INTR_MODE) 
+		{
+			for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) 
+			{
+				chan = dev2->priv;
+				if (chan->tx_int_status == WAITING_TO_BE_ENABLED) 
+				{
+					dlci_interface = chan->dlci_int_interface;
+					dlci_interface->gen_interrupt |= 0x40;
+					dlci_interface->packet_length = chan->pkt_length;
+					chan->tx_int_status = DISABLED;
+				}
+			}
+		}
+		card->wandev.enable_tx_int = 0;
+		flags->imask |= 0x02;
+		++card->statistics.isr_enable_tx_int;
+	}
+	save_flags(host_cpu_flags);
+	cli();
+	card->in_isr = 0;
+	card->wandev.critical = 0xD1;
+	flags->iflag = 0;
+	card->wandev.critical = 0;
+	restore_flags(host_cpu_flags);
+	/* Device is now ready to send. The instant this is executed the If_Send
+	   routine is called. That is why this is put at the bottom of the ISR
+	   to prevent a endless loop condition caused by repeated Interrupts and
+	   enable_tx_int flag.
+	 */
+	if (card->dlci_int_mode_unbusy)
+		mark_bh(NET_BH);
+	if (card->buff_int_mode_unbusy) 
+	{
+		for (;;) 
+		{
+			if (((fr_channel_t *) ((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint == 1) 
+			{
+				((fr_channel_t *) ((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint = 0;
+				mark_bh(NET_BH);
+			}
+			if ((card->devs_struct)->next == card->dev_to_devtint_next)
+				break;
+			card->devs_struct = (card->devs_struct)->next;
+		}
+		card->devs_struct = (card->dev_to_devtint_next)->next;
+		card->dev_to_devtint_next = card->devs_struct;
+	}
+}
+/*============================================================================
+ * Receive interrupt handler.
+ */
+
+static void fr502_rx_intr(sdla_t * card)
+{
+	fr_mbox_t *mbox = card->rxmb;
+	struct sk_buff *skb;
+	struct net_device *dev;
+	fr_channel_t *chan;
+	unsigned dlci, len;
+	void *buf;
+	unsigned char *sendpacket;
+	unsigned char buf2[3];
+	int udp_type;
+	sdla_mapmem(&card->hw, FR502_RX_VECTOR);
+	dlci = mbox->cmd.dlci;
+	len = mbox->cmd.length;
+	/* Find network interface for this packet */
+	dev = find_channel(card, dlci);
+	if (dev == NULL) 
+	{
+		/* Invalid channel, discard packet */
+		printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n",
+		       card->devname, dlci);
+		sdla_mapmem(&card->hw, FR_MB_VECTOR);
+	}
+	chan = dev->priv;
+	if (!dev->start) 
+	{
+		++chan->ifstats.rx_dropped;
+		sdla_mapmem(&card->hw, FR_MB_VECTOR);
+	}
+	/* Allocate socket buffer */
+	skb = dev_alloc_skb(len);
+	if (skb == NULL) 
+	{
+		printk(KERN_INFO "%s: no socket buffers available!\n",
+		       card->devname);
+		++chan->ifstats.rx_dropped;
+		sdla_mapmem(&card->hw, FR_MB_VECTOR);
+	}
+	/* Copy data to the socket buffer */
+	buf = skb_put(skb, len);
+	memcpy(buf, mbox->data, len);
+	sdla_mapmem(&card->hw, FR_MB_VECTOR);
+	/* Check if it's a UDP management packet */
+	sendpacket = skb->data;
+	memcpy(&buf2, &card->wandev.udp_port, 2);
+	udp_type = udp_pkt_type(skb, card);
+	if ((udp_type == UDP_FPIPE_TYPE) || (udp_type == UDP_DRVSTATS_TYPE)) 
+	{
+		if (udp_type == UDP_DRVSTATS_TYPE) 
+		{
+			++chan->rx_intr_DRVSTATS_request;
+			process_udp_driver_call(UDP_PKT_FRM_NETWORK, card, skb,
+						dev, dlci, chan);
+		}
+		else
+		{
+			++chan->rx_intr_FPIPE_request;
+			process_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, card, skb,
+					     dev, dlci, chan);
+		}
+	}
+	else
+	{
+		/* Decapsulate packet and pass it up the protocol stack */
+		skb->dev = dev;
+		buf = skb_pull(skb, 1);		/* remove hardware header */
+		if (!wanrouter_type_trans(skb, dev)) 
+		{
+			/* can't decapsulate packet */
+			dev_kfree_skb(skb);
+			++chan->ifstats.rx_errors;
+			++card->wandev.stats.rx_errors;
+		}
+		else 
+		{
+			netif_rx(skb);
+			++chan->ifstats.rx_packets;
+			++card->wandev.stats.rx_packets;
+			chan->ifstats.rx_bytes += skb->len;
+			card->wandev.stats.rx_bytes += skb->len;
+		}
+	}
+	sdla_mapmem(&card->hw, FR_MB_VECTOR);
+}
+/*============================================================================
+ * Receive interrupt handler.
+ */
+
+static void fr508_rx_intr(sdla_t * card)
+{
+	fr_buf_ctl_t *frbuf = card->rxmb;
+	struct sk_buff *skb;
+	struct net_device *dev;
+	fr_channel_t *chan;
+	unsigned dlci, len, offs;
+	void *buf;
+	unsigned rx_count = 0;
+	fr508_flags_t *flags = card->flags;
+	char *ptr = &flags->iflag;
+	int i, err, udp_type;
+	if (frbuf->flag != 0x01) 
+	{
+		printk(KERN_INFO
+		       "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n",
+		       card->devname, (unsigned) frbuf, frbuf->flag);
+		printk(KERN_INFO "%s: ID Bytes = ", card->devname);
+		for (i = 0; i < 8; i++)
+			printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
+		printk(KERN_INFO "\n");
+		++card->statistics.rx_intr_corrupt_rx_bfr;
+		return;
+	}
+	
+	do 
+	{
+		len = frbuf->length;
+		dlci = frbuf->dlci;
+		offs = frbuf->offset;
+		/* Find network interface for this packet */
+		dev = find_channel(card, dlci);
+		chan = dev->priv;
+		if (dev == NULL) 
+		{
+			/* Invalid channel, discard packet */
+			printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n"
+			       ,card->devname, dlci);
+			++card->statistics.rx_intr_on_orphaned_DLCI;
+		}
+		else
+		{
+			skb = dev_alloc_skb(len);
+			if (!dev->start || (skb == NULL)) 
+			{
+				++chan->ifstats.rx_dropped;
+				if (dev->start) 
+				{
+					printk(KERN_INFO
+					       "%s: no socket buffers available!\n",
+					       card->devname);
+					++chan->rx_intr_no_socket;
+				} else
+					++chan->rx_intr_dev_not_started;
+			}
+			else
+			{
+				/* Copy data to the socket buffer */
+				if ((offs + len) > card->u.f.rx_top + 1) 
+				{
+					unsigned tmp = card->u.f.rx_top - offs + 1;
+					buf = skb_put(skb, tmp);
+					sdla_peek(&card->hw, offs, buf, tmp);
+					offs = card->u.f.rx_base;
+					len -= tmp;
+				}
+				buf = skb_put(skb, len);
+				sdla_peek(&card->hw, offs, buf, len);
+				udp_type = udp_pkt_type(skb, card);
+				if (udp_type == UDP_DRVSTATS_TYPE) 
+				{
+					++chan->rx_intr_DRVSTATS_request;
+					process_udp_driver_call(
+					  UDP_PKT_FRM_NETWORK, card, skb,
+							dev, dlci, chan);
+				}
+				else if (udp_type == UDP_FPIPE_TYPE) 
+				{
+					++chan->rx_intr_FPIPE_request;
+					err = process_udp_mgmt_pkt(
+					       UDP_PKT_FRM_NETWORK, card,
+						   skb, dev, dlci, chan);
+				}
+				else if (handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number)) 
+				{
+					if (card->wandev.enable_IPX) 
+						fr508_send(card, dlci, 0, skb->len, skb->data);
+				} 
+				else
+				{
+					/* Decapsulate packet and pass it up the
+					   protocol stack */
+					skb->dev = dev;
+					/* remove hardware header */
+					buf = skb_pull(skb, 1);
+					if (!wanrouter_type_trans(skb, dev)) 
+					{
+						/* can't decapsulate packet */
+						dev_kfree_skb(skb);
+						++chan->
+						    rx_intr_bfr_not_passed_to_stack;
+						++chan->
+						    ifstats.rx_errors;
+						++card->
+						    wandev.stats.rx_errors;
+					}
+					else
+					{
+						netif_rx(skb);
+						++chan->rx_intr_bfr_passed_to_stack;
+						++chan->ifstats.rx_packets;
+						++card->wandev.stats.rx_packets;
+						chan->ifstats.rx_bytes += skb->len;
+						card->wandev.stats.rx_bytes += skb->len;
+					}
+				}
+			}
+		}
+		/* Release buffer element and calculate a pointer to the next 
+		   one */
+		frbuf->flag = 0;
+		card->rxmb = ++frbuf;
+		if ((void *) frbuf > card->u.f.rxmb_last)
+			card->rxmb = card->u.f.rxmb_base;
+		/* The loop put in is temporary, that is why the break is
+		 * placed here. (?????)
+		 */
+		break;
+		frbuf = card->rxmb;
+	}
+	while (frbuf->flag && ((++rx_count) < 4));
+}
+/*============================================================================
+ * Transmit interrupt handler.
+ * o print a warning
+ * o 
+ * If number of spurious interrupts exceeded some limit, then ???
+ */
+static void tx_intr(sdla_t * card)
+{
+	struct net_device *dev = card->wandev.dev;
+	if (card->intr_mode == BUFFER_INTR_MODE) 
+	{
+		for (; dev; dev = dev->slave) 
+		{
+			if (!dev || !dev->start) 
+			{
+				++card->statistics.tx_intr_dev_not_started;
+				continue;
+			}
+			dev->tbusy = 0;
+			mark_bh(NET_BH);
+		}
+	}
+	else
+	{
+		dev->tbusy = 0;
+		mark_bh(NET_BH);
+	}
+}
+
+/*============================================================================
+ * Spurious interrupt handler.
+ * o print a warning
+ * o 
+ * If number of spurious interrupts exceeded some limit, then ???
+ */
+
+static void spur_intr(sdla_t * card)
+{
+	printk(KERN_INFO "%s: spurious interrupt!\n", card->devname);
+}
+
+/*
+   Return 0 for non-IPXWAN packet
+   1 for IPXWAN packet or IPX is not enabled!
+ */
+
+static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number)
+{
+	int i;
+	if (sendpacket[1] == 0x00 &&
+	    sendpacket[2] == 0x80 &&
+	    sendpacket[6] == 0x81 &&
+	    sendpacket[7] == 0x37) 
+	{
+		/* It's an IPX packet */
+		if (!enable_IPX) {
+			/* Return 1 so we don't pass it up the stack. */
+			return 1;
+		}
+	}
+	else
+	{
+		/* It's not IPX so return and pass it up the stack. */
+		return 0;
+	}
+	if (sendpacket[24] == 0x90 &&
+	    sendpacket[25] == 0x04) 
+	{
+		/* It's IPXWAN */
+		if (sendpacket[10] == 0x02 &&
+		    sendpacket[42] == 0x00) 
+		{
+			/* It's a timer request packet */
+			printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", devname);
+			/* Go through the routing options and answer no to every */
+			/* option except Unnumbered RIP/SAP */
+			for (i = 49; sendpacket[i] == 0x00; i += 5) 
+			{
+				/* 0x02 is the option for Unnumbered RIP/SAP */
+				if (sendpacket[i + 4] != 0x02) 
+				{
+					sendpacket[i + 1] = 0;
+				}
+			}
+			/* Skip over the extended Node ID option */
+			if (sendpacket[i] == 0x04) 
+				i += 8;
+			/* We also want to turn off all header compression opt. */
+			for (; sendpacket[i] == 0x80;) 
+			{
+				sendpacket[i + 1] = 0;
+				i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4;
+			}
+			/* Set the packet type to timer response */
+			sendpacket[42] = 0x01;
+			printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", devname);
+		}
+		else if (sendpacket[42] == 0x02) 
+		{
+			/* This is an information request packet */
+			printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n", devname);
+			/* Set the packet type to information response */
+			sendpacket[42] = 0x03;
+			/* Set the router name */
+			sendpacket[59] = 'F';
+			sendpacket[60] = 'P';
+			sendpacket[61] = 'I';
+			sendpacket[62] = 'P';
+			sendpacket[63] = 'E';
+			sendpacket[64] = '-';
+			sendpacket[65] = CVHexToAscii(network_number >> 28);
+			sendpacket[66] = CVHexToAscii((network_number & 0x0F000000) >> 24);
+			sendpacket[67] = CVHexToAscii((network_number & 0x00F00000) >> 20);
+			sendpacket[68] = CVHexToAscii((network_number & 0x000F0000) >> 16);
+			sendpacket[69] = CVHexToAscii((network_number & 0x0000F000) >> 12);
+			sendpacket[70] = CVHexToAscii((network_number & 0x00000F00) >> 8);
+			sendpacket[71] = CVHexToAscii((network_number & 0x000000F0) >> 4);
+			sendpacket[72] = CVHexToAscii(network_number & 0x0000000F);
+			for (i = 73; i < 107; i += 1) 
+				sendpacket[i] = 0;
+			printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", devname);
+		}
+		else
+		{
+			printk(KERN_INFO "%s: Unknown IPXWAN packet!\n", devname);
+			return 0;
+		}
+		/* Set the WNodeID to our network address */
+		sendpacket[43] = (unsigned char) (network_number >> 24);
+		sendpacket[44] = (unsigned char) ((network_number & 0x00FF0000) >> 16);
+		sendpacket[45] = (unsigned char) ((network_number & 0x0000FF00) >> 8);
+		sendpacket[46] = (unsigned char) (network_number & 0x000000FF);
+		return 1;
+	}
+	/* If we get here, its an IPX-data packet so it'll get passed up the stack. */
+	/* switch the network numbers */
+	switch_net_numbers(sendpacket, network_number, 1);
+	return 0;
+}
+
+/****** Background Polling Routines  ****************************************/
+
+/*============================================================================
+ * Main polling routine.
+ * This routine is repeatedly called by the WANPIPE 'thead' to allow for
+ * time-dependent housekeeping work.
+ *
+ * o fetch asynchronous network events.
+ *
+ * Notes:
+ * 1. This routine may be called on interrupt context with all interrupts
+ *    enabled. Beware!
+ */
+
+static void wpf_poll(sdla_t * card)
+{
+/*      struct net_device* dev = card->wandev.dev;  */
+	fr508_flags_t *flags = card->flags;
+	unsigned long host_cpu_flags;
+	++card->statistics.poll_entry;
+	if (((jiffies - card->state_tick) < HZ) ||
+	    (card->intr_mode == INTR_TEST_MODE))
+		return;
+	disable_irq(card->hw.irq);
+	++card->irq_dis_poll_count;
+	if (test_and_set_bit(0, (void *) &card->wandev.critical)) 
+	{
+		++card->statistics.poll_already_critical;
+		save_flags(host_cpu_flags);
+		cli();
+		if ((!card->irq_dis_if_send_count) &&
+		    (!(--card->irq_dis_poll_count)))
+			enable_irq(card->hw.irq);
+		restore_flags(host_cpu_flags);
+		return;
+	}
+	card->wandev.critical = 0x11;
+	++card->statistics.poll_processed;
+	/* This is to be changed later ??? */
+	/*
+	   if( dev && dev->tbusy && !(flags->imask & 0x02) ) {
+	   printk(KERN_INFO "%s: Wpf_Poll: tbusy = 0x01, imask = 0x%02X\n",             card->devname, flags->imask);
+	   }
+	 */
+	if (flags->event) 
+	{
+		fr_mbox_t *mbox = card->mbox;
+		int err;
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		mbox->cmd.command = FR_READ_STATUS;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+		if (err)
+			fr_event(card, err, mbox);
+	}
+	card->wandev.critical = 0;
+	save_flags(host_cpu_flags);
+	cli();
+	if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count)))
+		enable_irq(card->hw.irq);
+	restore_flags(host_cpu_flags);
+	card->state_tick = jiffies;
+}
+
+/****** Frame Relay Firmware-Specific Functions *****************************/
+
+/*============================================================================
+ * Read firmware code version.
+ * o fill string str with firmware version info. 
+ */
+
+static int fr_read_version(sdla_t * card, char *str)
+{
+	fr_mbox_t *mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+	do 
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		mbox->cmd.command = FR_READ_CODE_VERSION;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- && fr_event(card, err, mbox));
+	
+	if (!err && str) 
+	{
+		int len = mbox->cmd.length;
+		memcpy(str, mbox->data, len);
+		str[len] = '\0';
+	}
+	return err;
+}
+/*============================================================================
+ * Set global configuration.
+ */
+ 
+static int fr_configure(sdla_t * card, fr_conf_t * conf)
+{
+	fr_mbox_t *mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int dlci_num = card->u.f.dlci_num;
+	int err, i;
+	do 
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		memcpy(mbox->data, conf, sizeof(fr_conf_t));
+		if (dlci_num)
+			for (i = 0; i < dlci_num; ++i)
+				((fr_conf_t *) mbox->data)->dlci[i] =
+				    card->u.f.node_dlci[i];
+		mbox->cmd.command = FR_SET_CONFIG;
+		mbox->cmd.length =
+		    sizeof(fr_conf_t) + dlci_num * sizeof(short);
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+	
+	return err;
+}
+/*============================================================================
+ * Set DLCI configuration.
+ */
+static int fr_dlci_configure(sdla_t * card, fr_dlc_conf_t * conf, unsigned dlci)
+{
+	fr_mbox_t *mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		memcpy(mbox->data, conf, sizeof(fr_dlc_conf_t));
+		mbox->cmd.dlci = (unsigned short) dlci;
+		mbox->cmd.command = FR_SET_CONFIG;
+		mbox->cmd.length = 0x0E;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry--);
+	return err;
+}
+/*============================================================================
+ * Set interrupt mode.
+ */
+static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu)
+{
+	fr_mbox_t *mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		if (card->hw.fwid == SFID_FR502) 
+		{
+			fr502_intr_ctl_t *ictl = (void *) mbox->data;
+			memset(ictl, 0, sizeof(fr502_intr_ctl_t));
+			ictl->mode = mode;
+			ictl->tx_len = mtu;
+			mbox->cmd.length = sizeof(fr502_intr_ctl_t);
+		}
+		else
+		{
+			fr508_intr_ctl_t *ictl = (void *) mbox->data;
+			memset(ictl, 0, sizeof(fr508_intr_ctl_t));
+			ictl->mode = mode;
+			ictl->tx_len = mtu;
+			ictl->irq = card->hw.irq;
+			mbox->cmd.length = sizeof(fr508_intr_ctl_t);
+		}
+		mbox->cmd.command = FR_SET_INTR_MODE;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+	
+	return err;
+}
+/*============================================================================
+ * Enable communications.
+ */
+static int fr_comm_enable(sdla_t * card)
+{
+	fr_mbox_t *mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+	do 
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		mbox->cmd.command = FR_COMM_ENABLE;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+	
+	return err;
+}
+/*============================================================================
+ * Disable communications. 
+ */
+static int fr_comm_disable(sdla_t * card)
+{
+	fr_mbox_t *mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		mbox->cmd.command = FR_COMM_DISABLE;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+	
+	return err;
+}
+/*============================================================================
+ * Get communications error statistics. 
+ */
+static int fr_get_err_stats(sdla_t * card)
+{
+	fr_mbox_t *mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+	
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		mbox->cmd.command = FR_READ_ERROR_STATS;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+	
+	if (!err) 
+	{
+		fr_comm_stat_t *stats = (void *) mbox->data;
+		card->wandev.stats.rx_over_errors = stats->rx_overruns;
+		card->wandev.stats.rx_crc_errors = stats->rx_bad_crc;
+		card->wandev.stats.rx_missed_errors = stats->rx_aborts;
+		card->wandev.stats.rx_length_errors = stats->rx_too_long;
+		card->wandev.stats.tx_aborted_errors = stats->tx_aborts;
+	}
+	return err;
+}
+/*============================================================================
+ * Get statistics. 
+ */
+static int fr_get_stats(sdla_t * card)
+{
+	fr_mbox_t *mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+	do 
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		mbox->cmd.command = FR_READ_STATISTICS;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+	
+	if (!err) 
+	{
+		fr_link_stat_t *stats = (void *) mbox->data;
+		card->wandev.stats.rx_frame_errors = stats->rx_bad_format;
+		card->wandev.stats.rx_dropped = stats->rx_dropped + stats->rx_dropped2;
+	}
+	return err;
+}
+/*============================================================================
+ * Add DLCI(s) (Access Node only!).
+ * This routine will perform the ADD_DLCIs command for the specified DLCI.
+ */
+static int fr_add_dlci(sdla_t * card, int dlci, int num)
+{
+	fr_mbox_t *mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err, i;
+	do 
+	{
+		unsigned short *dlci_list = (void *) mbox->data;
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		for (i = 0; i < num; ++i)
+			dlci_list[i] = card->u.f.node_dlci[i];
+		mbox->cmd.length = num * sizeof(short);
+		mbox->cmd.command = FR_ADD_DLCI;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+	
+	return err;
+}
+/*============================================================================
+ * Activate DLCI(s) (Access Node only!). 
+ * This routine will perform the ACTIVATE_DLCIs command with a list of DLCIs. 
+ */
+static int fr_activate_dlci(sdla_t * card, int dlci, int num)
+{
+	fr_mbox_t *mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err, i;
+	do
+	{
+		unsigned short *dlci_list = (void *) mbox->data;
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		for (i = 0; i < num; ++i)
+			dlci_list[i] = card->u.f.node_dlci[i];
+		mbox->cmd.length = num * sizeof(short);
+		mbox->cmd.command = FR_ACTIVATE_DLCI;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+	
+	return err;
+}
+/*============================================================================
+ * Issue in-channel signalling frame. 
+ */
+static int fr_issue_isf(sdla_t * card, int isf)
+{
+	fr_mbox_t *mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		mbox->data[0] = isf;
+		mbox->cmd.length = 1;
+		mbox->cmd.command = FR_ISSUE_IS_FRAME;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+	
+	return err;
+}
+/*============================================================================
+ * Send a frame (S502 version). 
+ */
+static int fr502_send(sdla_t * card, int dlci, int attr, int len, void *buf)
+{
+	fr_mbox_t *mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+	
+	do 
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		memcpy(mbox->data, buf, len);
+		mbox->cmd.dlci = dlci;
+		mbox->cmd.attr = attr;
+		mbox->cmd.length = len;
+		mbox->cmd.command = FR_WRITE;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+	
+	return err;
+}
+/*============================================================================
+ * Send a frame (S508 version). 
+ */
+static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf)
+{
+	fr_mbox_t *mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+	
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		mbox->cmd.dlci = dlci;
+		mbox->cmd.attr = attr;
+		mbox->cmd.length = len;
+		mbox->cmd.command = FR_WRITE;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+	
+	if (!err) 
+	{
+		fr_buf_ctl_t *frbuf = (void *) (*(unsigned long *) mbox->data -
+					FR_MB_VECTOR + card->hw.dpmbase);
+		sdla_poke(&card->hw, frbuf->offset, buf, len);
+		frbuf->flag = 0x01;
+	}
+	return err;
+}
+
+/****** Firmware Asynchronous Event Handlers ********************************/
+
+/*============================================================================
+ * Main asynchronous event/error handler.
+ *	This routine is called whenever firmware command returns non-zero
+ *	return code.
+ *
+ * Return zero if previous command has to be cancelled.
+ */
+
+static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox)
+{
+	fr508_flags_t *flags = card->flags;
+	char *ptr = &flags->iflag;
+	int i;
+	switch (event) 
+	{
+		case FRRES_MODEM_FAILURE:
+			return fr_modem_failure(card, mbox);
+		case FRRES_CHANNEL_DOWN:
+			wanpipe_set_state(card, WAN_DISCONNECTED);
+			return 1;
+		case FRRES_CHANNEL_UP:
+			wanpipe_set_state(card, WAN_CONNECTED);
+			return 1;
+		case FRRES_DLCI_CHANGE:
+			return fr_dlci_change(card, mbox);
+		case FRRES_DLCI_MISMATCH:
+			printk(KERN_INFO "%s: DLCI list mismatch!\n",
+			       card->devname);
+			return 1;
+		case CMD_TIMEOUT:
+			printk(KERN_ERR "%s: command 0x%02X timed out!\n",
+			       card->devname, mbox->cmd.command);
+			printk(KERN_INFO "%s: ID Bytes = ", card->devname);
+			for (i = 0; i < 8; i++)
+				printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
+			printk(KERN_INFO "\n");
+			break;
+		case FRRES_DLCI_INACTIVE:
+			printk(KERN_ERR "%s: DLCI %u is inactive!\n",
+			       card->devname, mbox->cmd.dlci);
+			break;
+		case FRRES_CIR_OVERFLOW:
+			break;
+		case FRRES_BUFFER_OVERFLOW:
+			break;
+		default:
+			printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n"
+			       ,card->devname, mbox->cmd.command, event);
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Handle modem error.
+ *
+ * Return zero if previous command has to be cancelled.
+ */
+static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox)
+{
+	printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)\n",
+	       card->devname, mbox->data[0]);
+	switch (mbox->cmd.command) 
+	{
+		case FR_WRITE:
+		case FR_READ:
+			return 0;
+	}
+	return 1;
+}
+/*============================================================================
+ * Handle DLCI status change.
+ *
+ * Return zero if previous command has to be cancelled.
+ */
+static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox)
+{
+	dlci_status_t *status = (void *) mbox->data;
+	int cnt = mbox->cmd.length / sizeof(dlci_status_t);
+	fr_dlc_conf_t cfg;
+	fr_channel_t *chan;
+	struct net_device *dev2;
+	for (; cnt; --cnt, ++status) 
+	{
+		unsigned short dlci = status->dlci;
+		struct net_device *dev = find_channel(card, dlci);
+		if (dev == NULL) 
+		{
+			printk(KERN_INFO
+			       "%s: CPE contains unconfigured DLCI= %d\n",
+			       card->devname, dlci);
+		}
+		else 
+		{
+			if (status->state & 0x01) 
+			{
+				printk(KERN_INFO
+				       "%s: DLCI %u has been deleted!\n",
+				       card->devname, dlci);
+				if (dev && dev->start)
+					set_chan_state(dev, WAN_DISCONNECTED);
+			}
+			else if (status->state & 0x02) 
+			{
+				printk(KERN_INFO
+				       "%s: DLCI %u becomes active!\n",
+				       card->devname, dlci);
+				chan = dev->priv;
+				/* This flag is used for configuring specific 
+				   DLCI(s) when they become active.
+				 */
+				chan->dlci_configured = DLCI_CONFIG_PENDING;
+				if (dev && dev->start)
+					set_chan_state(dev, WAN_CONNECTED);
+			}
+		}
+	}
+	for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) 
+	{
+		chan = dev2->priv;
+		if (chan->dlci_configured == DLCI_CONFIG_PENDING) 
+		{
+			memset(&cfg, 0, sizeof(cfg));
+			if (chan->cir_status == CIR_DISABLED) 
+			{
+				cfg.cir_fwd = cfg.cir_bwd = 16;
+				cfg.bc_fwd = cfg.bc_bwd = 16;
+				cfg.conf_flags = 0x0001;
+				printk(KERN_INFO "%s: CIR Disabled for %s\n",
+				       card->devname, chan->name);
+			} else if (chan->cir_status == CIR_ENABLED) {
+				cfg.cir_fwd = cfg.cir_bwd = chan->cir;
+				cfg.bc_fwd = cfg.bc_bwd = chan->bc;
+				cfg.be_fwd = cfg.be_bwd = chan->be;
+				cfg.conf_flags = 0x0000;
+				printk(KERN_INFO "%s: CIR Enabled for %s\n",
+				       card->devname, chan->name);
+			}
+			if (fr_dlci_configure(card, &cfg, chan->dlci)) 
+			{
+				printk(KERN_INFO
+				    "%s: DLCI Configure failed for %d\n",
+				       card->devname, chan->dlci);
+				return 1;
+			}
+			chan->dlci_configured = DLCI_CONFIGURED;
+			/* Read the interface byte mapping into the channel 
+			   structure.
+			 */
+			if (card->intr_mode == DLCI_LIST_INTR_MODE)
+				read_DLCI_IB_mapping(card, chan);
+		}
+	}
+	return 1;
+}
+/******* Miscellaneous ******************************************************/
+
+/*============================================================================
+ * Update channel state. 
+ */
+static int update_chan_state(struct net_device *dev)
+{
+	fr_channel_t *chan = dev->priv;
+	sdla_t *card = chan->card;
+	fr_mbox_t *mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+	int dlci_found = 0;
+
+	do 
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		mbox->cmd.command = FR_LIST_ACTIVE_DLCI;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+
+	if (!err) 
+	{
+		unsigned short *list = (void *) mbox->data;
+		int cnt = mbox->cmd.length / sizeof(short);
+		for (; cnt; --cnt, ++list) 
+		{
+			if (*list == chan->dlci) 
+			{
+				dlci_found = 1;
+				set_chan_state(dev, WAN_CONNECTED);
+				break;
+			}
+		}
+		if (!dlci_found)
+			printk(KERN_INFO "%s: DLCI %u is inactive\n",
+			       card->devname, chan->dlci);
+	}
+	
+	return err;
+}
+/*============================================================================
+ * Set channel state.
+ */
+static void set_chan_state(struct net_device *dev, int state)
+{
+	fr_channel_t *chan = dev->priv;
+	sdla_t *card = chan->card;
+	unsigned long flags;
+	
+	save_flags(flags);
+	cli();
+	
+	if (chan->state != state) 
+	{
+		switch (state) 
+		{
+			case WAN_CONNECTED:
+				printk(KERN_INFO "%s: interface %s connected!\n"
+				       ,card->devname, dev->name);
+				break;
+			case WAN_CONNECTING:
+				printk(KERN_INFO
+				       "%s: interface %s connecting...\n",
+				       card->devname, dev->name);
+				break;
+			case WAN_DISCONNECTED:
+				printk(KERN_INFO
+				       "%s: interface %s disconnected!\n",
+				       card->devname, dev->name);
+				break;
+		}
+		chan->state = state;
+	}
+	chan->state_tick = jiffies;
+	restore_flags(flags);
+}
+
+/*============================================================================
+ * Find network device by its channel number.
+ */
+static struct net_device *find_channel(sdla_t * card, unsigned dlci)
+{
+	struct net_device *dev;
+	for (dev = card->wandev.dev; dev; dev = dev->slave)
+		if (((fr_channel_t *) dev->priv)->dlci == dlci)
+			break;
+	return dev;
+}
+/*============================================================================
+ * Check to see if a frame can be sent. If no transmit buffers available,
+ * enable transmit interrupts.
+ *
+ * Return:	1 - Tx buffer(s) available
+ *		0 - no buffers available
+ */
+
+static int is_tx_ready(sdla_t * card, fr_channel_t * chan)
+{
+	if (card->hw.fwid == SFID_FR508) 
+	{
+		unsigned char sb = inb(card->hw.port);
+		if (sb & 0x02)
+			return 1;
+	}
+	else 
+	{
+		fr502_flags_t *flags = card->flags;
+		if (flags->tx_ready)
+			return 1;
+		flags->imask |= 0x02;
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Convert decimal string to unsigned integer.
+ * If len != 0 then only 'len' characters of the string are converted.
+ */
+static unsigned int dec_to_uint(unsigned char *str, int len)
+{
+	unsigned val;
+	if (!len)
+		len = strlen(str);
+	for (val = 0; len && is_digit(*str); ++str, --len)
+		val = (val * 10) + (*str - (unsigned) '0');
+	return val;
+}
+
+/*==============================================================================
+ * Process UDP call of type FPIPE8ND
+ */
+
+static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, int dlci, fr_channel_t * chan)
+{
+	int c_retry = MAX_CMD_RETRY;
+	unsigned char *data;
+	unsigned char *buf;
+	unsigned char buf2[5];
+	unsigned int loops, frames, len;
+	unsigned long data_ptr;
+	unsigned short real_len, buffer_length;
+	struct sk_buff *new_skb;
+	unsigned char *sendpacket;
+	fr_mbox_t *mbox = card->mbox;
+	int err;
+	struct timeval tv;
+	int udp_mgmt_req_valid = 1;
+	sendpacket = skb->data;
+	memcpy(&buf2, &card->wandev.udp_port, 2);
+	if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) 
+	{
+		printk(KERN_INFO
+		       "%s: Error allocating memory for UDP management cmnd 0x%02X",
+		       card->devname, data[47]);
+		++chan->UDP_FPIPE_mgmt_kmalloc_err;
+		return 1;
+	}
+	memcpy(data, sendpacket, skb->len);
+	switch (data[47]) 
+	{
+		/* FPIPE_ENABLE_TRACE */
+		case 0x41:
+		/* FPIPE_DISABLE_TRACE */
+		case 0x42:
+		/* FPIPE_GET_TRACE_INFO */
+		case 0x43:
+		/* SET FT1 MODE */
+		case 0x81:
+			if (udp_pkt_src == UDP_PKT_FRM_NETWORK) 
+			{
+				++chan->UDP_FPIPE_mgmt_direction_err;
+				udp_mgmt_req_valid = 0;
+				break;
+			}
+		/* FPIPE_FT1_READ_STATUS */
+		case 0x44:
+		/* FT1 MONITOR STATUS */
+		case 0x80:
+			if (card->hw.fwid != SFID_FR508) 
+			{
+				++chan->UDP_FPIPE_mgmt_adptr_type_err;
+				udp_mgmt_req_valid = 0;
+			}
+			break;
+		default:
+			break;
+	}
+	if (!udp_mgmt_req_valid) 
+	{
+		/* set length to 0 */
+		data[48] = data[49] = 0;
+		/* set return code */
+		data[50] = (card->hw.fwid != SFID_FR508) ? 0x1F : 0xCD;
+	}
+	else
+	{
+		switch (data[47]) 
+		{
+			/* FPIPE_ENABLE_TRACE */
+			case 0x41:
+				if (!TracingEnabled) 
+				{
+					do 
+					{
+						/* SET_TRACE_CONFIGURATION */
+						mbox->cmd.command = 0x60;
+						mbox->cmd.length = 1;
+						mbox->cmd.dlci = 0x00;
+						mbox->data[0] = 0x37;
+						err = sdla_exec(mbox) ?
+							mbox->cmd.result : CMD_TIMEOUT;
+					}
+					while (err && c_retry-- && fr_event(card, err, mbox));
+	
+					if (err) 
+					{
+						TracingEnabled = 0;
+						/* set the return code */
+						data[50] = mbox->cmd.result;
+						mbox->cmd.length = 0;
+						break;
+					}
+					/* get num_frames */
+					sdla_peek(&card->hw, 0x9000, &num_frames, 2);
+					sdla_peek(&card->hw, 0x9002, &curr_trace_addr,4);
+					start_trace_addr = curr_trace_addr;
+					/* MAX_SEND_BUFFER_SIZE - 
+					 * sizeof(UDP_MGMT_PACKET) - 41 */
+					available_buffer_space = 1926;
+					/* set return code */
+					data[50] = 0;
+				} 
+				else
+				{
+					/* set return code to line trace already 
+					   enabled */
+					data[50] = 1;
+				}
+				mbox->cmd.length = 0;
+				TracingEnabled = 1;
+				break;
+			/* FPIPE_DISABLE_TRACE */
+			case 0x42:
+				if (TracingEnabled) 
+				{
+					do 
+					{
+						/* SET_TRACE_CONFIGURATION */
+						mbox->cmd.command = 0x60;
+						mbox->cmd.length = 1;
+						mbox->cmd.dlci = 0x00;
+						mbox->data[0] = 0x36;
+						err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+					}
+					while (err && c_retry-- && fr_event(card, err, mbox));
+				}
+				/* set return code */
+				data[50] = 0;
+				mbox->cmd.length = 0;
+				TracingEnabled = 0;
+				break;
+			/* FPIPE_GET_TRACE_INFO */
+			case 0x43:
+				/* Line trace cannot be performed on the 502 */
+				if (!TracingEnabled) 
+				{
+					/* set return code */
+					data[50] = 1;
+					mbox->cmd.length = 0;
+					break;
+				}
+				buffer_length = 0;
+				loops = (num_frames < 20) ? num_frames : 20;
+				for (frames = 0; frames < loops; frames += 1) 
+				{
+					sdla_peek(&card->hw, curr_trace_addr, &buf2, 1);
+					/* no data on board so exit */
+					if (buf2[0] == 0x00)
+						break;
+					/* 1+sizeof(FRAME_DATA) = 9 */
+					if ((available_buffer_space - buffer_length) < 9) 
+					{
+						/* indicate we have more frames on board
+						   and exit */
+						data[62] |= 0x02;
+						break;
+					}
+					/* get frame status */
+					sdla_peek(&card->hw, curr_trace_addr + 0x05, &data[62 + buffer_length], 1);
+					/* get time stamp */
+					sdla_peek(&card->hw, curr_trace_addr + 0x06, &data[66 + buffer_length], 2);
+					/* get frame length */
+					sdla_peek(&card->hw, curr_trace_addr + 0x01, &data[64 + buffer_length], 2);
+					/* get pointer to real data */
+					sdla_peek(&card->hw, curr_trace_addr + 0x0C,&data_ptr, 4);
+					/* see if we can fit the frame into the user buffer */
+					memcpy(&real_len, &data[64 + buffer_length], 2);
+					if (data_ptr == 0 || real_len + 8 > available_buffer_space) 
+					{
+						data[63 + buffer_length] = 0x00;
+					}
+					else
+					{
+						/* we can take it next time */
+						if (available_buffer_space - buffer_length < real_len + 8) 
+						{
+							data[62] |= 0x02;
+							break;
+						}
+						/* ok, get the frame */
+						data[63 + buffer_length] = 0x01;
+						/* get the data */
+						sdla_peek(&card->hw, data_ptr, &data[68 + buffer_length], real_len);
+						/* zero the opp flag to show we got the frame */
+						buf2[0] = 0x00;
+						sdla_poke(&card->hw, curr_trace_addr, &buf2, 1);
+						/* now move onto the next frame */
+						curr_trace_addr += 16;
+						/* check if we passed the last address */
+						if (curr_trace_addr >= (start_trace_addr + num_frames * 16)) 
+							curr_trace_addr = start_trace_addr;
+						/* update buffer length and make sure 
+						   its even */
+						if (data[63 + buffer_length] == 0x01) 
+							buffer_length += real_len - 1;
+						/* for the header */
+						buffer_length += 8;
+						if (buffer_length & 0x0001)
+							buffer_length += 1;
+					}
+				}
+				/* ok now set the total number of frames passed in the 
+				   high 5 bits */
+				data[62] = (frames << 3) | data[62];
+				/* set the data length */
+				mbox->cmd.length = buffer_length;
+				memcpy(&data[48], &buffer_length, 2);
+				data[50] = 0;
+				break;
+			/* FPIPE_FT1_READ_STATUS */
+			case 0x44:
+				sdla_peek(&card->hw, 0xF020, &data[62], 2);
+				data[48] = 2;
+				data[49] = 0;
+				data[50] = 0;
+				mbox->cmd.length = 2;
+				break;
+			/* FPIPE_FLUSH_DRIVER_STATS */
+			case 0x48:
+				init_chan_statistics(chan);
+				init_global_statistics(card);
+				mbox->cmd.length = 0;
+				break;
+			case 0x49:
+				do_gettimeofday(&tv);
+				chan->router_up_time = tv.tv_sec - chan->router_start_time;
+				*(unsigned long *) &data[62] = chan->router_up_time;
+				mbox->cmd.length = 4;
+				break;
+			/* FPIPE_KILL_BOARD */
+			case 0x50:
+				break;
+			/* FT1 MONITOR STATUS */
+			case 0x80:
+				if (data[62] == 1) 
+				{
+					if (rCount++ != 0) 
+					{
+						data[50] = 0;
+						mbox->cmd.length = 1;
+						break;
+					}
+				}
+				/* Disable FT1 MONITOR STATUS */
+				if (data[62] == 0) 
+				{
+					if (--rCount != 0) 
+					{
+						data[50] = 0;
+						mbox->cmd.length = 1;
+						break;
+					}
+				}
+			default:
+				do 
+				{
+					memcpy(&mbox->cmd, &sendpacket[47], sizeof(fr_cmd_t));
+					if (mbox->cmd.length) 
+						memcpy(&mbox->data, &sendpacket[62],mbox->cmd.length);
+					err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+				}
+				while (err && c_retry-- && fr_event(card, err, mbox));
+			
+				if (!err) 
+				{
+					++chan->UDP_FPIPE_mgmt_adptr_cmnd_OK;
+					memcpy(data, sendpacket, skb->len);
+					memcpy(&data[47], &mbox->cmd, sizeof(fr_cmd_t));
+					if (mbox->cmd.length) 
+					{
+						memcpy(&data[62], &mbox->data,mbox->cmd.length);
+					}
+				}
+				else
+				{
+					++chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout;
+				}
+			}
+	}
+	/* Fill UDP TTL */
+	data[10] = card->wandev.ttl;
+	len = reply_udp(data, mbox->cmd.length);
+	if (udp_pkt_src == UDP_PKT_FRM_NETWORK) 
+	{
+		err = fr508_send(card, dlci, 0, len, data);
+		if (err)
+			++chan->UDP_FPIPE_mgmt_adptr_send_passed;
+		else
+			++chan->UDP_FPIPE_mgmt_adptr_send_failed;
+		dev_kfree_skb(skb);
+	}
+	else 
+	{
+		/* Allocate socket buffer */
+		if ((new_skb = dev_alloc_skb(len)) != NULL) 
+		{
+			/* copy data into new_skb */
+			buf = skb_put(new_skb, len);
+			memcpy(buf, data, len);
+			/* Decapsulate packet and pass it up the protocol 
+			   stack */
+			new_skb->dev = dev;
+			buf = skb_pull(new_skb, 1);	/* remove hardware header */
+			if (!wanrouter_type_trans(new_skb, dev)) 
+			{
+				++chan->UDP_FPIPE_mgmt_not_passed_to_stack;
+				/* can't decapsulate packet */
+				dev_kfree_skb(new_skb);
+			}
+			else 
+			{
+				++chan->UDP_FPIPE_mgmt_passed_to_stack;
+				netif_rx(new_skb);
+			}
+		}
+		else 
+		{
+			++chan->UDP_FPIPE_mgmt_no_socket;
+			printk(KERN_INFO
+			       "%s: UDP mgmt cmnd, no socket buffers available!\n",
+			       card->devname);
+		}
+	}
+	kfree(data);
+	return 0;
+}
+/*==============================================================================
+ * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_
+ * TEST_COUNTER times.
+ */
+ 
+static int intr_test(sdla_t * card)
+{
+	fr_mbox_t *mb = card->mbox;
+	int err, i;
+	/* The critical flag is unset here because we want to get into the
+	   ISR without the flag already set. The If_open sets the flag.
+	 */
+	card->wandev.critical = 0;
+	err = fr_set_intr_mode(card, 0x08, card->wandev.mtu);
+	if (err == CMD_OK) 
+	{
+		for (i = 0; i < MAX_INTR_TEST_COUNTER; i++) 
+		{
+			/* Run command READ_CODE_VERSION */
+			memset(&mb->cmd, 0, sizeof(fr_cmd_t));
+			mb->cmd.length = 0;
+			mb->cmd.command = 0x40;
+			err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+			if (err != CMD_OK)
+				fr_event(card, err, mb);
+		}
+	} 
+	else 
+	{
+		return err;
+	}
+	err = fr_set_intr_mode(card, 0, card->wandev.mtu);
+	if (err != CMD_OK)
+		return err;
+	card->wandev.critical = 1;
+	return 0;
+}
+/*============================================================================
+ * Process UDP call of type DRVSTATS.  
+ */
+static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, int dlci, fr_channel_t * chan)
+{
+	int c_retry = MAX_CMD_RETRY;
+	unsigned char *sendpacket;
+	unsigned char buf2[5];
+	unsigned char *data;
+	unsigned char *buf;
+	unsigned int len;
+	fr_mbox_t *mbox = card->mbox;
+	struct sk_buff *new_skb;
+	int err;
+	sendpacket = skb->data;
+	memcpy(&buf2, &card->wandev.udp_port, 2);
+	if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) 
+	{
+		printk(KERN_INFO
+		       "%s: Error allocating memory for UDP DRIVER STATS cmnd0x%02X"
+		       ,card->devname, data[45]);
+		++chan->UDP_DRVSTATS_mgmt_kmalloc_err;
+		return 1;
+	}
+	memcpy(data, sendpacket, skb->len);
+	switch (data[47]) 
+	{
+		case 0x45:
+			*(unsigned long *) &data[62] = chan->if_send_entry;
+			*(unsigned long *) &data[66] = chan->if_send_skb_null;
+			*(unsigned long *) &data[70] = chan->if_send_broadcast;
+			*(unsigned long *) &data[74] = chan->if_send_multicast;
+			*(unsigned long *) &data[78] = chan->if_send_critical_ISR;
+			*(unsigned long *) &data[82] = chan->if_send_critical_non_ISR;
+			*(unsigned long *) &data[86] = chan->if_send_busy;
+			*(unsigned long *) &data[90] = chan->if_send_busy_timeout;
+			*(unsigned long *) &data[94] = chan->if_send_DRVSTATS_request;
+			*(unsigned long *) &data[98] = chan->if_send_FPIPE_request;
+			*(unsigned long *) &data[102] = chan->if_send_wan_disconnected;
+			*(unsigned long *) &data[106] = chan->if_send_dlci_disconnected;
+			*(unsigned long *) &data[110] = chan->if_send_no_bfrs;
+			*(unsigned long *) &data[114] = chan->if_send_adptr_bfrs_full;
+			*(unsigned long *) &data[118] = chan->if_send_bfrs_passed_to_adptr;
+			*(unsigned long *) &data[120] = card->irq_dis_if_send_count;
+			mbox->cmd.length = 62;
+			break;
+		case 0x46:
+			*(unsigned long *) &data[62] = card->statistics.isr_entry;
+			*(unsigned long *) &data[66] = card->statistics.isr_already_critical;
+			*(unsigned long *) &data[70] = card->statistics.isr_rx;
+			*(unsigned long *) &data[74] = card->statistics.isr_tx;
+			*(unsigned long *) &data[78] = card->statistics.isr_intr_test;
+			*(unsigned long *) &data[82] = card->statistics.isr_spurious;
+			*(unsigned long *) &data[86] = card->statistics.isr_enable_tx_int;
+			*(unsigned long *) &data[90] = card->statistics.tx_intr_dev_not_started;
+			*(unsigned long *) &data[94] = card->statistics.rx_intr_corrupt_rx_bfr;
+			*(unsigned long *) &data[98] = card->statistics.rx_intr_on_orphaned_DLCI;
+			*(unsigned long *) &data[102] = chan->rx_intr_no_socket;
+			*(unsigned long *) &data[106] = chan->rx_intr_dev_not_started;
+			*(unsigned long *) &data[110] = chan->rx_intr_DRVSTATS_request;
+			*(unsigned long *) &data[114] = chan->rx_intr_FPIPE_request;
+			*(unsigned long *) &data[118] = chan->rx_intr_bfr_not_passed_to_stack;
+			*(unsigned long *) &data[122] = chan->rx_intr_bfr_passed_to_stack;
+			mbox->cmd.length = 64;
+			break;
+		case 0x47:
+			*(unsigned long *) &data[62] = chan->UDP_FPIPE_mgmt_kmalloc_err;
+			*(unsigned long *) &data[66] = chan->UDP_FPIPE_mgmt_adptr_type_err;
+			*(unsigned long *) &data[70] = chan->UDP_FPIPE_mgmt_direction_err;
+			*(unsigned long *) &data[74] = chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout;
+			*(unsigned long *) &data[78] = chan->UDP_FPIPE_mgmt_adptr_cmnd_OK;
+			*(unsigned long *) &data[82] = chan->UDP_FPIPE_mgmt_adptr_send_passed;
+			*(unsigned long *) &data[86] = chan->UDP_FPIPE_mgmt_adptr_send_failed;
+			*(unsigned long *) &data[90] = chan->UDP_FPIPE_mgmt_no_socket;
+			*(unsigned long *) &data[94] = chan->UDP_FPIPE_mgmt_not_passed_to_stack;
+			*(unsigned long *) &data[98] = chan->UDP_FPIPE_mgmt_passed_to_stack;
+			*(unsigned long *) &data[102] = chan->UDP_DRVSTATS_mgmt_kmalloc_err;
+			*(unsigned long *) &data[106] = chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
+			*(unsigned long *) &data[110] = chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
+			*(unsigned long *) &data[114] = chan->UDP_DRVSTATS_mgmt_adptr_send_passed;
+			*(unsigned long *) &data[118] = chan->UDP_DRVSTATS_mgmt_adptr_send_failed;
+			*(unsigned long *) &data[122] = chan->UDP_DRVSTATS_mgmt_no_socket;
+			*(unsigned long *) &data[126] = chan->UDP_DRVSTATS_mgmt_not_passed_to_stack;
+			*(unsigned long *) &data[130] = chan->UDP_DRVSTATS_mgmt_passed_to_stack;
+			*(unsigned long *) &data[134] = card->statistics.poll_entry;
+			*(unsigned long *) &data[138] = card->statistics.poll_already_critical;
+			*(unsigned long *) &data[142] = card->statistics.poll_processed;
+			*(unsigned long *) &data[144] = card->irq_dis_poll_count;
+			mbox->cmd.length = 86;
+			break;
+		default:
+			do 
+			{
+				memcpy(&mbox->cmd, &sendpacket[47], sizeof(fr_cmd_t));
+				if (mbox->cmd.length) 
+					memcpy(&mbox->data, &sendpacket[62], mbox->cmd.length);
+				err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+			} 
+			while (err && c_retry-- && fr_event(card, err, mbox));
+			
+			if (!err) 
+			{
+				++chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
+				memcpy(data, sendpacket, skb->len);
+				memcpy(&data[47], &mbox->cmd, sizeof(fr_cmd_t));
+				if (mbox->cmd.length) 
+					memcpy(&data[62], &mbox->data, mbox->cmd.length);
+			} 
+			else 
+			{
+				++chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
+			}
+	}
+	/* Fill UDP TTL */
+	data[10] = card->wandev.ttl;
+	len = reply_udp(data, mbox->cmd.length);
+	if (udp_pkt_src == UDP_PKT_FRM_NETWORK) 
+	{
+		err = fr508_send(card, dlci, 0, len, data);
+		if (err)
+			++chan->UDP_DRVSTATS_mgmt_adptr_send_failed;
+		else
+			++chan->UDP_DRVSTATS_mgmt_adptr_send_passed;
+		dev_kfree_skb(skb);
+	}
+	else
+	{
+		/* Allocate socket buffer */
+		if ((new_skb = dev_alloc_skb(len)) != NULL) 
+		{
+			/* copy data into new_skb */
+			buf = skb_put(new_skb, len);
+			memcpy(buf, data, len);
+			/* Decapsulate packet and pass it up the 
+			   protocol stack */
+			new_skb->dev = dev;
+			/* remove hardware header */
+			buf = skb_pull(new_skb, 1);
+			if (!wanrouter_type_trans(new_skb, dev)) 
+			{
+				/* can't decapsulate packet */
+				++chan->UDP_DRVSTATS_mgmt_not_passed_to_stack;
+				dev_kfree_skb(new_skb);
+			}
+			else
+			{
+				++chan->UDP_DRVSTATS_mgmt_passed_to_stack;
+				netif_rx(new_skb);
+			}
+		}
+		else
+		{
+			++chan->UDP_DRVSTATS_mgmt_no_socket;
+			printk(KERN_INFO "%s: UDP mgmt cmnd, no socket buffers available!\n", card->devname);
+		}
+	}
+	kfree(data);
+	return 0;
+}
+
+/*==============================================================================
+ * Determine what type of UDP call it is. DRVSTATS or FPIPE8ND ?
+ */
+
+static int udp_pkt_type(struct sk_buff *skb, sdla_t * card)
+{
+	unsigned char *sendpacket;
+	unsigned char buf2[5];
+	sendpacket = skb->data;
+	memcpy(&buf2, &card->wandev.udp_port, 2);
+	if (sendpacket[2] == 0x45 &&	/* IP packet */
+	    sendpacket[11] == 0x11 &&	/* UDP packet */
+	    sendpacket[24] == buf2[1] &&	/* UDP Port */
+	    sendpacket[25] == buf2[0] &&
+	    sendpacket[38] == 0x01) 
+	{
+		if (sendpacket[30] == 0x46 &&	/* FPIPE8ND: Signature */
+		    sendpacket[31] == 0x50 &&
+		    sendpacket[32] == 0x49 &&
+		    sendpacket[33] == 0x50 &&
+		    sendpacket[34] == 0x45 &&
+		    sendpacket[35] == 0x38 &&
+		    sendpacket[36] == 0x4E &&
+		    sendpacket[37] == 0x44) 
+		{
+			return UDP_FPIPE_TYPE;
+		} else if (sendpacket[30] == 0x44 &&	/* DRVSTATS: Signature */
+			   sendpacket[31] == 0x52 &&
+			   sendpacket[32] == 0x56 &&
+			   sendpacket[33] == 0x53 &&
+			   sendpacket[34] == 0x54 &&
+			   sendpacket[35] == 0x41 &&
+			   sendpacket[36] == 0x54 &&
+			   sendpacket[37] == 0x53) 
+		{
+			return UDP_DRVSTATS_TYPE;
+		}
+		else
+			return UDP_INVALID_TYPE;
+	}
+	else
+		return UDP_INVALID_TYPE;
+}
+/*==============================================================================
+ * Initializes the Statistics values in the fr_channel structure.
+ */
+ 
+void init_chan_statistics(fr_channel_t * chan)
+{
+	chan->if_send_entry = 0;
+	chan->if_send_skb_null = 0;
+	chan->if_send_broadcast = 0;
+	chan->if_send_multicast = 0;
+	chan->if_send_critical_ISR = 0;
+	chan->if_send_critical_non_ISR = 0;
+	chan->if_send_busy = 0;
+	chan->if_send_busy_timeout = 0;
+	chan->if_send_FPIPE_request = 0;
+	chan->if_send_DRVSTATS_request = 0;
+	chan->if_send_wan_disconnected = 0;
+	chan->if_send_dlci_disconnected = 0;
+	chan->if_send_no_bfrs = 0;
+	chan->if_send_adptr_bfrs_full = 0;
+	chan->if_send_bfrs_passed_to_adptr = 0;
+	chan->rx_intr_no_socket = 0;
+	chan->rx_intr_dev_not_started = 0;
+	chan->rx_intr_FPIPE_request = 0;
+	chan->rx_intr_DRVSTATS_request = 0;
+	chan->rx_intr_bfr_not_passed_to_stack = 0;
+	chan->rx_intr_bfr_passed_to_stack = 0;
+	chan->UDP_FPIPE_mgmt_kmalloc_err = 0;
+	chan->UDP_FPIPE_mgmt_direction_err = 0;
+	chan->UDP_FPIPE_mgmt_adptr_type_err = 0;
+	chan->UDP_FPIPE_mgmt_adptr_cmnd_OK = 0;
+	chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout = 0;
+	chan->UDP_FPIPE_mgmt_adptr_send_passed = 0;
+	chan->UDP_FPIPE_mgmt_adptr_send_failed = 0;
+	chan->UDP_FPIPE_mgmt_not_passed_to_stack = 0;
+	chan->UDP_FPIPE_mgmt_passed_to_stack = 0;
+	chan->UDP_FPIPE_mgmt_no_socket = 0;
+	chan->UDP_DRVSTATS_mgmt_kmalloc_err = 0;
+	chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK = 0;
+	chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout = 0;
+	chan->UDP_DRVSTATS_mgmt_adptr_send_passed = 0;
+	chan->UDP_DRVSTATS_mgmt_adptr_send_failed = 0;
+	chan->UDP_DRVSTATS_mgmt_not_passed_to_stack = 0;
+	chan->UDP_DRVSTATS_mgmt_passed_to_stack = 0;
+	chan->UDP_DRVSTATS_mgmt_no_socket = 0;
+}
+/*==============================================================================
+ * Initializes the Statistics values in the Sdla_t structure.
+ */
+
+void init_global_statistics(sdla_t * card)
+{
+	/* Intialize global statistics for a card */
+	card->statistics.isr_entry = 0;
+	card->statistics.isr_already_critical = 0;
+	card->statistics.isr_rx = 0;
+	card->statistics.isr_tx = 0;
+	card->statistics.isr_intr_test = 0;
+	card->statistics.isr_spurious = 0;
+	card->statistics.isr_enable_tx_int = 0;
+	card->statistics.rx_intr_corrupt_rx_bfr = 0;
+	card->statistics.rx_intr_on_orphaned_DLCI = 0;
+	card->statistics.tx_intr_dev_not_started = 0;
+	card->statistics.poll_entry = 0;
+	card->statistics.poll_already_critical = 0;
+	card->statistics.poll_processed = 0;
+}
+
+static void read_DLCI_IB_mapping(sdla_t * card, fr_channel_t * chan)
+{
+	fr_mbox_t *mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	dlci_IB_mapping_t *result;
+	int err, counter, found;
+	do 
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		mbox->cmd.command = FR_READ_DLCI_IB_MAPPING;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+	
+	if (mbox->cmd.result != 0)
+		printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", chan->name);
+
+	counter = mbox->cmd.length / sizeof(dlci_IB_mapping_t);
+	result = (void *) mbox->data;
+	found = 0;
+	for (; counter; --counter, ++result) 
+	{
+		if (result->dlci == chan->dlci) 
+		{
+			printk(KERN_INFO "%s: DLCI= %d, IB addr = %lx for %s\n"
+			 ,card->devname, result->dlci, result->addr_value ,chan->name);
+			chan->IB_addr = result->addr_value;
+			chan->dlci_int_interface = (void *) (card->hw.dpmbase +
+					   (chan->IB_addr & 0x00001FFF));
+			found = 1;
+			break;
+		}
+	}
+	if (!found)
+		printk(KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n",
+		       card->devname, chan->dlci);
+}
+
+/****** End *****************************************************************/
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/sdla_ppp.c linux/drivers/net/wan/sdla_ppp.c
--- v2.3.20/linux/drivers/net/wan/sdla_ppp.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/sdla_ppp.c	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,2261 @@
+/*****************************************************************************
+* sdla_ppp.c	WANPIPE(tm) Multiprotocol WAN Link Driver. PPP module.
+*
+* Author: 	Jaspreet Singh 	<jaspreet@sangoma.com>
+*
+* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
+*
+*		This program is free software; you can redistribute it and/or
+*		modify it under the terms of the GNU General Public License
+*		as published by the Free Software Foundation; either version
+*		2 of the License, or (at your option) any later version.
+* ============================================================================
+* Mar 15, 1998  Alan Cox	o 2.1.8x basic port.
+* Nov 27, 1997	Jaspreet Singh	o Added protection against enabling of irqs 
+*				  while they have been disabled.
+* Nov 24, 1997  Jaspreet Singh  o Fixed another RACE condition caused by
+*                                 disabling and enabling of irqs.
+*                               o Added new counters for stats on disable/enable*                                 IRQs.
+* Nov 10, 1997	Jaspreet Singh	o Initialized 'skb->mac.raw' to 'skb->data'
+*				  before every netif_rx().
+*				o Free up the device structure in del_if().
+* Nov 07, 1997	Jaspreet Singh	o Changed the delay to zero for Line tracing
+*				  command.
+* Oct 20, 1997 	Jaspreet Singh	o Added hooks in for Router UP time.
+* Oct 16, 1997	Jaspreet Singh  o The critical flag is used to maintain flow
+*				  control by avoiding RACE conditions.  The 
+*				  cli() and restore_flags() are taken out.
+*				  A new structure, "ppp_private_area", is added 
+*				  to provide Driver Statistics.   
+* Jul 21, 1997 	Jaspreet Singh	o Protected calls to sdla_peek() by adding 
+*				  save_flags(), cli() and restore_flags().
+* Jul 07, 1997	Jaspreet Singh  o Added configurable TTL for UDP packets
+*				o Added ability to discard mulitcast and
+*				  broacast source addressed packets.
+* Jun 27, 1997 	Jaspreet Singh	o Added FT1 monitor capabilities
+*				  New case (0x25) statement in if_send routine.
+*				  Added a global variable rCount to keep track
+*				  of FT1 status enabled on the board.
+* May 22, 1997	Jaspreet Singh	o Added change in the PPP_SET_CONFIG command for
+*				508 card to reflect changes in the new 
+*				ppp508.sfm for supporting:continous transmission
+*				of Configure-Request packets without receiving a
+*				reply 				
+*				OR-ed 0x300 to conf_flags 
+*			        o Changed connect_tmout from 900 to 0
+* May 21, 1997	Jaspreet Singh  o Fixed UDP Management for multiple boards
+* Apr 25, 1997  Farhan Thawar    o added UDP Management stuff
+* Mar 11, 1997  Farhan Thawar   Version 3.1.1
+*                                o fixed (+1) bug in rx_intr()
+*                                o changed if_send() to return 0 if
+*                                  wandev.critical() is true
+*                                o free socket buffer in if_send() if
+*                                  returning 0 
+* Jan 15, 1997	Gene Kozin	Version 3.1.0
+*				 o implemented exec() entry point
+* Jan 06, 1997	Gene Kozin	Initial version.
+*****************************************************************************/
+
+#include <linux/kernel.h>	/* printk(), and other useful stuff */
+#include <linux/stddef.h>	/* offsetof(), etc. */
+#include <linux/errno.h>	/* return codes */
+#include <linux/string.h>	/* inline memset(), etc. */
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
+#include <linux/wanrouter.h>	/* WAN router definitions */
+#include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
+#include <linux/if_arp.h>	/* ARPHRD_* defines */
+#include <asm/byteorder.h>	/* htons(), etc. */
+#include <asm/uaccess.h>	/* copyto/from user */
+#define	_GNUC_
+#include <linux/sdla_ppp.h>	/* PPP firmware API definitions */
+
+/****** Defines & Macros ****************************************************/
+
+#ifdef	_DEBUG_
+#define	STATIC
+#else
+#define	STATIC		static
+#endif
+#define	PPP_DFLT_MTU	1500	/* default MTU */
+#define	PPP_MAX_MTU	4000	/* maximum MTU */
+#define PPP_HDR_LEN	1
+#define	CONNECT_TIMEOUT	(90*HZ)	/* link connection timeout */
+#define	HOLD_DOWN_TIME	(30*HZ)	/* link hold down time */
+
+/* For handle_IPXWAN() */
+#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b)))
+
+/******Data Structures*****************************************************/
+/* This structure is placed in the private data area of the device structure.
+ * The card structure used to occupy the private area but now the following 
+ * structure will incorporate the card structure along with PPP specific data
+ */
+
+typedef struct ppp_private_area 
+{
+	sdla_t *card;
+	unsigned long router_start_time;	/*router start time in sec */
+	unsigned long tick_counter;	/*used for 5 second counter */
+	unsigned mc;		/*multicast support on or off */
+	/* PPP specific statistics */
+	unsigned long if_send_entry;
+	unsigned long if_send_skb_null;
+	unsigned long if_send_broadcast;
+	unsigned long if_send_multicast;
+	unsigned long if_send_critical_ISR;
+	unsigned long if_send_critical_non_ISR;
+	unsigned long if_send_busy;
+	unsigned long if_send_busy_timeout;
+	unsigned long if_send_DRVSTATS_request;
+	unsigned long if_send_PTPIPE_request;
+	unsigned long if_send_wan_disconnected;
+	unsigned long if_send_adptr_bfrs_full;
+	unsigned long if_send_protocol_error;
+	unsigned long if_send_tx_int_enabled;
+	unsigned long if_send_bfr_passed_to_adptr;
+	unsigned long rx_intr_no_socket;
+	unsigned long rx_intr_DRVSTATS_request;
+	unsigned long rx_intr_PTPIPE_request;
+	unsigned long rx_intr_bfr_not_passed_to_stack;
+	unsigned long rx_intr_bfr_passed_to_stack;
+	unsigned long UDP_PTPIPE_mgmt_kmalloc_err;
+	unsigned long UDP_PTPIPE_mgmt_adptr_type_err;
+	unsigned long UDP_PTPIPE_mgmt_direction_err;
+	unsigned long UDP_PTPIPE_mgmt_adptr_cmnd_timeout;
+	unsigned long UDP_PTPIPE_mgmt_adptr_cmnd_OK;
+	unsigned long UDP_PTPIPE_mgmt_passed_to_adptr;
+	unsigned long UDP_PTPIPE_mgmt_passed_to_stack;
+	unsigned long UDP_PTPIPE_mgmt_no_socket;
+	unsigned long UDP_DRVSTATS_mgmt_kmalloc_err;
+	unsigned long UDP_DRVSTATS_mgmt_adptr_type_err;
+	unsigned long UDP_DRVSTATS_mgmt_direction_err;
+	unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
+	unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
+	unsigned long UDP_DRVSTATS_mgmt_passed_to_adptr;
+	unsigned long UDP_DRVSTATS_mgmt_passed_to_stack;
+	unsigned long UDP_DRVSTATS_mgmt_no_socket;
+	unsigned long router_up_time;
+} ppp_private_area_t;
+
+/* variable for keeping track of enabling/disabling FT1 monitor status */
+
+static int rCount = 0;
+extern void disable_irq(unsigned int);
+extern void enable_irq(unsigned int);
+
+/****** Function Prototypes *************************************************/
+
+/* WAN link driver entry points. These are called by the WAN router module. */
+static int update(wan_device_t * wandev);
+static int new_if(wan_device_t * wandev, struct net_device *dev,
+		  wanif_conf_t * conf);
+static int del_if(wan_device_t * wandev, struct net_device *dev);
+/* WANPIPE-specific entry points */
+static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data);
+/* Network device interface */
+static int if_init(struct net_device *dev);
+static int if_open(struct net_device *dev);
+static int if_close(struct net_device *dev);
+static int if_header(struct sk_buff *skb, struct net_device *dev,
+	    unsigned short type, void *daddr, void *saddr, unsigned len);
+static int if_rebuild_hdr(struct sk_buff *skb);
+static int if_send(struct sk_buff *skb, struct net_device *dev);
+static struct enet_statistics *if_stats(struct net_device *dev);
+/* PPP firmware interface functions */
+static int ppp_read_version(sdla_t * card, char *str);
+static int ppp_configure(sdla_t * card, void *data);
+static int ppp_set_intr_mode(sdla_t * card, unsigned mode);
+static int ppp_comm_enable(sdla_t * card);
+static int ppp_comm_disable(sdla_t * card);
+static int ppp_get_err_stats(sdla_t * card);
+static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto);
+static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb);
+/* Interrupt handlers */
+STATIC void wpp_isr(sdla_t * card);
+static void rx_intr(sdla_t * card);
+static void tx_intr(sdla_t * card);
+/* Background polling routines */
+static void wpp_poll(sdla_t * card);
+static void poll_active(sdla_t * card);
+static void poll_connecting(sdla_t * card);
+static void poll_disconnected(sdla_t * card);
+/* Miscellaneous functions */
+static int config502(sdla_t * card);
+static int config508(sdla_t * card);
+static void show_disc_cause(sdla_t * card, unsigned cause);
+static unsigned char bps_to_speed_code(unsigned long bps);
+static int reply_udp(unsigned char *data, unsigned int mbox_len);
+static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, ppp_private_area_t * ppp_priv_area);
+static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, ppp_private_area_t * ppp_priv_area);
+static void init_ppp_tx_rx_buff(sdla_t * card);
+static int intr_test(sdla_t * card);
+static int udp_pkt_type(struct sk_buff *skb, sdla_t * card);
+static void init_ppp_priv_struct(ppp_private_area_t * ppp_priv_area);
+static void init_global_statistics(sdla_t * card);
+static int Intr_test_counter;
+static char TracingEnabled;
+static unsigned long curr_trace_addr;
+static unsigned long start_trace_addr;
+static unsigned short available_buffer_space;
+/* IPX functions */
+static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming);
+static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto);
+
+/****** Public Functions ****************************************************/
+
+/*============================================================================
+ * PPP protocol initialization routine.
+ *
+ * This routine is called by the main WANPIPE module during setup.  At this
+ * point adapter is completely initialized and firmware is running.
+ *  o read firmware version (to make sure it's alive)
+ *  o configure adapter
+ *  o initialize protocol-specific fields of the adapter data space.
+ *
+ * Return:	0	o.k.
+ *		< 0	failure.
+ */
+int wpp_init(sdla_t * card, wandev_conf_t * conf)
+{
+	union {
+		char str[80];
+	} u;
+	/* Verify configuration ID */
+	if (conf->config_id != WANCONFIG_PPP) {
+		printk(KERN_INFO "%s: invalid configuration ID %u!\n",
+		       card->devname, conf->config_id);
+		return -EINVAL;
+	}
+	/* Initialize protocol-specific fields */
+	switch (card->hw.fwid) {
+	case SFID_PPP502:
+		card->mbox = (void *) (card->hw.dpmbase + PPP502_MB_OFFS);
+		card->flags = (void *) (card->hw.dpmbase + PPP502_FLG_OFFS);
+		break;
+	case SFID_PPP508:
+		card->mbox = (void *) (card->hw.dpmbase + PPP508_MB_OFFS);
+		card->flags = (void *) (card->hw.dpmbase + PPP508_FLG_OFFS);
+		break;
+	default:
+		return -EINVAL;
+	}
+	/* Read firmware version.  Note that when adapter initializes, it
+	 * clears the mailbox, so it may appear that the first command was
+	 * executed successfully when in fact it was merely erased. To work
+	 * around this, we execute the first command twice.
+	 */
+	if (ppp_read_version(card, NULL) || ppp_read_version(card, u.str))
+		return -EIO;
+	printk(KERN_INFO "%s: running PPP firmware v%s\n", card->devname, u.str);
+	/* Adjust configuration and set defaults */
+	card->wandev.mtu = (conf->mtu) ?
+	    min(conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU;
+	card->wandev.bps = conf->bps;
+	card->wandev.interface = conf->interface;
+	card->wandev.clocking = conf->clocking;
+	card->wandev.station = conf->station;
+	card->isr = &wpp_isr;
+	card->poll = &wpp_poll;
+	card->exec = &wpp_exec;
+	card->wandev.update = &update;
+	card->wandev.new_if = &new_if;
+	card->wandev.del_if = &del_if;
+	card->wandev.state = WAN_DISCONNECTED;
+	card->wandev.udp_port = conf->udp_port;
+	card->wandev.ttl = conf->ttl;
+	card->irq_dis_if_send_count = 0;
+	card->irq_dis_poll_count = 0;
+	TracingEnabled = 0;
+	card->wandev.enable_IPX = conf->enable_IPX;
+	if (conf->network_number)
+		card->wandev.network_number = conf->network_number;
+	else
+		card->wandev.network_number = 0xDEADBEEF;
+	/* initialize global statistics */
+	init_global_statistics(card);
+	return 0;
+}
+
+/******* WAN Device Driver Entry Points *************************************/
+
+/*============================================================================
+ * Update device status & statistics.
+ */
+static int update(wan_device_t * wandev)
+{
+	sdla_t *card;
+	/* sanity checks */
+	if ((wandev == NULL) || (wandev->private == NULL))
+		return -EFAULT;
+	if (wandev->state == WAN_UNCONFIGURED)
+		return -ENODEV;
+	if (test_and_set_bit(0, (void *) &wandev->critical))
+		return -EAGAIN;
+	card = wandev->private;
+	ppp_get_err_stats(card);
+	wandev->critical = 0;
+	return 0;
+}
+
+/*============================================================================
+ * Create new logical channel.
+ * This routine is called by the router when ROUTER_IFNEW IOCTL is being
+ * handled.
+ * o parse media- and hardware-specific configuration
+ * o make sure that a new channel can be created
+ * o allocate resources, if necessary
+ * o prepare network device structure for registaration.
+ *
+ * Return:	0	o.k.
+ *		< 0	failure (channel will not be created)
+ */
+
+static int new_if(wan_device_t * wandev, struct net_device *dev, wanif_conf_t * conf)
+{
+	sdla_t *card = wandev->private;
+	ppp_private_area_t *ppp_priv_area;
+	if (wandev->ndev)
+		return -EEXIST;
+	if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) {
+		printk(KERN_INFO "%s: invalid interface name!\n",
+		       card->devname);
+		return -EINVAL;
+	}
+	/* allocate and initialize private data */
+	ppp_priv_area = kmalloc(sizeof(ppp_private_area_t), GFP_KERNEL);
+	if (ppp_priv_area == NULL)
+		return -ENOMEM;
+	memset(ppp_priv_area, 0, sizeof(ppp_private_area_t));
+	ppp_priv_area->card = card;
+	/* initialize data */
+	strcpy(card->u.p.if_name, conf->name);
+	/* initialize data in ppp_private_area structure */
+	init_ppp_priv_struct(ppp_priv_area);
+	ppp_priv_area->mc = conf->mc;
+	/* prepare network device data space for registration */
+	dev->name = card->u.p.if_name;
+	dev->init = &if_init;
+	dev->priv = ppp_priv_area;
+	return 0;
+}
+
+/*============================================================================
+ * Delete logical channel.
+ */
+
+static int del_if(wan_device_t * wandev, struct net_device *dev)
+{
+	if (dev->priv) {
+		kfree(dev->priv);
+		dev->priv = NULL;
+	}
+	return 0;
+}
+
+/****** WANPIPE-specific entry points ***************************************/
+
+/*============================================================================
+ * Execute adapter interface command.
+ */
+
+static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data)
+{
+	ppp_mbox_t *mbox = card->mbox;
+	int len;
+	if(copy_from_user((void *) &mbox->cmd, u_cmd, sizeof(ppp_cmd_t)))
+		return -EFAULT;
+	len = mbox->cmd.length;
+	if (len) {
+		if(copy_from_user((void *) &mbox->data, u_data, len))
+			return -EFAULT;
+	}
+	/* execute command */
+	if (!sdla_exec(mbox))
+		return -EIO;
+	/* return result */
+	if(copy_to_user(u_cmd, (void *) &mbox->cmd, sizeof(ppp_cmd_t)))
+		return -EFAULT;
+	len = mbox->cmd.length;
+	if (len && u_data && copy_to_user(u_data, (void *) &mbox->data, len))
+		return -EFAULT;
+	return 0;
+}
+
+/****** Network Device Interface ********************************************/
+
+/*============================================================================
+ * Initialize Linux network interface.
+ *
+ * This routine is called only once for each interface, during Linux network
+ * interface registration.  Returning anything but zero will fail interface
+ * registration.
+ */
+
+static int if_init(struct net_device *dev)
+{
+	ppp_private_area_t *ppp_priv_area = dev->priv;
+	sdla_t *card = ppp_priv_area->card;
+	wan_device_t *wandev = &card->wandev;
+
+	/* Initialize device driver entry points */
+	dev->open = &if_open;
+	dev->stop = &if_close;
+	dev->hard_header = &if_header;
+	dev->rebuild_header = &if_rebuild_hdr;
+	dev->hard_start_xmit = &if_send;
+	dev->get_stats = &if_stats;
+	/* Initialize media-specific parameters */
+	dev->type = ARPHRD_PPP;	/* ARP h/w type */
+	dev->mtu = wandev->mtu;
+	dev->hard_header_len = PPP_HDR_LEN;	/* media header length */
+	/* Initialize hardware parameters (just for reference) */
+	dev->irq = wandev->irq;
+	dev->dma = wandev->dma;
+	dev->base_addr = wandev->ioport;
+	dev->mem_start = (unsigned long)wandev->maddr;
+	dev->mem_end = dev->mem_start + wandev->msize - 1;
+	/* Set transmit buffer queue length */
+	dev->tx_queue_len = 100;
+	/* Initialize socket buffers */
+	dev_init_buffers(dev);
+	return 0;
+}
+
+/*============================================================================
+ * Open network interface.
+ * o enable communications and interrupts.
+ * o prevent module from unloading by incrementing use count
+ *
+ * Return 0 if O.k. or errno.
+ */
+
+static int if_open(struct net_device *dev)
+{
+	ppp_private_area_t *ppp_priv_area = dev->priv;
+	sdla_t *card = ppp_priv_area->card;
+	ppp_flags_t *flags = card->flags;
+	struct timeval tv;
+	int err = 0;
+	if (dev->start)
+		return -EBUSY;	/* only one open is allowed */
+	if (test_and_set_bit(0, (void *) &card->wandev.critical))
+		return -EAGAIN;
+	if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card)) {
+		err = -EIO;
+		card->wandev.critical = 0;
+		return err;
+	}
+	Intr_test_counter = 0;
+	err = intr_test(card);
+	if ((err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) {
+		printk(KERN_INFO "%s: Interrupt Test Failed, Counter: %i\n",
+		       card->devname, Intr_test_counter);
+		err = -EIO;
+		card->wandev.critical = 0;
+		return err;
+	}
+	printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n",
+	       card->devname, Intr_test_counter);
+	/* Initialize Rx/Tx buffer control fields */
+	init_ppp_tx_rx_buff(card);
+	if (ppp_set_intr_mode(card, 0x03)) {
+		err = -EIO;
+		card->wandev.critical = 0;
+		return err;
+	}
+	flags->imask &= ~0x02;
+	if (ppp_comm_enable(card)) {
+		err = -EIO;
+		card->wandev.critical = 0;
+		return err;
+	}
+	wanpipe_set_state(card, WAN_CONNECTING);
+	wanpipe_open(card);
+	dev->mtu = min(dev->mtu, card->wandev.mtu);
+	dev->interrupt = 0;
+	dev->tbusy = 0;
+	dev->start = 1;
+	do_gettimeofday(&tv);
+	ppp_priv_area->router_start_time = tv.tv_sec;
+	card->wandev.critical = 0;
+	return err;
+}
+
+/*============================================================================
+ * Close network interface.
+ * o if this is the last open, then disable communications and interrupts.
+ * o reset flags.
+ */
+
+static int if_close(struct net_device *dev)
+{
+	ppp_private_area_t *ppp_priv_area = dev->priv;
+	sdla_t *card = ppp_priv_area->card;
+	if (test_and_set_bit(0, (void *) &card->wandev.critical))
+		return -EAGAIN;
+	dev->start = 0;
+	wanpipe_close(card);
+	wanpipe_set_state(card, WAN_DISCONNECTED);
+	ppp_set_intr_mode(card, 0);
+	ppp_comm_disable(card);
+	card->wandev.critical = 0;
+	return 0;
+}
+
+/*============================================================================
+ * Build media header.
+ *
+ * The trick here is to put packet type (Ethertype) into 'protocol' field of
+ * the socket buffer, so that we don't forget it.  If packet type is not
+ * supported, set skb->protocol to 0 and discard packet later.
+ *
+ * Return:	media header length.
+ */
+
+static int if_header(struct sk_buff *skb, struct net_device *dev,
+	     unsigned short type, void *daddr, void *saddr, unsigned len)
+{
+	switch (type) 
+	{
+		case ETH_P_IP:
+		case ETH_P_IPX:
+			skb->protocol = type;
+			break;
+		default:
+			skb->protocol = 0;
+	}
+	return PPP_HDR_LEN;
+}
+
+/*============================================================================
+ * Re-build media header.
+ *
+ * Return:	1	physical address resolved.
+ *		0	physical address not resolved
+ */
+
+static int if_rebuild_hdr(struct sk_buff *skb)
+{
+	struct net_device *dev=skb->dev;
+	ppp_private_area_t *ppp_priv_area = dev->priv;
+	sdla_t *card = ppp_priv_area->card;
+	printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
+	       card->devname, dev->name);
+	return 1;
+}
+
+/*============================================================================
+ * Send a packet on a network interface.
+ * o set tbusy flag (marks start of the transmission) to block a timer-based
+ *   transmit from overlapping.
+ * o check link state. If link is not up, then drop the packet.
+ * o execute adapter send command.
+ * o free socket buffer
+ *
+ * Return:	0	complete (socket buffer must be freed)
+ *		non-0	packet may be re-transmitted (tbusy must be set)
+ *
+ * Notes:
+ * 1. This routine is called either by the protocol stack or by the "net
+ *    bottom half" (with interrupts enabled).
+ * 2. Setting tbusy flag will inhibit further transmit requests from the
+ *    protocol stack and can be used for flow control with protocol layer.
+ */
+
+static int if_send(struct sk_buff *skb, struct net_device *dev)
+{
+	ppp_private_area_t *ppp_priv_area = dev->priv;
+	sdla_t *card = ppp_priv_area->card;
+	unsigned char *sendpacket;
+	unsigned long check_braddr, check_mcaddr;
+	unsigned long host_cpu_flags;
+	ppp_flags_t *flags = card->flags;
+	int retry = 0;
+	int err, udp_type;
+	++ppp_priv_area->if_send_entry;
+	if (skb == NULL) {
+		/* If we get here, some higher layer thinks we've missed an
+		 * tx-done interrupt.
+		 */
+		printk(KERN_INFO "%s: interface %s got kicked!\n",
+		       card->devname, dev->name);
+		++ppp_priv_area->if_send_skb_null;
+		mark_bh(NET_BH);
+		return 0;
+	}
+	if (dev->tbusy) {
+		/* If our device stays busy for at least 5 seconds then we will
+		 * kick start the device by making dev->tbusy = 0.  We expect 
+		 * that our device never stays busy more than 5 seconds. So this
+		 * is only used as a last resort. 
+		 */
+		++ppp_priv_area->if_send_busy;
+		++card->wandev.stats.collisions;
+		if ((jiffies - ppp_priv_area->tick_counter) < (5 * HZ)) {
+			return 1;
+		}
+		printk(KERN_INFO "%s: Transmit times out\n", card->devname);
+		++ppp_priv_area->if_send_busy_timeout;
+		/* unbusy the card (because only one interface per card) */
+		dev->tbusy = 0;
+	}
+	sendpacket = skb->data;
+	udp_type = udp_pkt_type(skb, card);
+	if (udp_type == UDP_DRVSTATS_TYPE) {
+		++ppp_priv_area->if_send_DRVSTATS_request;
+		process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev,
+					ppp_priv_area);
+		dev_kfree_skb(skb);
+		return 0;
+	} else if (udp_type == UDP_PTPIPE_TYPE)
+		++ppp_priv_area->if_send_PTPIPE_request;
+	/* retreive source address in two forms: broadcast & multicast */
+	check_braddr = sendpacket[15];
+	check_mcaddr = sendpacket[12];
+	check_braddr = check_braddr << 8;
+	check_mcaddr = check_mcaddr << 8;
+	check_braddr |= sendpacket[14];
+	check_mcaddr |= sendpacket[13];
+	check_braddr = check_braddr << 8;
+	check_mcaddr = check_mcaddr << 8;
+	check_braddr |= sendpacket[13];
+	check_mcaddr |= sendpacket[14];
+	check_braddr = check_braddr << 8;
+	check_mcaddr = check_mcaddr << 8;
+	check_braddr |= sendpacket[12];
+	check_mcaddr |= sendpacket[15];
+	/* if the Source Address is a Multicast address */
+	if ((ppp_priv_area->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001)
+	    && (check_mcaddr <= 0xFFFFFFFE)) {
+		printk(KERN_INFO "%s: Mutlicast Src. Addr. silently discarded\n"
+		       ,card->devname);
+		dev_kfree_skb(skb);
+		++ppp_priv_area->if_send_multicast;
+		++card->wandev.stats.tx_dropped;
+		return 0;
+	}
+	disable_irq(card->hw.irq);
+	++card->irq_dis_if_send_count;
+	if (test_and_set_bit(0, (void *) &card->wandev.critical)) {
+		if (card->wandev.critical == CRITICAL_IN_ISR) {
+			/* If the critical flag is set due to an Interrupt
+			 * then set enable transmit interrupt flag to enable
+			 * transmit interrupt. (delay interrupt)
+			 */
+			card->wandev.enable_tx_int = 1;
+			dev->tbusy = 1;
+			/* set the counter to see if we get the interrupt in
+			 * 5 seconds. 
+			 */
+			ppp_priv_area->tick_counter = jiffies;
+			++ppp_priv_area->if_send_critical_ISR;
+			save_flags(host_cpu_flags);
+			cli();
+			if ((!(--card->irq_dis_if_send_count)) &&
+			    (!card->irq_dis_poll_count))
+				enable_irq(card->hw.irq);
+			restore_flags(host_cpu_flags);
+			return 1;
+		}
+		dev_kfree_skb(skb);
+		++ppp_priv_area->if_send_critical_non_ISR;
+		save_flags(host_cpu_flags);
+		cli();
+		if ((!(--card->irq_dis_if_send_count)) &&
+		    (!card->irq_dis_poll_count))
+			enable_irq(card->hw.irq);
+		restore_flags(host_cpu_flags);
+		return 0;
+	}
+	if (udp_type == UDP_PTPIPE_TYPE) {
+		err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb,
+					   dev, ppp_priv_area);
+	} else if (card->wandev.state != WAN_CONNECTED) {
+		++ppp_priv_area->if_send_wan_disconnected;
+		++card->wandev.stats.tx_dropped;
+	} else if (!skb->protocol) {
+		++ppp_priv_area->if_send_protocol_error;
+		++card->wandev.stats.tx_errors;
+	} else {
+		/*If it's IPX change the network numbers to 0 if they're ours. */
+		if (skb->protocol == ETH_P_IPX) {
+			if (card->wandev.enable_IPX) {
+				switch_net_numbers(skb->data,
+					 card->wandev.network_number, 0);
+			} else {
+				++card->wandev.stats.tx_dropped;
+				goto tx_done;
+			}
+		}
+		if (ppp_send(card, skb->data, skb->len, skb->protocol)) {
+			retry = 1;
+			dev->tbusy = 1;
+			++ppp_priv_area->if_send_adptr_bfrs_full;
+			++ppp_priv_area->if_send_tx_int_enabled;
+			ppp_priv_area->tick_counter = jiffies;
+			++card->wandev.stats.tx_errors;
+			flags->imask |= 0x02;	/* unmask Tx interrupts */
+		} else {
+			++ppp_priv_area->if_send_bfr_passed_to_adptr;
+			++card->wandev.stats.tx_packets;
+			card->wandev.stats.tx_bytes += skb->len;
+		}
+	}
+tx_done:
+	if (!retry) {
+		dev_kfree_skb(skb);
+	}
+	card->wandev.critical = 0;
+	save_flags(host_cpu_flags);
+	cli();
+	if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count))
+		enable_irq(card->hw.irq);
+	restore_flags(host_cpu_flags);
+	return retry;
+}
+
+/*============================================================================
+ * Reply to UDP Management system.
+ * Return length of reply.
+ */
+
+static int reply_udp(unsigned char *data, unsigned int mbox_len)
+{
+	unsigned short len, udp_length, temp, i, ip_length;
+	unsigned long sum;
+	/* Set length of packet */
+	len = mbox_len + 60;
+	/* fill in UDP reply */
+	data[36] = 0x02;
+	/* fill in UDP length */
+	udp_length = mbox_len + 40;
+	/* put it on an even boundary */
+	if (udp_length & 0x0001) {
+		udp_length += 1;
+		len += 1;
+	}
+	temp = (udp_length << 8) | (udp_length >> 8);
+	memcpy(&data[24], &temp, 2);
+	/* swap UDP ports */
+	memcpy(&temp, &data[20], 2);
+	memcpy(&data[20], &data[22], 2);
+	memcpy(&data[22], &temp, 2);
+	/* add UDP pseudo header */
+	temp = 0x1100;
+	memcpy(&data[udp_length + 20], &temp, 2);
+	temp = (udp_length << 8) | (udp_length >> 8);
+	memcpy(&data[udp_length + 22], &temp, 2);
+	/* calculate UDP checksum */
+	data[26] = data[27] = 0;
+	sum = 0;
+	for (i = 0; i < udp_length + 12; i += 2) {
+		memcpy(&temp, &data[12 + i], 2);
+		sum += (unsigned long) temp;
+	}
+	while (sum >> 16) {
+		sum = (sum & 0xffffUL) + (sum >> 16);
+	}
+	temp = (unsigned short) sum;
+	temp = ~temp;
+	if (temp == 0)
+		temp = 0xffff;
+	memcpy(&data[26], &temp, 2);
+	/* fill in IP length */
+	ip_length = udp_length + 20;
+	temp = (ip_length << 8) | (ip_length >> 8);
+	memcpy(&data[2], &temp, 2);
+	/* swap IP addresses */
+	memcpy(&temp, &data[12], 2);
+	memcpy(&data[12], &data[16], 2);
+	memcpy(&data[16], &temp, 2);
+	memcpy(&temp, &data[14], 2);
+	memcpy(&data[14], &data[18], 2);
+	memcpy(&data[18], &temp, 2);
+	/* fill in IP checksum */
+	data[10] = data[11] = 0;
+	sum = 0;
+	for (i = 0; i < 20; i += 2) {
+		memcpy(&temp, &data[i], 2);
+		sum += (unsigned long) temp;
+	}
+	while (sum >> 16) {
+		sum = (sum & 0xffffUL) + (sum >> 16);
+	}
+	temp = (unsigned short) sum;
+	temp = ~temp;
+	if (temp == 0)
+		temp = 0xffff;
+	memcpy(&data[10], &temp, 2);
+	return len;
+}				/* reply_udp */
+
+/*
+   If incoming is 0 (outgoing)- if the net numbers is ours make it 0
+   if incoming is 1 - if the net number is 0 make it ours 
+ */
+
+static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming)
+{
+	unsigned long pnetwork_number;
+	pnetwork_number = (unsigned long) ((sendpacket[6] << 24) +
+			   (sendpacket[7] << 16) + (sendpacket[8] << 8) +
+					   sendpacket[9]);
+	if (!incoming) {
+		/* If the destination network number is ours, make it 0 */
+		if (pnetwork_number == network_number) {
+			sendpacket[6] = sendpacket[7] = sendpacket[8] =
+			    sendpacket[9] = 0x00;
+		}
+	} else {
+		/* If the incoming network is 0, make it ours */
+		if (pnetwork_number == 0) {
+			sendpacket[6] = (unsigned char) (network_number >> 24);
+			sendpacket[7] = (unsigned char) ((network_number &
+						      0x00FF0000) >> 16);
+			sendpacket[8] = (unsigned char) ((network_number &
+						       0x0000FF00) >> 8);
+			sendpacket[9] = (unsigned char) (network_number &
+							 0x000000FF);
+		}
+	}
+	pnetwork_number = (unsigned long) ((sendpacket[18] << 24) +
+			 (sendpacket[19] << 16) + (sendpacket[20] << 8) +
+					   sendpacket[21]);
+	if (!incoming) {
+		/* If the source network is ours, make it 0 */
+		if (pnetwork_number == network_number) {
+			sendpacket[18] = sendpacket[19] = sendpacket[20] =
+			    sendpacket[21] = 0x00;
+		}
+	} else {
+		/* If the source network is 0, make it ours */
+		if (pnetwork_number == 0) {
+			sendpacket[18] = (unsigned char) (network_number >> 24);
+			sendpacket[19] = (unsigned char) ((network_number &
+						      0x00FF0000) >> 16);
+			sendpacket[20] = (unsigned char) ((network_number &
+						       0x0000FF00) >> 8);
+			sendpacket[21] = (unsigned char) (network_number &
+							  0x000000FF);
+		}
+	}
+}				/* switch_net_numbers */
+
+/*============================================================================
+ * Get Ethernet-style interface statistics.
+ * Return a pointer to struct enet_statistics.
+ */
+
+static struct enet_statistics *if_stats(struct net_device *dev)
+{
+	ppp_private_area_t *ppp_priv_area = dev->priv;
+	sdla_t *card;
+	
+	/*
+	 *	Device is down:No statistics
+	 */
+	 
+	if(ppp_priv_area==NULL)
+		return NULL;
+	
+	card = ppp_priv_area->card;
+	return &card->wandev.stats;
+}
+
+/****** PPP Firmware Interface Functions ************************************/
+
+/*============================================================================
+ * Read firmware code version.
+ *	Put code version as ASCII string in str. 
+ */
+
+static int ppp_read_version(sdla_t * card, char *str)
+{
+	ppp_mbox_t *mb = card->mbox;
+	int err;
+	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+	mb->cmd.command = PPP_READ_CODE_VERSION;
+	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+	if (err != CMD_OK)
+		ppp_error(card, err, mb);
+	else if (str) {
+		int len = mb->cmd.length;
+		memcpy(str, mb->data, len);
+		str[len] = '\0';
+	}
+	return err;
+}
+
+/*============================================================================
+ * Configure PPP firmware.
+ */
+
+static int ppp_configure(sdla_t * card, void *data)
+{
+	ppp_mbox_t *mb = card->mbox;
+	int data_len = (card->hw.fwid == SFID_PPP502) ?
+	sizeof(ppp502_conf_t) : sizeof(ppp508_conf_t);
+	int err;
+	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+	memcpy(mb->data, data, data_len);
+	mb->cmd.length = data_len;
+	mb->cmd.command = PPP_SET_CONFIG;
+	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+	if (err != CMD_OK)
+		ppp_error(card, err, mb);
+	return err;
+}
+
+/*============================================================================
+ * Set interrupt mode.
+ */
+
+static int ppp_set_intr_mode(sdla_t * card, unsigned mode)
+{
+	ppp_mbox_t *mb = card->mbox;
+	int err;
+	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+	mb->data[0] = mode;
+	switch (card->hw.fwid) {
+	case SFID_PPP502:
+		mb->cmd.length = 1;
+		break;
+	case SFID_PPP508:
+	default:
+		mb->data[1] = card->hw.irq;
+		mb->cmd.length = 2;
+	}
+	mb->cmd.command = PPP_SET_INTR_FLAGS;
+	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+	if (err != CMD_OK)
+		ppp_error(card, err, mb);
+	return err;
+}
+
+/*============================================================================
+ * Enable communications.
+ */
+
+static int ppp_comm_enable(sdla_t * card)
+{
+	ppp_mbox_t *mb = card->mbox;
+	int err;
+	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+	mb->cmd.command = PPP_COMM_ENABLE;
+	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+	if (err != CMD_OK)
+		ppp_error(card, err, mb);
+	return err;
+}
+
+/*============================================================================
+ * Disable communications.
+ */
+
+static int ppp_comm_disable(sdla_t * card)
+{
+	ppp_mbox_t *mb = card->mbox;
+	int err;
+	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+	mb->cmd.command = PPP_COMM_DISABLE;
+	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+	if (err != CMD_OK)
+		ppp_error(card, err, mb);
+	return err;
+}
+
+/*============================================================================
+ * Get communications error statistics.
+ */
+
+static int ppp_get_err_stats(sdla_t * card)
+{
+	ppp_mbox_t *mb = card->mbox;
+	int err;
+	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+	mb->cmd.command = PPP_READ_ERROR_STATS;
+	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+	if (err == CMD_OK) {
+		ppp_err_stats_t *stats = (void *) mb->data;
+		card->wandev.stats.rx_over_errors = stats->rx_overrun;
+		card->wandev.stats.rx_crc_errors = stats->rx_bad_crc;
+		card->wandev.stats.rx_missed_errors = stats->rx_abort;
+		card->wandev.stats.rx_length_errors = stats->rx_lost;
+		card->wandev.stats.tx_aborted_errors = stats->tx_abort;
+	} else
+		ppp_error(card, err, mb);
+	return err;
+}
+
+/*============================================================================
+ * Send packet.
+ *	Return:	0 - o.k.
+ *		1 - no transmit buffers available
+ */
+
+static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto)
+{
+	ppp_buf_ctl_t *txbuf = card->u.p.txbuf;
+	unsigned long addr;
+	if (txbuf->flag)
+		return 1
+		    ;
+	if (card->hw.fwid == SFID_PPP502)
+		addr = (txbuf->buf.o_p[1] << 8) + txbuf->buf.o_p[0];
+	else
+		addr = txbuf->buf.ptr;
+	sdla_poke(&card->hw, addr, data, len);
+	txbuf->length = len;	/* frame length */
+	if (proto == ETH_P_IPX)
+		txbuf->proto = 0x01;	/* protocol ID */
+	txbuf->flag = 1;	/* start transmission */
+	/* Update transmit buffer control fields */
+	card->u.p.txbuf = ++txbuf;
+	if ((void *) txbuf > card->u.p.txbuf_last)
+		card->u.p.txbuf = card->u.p.txbuf_base;
+	return 0;
+}
+
+/****** Firmware Error Handler **********************************************/
+
+/*============================================================================
+ * Firmware error handler.
+ *	This routine is called whenever firmware command returns non-zero
+ *	return code.
+ *
+ * Return zero if previous command has to be cancelled.
+ */
+
+static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb)
+{
+	unsigned cmd = mb->cmd.command;
+	switch (err) {
+	case CMD_TIMEOUT:
+		printk(KERN_ERR "%s: command 0x%02X timed out!\n",
+		       card->devname, cmd);
+		break;
+	default:
+		printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n"
+		       ,card->devname, cmd, err);
+	}
+	return 0;
+}
+
+/****** Interrupt Handlers **************************************************/
+
+/*============================================================================
+ * PPP interrupt service routine.
+ */
+
+STATIC void wpp_isr(sdla_t * card)
+{
+	ppp_flags_t *flags = card->flags;
+	char *ptr = &flags->iflag;
+	unsigned long host_cpu_flags;
+	struct net_device *dev = card->wandev.dev;
+	int i;
+	card->in_isr = 1;
+	++card->statistics.isr_entry;
+	if (test_and_set_bit(0, (void *) &card->wandev.critical)) {
+		++card->statistics.isr_already_critical;
+		printk(KERN_INFO "%s: Critical while in ISR!\n", card->devname);
+		card->in_isr = 0;
+		return;
+	}
+	/* For all interrupts set the critical flag to CRITICAL_IN_ISR. 
+	 * If the if_send routine is called with this flag set it will set 
+	 * the enable transmit flag to 1. (for a delayed interrupt) 
+	 */
+	card->wandev.critical = CRITICAL_IN_ISR;
+	card->buff_int_mode_unbusy = 0;
+	switch (flags->iflag) {
+	case 0x01:		/* receive interrupt */
+		++card->statistics.isr_rx;
+		rx_intr(card);
+		break;
+	case 0x02:		/* transmit interrupt */
+		++card->statistics.isr_tx;
+		flags->imask &= ~0x02;
+		dev->tbusy = 0;
+		card->buff_int_mode_unbusy = 1;
+		break;
+	case 0x08:
+		++Intr_test_counter;
+		++card->statistics.isr_intr_test;
+		break;
+	default:		/* unexpected interrupt */
+		++card->statistics.isr_spurious;
+		printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n",
+		       card->devname, flags->iflag);
+		printk(KERN_INFO "%s: ID Bytes = ", card->devname);
+		for (i = 0; i < 8; i++)
+			printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
+		printk(KERN_INFO "\n");
+	}
+	/* The critical flag is set to CRITICAL_INTR_HANDLED to let the
+	 * if_send call know that the interrupt is handled so that 
+	 * transmit interrupts are not enabled again.
+	 */
+	card->wandev.critical = CRITICAL_INTR_HANDLED;
+	/* If the enable transmit interrupt flag is set then enable transmit 
+	 * interrupt on the board. This only goes through if if_send is called 
+	 * and the critical flag is set due to an Interrupt. 
+	 */
+	if (card->wandev.enable_tx_int) {
+		flags->imask |= 0x02;
+		card->wandev.enable_tx_int = 0;
+		++card->statistics.isr_enable_tx_int;
+	}
+	save_flags(host_cpu_flags);
+	cli();
+	card->in_isr = 0;
+	flags->iflag = 0;
+	card->wandev.critical = 0;
+	restore_flags(host_cpu_flags);
+	if (card->buff_int_mode_unbusy)
+		mark_bh(NET_BH);
+}
+
+/*============================================================================
+ * Receive interrupt handler.
+ */
+
+static void rx_intr(sdla_t * card)
+{
+	ppp_buf_ctl_t *rxbuf = card->rxmb;
+	struct net_device *dev = card->wandev.dev;
+	ppp_private_area_t *ppp_priv_area;
+	struct sk_buff *skb;
+	unsigned len;
+	void *buf;
+	int i, err;
+	ppp_flags_t *flags = card->flags;
+	char *ptr = &flags->iflag;
+	int udp_type;
+	if (rxbuf->flag != 0x01) {
+		printk(KERN_INFO
+		       "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n",
+		       card->devname, (unsigned) rxbuf, rxbuf->flag);
+		printk(KERN_INFO "%s: ID Bytes = ", card->devname);
+		for (i = 0; i < 8; i++)
+			printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
+		printk(KERN_INFO "\n");
+		++card->statistics.rx_intr_corrupt_rx_bfr;
+		return;
+	}
+	if (dev && dev->start) {
+		len = rxbuf->length;
+		ppp_priv_area = dev->priv;
+		/* Allocate socket buffer */
+		skb = dev_alloc_skb(len);
+		if (skb != NULL) {
+			/* Copy data to the socket buffer */
+			if (card->hw.fwid == SFID_PPP502) {
+				unsigned addr = (rxbuf->buf.o_p[1] << 8) +
+				rxbuf->buf.o_p[0];
+				buf = skb_put(skb, len);
+				sdla_peek(&card->hw, addr, buf, len);
+			} else {
+				unsigned addr = rxbuf->buf.ptr;
+				if ((addr + len) > card->u.p.rx_top + 1) {
+					unsigned tmp = card->u.p.rx_top - addr
+					+ 1;
+					buf = skb_put(skb, tmp);
+					sdla_peek(&card->hw, addr, buf, tmp);
+					addr = card->u.p.rx_base;
+					len -= tmp;
+				}
+				buf = skb_put(skb, len);
+				sdla_peek(&card->hw, addr, buf, len);
+			}
+			/* Decapsulate packet */
+			switch (rxbuf->proto) {
+			case 0x00:
+				skb->protocol = htons(ETH_P_IP);
+				break;
+			case 0x01:
+				skb->protocol = htons(ETH_P_IPX);
+				break;
+			}
+			udp_type = udp_pkt_type(skb, card);
+			if (udp_type == UDP_DRVSTATS_TYPE) {
+				++ppp_priv_area->rx_intr_DRVSTATS_request;
+				process_udp_driver_call(
+					  UDP_PKT_FRM_NETWORK, card, skb,
+						     dev, ppp_priv_area);
+				dev_kfree_skb(skb);
+			} else if (udp_type == UDP_PTPIPE_TYPE) {
+				++ppp_priv_area->rx_intr_PTPIPE_request;
+				err = process_udp_mgmt_pkt(
+					       UDP_PKT_FRM_NETWORK, card,
+						skb, dev, ppp_priv_area);
+				dev_kfree_skb(skb);
+			} else if (handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) {
+				if (card->wandev.enable_IPX) {
+					ppp_send(card, skb->data, skb->len, ETH_P_IPX);
+					dev_kfree_skb(skb);
+				} else {
+					++card->wandev.stats.rx_dropped;
+				}
+			} else {
+				/* Pass it up the protocol stack */
+				skb->dev = dev;
+				skb->mac.raw = skb->data;
+				netif_rx(skb);
+				++card->wandev.stats.rx_packets;
+ 				card->wandev.stats.rx_bytes += skb->len;
+				++ppp_priv_area->rx_intr_bfr_passed_to_stack;
+			}
+		} else {
+			printk(KERN_INFO "%s: no socket buffers available!\n",
+			       card->devname);
+			++card->wandev.stats.rx_dropped;
+			++ppp_priv_area->rx_intr_no_socket;
+		}
+	} else
+		++card->statistics.rx_intr_dev_not_started;
+	/* Release buffer element and calculate a pointer to the next one */
+	rxbuf->flag = (card->hw.fwid == SFID_PPP502) ? 0xFF : 0x00;
+	card->rxmb = ++rxbuf;
+	if ((void *) rxbuf > card->u.p.rxbuf_last)
+		card->rxmb = card->u.p.rxbuf_base;
+}
+
+/*============================================================================
+ * Transmit interrupt handler.
+ */
+
+static void tx_intr(sdla_t * card)
+{
+	struct net_device *dev = card->wandev.dev;
+	if (!dev || !dev->start) {
+		++card->statistics.tx_intr_dev_not_started;
+		return;
+	}
+	dev->tbusy = 0;
+	mark_bh(NET_BH);
+}
+
+static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto)
+{
+	int i;
+	if (proto == htons(ETH_P_IPX)) {
+		/* It's an IPX packet */
+		if (!enable_IPX) {
+			/* Return 1 so we don't pass it up the stack. */
+			return 1;
+		}
+	} else {
+		/* It's not IPX so pass it up the stack. */
+		return 0;
+	}
+	if (sendpacket[16] == 0x90 &&
+	    sendpacket[17] == 0x04) {
+		/* It's IPXWAN */
+		if (sendpacket[2] == 0x02 &&
+		    sendpacket[34] == 0x00) {
+			/* It's a timer request packet */
+			printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", devname);
+			/* Go through the routing options and answer no to every */
+			/* option except Unnumbered RIP/SAP */
+			for (i = 41; sendpacket[i] == 0x00; i += 5) {
+				/* 0x02 is the option for Unnumbered RIP/SAP */
+				if (sendpacket[i + 4] != 0x02) {
+					sendpacket[i + 1] = 0;
+				}
+			}
+			/* Skip over the extended Node ID option */
+			if (sendpacket[i] == 0x04) {
+				i += 8;
+			}
+			/* We also want to turn off all header compression opt. */
+			for (; sendpacket[i] == 0x80;) {
+				sendpacket[i + 1] = 0;
+				i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4;
+			}
+			/* Set the packet type to timer response */
+			sendpacket[34] = 0x01;
+			printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", devname);
+		} else if (sendpacket[34] == 0x02) {
+			/* This is an information request packet */
+			printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n", devname);
+			/* Set the packet type to information response */
+			sendpacket[34] = 0x03;
+			/* Set the router name */
+			sendpacket[51] = 'P';
+			sendpacket[52] = 'T';
+			sendpacket[53] = 'P';
+			sendpacket[54] = 'I';
+			sendpacket[55] = 'P';
+			sendpacket[56] = 'E';
+			sendpacket[57] = '-';
+			sendpacket[58] = CVHexToAscii(network_number >> 28);
+			sendpacket[59] = CVHexToAscii((network_number & 0x0F000000) >> 24);
+			sendpacket[60] = CVHexToAscii((network_number & 0x00F00000) >> 20);
+			sendpacket[61] = CVHexToAscii((network_number & 0x000F0000) >> 16);
+			sendpacket[62] = CVHexToAscii((network_number & 0x0000F000) >> 12);
+			sendpacket[63] = CVHexToAscii((network_number & 0x00000F00) >> 8);
+			sendpacket[64] = CVHexToAscii((network_number & 0x000000F0) >> 4);
+			sendpacket[65] = CVHexToAscii(network_number & 0x0000000F);
+			for (i = 66; i < 99; i += 1)
+				sendpacket[i] = 0;
+			printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", devname);
+		} else {
+			printk(KERN_INFO "%s: Unknown IPXWAN packet!\n", devname);
+			return 0;
+		}
+		/* Set the WNodeID to our network address */
+		sendpacket[35] = (unsigned char) (network_number >> 24);
+		sendpacket[36] = (unsigned char) ((network_number & 0x00FF0000) >> 16);
+		sendpacket[37] = (unsigned char) ((network_number & 0x0000FF00) >> 8);
+		sendpacket[38] = (unsigned char) (network_number & 0x000000FF);
+		return 1;
+	} else {
+		/* If we get here's its an IPX-data packet, so it'll get passed up the stack. */
+		/* switch the network numbers */
+		switch_net_numbers(sendpacket, network_number, 1);
+		return 0;
+	}
+}
+
+/****** Background Polling Routines  ****************************************/
+
+/*============================================================================
+ * Main polling routine.
+ * This routine is repeatedly called by the WANPIPE 'thread' to allow for
+ * time-dependent housekeeping work.
+ *
+ * Notes:
+ * 1. This routine may be called on interrupt context with all interrupts
+ *    enabled. Beware!
+ */
+
+static void wpp_poll(sdla_t * card)
+{
+	struct net_device *dev = card->wandev.dev;
+	ppp_flags_t *adptr_flags = card->flags;
+	unsigned long host_cpu_flags;
+	++card->statistics.poll_entry;
+	/* The wpp_poll is called continously by the WANPIPE thread to allow
+	 * for line state housekeeping. However if we are in a connected state
+	 * then we do not need to go through all the checks everytime. When in
+	 * connected state execute wpp_poll once every second.
+	 */
+	if (card->wandev.state == WAN_CONNECTED) {
+		if ((jiffies - card->state_tick) < HZ)
+			return;
+	}
+	disable_irq(card->hw.irq);
+	++card->irq_dis_poll_count;
+	if (test_and_set_bit(0, (void *) &card->wandev.critical)) {
+		++card->statistics.poll_already_critical;
+		printk(KERN_INFO "%s: critical inside wpp_poll\n",
+		       card->devname);
+		save_flags(host_cpu_flags);
+		cli();
+		if ((!card->irq_dis_if_send_count) &&
+		    (!(--card->irq_dis_poll_count)))
+			enable_irq(card->hw.irq);
+		restore_flags(host_cpu_flags);
+		return;
+	}
+	++card->statistics.poll_processed;
+	if (dev && dev->tbusy && !(adptr_flags->imask & 0x02)) {
+		++card->statistics.poll_tbusy_bad_status;
+		printk(KERN_INFO "%s: Wpp_Poll: tbusy = 0x01, imask = 0x%02X\n"
+		       ,card->devname, adptr_flags->imask);
+	}
+	switch (card->wandev.state) {
+	case WAN_CONNECTED:
+		card->state_tick = jiffies;
+		poll_active(card);
+		break;
+	case WAN_CONNECTING:
+		poll_connecting(card);
+		break;
+	case WAN_DISCONNECTED:
+		poll_disconnected(card);
+		break;
+	default:
+		printk(KERN_INFO "%s: Unknown Poll State 0x%02X\n",
+		       card->devname, card->wandev.state);
+		break;
+	}
+	card->wandev.critical = 0;
+	save_flags(host_cpu_flags);
+	cli();
+	if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count)))
+		enable_irq(card->hw.irq);
+	restore_flags(host_cpu_flags);
+}
+
+/*============================================================================
+ * Monitor active link phase.
+ */
+
+static void poll_active(sdla_t * card)
+{
+	ppp_flags_t *flags = card->flags;
+	/* We check the lcp_state to see if we are in DISCONNECTED state.
+	 * We are considered to be connected for lcp states 0x06, 0x07, 0x08
+	 * and 0x09.
+	 */
+	if ((flags->lcp_state <= 0x05) || (flags->disc_cause & 0x03)) {
+		wanpipe_set_state(card, WAN_DISCONNECTED);
+		show_disc_cause(card, flags->disc_cause);
+	}
+}
+
+/*============================================================================
+ * Monitor link establishment phase.
+ * o if connection timed out, disconnect the link.
+ */
+
+static void poll_connecting(sdla_t * card)
+{
+	ppp_flags_t *flags = card->flags;
+	if (flags->lcp_state == 0x09) {
+		wanpipe_set_state(card, WAN_CONNECTED);
+	} else if (flags->disc_cause & 0x03) {
+		wanpipe_set_state(card, WAN_DISCONNECTED);
+		show_disc_cause(card, flags->disc_cause);
+	}
+}
+
+/*============================================================================
+ * Monitor physical link disconnected phase.
+ *  o if interface is up and the hold-down timeout has expired, then retry
+ *    connection.
+ */
+
+static void poll_disconnected(sdla_t * card)
+{
+	struct net_device *dev = card->wandev.dev;
+	if (dev && dev->start &&
+	    ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) {
+		wanpipe_set_state(card, WAN_CONNECTING);
+		if (ppp_comm_enable(card) == CMD_OK)
+			init_ppp_tx_rx_buff(card);
+	}
+}
+
+/****** Miscellaneous Functions *********************************************/
+
+/*============================================================================
+ * Configure S502 adapter.
+ */
+
+static int config502(sdla_t * card)
+{
+	ppp502_conf_t cfg;
+	/* Prepare PPP configuration structure */
+	memset(&cfg, 0, sizeof(ppp502_conf_t));
+	if (card->wandev.clocking)
+		cfg.line_speed = bps_to_speed_code(card->wandev.bps);
+	cfg.txbuf_num = 4;
+	cfg.mtu_local = card->wandev.mtu;
+	cfg.mtu_remote = card->wandev.mtu;
+	cfg.restart_tmr = 30;
+	cfg.auth_rsrt_tmr = 30;
+	cfg.auth_wait_tmr = 300;
+	cfg.mdm_fail_tmr = 5;
+	cfg.dtr_drop_tmr = 1;
+	cfg.connect_tmout = 0;	/* changed it from 900 */
+	cfg.conf_retry = 10;
+	cfg.term_retry = 2;
+	cfg.fail_retry = 5;
+	cfg.auth_retry = 10;
+	cfg.ip_options = 0x80;
+	cfg.ipx_options = 0xA0;
+	cfg.conf_flags |= 0x0E;
+/*
+   cfg.ip_local         = dev->pa_addr;
+   cfg.ip_remote                = dev->pa_dstaddr;
+ */
+	return ppp_configure(card, &cfg);
+}
+
+/*============================================================================
+ * Configure S508 adapter.
+ */
+
+static int config508(sdla_t * card)
+{
+	ppp508_conf_t cfg;
+	/* Prepare PPP configuration structure */
+	memset(&cfg, 0, sizeof(ppp508_conf_t));
+	if (card->wandev.clocking)
+		cfg.line_speed = card->wandev.bps;
+	if (card->wandev.interface == WANOPT_RS232)
+		cfg.conf_flags |= 0x0020;
+	cfg.conf_flags |= 0x300;	/*send Configure-Request packets forever */
+	cfg.txbuf_percent = 60;	/* % of Tx bufs */
+	cfg.mtu_local = card->wandev.mtu;
+	cfg.mtu_remote = card->wandev.mtu;
+	cfg.restart_tmr = 30;
+	cfg.auth_rsrt_tmr = 30;
+	cfg.auth_wait_tmr = 300;
+	cfg.mdm_fail_tmr = 100;
+	cfg.dtr_drop_tmr = 1;
+	cfg.connect_tmout = 0;	/* changed it from 900 */
+	cfg.conf_retry = 10;
+	cfg.term_retry = 2;
+	cfg.fail_retry = 5;
+	cfg.auth_retry = 10;
+	cfg.ip_options = 0x80;
+	cfg.ipx_options = 0xA0;
+/*
+   cfg.ip_local         = dev->pa_addr;
+   cfg.ip_remote                = dev->pa_dstaddr;
+ */
+	return ppp_configure(card, &cfg);
+}
+
+/*============================================================================
+ * Show disconnection cause.
+ */
+
+static void show_disc_cause(sdla_t * card, unsigned cause)
+{
+	if (cause & 0x0002)
+		printk(KERN_INFO "%s: link terminated by peer\n",
+		       card->devname);
+	else if (cause & 0x0004)
+		printk(KERN_INFO "%s: link terminated by user\n",
+		       card->devname);
+	else if (cause & 0x0008)
+		printk(KERN_INFO "%s: authentication failed\n", card->devname);
+	else if (cause & 0x0010)
+		printk(KERN_INFO
+		       "%s: authentication protocol negotiation failed\n",
+		       card->devname);
+	else if (cause & 0x0020)
+		printk(KERN_INFO
+		       "%s: peer's request for authentication rejected\n",
+		       card->devname);
+	else if (cause & 0x0040)
+		printk(KERN_INFO "%s: MRU option rejected by peer\n",
+		       card->devname);
+	else if (cause & 0x0080)
+		printk(KERN_INFO "%s: peer's MRU was too small\n",
+		       card->devname);
+	else if (cause & 0x0100)
+		printk(KERN_INFO "%s: failed to negotiate peer's LCP options\n",
+		       card->devname);
+	else if (cause & 0x0200)
+		printk(KERN_INFO "%s: failed to negotiate peer's IPCP options\n"
+		       ,card->devname);
+	else if (cause & 0x0400)
+		printk(KERN_INFO
+		       "%s: failed to negotiate peer's IPXCP options\n",
+		       card->devname);
+}
+
+/*============================================================================
+ * Convert line speed in bps to a number used by S502 code.
+ */
+
+static unsigned char bps_to_speed_code(unsigned long bps)
+{
+	unsigned char number;
+	if (bps <= 1200)
+		number = 0x01;
+	else if (bps <= 2400)
+		number = 0x02;
+	else if (bps <= 4800)
+		number = 0x03;
+	else if (bps <= 9600)
+		number = 0x04;
+	else if (bps <= 19200)
+		number = 0x05;
+	else if (bps <= 38400)
+		number = 0x06;
+	else if (bps <= 45000)
+		number = 0x07;
+	else if (bps <= 56000)
+		number = 0x08;
+	else if (bps <= 64000)
+		number = 0x09;
+	else if (bps <= 74000)
+		number = 0x0A;
+	else if (bps <= 112000)
+		number = 0x0B;
+	else if (bps <= 128000)
+		number = 0x0C;
+	else
+		number = 0x0D;
+	return number;
+}
+
+/*============================================================================
+ * Process UDP call of type DRVSTATS.  
+ */
+
+static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, ppp_private_area_t * ppp_priv_area)
+{
+	unsigned char *sendpacket;
+	unsigned char buf2[5];
+	unsigned char *data;
+	unsigned char *buf;
+	unsigned int len;
+	ppp_mbox_t *mbox = card->mbox;
+	struct sk_buff *new_skb;
+	int err;
+	sendpacket = skb->data;
+	memcpy(&buf2, &card->wandev.udp_port, 2);
+	if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) {
+		printk(KERN_INFO
+		       "%s: Error allocating memory for UDP DRIVER STATS cmnd0x%02X"
+		       ,card->devname, data[45]);
+		++ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err;
+		return 1;
+	}
+	memcpy(data, sendpacket, skb->len);
+	switch (data[45]) {
+		/* PPIPE_DRIVER_STATISTICS */
+	case 0x26:
+		*(unsigned long *) &data[60] =
+		    ppp_priv_area->if_send_entry;
+		*(unsigned long *) &data[64] =
+		    ppp_priv_area->if_send_skb_null;
+		*(unsigned long *) &data[68] =
+		    ppp_priv_area->if_send_broadcast;
+		*(unsigned long *) &data[72] =
+		    ppp_priv_area->if_send_multicast;
+		*(unsigned long *) &data[76] =
+		    ppp_priv_area->if_send_critical_ISR;
+		*(unsigned long *) &data[80] =
+		    ppp_priv_area->if_send_critical_non_ISR;
+		*(unsigned long *) &data[84] =
+		    ppp_priv_area->if_send_busy;
+		*(unsigned long *) &data[88] =
+		    ppp_priv_area->if_send_busy_timeout;
+		*(unsigned long *) &data[92] =
+		    ppp_priv_area->if_send_DRVSTATS_request;
+		*(unsigned long *) &data[96] =
+		    ppp_priv_area->if_send_PTPIPE_request;
+		*(unsigned long *) &data[100] =
+		    ppp_priv_area->if_send_wan_disconnected;
+		*(unsigned long *) &data[104] =
+		    ppp_priv_area->if_send_adptr_bfrs_full;
+		*(unsigned long *) &data[108] =
+		    ppp_priv_area->if_send_protocol_error;
+		*(unsigned long *) &data[112] =
+		    ppp_priv_area->if_send_tx_int_enabled;
+		*(unsigned long *) &data[116] =
+		    ppp_priv_area->if_send_bfr_passed_to_adptr;
+		*(unsigned long *) &data[118] =
+		    card->irq_dis_if_send_count;
+		mbox->cmd.length = 62;
+		break;
+	case 0x27:
+		*(unsigned long *) &data[60] = card->statistics.isr_entry;
+		*(unsigned long *) &data[64] =
+		    card->statistics.isr_already_critical;
+		*(unsigned long *) &data[68] = card->statistics.isr_rx;
+		*(unsigned long *) &data[72] = card->statistics.isr_tx;
+		*(unsigned long *) &data[76] =
+		    card->statistics.isr_intr_test;
+		*(unsigned long *) &data[80] =
+		    card->statistics.isr_spurious;
+		*(unsigned long *) &data[84] =
+		    card->statistics.isr_enable_tx_int;
+		*(unsigned long *) &data[88] =
+		    card->statistics.rx_intr_corrupt_rx_bfr;
+		*(unsigned long *) &data[92] =
+		    ppp_priv_area->rx_intr_no_socket;
+		*(unsigned long *) &data[96] =
+		    ppp_priv_area->rx_intr_DRVSTATS_request;
+		*(unsigned long *) &data[100] =
+		    ppp_priv_area->rx_intr_PTPIPE_request;
+		*(unsigned long *) &data[104] =
+		    ppp_priv_area->rx_intr_bfr_passed_to_stack;
+		*(unsigned long *) &data[108] =
+		    card->statistics.rx_intr_dev_not_started;
+		*(unsigned long *) &data[112] =
+		    card->statistics.tx_intr_dev_not_started;
+		mbox->cmd.length = 56;
+		break;
+	case 0x28:
+		*(unsigned long *) &data[60] =
+		    ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err;
+		*(unsigned long *) &data[64] =
+		    ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err;
+		*(unsigned long *) &data[68] =
+		    ppp_priv_area->UDP_PTPIPE_mgmt_direction_err;
+		*(unsigned long *) &data[72] =
+		    ppp_priv_area->
+		    UDP_PTPIPE_mgmt_adptr_cmnd_timeout;
+		*(unsigned long *) &data[76] =
+		    ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK;
+		*(unsigned long *) &data[80] =
+		    ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr;
+		*(unsigned long *) &data[84] =
+		    ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack;
+		*(unsigned long *) &data[88] =
+		    ppp_priv_area->UDP_PTPIPE_mgmt_no_socket;
+		*(unsigned long *) &data[92] =
+		    ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err;
+		*(unsigned long *) &data[96] =
+		    ppp_priv_area->
+		    UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
+		*(unsigned long *) &data[100] =
+		    ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
+		*(unsigned long *) &data[104] =
+		    ppp_priv_area->
+		    UDP_DRVSTATS_mgmt_passed_to_adptr;
+		*(unsigned long *) &data[108] =
+		    ppp_priv_area->
+		    UDP_DRVSTATS_mgmt_passed_to_stack;
+		*(unsigned long *) &data[112] =
+		    ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket;
+		*(unsigned long *) &data[116] =
+		    card->statistics.poll_entry;
+		*(unsigned long *) &data[120] =
+		    card->statistics.poll_already_critical;
+		*(unsigned long *) &data[124] =
+		    card->statistics.poll_processed;
+		*(unsigned long *) &data[126] =
+		    card->irq_dis_poll_count;
+		mbox->cmd.length = 70;
+		break;
+	default:
+		/* it's a board command */
+		memcpy(&mbox->cmd, &sendpacket[45], sizeof(ppp_cmd_t));
+		if (mbox->cmd.length) {
+			memcpy(&mbox->data, &sendpacket[60],
+			       mbox->cmd.length);
+		}
+		/* run the command on the board */
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+		if (err != CMD_OK) {
+			ppp_error(card, err, mbox);
+			++ppp_priv_area->
+			    UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
+			break;
+		}
+		++ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
+		/* copy the result back to our buffer */
+		memcpy(data, sendpacket, skb->len);
+		memcpy(&data[45], &mbox->cmd, sizeof(ppp_cmd_t));
+		if (mbox->cmd.length) {
+			memcpy(&data[60], &mbox->data, mbox->cmd.length);
+		}
+	}
+	/* Fill UDP TTL */
+	data[8] = card->wandev.ttl;
+	len = reply_udp(data, mbox->cmd.length);
+	if (udp_pkt_src == UDP_PKT_FRM_NETWORK) {
+		++ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_adptr;
+		ppp_send(card, data, len, skb->protocol);
+	} else {
+		/* Pass it up the stack
+		   Allocate socket buffer */
+		if ((new_skb = dev_alloc_skb(len)) != NULL) {
+			/* copy data into new_skb */
+			buf = skb_put(new_skb, len);
+			memcpy(buf, data, len);
+			++ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack;
+			/* Decapsulate packet and pass it up the protocol 
+			   stack */
+			new_skb->protocol = htons(ETH_P_IP);
+			new_skb->dev = dev;
+			new_skb->mac.raw = new_skb->data;
+			netif_rx(new_skb);
+		} else {
+			++ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket;
+			printk(KERN_INFO "no socket buffers available!\n");
+		}
+	}
+	kfree(data);
+	return 0;
+}
+
+/*=============================================================================
+ * Process UDP call of type PTPIPEAB.
+ */
+
+static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card,
+				struct sk_buff *skb, struct net_device *dev,
+				ppp_private_area_t * ppp_priv_area)
+{
+	unsigned char *sendpacket;
+	unsigned char buf2[5];
+	unsigned char *data;
+	unsigned char *buf;
+	unsigned int frames, len;
+	struct sk_buff *new_skb;
+	unsigned short buffer_length, real_len;
+	unsigned long data_ptr;
+	int udp_mgmt_req_valid = 1;
+	ppp_mbox_t *mbox = card->mbox;
+	struct timeval tv;
+	int err;
+	sendpacket = skb->data;
+	memcpy(&buf2, &card->wandev.udp_port, 2);
+	if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) {
+		printk(KERN_INFO
+		       "%s: Error allocating memory for UDP management cmnd0x%02X"
+		       ,card->devname, data[45]);
+		++ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err;
+		return 1;
+	}
+	memcpy(data, sendpacket, skb->len);
+	switch (data[45]) {
+		/* FT1 MONITOR STATUS */
+	case 0x80:
+		if (card->hw.fwid != SFID_PPP508) {
+			++ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err;
+			udp_mgmt_req_valid = 0;
+			break;
+		}
+		/* PPIPE_ENABLE_TRACING */
+	case 0x20:
+		/* PPIPE_DISABLE_TRACING */
+	case 0x21:
+		/* PPIPE_GET_TRACE_INFO */
+	case 0x22:
+		/* SET FT1 MODE */
+	case 0x81:
+		if (udp_pkt_src == UDP_PKT_FRM_NETWORK) {
+			++ppp_priv_area->UDP_PTPIPE_mgmt_direction_err;
+			udp_mgmt_req_valid = 0;
+		}
+		break;
+	default:
+		break;
+	}
+	if (!udp_mgmt_req_valid) {
+		/* set length to 0 */
+		data[46] = data[47] = 0;
+		/* set return code */
+		data[48] = 0xCD;
+	} else {
+		switch (data[45]) {
+			/* PPIPE_ENABLE_TRACING */
+		case 0x20:
+			if (!TracingEnabled) {
+				/* OPERATE_DATALINE_MONITOR */
+				mbox->cmd.command = 0x33;
+				mbox->cmd.length = 1;
+				mbox->data[0] = 0x03;
+				err = sdla_exec(mbox) ?
+				    mbox->cmd.result : CMD_TIMEOUT;
+				if (err != CMD_OK) {
+					ppp_error(card, err, mbox);
+					TracingEnabled = 0;
+					/* set the return code */
+					data[48] = mbox->cmd.result;
+					mbox->cmd.length = 0;
+					break;
+				}
+				if (card->hw.fwid == SFID_PPP502) {
+					sdla_peek(&card->hw, 0x9000, &buf2, 2);
+				} else {
+					sdla_peek(&card->hw, 0xC000, &buf2, 2);
+				}
+				curr_trace_addr = 0;
+				memcpy(&curr_trace_addr, &buf2, 2);
+				start_trace_addr = curr_trace_addr;
+				/* MAX_SEND_BUFFER_SIZE -sizeof(UDP_MGMT_PACKET)
+				   - 41 */
+				available_buffer_space = 1926;
+			}
+			data[48] = 0;
+			mbox->cmd.length = 0;
+			TracingEnabled = 1;
+			break;
+			/* PPIPE_DISABLE_TRACING */
+		case 0x21:
+			if (TracingEnabled) {
+				/* OPERATE_DATALINE_MONITOR */
+				mbox->cmd.command = 0x3;
+				mbox->cmd.length = 1;
+				mbox->data[0] = 0x00;
+				err = sdla_exec(mbox) ?
+				    mbox->cmd.result : CMD_TIMEOUT;
+			}
+			/*set return code */
+			data[48] = 0;
+			mbox->cmd.length = 0;
+			TracingEnabled = 0;
+			break;
+			/* PPIPE_GET_TRACE_INFO */
+		case 0x22:
+			if (TracingEnabled) {
+				buffer_length = 0;
+				/* frames < NUM_TRACE_FRAMES */
+				for (frames = 0; frames < 62; frames += 1) {
+					sdla_peek(&card->hw, curr_trace_addr,
+						  &buf2, 1);
+					/* no data on board so exit */
+					if (buf2[0] == 0x00)
+						break;
+					/*1+sizeof(FRAME_DATA) = 9 */
+					if ((available_buffer_space -
+					     buffer_length) < 9) {
+						/*indicate we have more frames 
+						   on board and exit */
+						data[60] |= 0x02;
+						break;
+					}
+					/* get frame status */
+					sdla_peek(&card->hw, curr_trace_addr +
+						  0x01, &data[60 + buffer_length], 1);
+					/* get time stamp */
+					sdla_peek(&card->hw, curr_trace_addr +
+						  0x06, &data[64 + buffer_length], 2);
+					/* get frame length */
+					sdla_peek(&card->hw, curr_trace_addr +
+						  0x02, &data[62 + buffer_length], 2);
+					/* get pointer to real data */
+					sdla_peek(&card->hw, curr_trace_addr +
+						  0x04, &buf2, 2);
+					data_ptr = 0;
+					memcpy(&data_ptr, &buf2, 2);
+					/* see if we can fit the frame into the 
+					   user buffer */
+					memcpy(&real_len,
+					   &data[62 + buffer_length], 2);
+					if ((data_ptr == 0) ||
+					    ((real_len + 8) >
+					     available_buffer_space)) {
+						data[61 + buffer_length] = 0x00;
+					} else {
+						/* we can take it next time */
+						if ((available_buffer_space -
+						     buffer_length) <
+						    (real_len + 8)) {
+							data[60] |= 0x02;
+							break;
+						}
+						/* ok, get the frame */
+						data[61 + buffer_length] = 0x01;
+						/* get the data */
+						sdla_peek(&card->hw, data_ptr,
+						&data[66 + buffer_length],
+							  real_len);
+						/* zero the opp flag to 
+						   show we got the frame */
+						buf2[0] = 0x00;
+						sdla_poke(&card->hw,
+							  curr_trace_addr, &buf2, 1);
+						/* now move onto the next 
+						   frame */
+						curr_trace_addr += 8;
+						/* check if we passed the last 
+						   address */
+						if (curr_trace_addr >=
+						    start_trace_addr + 0x1F0) {
+							curr_trace_addr =
+							    start_trace_addr;
+						}
+						/* update buffer length and make                                                   sure its even */
+						if (data[61 + buffer_length]
+						    == 0x01) {
+							buffer_length +=
+							    real_len - 1;
+						}
+						/* for the header */
+						buffer_length += 8;
+						if (buffer_length & 0x0001)
+							buffer_length += 1;
+					}
+				}
+				/* ok now set the total number of frames passed
+				   in the high 5 bits */
+				data[60] = (frames << 2) | data[60];
+				/* set the data length */
+				mbox->cmd.length = buffer_length;
+				memcpy(&data[46], &buffer_length, 2);
+				/* set return code */
+				data[48] = 0;
+			} else {
+				/* set return code */
+				data[48] = 1;
+				mbox->cmd.length = 0;
+			}
+			break;
+			/* PPIPE_GET_IBA_DATA */
+		case 0x23:
+			mbox->cmd.length = 0x09;
+			if (card->hw.fwid == SFID_PPP502) {
+				sdla_peek(&card->hw, 0xA003, &data[60],
+					  mbox->cmd.length);
+			} else {
+				sdla_peek(&card->hw, 0xF003, &data[60],
+					  mbox->cmd.length);
+			}
+			/* set the length of the data */
+			data[46] = 0x09;
+			/* set return code */
+			data[48] = 0x00;
+			break;
+			/* PPIPE_KILL_BOARD */
+		case 0x24:
+			break;
+			/* PPIPE_FT1_READ_STATUS */
+		case 0x25:
+			sdla_peek(&card->hw, 0xF020, &data[60], 2);
+			data[46] = 2;
+			data[47] = 0;
+			data[48] = 0;
+			mbox->cmd.length = 2;
+			break;
+		case 0x29:
+			init_ppp_priv_struct(ppp_priv_area);
+			init_global_statistics(card);
+			mbox->cmd.length = 0;
+			break;
+		case 0x30:
+			do_gettimeofday(&tv);
+			ppp_priv_area->router_up_time = tv.tv_sec -
+			    ppp_priv_area->router_start_time;
+			*(unsigned long *) &data[60] =
+			    ppp_priv_area->router_up_time;
+			mbox->cmd.length = 4;
+			break;
+			/* FT1 MONITOR STATUS */
+		case 0x80:
+			/* Enable FT1 MONITOR STATUS */
+			if (data[60] == 1) {
+				if (rCount++ != 0) {
+					data[48] = 0;
+					mbox->cmd.length = 1;
+					break;
+				}
+			}
+			/* Disable FT1 MONITOR STATUS */
+			if (data[60] == 0) {
+				if (--rCount != 0) {
+					data[48] = 0;
+					mbox->cmd.length = 1;
+					break;
+				}
+			}
+		default:
+			/* it's a board command */
+			memcpy(&mbox->cmd, &sendpacket[45], sizeof(ppp_cmd_t));
+			if (mbox->cmd.length) {
+				memcpy(&mbox->data, &sendpacket[60],
+				       mbox->cmd.length);
+			}
+			/* run the command on the board */
+			err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+			if (err != CMD_OK) {
+				ppp_error(card, err, mbox);
+				++ppp_priv_area->
+				    UDP_PTPIPE_mgmt_adptr_cmnd_timeout;
+				break;
+			}
+			++ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK;
+			/* copy the result back to our buffer */
+			memcpy(data, sendpacket, skb->len);
+			memcpy(&data[45], &mbox->cmd, sizeof(ppp_cmd_t));
+			if (mbox->cmd.length) {
+				memcpy(&data[60], &mbox->data, mbox->cmd.length);
+			}
+		}		/* end of switch */
+	}			/* end of else */
+	/* Fill UDP TTL */
+	data[8] = card->wandev.ttl;
+	len = reply_udp(data, mbox->cmd.length);
+	if (udp_pkt_src == UDP_PKT_FRM_NETWORK) {
+		++ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr;
+		ppp_send(card, data, len, skb->protocol);
+	} else {
+		/* Pass it up the stack
+		   Allocate socket buffer */
+		if ((new_skb = dev_alloc_skb(len)) != NULL) {
+			/* copy data into new_skb */
+			buf = skb_put(new_skb, len);
+			memcpy(buf, data, len);
+			++ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack;
+			/* Decapsulate packet and pass it up the protocol 
+			   stack */
+			new_skb->protocol = htons(ETH_P_IP);
+			new_skb->dev = dev;
+			new_skb->mac.raw = new_skb->data;
+			netif_rx(new_skb);
+		} else {
+			++ppp_priv_area->UDP_PTPIPE_mgmt_no_socket;
+			printk(KERN_INFO "no socket buffers available!\n");
+		}
+	}
+	kfree(data);
+	return 0;
+}
+
+/*=============================================================================
+ * Initial the ppp_private_area structure.
+ */
+
+static void init_ppp_priv_struct(ppp_private_area_t * ppp_priv_area)
+{
+	ppp_priv_area->if_send_entry = 0;
+	ppp_priv_area->if_send_skb_null = 0;
+	ppp_priv_area->if_send_broadcast = 0;
+	ppp_priv_area->if_send_multicast = 0;
+	ppp_priv_area->if_send_critical_ISR = 0;
+	ppp_priv_area->if_send_critical_non_ISR = 0;
+	ppp_priv_area->if_send_busy = 0;
+	ppp_priv_area->if_send_busy_timeout = 0;
+	ppp_priv_area->if_send_DRVSTATS_request = 0;
+	ppp_priv_area->if_send_PTPIPE_request = 0;
+	ppp_priv_area->if_send_wan_disconnected = 0;
+	ppp_priv_area->if_send_adptr_bfrs_full = 0;
+	ppp_priv_area->if_send_bfr_passed_to_adptr = 0;
+	ppp_priv_area->rx_intr_no_socket = 0;
+	ppp_priv_area->rx_intr_DRVSTATS_request = 0;
+	ppp_priv_area->rx_intr_PTPIPE_request = 0;
+	ppp_priv_area->rx_intr_bfr_not_passed_to_stack = 0;
+	ppp_priv_area->rx_intr_bfr_passed_to_stack = 0;
+	ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err = 0;
+	ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err = 0;
+	ppp_priv_area->UDP_PTPIPE_mgmt_direction_err = 0;
+	ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_timeout = 0;
+	ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK = 0;
+	ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr = 0;
+	ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack = 0;
+	ppp_priv_area->UDP_PTPIPE_mgmt_no_socket = 0;
+	ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err = 0;
+	ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_type_err = 0;
+	ppp_priv_area->UDP_DRVSTATS_mgmt_direction_err = 0;
+	ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout = 0;
+	ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK = 0;
+	ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_adptr = 0;
+	ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack = 0;
+	ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket = 0;
+}
+
+/*============================================================================
+ * Initialize Global Statistics
+ */
+
+static void init_global_statistics(sdla_t * card)
+{
+	card->statistics.isr_entry = 0;
+	card->statistics.isr_already_critical = 0;
+	card->statistics.isr_tx = 0;
+	card->statistics.isr_rx = 0;
+	card->statistics.isr_intr_test = 0;
+	card->statistics.isr_spurious = 0;
+	card->statistics.isr_enable_tx_int = 0;
+	card->statistics.rx_intr_corrupt_rx_bfr = 0;
+	card->statistics.rx_intr_dev_not_started = 0;
+	card->statistics.tx_intr_dev_not_started = 0;
+	card->statistics.poll_entry = 0;
+	card->statistics.poll_already_critical = 0;
+	card->statistics.poll_processed = 0;
+	card->statistics.poll_tbusy_bad_status = 0;
+}
+
+/*============================================================================
+ * Initialize Receive and Transmit Buffers.
+ */
+
+static void init_ppp_tx_rx_buff(sdla_t * card)
+{
+	if (card->hw.fwid == SFID_PPP502) {
+		ppp502_buf_info_t *info =
+		(void *) (card->hw.dpmbase + PPP502_BUF_OFFS);
+		card->u.p.txbuf_base =
+		    (void *) (card->hw.dpmbase + info->txb_offs);
+		card->u.p.txbuf_last = (ppp_buf_ctl_t *) card->u.p.txbuf_base +
+		    (info->txb_num - 1);
+		card->u.p.rxbuf_base =
+		    (void *) (card->hw.dpmbase + info->rxb_offs);
+		card->u.p.rxbuf_last = (ppp_buf_ctl_t *) card->u.p.rxbuf_base +
+		    (info->rxb_num - 1);
+	} else {
+		ppp508_buf_info_t *info =
+		(void *) (card->hw.dpmbase + PPP508_BUF_OFFS);
+		card->u.p.txbuf_base = (void *) (card->hw.dpmbase +
+				       (info->txb_ptr - PPP508_MB_VECT));
+		card->u.p.txbuf_last = (ppp_buf_ctl_t *) card->u.p.txbuf_base +
+		    (info->txb_num - 1);
+		card->u.p.rxbuf_base = (void *) (card->hw.dpmbase +
+				       (info->rxb_ptr - PPP508_MB_VECT));
+		card->u.p.rxbuf_last = (ppp_buf_ctl_t *) card->u.p.rxbuf_base +
+		    (info->rxb_num - 1);
+		card->u.p.rx_base = info->rxb_base;
+		card->u.p.rx_top = info->rxb_end;
+	}
+	card->u.p.txbuf = card->u.p.txbuf_base;
+	card->rxmb = card->u.p.rxbuf_base;
+}
+
+/*=============================================================================
+ * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR
+ * _TEST_COUNTER times.
+ */
+
+static int intr_test(sdla_t * card)
+{
+	ppp_mbox_t *mb = card->mbox;
+	int err, i;
+	/* The critical flag is unset because during initialization (if_open) 
+	 * we want the interrupts to be enabled so that when the wpp_isr is
+	 * called it does not exit due to critical flag set.
+	 */
+	card->wandev.critical = 0;
+	err = ppp_set_intr_mode(card, 0x08);
+	if (err == CMD_OK) {
+		for (i = 0; i < MAX_INTR_TEST_COUNTER; i++) {
+			/* Run command READ_CODE_VERSION */
+			memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+			mb->cmd.length = 0;
+			mb->cmd.command = 0x10;
+			err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+			if (err != CMD_OK)
+				ppp_error(card, err, mb);
+		}
+	} else
+		return err;
+	err = ppp_set_intr_mode(card, 0);
+	if (err != CMD_OK)
+		return err;
+	card->wandev.critical = 1;
+	return 0;
+}
+
+/*==============================================================================
+ * Determine what type of UDP call it is. DRVSTATS or PTPIPEAB ?
+ */
+
+static int udp_pkt_type(struct sk_buff *skb, sdla_t * card)
+{
+	unsigned char *sendpacket;
+	unsigned char buf2[5];
+	sendpacket = skb->data;
+	memcpy(&buf2, &card->wandev.udp_port, 2);
+	if (sendpacket[0] == 0x45 &&	/* IP packet */
+	    sendpacket[9] == 0x11 &&	/* UDP packet */
+	    sendpacket[22] == buf2[1] &&	/* UDP Port */
+	    sendpacket[23] == buf2[0] &&
+	    sendpacket[36] == 0x01) {
+		if (sendpacket[28] == 0x50 &&	/* PTPIPEAB: Signature */
+		    sendpacket[29] == 0x54 &&
+		    sendpacket[30] == 0x50 &&
+		    sendpacket[31] == 0x49 &&
+		    sendpacket[32] == 0x50 &&
+		    sendpacket[33] == 0x45 &&
+		    sendpacket[34] == 0x41 &&
+		    sendpacket[35] == 0x42) {
+			return UDP_PTPIPE_TYPE;
+		} else if (sendpacket[28] == 0x44 &&	/* DRVSTATS: Signature */
+			   sendpacket[29] == 0x52 &&
+			   sendpacket[30] == 0x56 &&
+			   sendpacket[31] == 0x53 &&
+			   sendpacket[32] == 0x54 &&
+			   sendpacket[33] == 0x41 &&
+			   sendpacket[34] == 0x54 &&
+			   sendpacket[35] == 0x53) {
+			return UDP_DRVSTATS_TYPE;
+		} else
+			return UDP_INVALID_TYPE;
+	} else
+		return UDP_INVALID_TYPE;
+}
+
+/****** End *****************************************************************/
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/sdla_x25.c linux/drivers/net/wan/sdla_x25.c
--- v2.3.20/linux/drivers/net/wan/sdla_x25.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/sdla_x25.c	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,2435 @@
+/*****************************************************************************
+* sdla_x25.c	WANPIPE(tm) Multiprotocol WAN Link Driver.  X.25 module.
+*
+* Author:	Gene Kozin	<genek@compuserve.com>
+*
+* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
+*
+*		This program is free software; you can redistribute it and/or
+*		modify it under the terms of the GNU General Public License
+*		as published by the Free Software Foundation; either version
+*		2 of the License, or (at your option) any later version.
+* ============================================================================
+* Mar 15, 1998  Alan Cox	 o 2.1.x porting
+* Nov 27, 1997	Jaspreet Singh	 o Added protection against enabling of irqs
+*				   when they are disabled.
+* Nov 17, 1997  Farhan Thawar    o Added IPX support
+*				 o Changed if_send() to now buffer packets when
+*				   the board is busy
+*				 o Removed queueing of packets via the polling
+*				   routing
+*				 o Changed if_send() critical flags to properly
+*				   handle race conditions
+* Nov 06, 1997  Farhan Thawar    o Added support for SVC timeouts
+*				 o Changed PVC encapsulation to ETH_P_IP
+* Jul 21, 1997  Jaspreet Singh	 o Fixed freeing up of buffers using kfree()
+*				   when packets are received.
+* Mar 11, 1997  Farhan Thawar   Version 3.1.1
+*                                o added support for V35
+*                                o changed if_send() to return 0 if
+*                                  wandev.critical() is true
+*                                o free socket buffer in if_send() if
+*                                  returning 0
+*                                o added support for single '@' address to
+*                                  accept all incoming calls
+*                                o fixed bug in set_chan_state() to disconnect
+* Jan 15, 1997	Gene Kozin	Version 3.1.0
+*				 o implemented exec() entry point
+* Jan 07, 1997	Gene Kozin	Initial version.
+*****************************************************************************/
+
+
+#include <linux/kernel.h>	/* printk(), and other useful stuff */
+#include <linux/stddef.h>	/* offsetof(), etc. */
+#include <linux/errno.h>	/* return codes */
+#include <linux/string.h>	/* inline memset(), etc. */
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
+#include <linux/wanrouter.h>	/* WAN router definitions */
+#include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
+#include <asm/byteorder.h>	/* htons(), etc. */
+#include <asm/uaccess.h>
+
+#define	_GNUC_
+#include <linux/sdla_x25.h>	/* X.25 firmware API definitions */
+
+/****** Defines & Macros ****************************************************/
+
+#define	CMD_OK		0		/* normal firmware return code */
+#define	CMD_TIMEOUT	0xFF		/* firmware command timed out */
+#define	MAX_CMD_RETRY	10		/* max number of firmware retries */
+
+#define	X25_CHAN_MTU	4096		/* unfragmented logical channel MTU */
+#define	X25_HRDHDR_SZ	7		/* max encapsulation header size */
+#define	X25_CONCT_TMOUT	(90*HZ)		/* link connection timeout */
+#define	X25_RECON_TMOUT	(10*HZ)		/* link connection timeout */
+#define	CONNECT_TIMEOUT	(90*HZ)		/* link connection timeout */
+#define	HOLD_DOWN_TIME	(30*HZ)		/* link hold down time */
+
+/* For IPXWAN */
+#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b)))
+
+/****** Data Structures *****************************************************/
+
+/* This is an extention of the 'struct net_device' we create for each network
+ * interface to keep the rest of X.25 channel-specific data.
+ */
+typedef struct x25_channel
+{
+	char name[WAN_IFNAME_SZ+1];	/* interface name, ASCIIZ */
+	char addr[WAN_ADDRESS_SZ+1];	/* media address, ASCIIZ */
+	unsigned lcn;			/* logical channel number */
+	unsigned tx_pkt_size;
+	unsigned short protocol;	/* ethertype, 0 - multiplexed */
+	char svc;			/* 0 - permanent, 1 - switched */
+	char state;			/* channel state */
+	char drop_sequence;		/* mark sequence for dropping */
+	unsigned long state_tick;	/* time of the last state change */
+	unsigned idle_timeout;		/* sec, before disconnecting */
+	unsigned long i_timeout_sofar;  /* # of sec's we've been idle */
+	unsigned hold_timeout;		/* sec, before re-connecting */
+	unsigned long tick_counter;	/* counter for transmit time out */
+	char devtint;			/* Weather we should dev_tint() */
+	struct sk_buff* rx_skb;		/* receive socket buffer */
+	struct sk_buff* tx_skb;		/* transmit socket buffer */
+	sdla_t* card;			/* -> owner */
+	int ch_idx;
+	struct net_device_stats ifstats;	/* interface statistics */
+} x25_channel_t;
+
+typedef struct x25_call_info
+{
+	char dest[17];			/* ASCIIZ destination address */
+	char src[17];			/* ASCIIZ source address */
+	char nuser;			/* number of user data bytes */
+	unsigned char user[127];	/* user data */
+	char nfacil;			/* number of facilities */
+	struct
+	{
+		unsigned char code;
+		unsigned char parm;
+	} facil[64];			/* facilities */
+} x25_call_info_t;
+
+/****** Function Prototypes *************************************************/
+
+/* WAN link driver entry points. These are called by the WAN router module. */
+static int update (wan_device_t* wandev);
+static int new_if (wan_device_t* wandev, struct net_device* dev,
+	wanif_conf_t* conf);
+static int del_if (wan_device_t* wandev, struct net_device* dev);
+
+/* WANPIPE-specific entry points */
+static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data);
+
+/* Network device interface */
+static int if_init   (struct net_device* dev);
+static int if_open   (struct net_device* dev);
+static int if_close  (struct net_device* dev);
+static int if_header (struct sk_buff* skb, struct net_device* dev,
+	unsigned short type, void* daddr, void* saddr, unsigned len);
+static int if_rebuild_hdr (struct sk_buff* skb);
+static int if_send (struct sk_buff* skb, struct net_device* dev);
+static struct net_device_stats * if_stats (struct net_device* dev);
+
+/* Interrupt handlers */
+static void wpx_isr	(sdla_t* card);
+static void rx_intr	(sdla_t* card);
+static void tx_intr	(sdla_t* card);
+static void status_intr	(sdla_t* card);
+static void event_intr	(sdla_t* card);
+static void spur_intr	(sdla_t* card);
+
+/* Background polling routines */
+static void wpx_poll (sdla_t* card);
+static void poll_disconnected (sdla_t* card);
+static void poll_connecting (sdla_t* card);
+static void poll_active (sdla_t* card);
+
+/* X.25 firmware interface functions */
+static int x25_get_version (sdla_t* card, char* str);
+static int x25_configure (sdla_t* card, TX25Config* conf);
+static int x25_get_err_stats (sdla_t* card);
+static int x25_get_stats (sdla_t* card);
+static int x25_set_intr_mode (sdla_t* card, int mode);
+static int x25_close_hdlc (sdla_t* card);
+static int x25_open_hdlc (sdla_t* card);
+static int x25_setup_hdlc (sdla_t* card);
+static int x25_set_dtr (sdla_t* card, int dtr);
+static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan);
+static int x25_place_call (sdla_t* card, x25_channel_t* chan);
+static int x25_accept_call (sdla_t* card, int lcn, int qdm);
+static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn);
+static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf);
+static int x25_fetch_events (sdla_t* card);
+static int x25_error (sdla_t* card, int err, int cmd, int lcn);
+
+/* X.25 asynchronous event handlers */
+static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
+static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
+static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
+static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
+static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
+
+/* Miscellaneous functions */
+static int connect (sdla_t* card);
+static int disconnect (sdla_t* card);
+static struct net_device* get_dev_by_lcn(wan_device_t* wandev, unsigned lcn);
+static int chan_connect (struct net_device* dev);
+static int chan_disc (struct net_device* dev);
+static void set_chan_state (struct net_device* dev, int state);
+static int chan_send (struct net_device* dev, struct sk_buff* skb);
+static unsigned char bps_to_speed_code (unsigned long bps);
+static unsigned int dec_to_uint (unsigned char* str, int len);
+static unsigned int hex_to_uint (unsigned char* str, int len);
+static void parse_call_info (unsigned char* str, x25_call_info_t* info);
+
+/* IPX functions */
+static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming);
+static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto);
+
+extern void disable_irq(unsigned int);
+extern void enable_irq(unsigned int);
+
+/****** Global Data **********************************************************
+ * Note: All data must be explicitly initialized!!!
+ */
+
+/****** Public Functions ****************************************************/
+
+/*============================================================================
+ * X.25 Protocol Initialization routine.
+ *
+ * This routine is called by the main WANPIPE module during setup.  At this
+ * point adapter is completely initialized and X.25 firmware is running.
+ *  o read firmware version (to make sure it's alive)
+ *  o configure adapter
+ *  o initialize protocol-specific fields of the adapter data space.
+ *
+ * Return:	0	o.k.
+ *		< 0	failure.
+ */
+int wpx_init (sdla_t* card, wandev_conf_t* conf)
+{
+	union
+	{
+		char str[80];
+		TX25Config cfg;
+	} u;
+
+	/* Verify configuration ID */
+	if (conf->config_id != WANCONFIG_X25)
+	{
+		printk(KERN_INFO "%s: invalid configuration ID %u!\n",
+			card->devname, conf->config_id)
+		;
+		return -EINVAL;
+	}
+
+	/* Initialize protocol-specific fields */
+	card->mbox  = (void*)(card->hw.dpmbase + X25_MBOX_OFFS);
+	card->rxmb  = (void*)(card->hw.dpmbase + X25_RXMBOX_OFFS);
+	card->flags = (void*)(card->hw.dpmbase + X25_STATUS_OFFS);
+
+	/* Read firmware version.  Note that when adapter initializes, it
+	 * clears the mailbox, so it may appear that the first command was
+	 * executed successfully when in fact it was merely erased. To work
+	 * around this, we execute the first command twice.
+	 */
+	if (x25_get_version(card, NULL) || x25_get_version(card, u.str))
+		return -EIO
+	;
+	printk(KERN_INFO "%s: running X.25 firmware v%s\n",
+		card->devname, u.str)
+	;
+
+	/* Configure adapter. Here we set resonable defaults, then parse
+	 * device configuration structure and set configuration options.
+	 * Most configuration options are verified and corrected (if
+	 * necessary) since we can't rely on the adapter to do so and don't
+	 * want it to fail either.
+	 */
+	memset(&u.cfg, 0, sizeof(u.cfg));
+	u.cfg.t1		= 3;
+	u.cfg.n2		= 10;
+	u.cfg.autoHdlc		= 1;		/* automatic HDLC connection */
+	u.cfg.hdlcWindow	= 7;
+	u.cfg.pktWindow		= 2;
+	u.cfg.station		= 1;		/* DTE */
+	u.cfg.options		= 0x00B0;	/* disable D-bit pragmatics */
+	u.cfg.ccittCompat	= 1988;
+	u.cfg.t10t20		= 30;
+	u.cfg.t11t21		= 30;
+	u.cfg.t12t22		= 30;
+	u.cfg.t13t23		= 30;
+	u.cfg.t16t26		= 30;
+	u.cfg.t28		= 30;
+	u.cfg.r10r20		= 5;
+	u.cfg.r12r22		= 5;
+	u.cfg.r13r23		= 5;
+	u.cfg.responseOpt	= 1;		/* RR's after every packet */
+
+	if (conf->clocking != WANOPT_EXTERNAL)
+		u.cfg.baudRate = bps_to_speed_code(conf->bps)
+	;
+	if (conf->station != WANOPT_DTE)
+	{
+		u.cfg.station = 0;		/* DCE mode */
+	}
+        if (conf->interface != WANOPT_RS232 ) {
+	        u.cfg.hdlcOptions |= 0x80;      /* V35 mode */
+	} 
+	/* adjust MTU */
+	if (!conf->mtu || (conf->mtu >= 1024))
+		card->wandev.mtu = 1024
+	;
+	else if (conf->mtu >= 512)
+		card->wandev.mtu = 512
+	;
+	else if (conf->mtu >= 256)
+		card->wandev.mtu = 256
+	;
+	else if (conf->mtu >= 128)
+		card->wandev.mtu = 128
+	;
+	else card->wandev.mtu = 64;
+	u.cfg.defPktSize = u.cfg.pktMTU = card->wandev.mtu;
+
+	if (conf->u.x25.hi_pvc)
+	{
+		card->u.x.hi_pvc = min(conf->u.x25.hi_pvc, 4095);
+		card->u.x.lo_pvc = min(conf->u.x25.lo_pvc, card->u.x.hi_pvc);
+	}
+	if (conf->u.x25.hi_svc)
+	{
+		card->u.x.hi_svc = min(conf->u.x25.hi_svc, 4095);
+		card->u.x.lo_svc = min(conf->u.x25.lo_svc, card->u.x.hi_svc);
+	}
+	u.cfg.loPVC	  = card->u.x.lo_pvc;
+	u.cfg.hiPVC	  = card->u.x.hi_pvc;
+	u.cfg.loTwoWaySVC = card->u.x.lo_svc;
+	u.cfg.hiTwoWaySVC = card->u.x.hi_svc;
+
+	if (conf->u.x25.hdlc_window)
+		u.cfg.hdlcWindow = min(conf->u.x25.hdlc_window, 7)
+	;
+	if (conf->u.x25.pkt_window)
+		u.cfg.pktWindow = min(conf->u.x25.pkt_window, 7)
+	;
+	if (conf->u.x25.t1)
+		u.cfg.t1 = min(conf->u.x25.t1, 30)
+	;
+	u.cfg.t2 = min(conf->u.x25.t2, 29);
+	u.cfg.t4 = min(conf->u.x25.t4, 240);
+	if (conf->u.x25.n2)
+		u.cfg.n2 = min(conf->u.x25.n2, 30)
+	;
+	if (conf->u.x25.ccitt_compat)
+		u.cfg.ccittCompat = conf->u.x25.ccitt_compat
+	;
+
+	/* initialize adapter */
+	if ((x25_configure(card, &u.cfg) != CMD_OK) ||
+	    (x25_close_hdlc(card) != CMD_OK) ||		/* close HDLC link */
+	    (x25_set_dtr(card, 0) != CMD_OK))		/* drop DTR */
+		return -EIO
+	;
+
+	/* Initialize protocol-specific fields of adapter data space */
+	card->wandev.bps	= conf->bps;
+	card->wandev.interface	= conf->interface;
+	card->wandev.clocking	= conf->clocking;
+	card->wandev.station	= conf->station;
+	card->isr		= &wpx_isr;
+	card->poll		= &wpx_poll;
+	card->exec		= &wpx_exec;
+	card->wandev.update	= &update;
+	card->wandev.new_if	= &new_if;
+	card->wandev.del_if	= &del_if;
+	card->wandev.state	= WAN_DISCONNECTED;
+	card->wandev.enable_tx_int = 0;
+	card->irq_dis_if_send_count = 0;
+        card->irq_dis_poll_count = 0;
+	card->wandev.enable_IPX = conf->enable_IPX;
+	
+	if (conf->network_number)
+		card->wandev.network_number = conf->network_number;
+	else
+		card->wandev.network_number = 0xDEADBEEF;
+	return 0;
+}
+
+/******* WAN Device Driver Entry Points *************************************/
+
+/*============================================================================
+ * Update device status & statistics.
+ */
+static int update (wan_device_t* wandev)
+{
+	sdla_t* card;
+
+	/* sanity checks */
+	if ((wandev == NULL) || (wandev->private == NULL))
+		return -EFAULT;
+	if (wandev->state == WAN_UNCONFIGURED)
+		return -ENODEV;
+	if (test_and_set_bit(0, (void*)&wandev->critical))
+		return -EAGAIN;
+	card = wandev->private;
+
+	x25_get_err_stats(card);
+	x25_get_stats(card);
+	wandev->critical = 0;
+	return 0;
+}
+
+/*============================================================================
+ * Create new logical channel.
+ * This routine is called by the router when ROUTER_IFNEW IOCTL is being
+ * handled.
+ * o parse media- and hardware-specific configuration
+ * o make sure that a new channel can be created
+ * o allocate resources, if necessary
+ * o prepare network device structure for registaration.
+ *
+ * Return:	0	o.k.
+ *		< 0	failure (channel will not be created)
+ */
+static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf)
+{
+	sdla_t* card = wandev->private;
+	x25_channel_t* chan;
+	int err = 0;
+
+	if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ))
+	{
+		printk(KERN_INFO "%s: invalid interface name!\n",
+			card->devname)
+		;
+		return -EINVAL;
+	}
+
+	/* allocate and initialize private data */
+	chan = kmalloc(sizeof(x25_channel_t), GFP_KERNEL);
+	if (chan == NULL)
+		return -ENOMEM
+	;
+	memset(chan, 0, sizeof(x25_channel_t));
+	strcpy(chan->name, conf->name);
+	chan->card = card;
+	chan->protocol = ETH_P_IP;
+	chan->tx_skb = chan->rx_skb = NULL;
+
+	/* verify media address */
+	if (conf->addr[0] == '@')		/* SVC */
+	{
+		chan->svc = 1;
+		strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ);
+
+		/* Set channel timeouts (default if not specified) */
+		chan->idle_timeout = (conf->idle_timeout) ? conf->idle_timeout : 					90;
+		chan->hold_timeout = (conf->hold_timeout) ? conf->hold_timeout :					10;
+	}
+	else if (is_digit(conf->addr[0]))	/* PVC */
+	{
+		int lcn = dec_to_uint(conf->addr, 0);
+
+		if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc))
+		{
+			chan->lcn = lcn;
+		}
+		else
+		{
+			printk(KERN_ERR
+				"%s: PVC %u is out of range on interface %s!\n",
+				wandev->name, lcn, chan->name)
+			;
+			err = -EINVAL;
+		}
+	}
+	else
+	{
+		printk(KERN_ERR
+			"%s: invalid media address on interface %s!\n",
+			wandev->name, chan->name)
+		;
+		err = -EINVAL;
+	}
+	if (err)
+	{
+		kfree(chan);
+		return err;
+	}
+
+	/* prepare network device data space for registration */
+	dev->name = chan->name;
+	dev->init = &if_init;
+	dev->priv = chan;
+	return 0;
+}
+
+/*============================================================================
+ * Delete logical channel.
+ */
+static int del_if (wan_device_t* wandev, struct net_device* dev)
+{
+	if (dev->priv)
+	{
+		kfree(dev->priv);
+		dev->priv = NULL;
+	}
+	return 0;
+}
+
+/****** WANPIPE-specific entry points ***************************************/
+
+/*============================================================================
+ * Execute adapter interface command.
+ */
+
+static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data)
+{
+	TX25Mbox* mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err, len;
+	TX25Cmd cmd;
+
+	if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd)))
+		return -EFAULT;
+		
+	/* execute command */
+
+	do
+	{
+		memcpy(&mbox->cmd, &cmd, sizeof(cmd));
+		if (cmd.length)
+		{
+			if(copy_from_user((void*)&mbox->data, u_data, cmd.length))
+				return-EFAULT;
+		}
+		if (sdla_exec(mbox))
+			err = mbox->cmd.result
+		;
+		else return -EIO;
+	}
+	while (err && retry-- && x25_error(card, err, cmd.command, cmd.lcn));
+
+	/* return result */
+	if(copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(TX25Cmd)))
+		return -EFAULT;
+	len = mbox->cmd.length;
+	if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len))
+		return -EFAULT;
+	return 0;
+}
+
+/****** Network Device Interface ********************************************/
+
+/*============================================================================
+ * Initialize Linux network interface.
+ *
+ * This routine is called only once for each interface, during Linux network
+ * interface registration.  Returning anything but zero will fail interface
+ * registration.
+ */
+static int if_init (struct net_device* dev)
+{
+	x25_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+	wan_device_t* wandev = &card->wandev;
+
+	/* Initialize device driver entry points */
+	dev->open		= &if_open;
+	dev->stop		= &if_close;
+	dev->hard_header	= &if_header;
+	dev->rebuild_header	= &if_rebuild_hdr;
+	dev->hard_start_xmit	= &if_send;
+	dev->get_stats		= &if_stats;
+
+	/* Initialize media-specific parameters */
+	dev->type		= 30;		/* ARP h/w type */
+	dev->mtu		= X25_CHAN_MTU;
+	dev->hard_header_len	= X25_HRDHDR_SZ; /* media header length */
+	dev->addr_len		= 2;		/* hardware address length */
+	if (!chan->svc)
+		*(unsigned short*)dev->dev_addr = htons(chan->lcn);
+
+	/* Initialize hardware parameters (just for reference) */
+	dev->irq	= wandev->irq;
+	dev->dma	= wandev->dma;
+	dev->base_addr	= wandev->ioport;
+	dev->mem_start	= (unsigned long)wandev->maddr;
+	dev->mem_end	= dev->mem_end + wandev->msize - 1;
+
+        /* Set transmit buffer queue length */
+        dev->tx_queue_len = 10;
+
+	/* Initialize socket buffers */
+	
+	dev_init_buffers(dev);
+	set_chan_state(dev, WAN_DISCONNECTED);
+	return 0;
+}
+
+/*============================================================================
+ * Open network interface.
+ * o prevent module from unloading by incrementing use count
+ * o if link is disconnected then initiate connection
+ *
+ * Return 0 if O.k. or errno.
+ */
+static int if_open (struct net_device* dev)
+{
+	x25_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+
+	if (dev->start)
+		return -EBUSY;		/* only one open is allowed */
+	
+	if (test_and_set_bit(0, (void*)&card->wandev.critical))
+		return -EAGAIN;
+
+	dev->interrupt = 0;
+	dev->tbusy = 0;
+	dev->start = 1;
+	wanpipe_open(card);
+
+	/* If this is the first open, initiate physical connection */
+	if (card->open_cnt == 1)
+		connect(card);
+	card->wandev.critical = 0;
+	return 0;
+}
+
+/*============================================================================
+ * Close network interface.
+ * o reset flags.
+ * o if there's no more open channels then disconnect physical link.
+ */
+static int if_close (struct net_device* dev)
+{
+	x25_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+
+	if (test_and_set_bit(0, (void*)&card->wandev.critical))
+		return -EAGAIN;
+
+	dev->start = 0;
+	if ((chan->state == WAN_CONNECTED) || (chan->state == WAN_CONNECTING))
+		chan_disc(dev);
+		
+	wanpipe_close(card);
+
+	/* If this is the last close, disconnect physical link */
+	if (!card->open_cnt)
+		disconnect(card);
+		
+	card->wandev.critical = 0;
+	return 0;
+}
+
+/*============================================================================
+ * Build media header.
+ * o encapsulate packet according to encapsulation type.
+ *
+ * The trick here is to put packet type (Ethertype) into 'protocol' field of
+ * the socket buffer, so that we don't forget it.  If encapsulation fails,
+ * set skb->protocol to 0 and discard packet later.
+ *
+ * Return:	media header length.
+ */
+static int if_header (struct sk_buff* skb, struct net_device* dev,
+	unsigned short type, void* daddr, void* saddr, unsigned len)
+{
+	x25_channel_t* chan = dev->priv;
+	int hdr_len = dev->hard_header_len;
+
+	skb->protocol = type;
+	if (!chan->protocol)
+	{
+		hdr_len = wanrouter_encapsulate(skb, dev);
+		if (hdr_len < 0)
+		{
+			hdr_len = 0;
+			skb->protocol = 0;
+		}
+	}
+	return hdr_len;
+}
+
+/*============================================================================
+ * Re-build media header.
+ *
+ * Return:	1	physical address resolved.
+ *		0	physical address not resolved
+ */
+ 
+static int if_rebuild_hdr (struct sk_buff* skb)
+{
+	struct net_device *dev=skb->dev;
+	x25_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+
+	printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
+		card->devname, dev->name);
+	return 1;
+}
+
+/*============================================================================
+ * Send a packet on a network interface.
+ * o set tbusy flag (marks start of the transmission).
+ * o check link state. If link is not up, then drop the packet.
+ * o check channel status. If it's down then initiate a call.
+ * o pass a packet to corresponding WAN device.
+ * o free socket buffer
+ *
+ * Return:	0	complete (socket buffer must be freed)
+ *		non-0	packet may be re-transmitted (tbusy must be set)
+ *
+ * Notes:
+ * 1. This routine is called either by the protocol stack or by the "net
+ *    bottom half" (with interrupts enabled).
+ * 2. Setting tbusy flag will inhibit further transmit requests from the
+ *    protocol stack and can be used for flow control with protocol layer.
+ */
+
+static int if_send (struct sk_buff* skb, struct net_device* dev)
+{
+	x25_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+	struct net_device *dev2;
+	TX25Status* status = card->flags;
+	unsigned long host_cpu_flags;
+
+	if (dev->tbusy)
+	{
+		++chan->ifstats.rx_dropped;	
+		if ((jiffies - chan->tick_counter) < (5*HZ))
+		{
+			return dev->tbusy;
+		}
+		printk(KERN_INFO "%s: Transmit time out %s!\n",
+			card->devname, dev->name)
+		;
+		for( dev2 = card->wandev.dev; dev2; dev2 = dev2->slave)
+		{
+	        	dev2->tbusy = 0;
+		}
+	}
+	chan->tick_counter = jiffies;
+
+	disable_irq(card->hw.irq);
+	++card->irq_dis_if_send_count;
+
+	if (test_and_set_bit(0, (void*)&card->wandev.critical)) 
+	{
+		printk(KERN_INFO "Hit critical in if_send()!\n");
+		if (card->wandev.critical == CRITICAL_IN_ISR) 
+		{
+			card->wandev.enable_tx_int = 1;
+			dev->tbusy = 1;
+			
+			save_flags(host_cpu_flags);
+                        cli();
+                        if ((!(--card->irq_dis_if_send_count)) &&
+                                        (!card->irq_dis_poll_count))
+                                enable_irq(card->hw.irq);
+                        restore_flags(host_cpu_flags);
+			
+			return dev->tbusy;
+		}
+		dev_kfree_skb(skb);
+		
+		save_flags(host_cpu_flags);
+                cli();
+                if ((!(--card->irq_dis_if_send_count)) &&
+                                         (!card->irq_dis_poll_count))
+                        enable_irq(card->hw.irq);
+                restore_flags(host_cpu_flags);
+
+		return dev->tbusy;
+	}
+
+	/* Below is only until we have per-channel IPX going.... */
+	if(!(chan->svc))
+		chan->protocol = skb->protocol;
+
+	if (card->wandev.state != WAN_CONNECTED)
+		++chan->ifstats.tx_dropped;
+
+	/* Below is only until we have per-channel IPX going.... */
+	else if ( (chan->svc) && (chan->protocol && (chan->protocol != skb->protocol)))
+	{
+		printk(KERN_INFO
+			"%s: unsupported Ethertype 0x%04X on interface %s!\n",
+			card->devname, skb->protocol, dev->name);
+		++chan->ifstats.tx_errors;
+	}
+	else switch (chan->state)
+	{
+		case WAN_DISCONNECTED:
+			/* Try to establish connection. If succeded, then start
+			 * transmission, else drop a packet.
+			 */
+			if (chan_connect(dev) != 0)
+			{
+				++chan->ifstats.tx_dropped;
+				++card->wandev.stats.tx_dropped;
+				break;
+			}
+			/* fall through */
+
+		case WAN_CONNECTED:
+			if( skb->protocol == ETH_P_IPX ) 
+			{
+				if(card->wandev.enable_IPX) 
+				{
+					switch_net_numbers( skb->data, 
+						card->wandev.network_number, 0);
+				}
+				else 
+				{
+					++card->wandev.stats.tx_dropped;
+					++chan->ifstats.tx_dropped;
+					goto tx_done;
+				}
+			}
+			dev->trans_start = jiffies;
+			if(chan_send(dev, skb))
+			{
+				dev->tbusy = 1;
+				status->imask |= 0x2;
+			}
+			break;
+
+		default:
+			++chan->ifstats.tx_dropped;	
+			++card->wandev.stats.tx_dropped;
+	}
+tx_done:
+	if (!dev->tbusy)
+		dev_kfree_skb(skb);
+
+	card->wandev.critical = 0;
+	save_flags(host_cpu_flags);
+        cli();
+        if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count))
+                enable_irq(card->hw.irq);
+        restore_flags(host_cpu_flags);
+	return dev->tbusy;
+}
+
+/*============================================================================
+ * Get Ethernet-style interface statistics.
+ * Return a pointer to struct net_device_stats
+ */
+ 
+static struct net_device_stats* if_stats (struct net_device* dev)
+{
+	x25_channel_t* chan = dev->priv;
+	if(chan==NULL)
+		return NULL;
+	return &chan->ifstats;
+}
+
+/****** Interrupt Handlers **************************************************/
+
+/*============================================================================
+ * X.25 Interrupt Service Routine.
+ */
+ 
+static void wpx_isr (sdla_t* card)
+{
+	TX25Status* status = card->flags;
+	struct net_device *dev;
+	unsigned long host_cpu_flags;
+
+	card->in_isr = 1;
+	card->buff_int_mode_unbusy = 0;
+
+	if (test_and_set_bit(0, (void*)&card->wandev.critical)) 
+	{
+
+ 		printk(KERN_INFO "wpx_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, status->iflags);
+		card->in_isr = 0;
+		return;
+	}
+
+	/* For all interrupts set the critical flag to CRITICAL_RX_INTR.
+         * If the if_send routine is called with this flag set it will set
+         * the enable transmit flag to 1. (for a delayed interrupt)
+         */
+	card->wandev.critical = CRITICAL_IN_ISR;
+
+	switch (status->iflags)
+	{
+		case 0x01:		/* receive interrupt */
+			rx_intr(card);
+			break;
+
+		case 0x02:		/* transmit interrupt */
+			tx_intr(card);
+			card->buff_int_mode_unbusy = 1;
+			status->imask &= ~0x2;
+			break;
+
+		case 0x04:		/* modem status interrupt */
+			status_intr(card);
+			break;
+
+		case 0x10:		/* network event interrupt */
+			event_intr(card);
+			break;
+
+		default:		/* unwanted interrupt */
+			spur_intr(card);
+	}
+	card->wandev.critical = CRITICAL_INTR_HANDLED;
+	if( card->wandev.enable_tx_int)
+	{
+		card->wandev.enable_tx_int = 0;
+		status->imask |= 0x2;
+	}
+	save_flags(host_cpu_flags);
+	cli();
+	card->in_isr = 0;
+	status->iflags = 0;	/* clear interrupt condition */
+	card->wandev.critical = 0;
+	restore_flags(host_cpu_flags);
+
+	if(card->buff_int_mode_unbusy)
+	{
+		for(dev = card->wandev.dev; dev; dev = dev->slave)
+		{
+			if(((x25_channel_t*)dev->priv)->devtint)
+			{
+				mark_bh(NET_BH);
+				return;
+			}	
+		}
+	}
+}
+
+/*============================================================================
+ * Receive interrupt handler.
+ * This routine handles fragmented IP packets using M-bit according to the
+ * RFC1356.
+ * o map ligical channel number to network interface.
+ * o allocate socket buffer or append received packet to the existing one.
+ * o if M-bit is reset (i.e. it's the last packet in a sequence) then 
+ *   decapsulate packet and pass socket buffer to the protocol stack.
+ *
+ * Notes:
+ * 1. When allocating a socket buffer, if M-bit is set then more data is
+ *    comming and we have to allocate buffer for the maximum IP packet size
+ *    expected on this channel.
+ * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no
+ *    socket buffers available) the whole packet sequence must be discarded.
+ */
+
+static void rx_intr (sdla_t* card)
+{
+	TX25Mbox* rxmb = card->rxmb;
+	unsigned lcn = rxmb->cmd.lcn;		/* logical channel number */
+	unsigned len = rxmb->cmd.length;	/* packet length */
+	unsigned qdm = rxmb->cmd.qdm;		/* Q,D and M bits */
+	wan_device_t* wandev = &card->wandev;
+	struct net_device* dev = get_dev_by_lcn(wandev, lcn);
+	x25_channel_t* chan;
+	struct sk_buff* skb;
+	void* bufptr;
+
+	if (dev == NULL)
+	{
+		/* Invalid channel, discard packet */
+		printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n",
+			card->devname, lcn);
+		return;
+	}
+
+	chan = dev->priv;
+	chan->i_timeout_sofar = jiffies;
+	if (chan->drop_sequence)
+	{
+		if (!(qdm & 0x01)) chan->drop_sequence = 0;
+		return;
+	}
+
+	skb = chan->rx_skb;
+	if (skb == NULL)
+	{
+		/* Allocate new socket buffer */
+		int bufsize = (qdm & 0x01) ? dev->mtu : len;
+
+		skb = dev_alloc_skb(bufsize + dev->hard_header_len);
+		if (skb == NULL)
+		{
+			printk(KERN_INFO "%s: no socket buffers available!\n",
+				card->devname);
+			chan->drop_sequence = 1;	/* set flag */
+			++chan->ifstats.rx_dropped;
+			return;
+		}
+		skb->dev = dev;
+		skb->protocol = htons(chan->protocol);
+		chan->rx_skb = skb;
+	}
+
+	if (skb_tailroom(skb) < len)
+	{
+		/* No room for the packet. Call off the whole thing! */
+		dev_kfree_skb(skb);
+		chan->rx_skb = NULL;
+		if (qdm & 0x01) chan->drop_sequence = 1;
+
+		printk(KERN_INFO "%s: unexpectedly long packet sequence "
+			"on interface %s!\n", card->devname, dev->name);
+		++chan->ifstats.rx_length_errors;
+		return;
+	}
+
+	/* Append packet to the socket buffer */
+	bufptr = skb_put(skb, len);
+	memcpy(bufptr, rxmb->data, len);
+
+	if (qdm & 0x01)
+		return;		/* more data is comming */
+
+	dev->last_rx = jiffies;		/* timestamp */
+	chan->rx_skb = NULL;		/* dequeue packet */
+
+	/* Decapsulate packet, if necessary */
+	if (!skb->protocol && !wanrouter_type_trans(skb, dev))
+	{
+		/* can't decapsulate packet */
+		dev_kfree_skb(skb);
+		++chan->ifstats.rx_errors;
+	}
+	else
+	{
+		if( handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol))
+		{
+			if( card->wandev.enable_IPX )
+			{
+				if(chan_send(dev, skb))
+				{
+					chan->tx_skb = skb;
+				}
+				else
+				{
+					dev_kfree_skb(skb);
+				}
+			}
+			else
+			{
+				/* FIXME: increment IPX packet dropped statistic */
+			}
+		}
+		else
+		{
+			netif_rx(skb);
+			++chan->ifstats.rx_packets;
+			chan->ifstats.rx_bytes += skb->len;
+		}
+	}
+}
+
+/*============================================================================
+ * Transmit interrupt handler.
+ *	o Release socket buffer
+ *	o Clear 'tbusy' flag
+ */
+
+static void tx_intr (sdla_t* card)
+{
+	struct net_device *dev;
+
+	/* unbusy all devices and then dev_tint(); */
+	for(dev = card->wandev.dev; dev; dev = dev->slave)
+	{
+		((x25_channel_t*)dev->priv)->devtint = dev->tbusy; 
+		dev->tbusy = 0;
+	}
+
+}
+
+/*============================================================================
+ * Modem status interrupt handler.
+ */
+static void status_intr (sdla_t* card)
+{
+}
+
+/*============================================================================
+ * Network event interrupt handler.
+ */
+static void event_intr (sdla_t* card)
+{
+}
+
+/*============================================================================
+ * Spurious interrupt handler.
+ * o print a warning
+ * o 
+ * If number of spurious interrupts exceeded some limit, then ???
+ */
+static void spur_intr (sdla_t* card)
+{
+	printk(KERN_INFO "%s: spurious interrupt!\n", card->devname);
+}
+
+/****** Background Polling Routines  ****************************************/
+
+/*============================================================================
+ * Main polling routine.
+ * This routine is repeatedly called by the WANPIPE 'thread' to allow for
+ * time-dependent housekeeping work.
+ *
+ * Notes:
+ * 1. This routine may be called on interrupt context with all interrupts
+ *    enabled. Beware!
+ */
+
+static void wpx_poll (sdla_t* card)
+{
+	unsigned long host_cpu_flags;
+
+	disable_irq(card->hw.irq);
+	++card->irq_dis_poll_count;
+
+	if (test_and_set_bit(0, (void*)&card->wandev.critical)) 
+	{
+ 		printk(KERN_INFO "%s: critical in polling!\n",card->devname);	
+		save_flags(host_cpu_flags);
+                cli();
+		if ((!card->irq_dis_if_send_count) &&
+                                (!(--card->irq_dis_poll_count)))
+                        enable_irq(card->hw.irq);
+                restore_flags(host_cpu_flags);
+		return;
+	}
+
+	switch(card->wandev.state)
+	{
+		case WAN_CONNECTED:
+			poll_active(card);
+			break;
+
+		case WAN_CONNECTING:
+			poll_connecting(card);
+			break;
+
+		case WAN_DISCONNECTED:
+			poll_disconnected(card);
+	}
+	card->wandev.critical = 0;
+	save_flags(host_cpu_flags);
+        cli();
+        if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count)))
+                enable_irq(card->hw.irq);
+        restore_flags(host_cpu_flags);
+}
+
+/*============================================================================
+ * Handle physical link establishment phase.
+ * o if connection timed out, disconnect the link.
+ */
+static void poll_connecting (sdla_t* card)
+{
+	TX25Status* status = card->flags;
+
+	if (status->gflags & X25_HDLC_ABM)
+	{
+		wanpipe_set_state(card, WAN_CONNECTED);
+		x25_set_intr_mode(card, 0x83);	/* enable Rx interrupts */
+		status->imask &= ~0x2;		/* mask Tx interupts */
+	}
+	else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT)
+	    disconnect(card);
+}
+
+/*============================================================================
+ * Handle physical link disconnected phase.
+ * o if hold-down timeout has expired and there are open interfaces, connect
+ *   link.
+ */
+static void poll_disconnected (sdla_t* card)
+{
+	if (card->open_cnt && ((jiffies - card->state_tick) > HOLD_DOWN_TIME))
+		connect(card);
+}
+
+/*============================================================================
+ * Handle active link phase.
+ * o fetch X.25 asynchronous events.
+ * o kick off transmission on all interfaces.
+ */
+static void poll_active (sdla_t* card)
+{
+	struct net_device* dev;
+
+	/* Fetch X.25 asynchronous events */
+	x25_fetch_events(card);
+
+	for (dev = card->wandev.dev; dev; dev = dev->slave)
+	{
+		x25_channel_t* chan = dev->priv;
+		struct sk_buff* skb = chan->tx_skb;
+
+		/* If there is a packet queued for transmission then kick
+		 * the channel's send routine. When transmission is complete
+		 * or if error has occurred, release socket buffer and reset
+		 * 'tbusy' flag.
+		 */
+		if (skb && (chan_send(dev, skb) == 0))
+		{
+			chan->tx_skb = NULL;
+			dev->tbusy = 0;
+			dev_kfree_skb(skb);
+		}
+
+		/* If SVC has been idle long enough, close virtual circuit */
+
+		if(( chan->svc )&&( chan->state == WAN_CONNECTED ))
+		{
+			if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout )
+			{
+				/* Close svc */
+				printk(KERN_INFO "%s: Closing down Idle link %s on LCN %d\n",card->devname,chan->name,chan->lcn); 
+				chan->i_timeout_sofar = jiffies;
+				chan_disc(dev);
+			}
+		}
+	}
+}
+
+/****** SDLA Firmware-Specific Functions *************************************
+ * Almost all X.25 commands can unexpetedly fail due to so called 'X.25
+ * asynchronous events' such as restart, interrupt, incoming call request,
+ * call clear request, etc.  They can't be ignored and have to be dealt with
+ * immediately.  To tackle with this problem we execute each interface command
+ * in a loop until good return code is received or maximum number of retries
+ * is reached.  Each interface command returns non-zero return code, an
+ * asynchronous event/error handler x25_error() is called.
+ */
+
+/*============================================================================
+ * Read X.25 firmware version.
+ *	Put code version as ASCII string in str. 
+ */
+static int x25_get_version (sdla_t* card, char* str)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->cmd.command = X25_READ_CODE_VERSION;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- &&
+		 x25_error(card, err, X25_READ_CODE_VERSION, 0));
+
+	if (!err && str)
+	{
+		int len = mbox->cmd.length;
+		memcpy(str, mbox->data, len);
+		str[len] = '\0';
+	}
+	return err;
+}
+
+/*============================================================================
+ * Configure adapter.
+ */
+
+static int x25_configure (sdla_t* card, TX25Config* conf)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		memcpy(mbox->data, (void*)conf, sizeof(TX25Config));
+		mbox->cmd.length  = sizeof(TX25Config);
+		mbox->cmd.command = X25_SET_CONFIGURATION;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0));
+	return err;
+}
+
+/*============================================================================
+ * Get communications error statistics.
+ */
+static int x25_get_err_stats (sdla_t* card)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->cmd.command = X25_HDLC_READ_COMM_ERR;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- && x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0));
+
+	if (!err)
+	{
+		THdlcCommErr* stats = (void*)mbox->data;
+
+		card->wandev.stats.rx_over_errors    = stats->rxOverrun;
+		card->wandev.stats.rx_crc_errors     = stats->rxBadCrc;
+		card->wandev.stats.rx_missed_errors  = stats->rxAborted;
+		card->wandev.stats.tx_aborted_errors = stats->txAborted;
+	}
+	return err;
+}
+
+/*============================================================================
+ * Get protocol statistics.
+ */
+static int x25_get_stats (sdla_t* card)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->cmd.command = X25_READ_STATISTICS;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0));
+	
+	if (!err)
+	{
+		TX25Stats* stats = (void*)mbox->data;
+
+		card->wandev.stats.rx_packets = stats->rxData;
+		card->wandev.stats.tx_packets = stats->rxData;
+	}
+	return err;
+}
+
+/*============================================================================
+ * Close HDLC link.
+ */
+static int x25_close_hdlc (sdla_t* card)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->cmd.command = X25_HDLC_LINK_CLOSE;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_CLOSE, 0));
+
+	return err;
+}
+
+/*============================================================================
+ * Open HDLC link.
+ */
+static int x25_open_hdlc (sdla_t* card)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->cmd.command = X25_HDLC_LINK_OPEN;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_OPEN, 0));
+	
+	return err;
+}
+
+/*============================================================================
+ * Setup HDLC link.
+ */
+static int x25_setup_hdlc (sdla_t* card)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->cmd.command = X25_HDLC_LINK_SETUP;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_SETUP, 0));
+	
+	return err;
+}
+
+/*============================================================================
+ * Set (raise/drop) DTR.
+ */
+static int x25_set_dtr (sdla_t* card, int dtr)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->data[0] = 0;
+		mbox->data[2] = 0;
+		mbox->data[1] = dtr ? 0x02 : 0x01;
+		mbox->cmd.length  = 3;
+		mbox->cmd.command = X25_SET_GLOBAL_VARS;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- && x25_error(card, err, X25_SET_GLOBAL_VARS, 0));
+
+	return err;
+}
+
+/*============================================================================
+ * Set interrupt mode.
+ */
+static int x25_set_intr_mode (sdla_t* card, int mode)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->data[0] = mode;
+		if (card->hw.fwid == SFID_X25_508)
+		{
+			mbox->data[1] = card->hw.irq;
+			mbox->cmd.length = 2;
+		}
+		else mbox->cmd.length  = 1;
+		mbox->cmd.command = X25_SET_INTERRUPT_MODE;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)) ;
+	return err;
+}
+
+/*============================================================================
+ * Read X.25 channel configuration.
+ */
+static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int lcn = chan->lcn;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->cmd.lcn     = lcn;
+		mbox->cmd.command = X25_READ_CHANNEL_CONFIG;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- && x25_error(card, err, X25_READ_CHANNEL_CONFIG, lcn));
+
+	if (!err)
+	{
+		TX25Status* status = card->flags;
+
+		/* calculate an offset into the array of status bytes */
+		if (card->u.x.hi_svc <= 255) 
+			chan->ch_idx = lcn - 1;
+		else
+		{
+			int offset;
+
+			switch (mbox->data[0] && 0x1F)
+			{
+				case 0x01:
+					offset = status->pvc_map; break;
+				case 0x03:
+					offset = status->icc_map; break;
+				case 0x07:
+					offset = status->twc_map; break;
+				case 0x0B: 
+					offset = status->ogc_map; break;
+				default: 
+					offset = 0;
+			}
+			chan->ch_idx = lcn - 1 - offset;
+		}
+
+		/* get actual transmit packet size on this channel */
+		switch(mbox->data[1] & 0x38)
+		{
+			case 0x00:
+				chan->tx_pkt_size = 16;
+				break;
+			case 0x08:
+				chan->tx_pkt_size = 32;
+				break;
+			case 0x10:
+				chan->tx_pkt_size = 64;
+				break;
+			case 0x18:
+				chan->tx_pkt_size = 128;
+				break;
+			case 0x20:
+				chan->tx_pkt_size = 256;
+				break;
+			case 0x28:
+				chan->tx_pkt_size = 512;
+				break;
+			case 0x30:
+				chan->tx_pkt_size = 1024;
+				break;
+		}
+		printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n",
+			card->devname, lcn, chan->tx_pkt_size);
+	}
+	return err;
+}
+
+/*============================================================================
+ * Place X.25 call.
+ */
+
+static int x25_place_call (sdla_t* card, x25_channel_t* chan)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+	char str[64];
+
+	sprintf(str, "-d%s -uCC", chan->addr);
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		strcpy(mbox->data, str);
+		mbox->cmd.length  = strlen(str);
+		mbox->cmd.command = X25_PLACE_CALL;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- && x25_error(card, err, X25_PLACE_CALL, 0));
+
+	if (!err)
+	{
+		chan->lcn = mbox->cmd.lcn;
+		chan->protocol = ETH_P_IP;
+	}
+	return err;
+}
+
+/*============================================================================
+ * Accept X.25 call.
+ */
+
+static int x25_accept_call (sdla_t* card, int lcn, int qdm)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->cmd.lcn     = lcn;
+		mbox->cmd.qdm     = qdm;
+		mbox->cmd.command = X25_ACCEPT_CALL;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- && x25_error(card, err, X25_ACCEPT_CALL, lcn));
+
+	return err;
+}
+
+/*============================================================================
+ * Clear X.25 call.
+ */
+static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->cmd.lcn     = lcn;
+		mbox->cmd.cause   = cause;
+		mbox->cmd.diagn   = diagn;
+		mbox->cmd.command = X25_CLEAR_CALL;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- && x25_error(card, err, X25_CLEAR_CALL, lcn));
+
+	return err;
+}
+
+/*============================================================================
+ * Send X.25 data packet.
+ */
+static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+	
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		memcpy(mbox->data, buf, len);
+		mbox->cmd.length  = len;
+		mbox->cmd.lcn     = lcn;
+		mbox->cmd.qdm     = qdm;
+		mbox->cmd.command = X25_WRITE;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- && x25_error(card, err, X25_WRITE, lcn));
+	return err;
+}
+
+/*============================================================================
+ * Fetch X.25 asynchronous events.
+ */
+static int x25_fetch_events (sdla_t* card)
+{
+	TX25Status* status = card->flags;
+	TX25Mbox* mbox = card->mbox;
+	int err = 0;
+
+	if (status->gflags & 0x20)
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->cmd.command = X25_IS_DATA_AVAILABLE;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+ 		if (err)
+ 			x25_error(card, err, X25_IS_DATA_AVAILABLE, 0);
+	}
+	return err;
+}
+
+/*============================================================================
+ * X.25 asynchronous event/error handler.
+ *	This routine is called each time interface command returns non-zero
+ *	return code to handle X.25 asynchronous events and common errors.
+ *	Return non-zero to repeat command or zero to cancel it.
+ *
+ * Notes:
+ * 1. This function may be called recursively, as handling some of the
+ *    asynchronous events (e.g. call request) requires execution of the
+ *    interface command(s) that, in turn, may also return asynchronous
+ *    events.  To avoid re-entrancy problems we copy mailbox to dynamically
+ *    allocated memory before processing events.
+ */
+static int x25_error (sdla_t* card, int err, int cmd, int lcn)
+{
+	int retry = 1;
+	unsigned dlen = ((TX25Mbox*)card->mbox)->cmd.length;
+	TX25Mbox* mb;
+
+	mb = kmalloc(sizeof(TX25Mbox) + dlen, GFP_ATOMIC);
+	if (mb == NULL)
+	{
+		printk(KERN_ERR "%s: x25_error() out of memory!\n",
+			card->devname);
+		return 0;
+	}
+	memcpy(mb, card->mbox, sizeof(TX25Mbox) + dlen);
+	switch (err)
+	{
+		case 0x40:	/* X.25 asynchronous packet was received */
+			mb->data[dlen] = '\0';
+			switch (mb->cmd.pktType & 0x7F)
+			{
+				case 0x30:		/* incoming call */
+					retry = incoming_call(card, cmd, lcn, mb);
+					break;
+
+				case 0x31:		/* connected */
+					retry = call_accepted(card, cmd, lcn, mb);
+					break;
+
+				case 0x02:		/* call clear request */
+					retry = call_cleared(card, cmd, lcn, mb);
+					break;
+
+				case 0x04:		/* reset request */
+					printk(KERN_INFO "%s: X.25 reset request on LCN %d! "
+						"Cause:0x%02X Diagn:0x%02X\n",
+						card->devname, mb->cmd.lcn, mb->cmd.cause,
+						mb->cmd.diagn);
+					break;
+
+				case 0x08:		/* restart request */
+					retry = restart_event(card, cmd, lcn, mb);
+					break;
+
+				default:
+					printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! "
+						"Cause:0x%02X Diagn:0x%02X\n",
+						card->devname, mb->cmd.pktType,
+						mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn);
+			}
+			break;
+
+		case 0x41:	/* X.25 protocol violation indication */
+			printk(KERN_INFO
+				"%s: X.25 protocol violation on LCN %d! "
+				"Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n",
+				card->devname, mb->cmd.lcn,
+				mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn);
+			break;
+
+		case 0x42:	/* X.25 timeout */
+			retry = timeout_event(card, cmd, lcn, mb);
+			break;
+
+		case 0x43:	/* X.25 retry limit exceeded */
+			printk(KERN_INFO
+				"%s: exceeded X.25 retry limit on LCN %d! "
+				"Packet:0x%02X Diagn:0x%02X\n", card->devname,
+				mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn);
+			break;
+
+		case 0x08:	/* modem failure */
+			printk(KERN_INFO "%s: modem failure!\n", card->devname);
+			break;
+
+		case 0x09:	/* N2 retry limit */
+			printk(KERN_INFO "%s: exceeded HDLC retry limit!\n",
+				card->devname);
+			break;
+
+		case 0x06:	/* unnumbered frame was received while in ABM */
+			printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n",
+				card->devname, mb->data[0]);
+			break;
+
+		case CMD_TIMEOUT:
+			printk(KERN_ERR "%s: command 0x%02X timed out!\n",
+				card->devname, cmd);
+			retry = 0;	/* abort command */
+			break;
+
+		default:
+			printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n",
+				card->devname, cmd, err);
+			retry = 0;	/* abort command */
+	}
+	kfree(mb);
+	return retry;
+}
+
+/****** X.25 Asynchronous Event Handlers *************************************
+ * These functions are called by the x25_error() and should return 0, if
+ * the command resulting in the asynchronous event must be aborted.
+ */
+
+/*============================================================================
+ * Handle X.25 incoming call request.
+ *	RFC 1356 establishes the following rules:
+ *	1. The first octet in the Call User Data (CUD) field of the call
+ *	   request packet contains NLPID identifying protocol encapsulation.
+ *	2. Calls MUST NOT be accepted unless router supports requested
+ *	   protocol encapsulation.
+ *	3. A diagnostic code 249 defined by ISO/IEC 8208 may be used when
+ *	   clearing a call because protocol encapsulation is not supported.
+ *	4. If an incoming call is received while a call request is pending
+ *	   (i.e. call collision has occurred), the incoming call shall be
+ *	   rejected and call request shall be retried.
+ */
+
+static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
+{
+	wan_device_t* wandev = &card->wandev;
+	int new_lcn = mb->cmd.lcn;
+	struct net_device* dev = get_dev_by_lcn(wandev, new_lcn);
+	x25_channel_t* chan = NULL;
+	int accept = 0;		/* set to '1' if o.k. to accept call */
+	x25_call_info_t* info;
+
+	/* Make sure there is no call collision */
+	if (dev != NULL)
+	{
+		printk(KERN_INFO
+			"%s: X.25 incoming call collision on LCN %d!\n",
+			card->devname, new_lcn);
+		x25_clear_call(card, new_lcn, 0, 0);
+		return 1;
+	}
+
+	/* Make sure D bit is not set in call request */
+	if (mb->cmd.qdm & 0x02)
+	{
+		printk(KERN_INFO
+			"%s: X.25 incoming call on LCN %d with D-bit set!\n",
+			card->devname, new_lcn);
+		x25_clear_call(card, new_lcn, 0, 0);
+		return 1;
+	}
+
+	/* Parse call request data */
+	info = kmalloc(sizeof(x25_call_info_t), GFP_ATOMIC);
+	if (info == NULL)
+	{
+		printk(KERN_ERR
+			"%s: not enough memory to parse X.25 incoming call "
+			"on LCN %d!\n", card->devname, new_lcn);
+		x25_clear_call(card, new_lcn, 0, 0);
+		return 1;
+	}
+	parse_call_info(mb->data, info);
+	printk(KERN_INFO "%s: X.25 incoming call on LCN %d! Call data: %s\n",
+		card->devname, new_lcn, mb->data);
+
+	/* Find available channel */
+	for (dev = wandev->dev; dev; dev = dev->slave)
+	{
+		chan = dev->priv;
+
+		if (!chan->svc || (chan->state != WAN_DISCONNECTED))
+			continue;
+		if (strcmp(info->src, chan->addr) == 0)
+			break;
+	        /* If just an '@' is specified, accept all incoming calls */
+	        if (strcmp(chan->addr, "") == 0)
+	                break;
+	}
+
+	if (dev == NULL)
+	{
+		printk(KERN_INFO "%s: no channels available!\n",
+			card->devname);
+		x25_clear_call(card, new_lcn, 0, 0);
+	}
+
+	/* Check requested protocol encapsulation */
+	else if (info->nuser == 0)
+	{
+		printk(KERN_INFO
+			"%s: no user data in incoming call on LCN %d!\n",
+			card->devname, new_lcn);
+		x25_clear_call(card, new_lcn, 0, 0);
+	}
+	else switch (info->user[0])
+	{
+		case 0:		/* multiplexed */
+			chan->protocol = 0;
+			accept = 1;
+			break;
+
+		case NLPID_IP:	/* IP datagrams */
+			chan->protocol = ETH_P_IP;
+			accept = 1;
+			break;
+
+		case NLPID_SNAP: /* IPX datagrams */
+			chan->protocol = ETH_P_IPX;
+			accept = 1;
+			break;
+		default:
+			printk(KERN_INFO
+				"%s: unsupported NLPID 0x%02X in incoming call "
+				"on LCN %d!\n", card->devname, info->user[0], new_lcn);
+			x25_clear_call(card, new_lcn, 0, 249);
+	}
+
+	if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK))
+	{
+		chan->lcn = new_lcn;
+		if (x25_get_chan_conf(card, chan) == CMD_OK)
+			set_chan_state(dev, WAN_CONNECTED);
+		else
+			x25_clear_call(card, new_lcn, 0, 0);
+	}
+	kfree(info);
+	return 1;
+}
+
+/*============================================================================
+ * Handle accepted call.
+ */
+
+static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
+{
+	unsigned new_lcn = mb->cmd.lcn;
+	struct net_device* dev = get_dev_by_lcn(&card->wandev, new_lcn);
+	x25_channel_t* chan;
+
+	printk(KERN_INFO "%s: X.25 call accepted on LCN %d!\n",
+		card->devname, new_lcn);
+	if (dev == NULL)
+	{
+		printk(KERN_INFO
+			"%s: clearing orphaned connection on LCN %d!\n",
+			card->devname, new_lcn);
+		x25_clear_call(card, new_lcn, 0, 0);
+		return 1;
+	}
+
+	/* Get channel configuration and notify router */
+	chan = dev->priv;
+	if (x25_get_chan_conf(card, chan) != CMD_OK)
+	{
+		x25_clear_call(card, new_lcn, 0, 0);
+		return 1;
+	}
+	set_chan_state(dev, WAN_CONNECTED);
+	return 1;
+}
+
+/*============================================================================
+ * Handle cleared call.
+ */
+
+static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
+{
+	unsigned new_lcn = mb->cmd.lcn;
+	struct net_device* dev = get_dev_by_lcn(&card->wandev, new_lcn);
+
+	printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X "
+		"Diagn:0x%02X\n",
+		card->devname, new_lcn, mb->cmd.cause, mb->cmd.diagn);
+	if (dev == NULL)
+		return 1;
+	set_chan_state(dev, WAN_DISCONNECTED);
+	return ((cmd == X25_WRITE) && (lcn == new_lcn)) ? 0 : 1;
+}
+
+/*============================================================================
+ * Handle X.25 restart event.
+ */
+ 
+static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
+{
+	wan_device_t* wandev = &card->wandev;
+	struct net_device* dev;
+
+	printk(KERN_INFO
+		"%s: X.25 restart request! Cause:0x%02X Diagn:0x%02X\n",
+		card->devname, mb->cmd.cause, mb->cmd.diagn);
+
+	/* down all logical channels */
+	for (dev = wandev->dev; dev; dev = dev->slave)
+		set_chan_state(dev, WAN_DISCONNECTED);
+	return (cmd == X25_WRITE) ? 0 : 1;
+}
+
+/*============================================================================
+ * Handle timeout event.
+ */
+static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
+{
+	unsigned new_lcn = mb->cmd.lcn;
+
+	if (mb->cmd.pktType == 0x05)	/* call request time out */
+	{
+		struct net_device* dev = get_dev_by_lcn(&card->wandev, new_lcn);
+
+		printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n",
+			card->devname, new_lcn);
+		if (dev)
+			set_chan_state(dev, WAN_DISCONNECTED);
+	}
+	else printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n",
+		card->devname, mb->cmd.pktType, new_lcn);
+	return 1;
+}
+
+/******* Miscellaneous ******************************************************/
+
+/*============================================================================
+ * Establish physical connection.
+ * o open HDLC and raise DTR
+ *
+ * Return:	0	connection established
+ *		1	connection is in progress
+ *		<0	error
+ */
+static int connect (sdla_t* card)
+{
+	if (x25_open_hdlc(card) || x25_setup_hdlc(card))
+		return -EIO;
+	wanpipe_set_state(card, WAN_CONNECTING);
+	return 1;
+}
+
+/*============================================================================
+ * Tear down physical connection.
+ * o close HDLC link
+ * o drop DTR
+ *
+ * Return:	0
+ *		<0	error
+ */
+static int disconnect (sdla_t* card)
+{
+	wanpipe_set_state(card, WAN_DISCONNECTED);
+	x25_set_intr_mode(card, 0);	/* disable interrupt generation */
+	x25_close_hdlc(card);		/* close HDLC link */
+	x25_set_dtr(card, 0);		/* drop DTR */
+	return 0;
+}
+
+/*============================================================================
+ * Find network device by its channel number.
+ */
+static struct net_device* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn)
+{
+	struct net_device* dev;
+
+	for (dev = wandev->dev; dev; dev = dev->slave)
+		if (((x25_channel_t*)dev->priv)->lcn == lcn)
+			break;
+	return dev;
+}
+
+/*============================================================================
+ * Initiate connection on the logical channel.
+ * o for PVC we just get channel configuration
+ * o for SVCs place an X.25 call
+ *
+ * Return:	0	connected
+ *		>0	connection in progress
+ *		<0	failure
+ */
+static int chan_connect (struct net_device* dev)
+{
+	x25_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+
+	if (chan->svc)
+	{
+		if (!chan->addr[0])
+			return -EINVAL;	/* no destination address */
+		printk(KERN_INFO "%s: placing X.25 call to %s ...\n",
+			card->devname, chan->addr);
+		if (x25_place_call(card, chan) != CMD_OK)
+			return -EIO;
+		set_chan_state(dev, WAN_CONNECTING);
+		return 1;
+	}
+	else
+	{
+		if (x25_get_chan_conf(card, chan) != CMD_OK)
+			return -EIO;
+		set_chan_state(dev, WAN_CONNECTED);
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Disconnect logical channel.
+ * o if SVC then clear X.25 call
+ */
+static int chan_disc (struct net_device* dev)
+{
+	x25_channel_t* chan = dev->priv;
+
+	if (chan->svc)
+		x25_clear_call(chan->card, chan->lcn, 0, 0);
+	set_chan_state(dev, WAN_DISCONNECTED);
+	return 0;
+}
+
+/*============================================================================
+ * Set logical channel state.
+ */
+static void set_chan_state (struct net_device* dev, int state)
+{
+	x25_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	if (chan->state != state)
+	{
+		switch (state)
+		{
+			case WAN_CONNECTED:
+				printk (KERN_INFO "%s: interface %s connected!\n",
+					card->devname, dev->name);
+				*(unsigned short*)dev->dev_addr = htons(chan->lcn);
+				chan->i_timeout_sofar = jiffies;
+				break;
+
+			case WAN_CONNECTING:
+				printk (KERN_INFO "%s: interface %s connecting...\n",
+					card->devname, dev->name);
+				break;
+
+			case WAN_DISCONNECTED:
+				printk (KERN_INFO "%s: interface %s disconnected!\n",
+					card->devname, dev->name);
+				if (chan->svc) 
+				{
+					*(unsigned short*)dev->dev_addr = 0;
+		                	chan->lcn = 0;
+				}
+				break;
+		}
+		chan->state = state;
+	}
+	chan->state_tick = jiffies;
+	restore_flags(flags);
+}
+
+/*============================================================================
+ * Send packet on a logical channel.
+ *	When this function is called, tx_skb field of the channel data space
+ *	points to the transmit socket buffer.  When transmission is complete,
+ *	release socket buffer and reset 'tbusy' flag.
+ *
+ * Return:	0	- transmission complete
+ *		1	- busy
+ *
+ * Notes:
+ * 1. If packet length is greater than MTU for this channel, we'll fragment
+ *    the packet into 'complete sequence' using M-bit.
+ * 2. When transmission is complete, an event notification should be issued
+ *    to the router.
+ */
+static int chan_send (struct net_device* dev, struct sk_buff* skb)
+{
+	x25_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+	TX25Status* status = card->flags;
+	unsigned len, qdm;
+
+	/* Check to see if channel is ready */
+	if (!(status->cflags[chan->ch_idx] & 0x40))
+		return 1;
+
+	if (skb->len > chan->tx_pkt_size)
+	{
+		len = chan->tx_pkt_size;
+		qdm = 0x01;		/* set M-bit (more data) */
+	}
+	else	/* final packet */
+	{
+		len = skb->len;
+		qdm = 0;
+	}
+	switch(x25_send(card, chan->lcn, qdm, len, skb->data))
+	{
+		case 0x00:	/* success */
+			chan->i_timeout_sofar = jiffies;
+			if (qdm)
+			{
+				skb_pull(skb, len);
+				return 1;
+			}
+			++chan->ifstats.tx_packets;
+			chan->ifstats.tx_bytes += skb->len;
+			break;
+
+		case 0x33:	/* Tx busy */
+			return 1;
+
+		default:	/* failure */
+			++chan->ifstats.tx_errors;
+/*			return 1; */
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Parse X.25 call request data and fill x25_call_info_t structure.
+ */
+
+static void parse_call_info (unsigned char* str, x25_call_info_t* info)
+{
+	memset(info, 0, sizeof(x25_call_info_t));
+	for (; *str; ++str)
+	{
+		int i;
+		unsigned ch;
+
+		if (*str == '-') switch (str[1])
+		{
+			case 'd':	/* destination address */
+				for (i = 0; i < 16; ++i)
+				{
+					ch = str[2+i];
+					if (!is_digit(ch)) 
+						break;
+					info->dest[i] = ch;
+				}
+				break;
+	
+			case 's':	/* source address */
+				for (i = 0; i < 16; ++i)
+				{
+					ch = str[2+i];
+					if (!is_digit(ch))
+						break;
+					info->src[i] = ch;
+				}
+				break;
+
+			case 'u':	/* user data */
+				for (i = 0; i < 127; ++i)
+				{
+					ch = str[2+2*i];
+					if (!is_hex_digit(ch)) 
+						break;
+					info->user[i] = hex_to_uint(&str[2+2*i], 2);
+				}
+				info->nuser = i;
+				break;
+
+			case 'f':	/* facilities */
+				for (i = 0; i < 64; ++i)
+				{
+					ch = str[2+4*i];
+					if (!is_hex_digit(ch))
+						break;
+					info->facil[i].code =
+						hex_to_uint(&str[2+4*i], 2);
+					ch = str[4+4*i];
+					if (!is_hex_digit(ch))
+						break;
+					info->facil[i].parm =
+						hex_to_uint(&str[4+4*i], 2);
+				}
+				info->nfacil = i;
+				break;
+		}
+	}
+}
+
+/*============================================================================
+ * Convert line speed in bps to a number used by S502 code.
+ */
+static unsigned char bps_to_speed_code (unsigned long bps)
+{
+	unsigned char	number;
+
+	if (bps <= 1200)        number = 0x01 ;
+	else if (bps <= 2400)   number = 0x02;
+	else if (bps <= 4800)   number = 0x03;
+	else if (bps <= 9600)   number = 0x04;
+	else if (bps <= 19200)  number = 0x05;
+	else if (bps <= 38400)  number = 0x06;
+	else if (bps <= 45000)  number = 0x07;
+	else if (bps <= 56000)  number = 0x08;
+	else if (bps <= 64000)  number = 0x09;
+	else if (bps <= 74000)  number = 0x0A;
+	else if (bps <= 112000) number = 0x0B;
+	else if (bps <= 128000) number = 0x0C;
+	else number = 0x0D;
+
+	return number;
+}
+
+/*============================================================================
+ * Convert decimal string to unsigned integer.
+ * If len != 0 then only 'len' characters of the string are converted.
+ */
+static unsigned int dec_to_uint (unsigned char* str, int len)
+{
+	unsigned val;
+
+	if (!len) len = strlen(str);
+	for (val = 0; len && is_digit(*str); ++str, --len)
+		val = (val * 10) + (*str - (unsigned)'0');
+	return val;
+}
+
+/*============================================================================
+ * Convert hex string to unsigned integer.
+ * If len != 0 then only 'len' characters of the string are conferted.
+ */
+static unsigned int hex_to_uint (unsigned char* str, int len)
+{
+	unsigned val, ch;
+
+	if (!len) len = strlen(str);
+	for (val = 0; len; ++str, --len)
+	{
+		ch = *str;
+		if (is_digit(ch))
+			val = (val << 4) + (ch - (unsigned)'0');
+		else if (is_hex_digit(ch))
+			val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10);
+		else
+			break;
+	}
+	return val;
+}
+
+
+static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto)
+{
+	int i;
+
+	if( proto == htons(ETH_P_IPX) ) {
+		/* It's an IPX packet */
+		if(!enable_IPX) {
+			/* Return 1 so we don't pass it up the stack. */
+			return 1;
+		}
+	} else {
+		/* It's not IPX so pass it up the stack. */
+		return 0;
+	}
+
+	if( sendpacket[16] == 0x90 &&
+	    sendpacket[17] == 0x04)
+	{
+		/* It's IPXWAN */
+
+		if( sendpacket[2] == 0x02 &&
+		    sendpacket[34] == 0x00)
+		{
+			/* It's a timer request packet */
+			printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname);
+
+			/* Go through the routing options and answer no to every
+			 * option except Unnumbered RIP/SAP */
+			for(i = 41; sendpacket[i] == 0x00; i += 5)
+			{
+				/* 0x02 is the option for Unnumbered RIP/SAP */
+				if( sendpacket[i + 4] != 0x02)
+					sendpacket[i + 1] = 0;
+			}
+
+			/* Skip over the extended Node ID option */
+			if( sendpacket[i] == 0x04 )
+				i += 8;
+
+			/* We also want to turn off all header compression opt. */
+			for(; sendpacket[i] == 0x80 ;)
+			{
+				sendpacket[i + 1] = 0;
+				i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4;
+			}
+
+			/* Set the packet type to timer response */
+			sendpacket[34] = 0x01;
+
+			printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname);
+		}
+		else if( sendpacket[34] == 0x02 )
+		{
+			/* This is an information request packet */
+			printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname);
+
+			/* Set the packet type to information response */
+			sendpacket[34] = 0x03;
+
+			/* Set the router name */
+			sendpacket[51] = 'X';
+			sendpacket[52] = 'T';
+			sendpacket[53] = 'P';
+			sendpacket[54] = 'I';
+			sendpacket[55] = 'P';
+			sendpacket[56] = 'E';
+			sendpacket[57] = '-';
+			sendpacket[58] = CVHexToAscii(network_number >> 28);
+			sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24);
+			sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20);
+			sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16);
+			sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12);
+			sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8);
+			sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4);
+			sendpacket[65] = CVHexToAscii(network_number & 0x0000000F);
+			for(i = 66; i < 99; i+= 1)
+				sendpacket[i] = 0;
+
+			printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname);
+		}
+		else
+		{
+			printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname);
+			return 0;
+		}
+
+		/* Set the WNodeID to our network address */
+		sendpacket[35] = (unsigned char)(network_number >> 24);
+		sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16);
+		sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8);
+		sendpacket[38] = (unsigned char)(network_number & 0x000000FF);
+
+		return 1;
+	} else {
+		/* If we get here its an IPX-data packet, so it'll get passed up the stack.
+		   switch the network numbers */
+		switch_net_numbers(sendpacket, network_number, 1);	
+		return 0;
+	}
+}
+
+/*
+   If incoming is 0 (outgoing)- if the net numbers is ours make it 0
+   if incoming is 1 - if the net number is 0 make it ours 
+
+*/
+
+static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming)
+{
+	unsigned long pnetwork_number;
+
+	pnetwork_number = (unsigned long)((sendpacket[6] << 24) + 
+			  (sendpacket[7] << 16) + (sendpacket[8] << 8) + 
+			  sendpacket[9]);
+
+	if (!incoming) 
+	{
+		/* If the destination network number is ours, make it 0 */
+		if( pnetwork_number == network_number) 
+		{
+			sendpacket[6] = sendpacket[7] = sendpacket[8] = 
+					 sendpacket[9] = 0x00;
+		}
+	} 
+	else 
+	{
+		/* If the incoming network is 0, make it ours */
+		if( pnetwork_number == 0) 
+		{
+			sendpacket[6] = (unsigned char)(network_number >> 24);
+			sendpacket[7] = (unsigned char)((network_number & 
+					 0x00FF0000) >> 16);
+			sendpacket[8] = (unsigned char)((network_number & 
+					 0x0000FF00) >> 8);
+			sendpacket[9] = (unsigned char)(network_number & 
+					 0x000000FF);
+		}
+	}
+
+
+	pnetwork_number = (unsigned long)((sendpacket[18] << 24) + 
+			  (sendpacket[19] << 16) + (sendpacket[20] << 8) + 
+			  sendpacket[21]);
+
+	if( !incoming ) 
+	{
+		/* If the source network is ours, make it 0 */
+		if( pnetwork_number == network_number) 
+		{
+			sendpacket[18] = sendpacket[19] = sendpacket[20] = 
+					 sendpacket[21] = 0x00;
+		}
+	}
+	else
+	{
+		/* If the source network is 0, make it ours */
+		if( pnetwork_number == 0 ) 
+		{
+			sendpacket[18] = (unsigned char)(network_number >> 24);
+			sendpacket[19] = (unsigned char)((network_number & 
+					 0x00FF0000) >> 16);
+			sendpacket[20] = (unsigned char)((network_number & 
+					 0x0000FF00) >> 8);
+			sendpacket[21] = (unsigned char)(network_number & 
+					 0x000000FF);
+		}
+	}
+} /* switch_net_numbers */
+
+
+/****** End *****************************************************************/
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/sdladrv.c linux/drivers/net/wan/sdladrv.c
--- v2.3.20/linux/drivers/net/wan/sdladrv.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/sdladrv.c	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,1857 @@
+/*****************************************************************************
+* sdladrv.c	SDLA Support Module.  Main module.
+*
+*		This module is a library of common hardware-specific functions
+*		used by all Sangoma drivers.
+*
+* Author:	Gene Kozin	<genek@compuserve.com>
+* Fixes:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+*
+* Copyright:	(c) 1995-1996 Sangoma Technologies Inc.
+*
+*		This program is free software; you can redistribute it and/or
+*		modify it under the terms of the GNU General Public License
+*		as published by the Free Software Foundation; either version
+*		2 of the License, or (at your option) any later version.
+* ============================================================================
+* May 19, 1999	Arnaldo Melo	wanpipe_init belongs to sdlamain.c
+* Dec 20, 1996	Gene Kozin	Version 3.0.0. Complete overhaul.
+* Jul 12, 1996	Gene Kozin	Changes for Linux 2.0 compatibility.
+* Jun 12, 1996	Gene Kozin 	Added support for S503 card.
+* Apr 30, 1996	Gene Kozin	SDLA hardware interrupt is acknowledged before
+*				calling protocolspecific ISR.
+*				Register I/O ports with Linux kernel.
+*				Miscellaneous bug fixes.
+* Dec 20, 1995	Gene Kozin	Fixed a bug in interrupt routine.
+* Oct 14, 1995	Gene Kozin	Initial version.
+*****************************************************************************/
+
+/*****************************************************************************
+ * Notes:
+ * ------
+ * 1. This code is ment to be system-independent (as much as possible).  To
+ *    achive this, various macros are used to hide system-specific interfaces.
+ *    To compile this code, one of the following constants must be defined:
+ *
+ *	Platform	Define
+ *	--------	------
+ *	Linux		_LINUX_
+ *	SCO Unix	_SCO_UNIX_
+ *
+ * 2. Supported adapter types:
+ *
+ *	S502A
+ *	ES502A (S502E)
+ *	S503
+ *	S507
+ *	S508 (S509)
+ *
+ * 3. S502A Notes:
+ *
+ *	There is no separate DPM window enable/disable control in S502A.  It
+ *	opens immediately after a window number it written to the HMCR
+ *	register.  To close the window, HMCR has to be written a value
+ *	????1111b (e.g. 0x0F or 0xFF).
+ *
+ *	S502A DPM window cannot be located at offset E000 (e.g. 0xAE000).
+ *
+ *	There should be a delay of ??? before reading back S502A status
+ *	register.
+ *
+ * 4. S502E Notes:
+ *
+ *	S502E has a h/w bug: although default IRQ line state is HIGH, enabling
+ *	interrupts by setting bit 1 of the control register (BASE) to '1'
+ *	causes it to go LOW! Therefore, disabling interrupts by setting that
+ *	bit to '0' causes low-to-high transition on IRQ line (ghosty
+ *	interrupt). The same occurs when disabling CPU by resetting bit 0 of
+ *	CPU control register (BASE+3) - see the next note.
+ *
+ *	S502E CPU and DPM control is limited:
+ *
+ *	o CPU cannot be stopped independently. Resetting bit 0 of the CPUi
+ *	  control register (BASE+3) shuts the board down entirely, including
+ *	  DPM;
+ *
+ *	o DPM access cannot be controlled dynamically. Ones CPU is started,
+ *	  bit 1 of the control register (BASE) is used to enable/disable IRQ,
+ *	  so that access to shared memory cannot be disabled while CPU is
+ *	  running.
+ ****************************************************************************/
+
+#define	_LINUX_
+
+#if	defined(_LINUX_)	/****** Linux *******************************/
+
+#include <linux/kernel.h>	/* printk(), and other useful stuff */
+#include <linux/stddef.h>	/* offsetof(), etc. */
+#include <linux/errno.h>	/* return codes */
+#include <linux/string.h>	/* inline memset(), etc. */
+#include <linux/module.h>	/* support for loadable modules */
+#include <linux/sched.h>	/* for jiffies, HZ, etc. */
+#include <linux/sdladrv.h>	/* API definitions */
+#include <linux/sdlasfm.h>	/* SDLA firmware module definitions */
+#include <asm/io.h>		/* for inb(), outb(), etc. */
+#define _INB(port)		(inb(port))
+#define _OUTB(port, byte)	(outb((byte),(port)))
+#define	SYSTEM_TICK		jiffies
+
+#elif	defined(_SCO_UNIX_)	/****** SCO Unix ****************************/
+#if	!defined(INKERNEL)
+#error	This code MUST be compiled in kernel mode!
+#endif
+#include <sys/sdladrv.h>	/* API definitions */
+#include <sys/sdlasfm.h>	/* SDLA firmware module definitions */
+#include <sys/inline.h>		/* for inb(), outb(), etc. */
+#define _INB(port)		(inb(port))
+#define _OUTB(port, byte)	(outb((port),(byte)))
+#define	SYSTEM_TICK		lbolt
+
+#else
+#error	Unknown system type!
+#endif
+
+#define	MOD_VERSION	3
+#define	MOD_RELEASE	0
+
+#define	SDLA_IODELAY	100	/* I/O Rd/Wr delay, 10 works for 486DX2-66 */
+#define	EXEC_DELAY	20	/* shared memory access delay, mks */
+#define	EXEC_TIMEOUT	(HZ*2)	/* command timeout, in ticks */
+
+/* I/O port address range */
+#define S502A_IORANGE	3
+#define S502E_IORANGE	4
+#define S503_IORANGE	3
+#define S507_IORANGE	4
+#define S508_IORANGE	4
+
+/* Maximum amount of memory */
+#define S502_MAXMEM	0x10000L
+#define S503_MAXMEM	0x10000L
+#define S507_MAXMEM	0x40000L
+#define S508_MAXMEM	0x40000L
+
+/* Minimum amount of memory */
+#define S502_MINMEM	0x8000L
+#define S503_MINMEM	0x8000L
+#define S507_MINMEM	0x20000L
+#define S508_MINMEM	0x20000L
+
+/****** Function Prototypes *************************************************/
+
+/* Module entry points. These are called by the OS and must be public. */
+int init_module (void);
+void cleanup_module (void);
+
+/* Hardware-specific functions */
+static int sdla_detect	(sdlahw_t* hw);
+static int sdla_autodpm	(sdlahw_t* hw);
+static int sdla_setdpm	(sdlahw_t* hw);
+static int sdla_load	(sdlahw_t* hw, sfm_t* sfm, unsigned len);
+static int sdla_init	(sdlahw_t* hw);
+static unsigned long sdla_memtest (sdlahw_t* hw);
+static int sdla_bootcfg	(sdlahw_t* hw, sfm_info_t* sfminfo);
+static unsigned char make_config_byte (sdlahw_t* hw);
+static int sdla_start	(sdlahw_t* hw, unsigned addr);
+
+static int init_s502a	(sdlahw_t* hw);
+static int init_s502e	(sdlahw_t* hw);
+static int init_s503	(sdlahw_t* hw);
+static int init_s507	(sdlahw_t* hw);
+static int init_s508	(sdlahw_t* hw);
+
+static int detect_s502a	(int port);
+static int detect_s502e	(int port);
+static int detect_s503	(int port);
+static int detect_s507	(int port);
+static int detect_s508	(int port);
+
+/* Miscellaneous functions */
+static int calibrate_delay (int mks);
+static int get_option_index (unsigned* optlist, unsigned optval);
+static unsigned check_memregion (void* ptr, unsigned len);
+static unsigned	test_memregion (void* ptr, unsigned len);
+static unsigned short checksum (unsigned char* buf, unsigned len);
+
+/****** Global Data **********************************************************
+ * Note: All data must be explicitly initialized!!!
+ */
+
+/* private data */
+static char modname[]	= "sdladrv";
+static char fullname[]	= "SDLA Support Module";
+static char copyright[]	= "(c) 1995-1996 Sangoma Technologies Inc.";
+static unsigned	exec_idle;
+
+/* Hardware configuration options.
+ * These are arrays of configuration options used by verification routines.
+ * The first element of each array is its size (i.e. number of options).
+ */
+static unsigned	s502_port_options[] =
+	{ 4, 0x250, 0x300, 0x350, 0x360 }
+;
+static unsigned	s503_port_options[] =
+	{ 8, 0x250, 0x254, 0x300, 0x304, 0x350, 0x354, 0x360, 0x364 }
+;
+static unsigned	s508_port_options[] =
+	{ 8, 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390 }
+;
+
+static unsigned s502a_irq_options[] = { 0 };
+static unsigned s502e_irq_options[] = { 4, 2, 3, 5, 7 };
+static unsigned s503_irq_options[]  = { 5, 2, 3, 4, 5, 7 };
+static unsigned s508_irq_options[]  = { 8, 3, 4, 5, 7, 10, 11, 12, 15 };
+
+static unsigned s502a_dpmbase_options[] =
+{
+	28,
+	0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000,
+	0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000,
+	0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000,
+	0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000,
+};
+static unsigned s507_dpmbase_options[] =
+{
+	32,
+	0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000,
+	0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000,
+	0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000,
+	0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000,
+};
+static unsigned s508_dpmbase_options[] =	/* incl. S502E and S503 */
+{
+	32,
+	0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000,
+	0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000,
+	0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, 0xDE000,
+	0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000,
+};
+
+/*
+static unsigned	s502_dpmsize_options[] = { 2, 0x2000, 0x10000 };
+static unsigned	s507_dpmsize_options[] = { 2, 0x2000, 0x4000 };
+static unsigned	s508_dpmsize_options[] = { 1, 0x2000 };
+*/
+
+static unsigned	s502a_pclk_options[] = { 2, 3600, 7200 };
+static unsigned	s502e_pclk_options[] = { 5, 3600, 5000, 7200, 8000, 10000 };
+static unsigned	s503_pclk_options[]  = { 3, 7200, 8000, 10000 };
+static unsigned	s507_pclk_options[]  = { 1, 12288 };
+static unsigned	s508_pclk_options[]  = { 1, 16000 };
+
+/* Host memory control register masks */
+static unsigned char s502a_hmcr[] =
+{
+	0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C,	/* A0000 - AC000 */
+	0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C,	/* C0000 - CC000 */
+	0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C,	/* D0000 - DC000 */
+	0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C,	/* E0000 - EC000 */
+};
+static unsigned char s502e_hmcr[] =
+{
+	0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E,	/* A0000 - AE000 */
+	0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E,	/* C0000 - CE000 */
+	0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,	/* D0000 - DE000 */
+	0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E,	/* E0000 - EE000 */
+};
+static unsigned char s507_hmcr[] =
+{
+	0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,	/* A0000 - AE000 */
+	0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E,	/* B0000 - BE000 */
+	0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E,	/* C0000 - CE000 */
+	0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE,	/* E0000 - EE000 */
+};
+static unsigned char s508_hmcr[] =
+{
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,	/* A0000 - AE000 */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,	/* C0000 - CE000 */
+	0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,	/* D0000 - DE000 */
+	0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,	/* E0000 - EE000 */
+};
+
+static unsigned char s507_irqmask[] =
+{
+	0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0
+};
+
+/******* Kernel Loadable Module Entry Points ********************************/
+
+/*============================================================================
+ * Module 'insert' entry point.
+ * o print announcement
+ * o initialize static data
+ * o calibrate SDLA shared memory access delay.
+ *
+ * Return:	0	Ok
+ *		< 0	error.
+ * Context:	process
+ */
+
+#ifdef MODULE
+int init_module (void)
+{
+	printk(KERN_INFO "%s v%u.%u %s\n",
+		fullname, MOD_VERSION, MOD_RELEASE, copyright);
+	exec_idle = calibrate_delay(EXEC_DELAY);
+#ifdef WANDEBUG	
+	printk(KERN_DEBUG "%s: exec_idle = %d\n", modname, exec_idle);
+#endif	
+	return 0;
+}
+
+/*============================================================================
+ * Module 'remove' entry point.
+ * o release all remaining system resources
+ */
+void cleanup_module (void)
+{
+}
+#endif
+
+/******* Kernel APIs ********************************************************/
+
+/*============================================================================
+ * Set up adapter.
+ * o detect adapter type
+ * o verify hardware configuration options
+ * o check for hardware conflicts
+ * o set up adapter shared memory
+ * o test adapter memory
+ * o load firmware
+ * Return:	0	ok.
+ *		< 0	error
+ */
+ 
+EXPORT_SYMBOL(sdla_setup);
+
+int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len)
+{
+	unsigned* irq_opt	= NULL;	/* IRQ options */
+	unsigned* dpmbase_opt	= NULL;	/* DPM window base options */
+	unsigned* pclk_opt	= NULL;	/* CPU clock rate options */
+	int err;
+
+	if (sdla_detect(hw))
+	{
+		printk(KERN_ERR "%s: adapter S%04u not found at port 0x%X!\n",
+			modname, hw->type, hw->port)
+		;
+		return -EINVAL;
+	}
+	printk(KERN_INFO "%s: found S%04u card at port 0x%X.\n",
+		modname, hw->type, hw->port)
+	;
+
+	hw->dpmsize = SDLA_WINDOWSIZE;
+	switch (hw->type)
+	{
+	case SDLA_S502A:
+		hw->io_range	= S502A_IORANGE;
+		irq_opt		= s502a_irq_options;
+		dpmbase_opt	= s502a_dpmbase_options;
+		pclk_opt	= s502a_pclk_options;
+		break;
+
+	case SDLA_S502E:
+		hw->io_range	= S502E_IORANGE;
+		irq_opt		= s502e_irq_options;
+		dpmbase_opt	= s508_dpmbase_options;
+		pclk_opt	= s502e_pclk_options;
+		break;
+
+	case SDLA_S503:
+		hw->io_range	= S503_IORANGE;
+		irq_opt		= s503_irq_options;
+		dpmbase_opt	= s508_dpmbase_options;
+		pclk_opt	= s503_pclk_options;
+		break;
+
+	case SDLA_S507:
+		hw->io_range	= S507_IORANGE;
+		irq_opt		= s508_irq_options;
+		dpmbase_opt	= s507_dpmbase_options;
+		pclk_opt	= s507_pclk_options;
+		break;
+
+	case SDLA_S508:
+		hw->io_range	= S508_IORANGE;
+		irq_opt		= s508_irq_options;
+		dpmbase_opt	= s508_dpmbase_options;
+		pclk_opt	= s508_pclk_options;
+		break;
+	}
+
+	/* Verify IRQ configuration options */
+	if (!get_option_index(irq_opt, hw->irq))
+	{
+		printk(KERN_ERR "%s: IRQ %d is illegal!\n",
+			modname, hw->irq)
+		;
+		return -EINVAL;
+	} 
+
+	/* Verify CPU clock rate configuration options */
+	if (hw->pclk == 0)
+		hw->pclk = pclk_opt[1]	/* use default */
+	;
+	else if (!get_option_index(pclk_opt, hw->pclk))
+	{
+		printk(KERN_ERR "%s: CPU clock %u is illegal!\n",
+			modname, hw->pclk)
+		;
+		return -EINVAL;
+	} 
+	printk(KERN_INFO "%s: assuming CPU clock rate of %u kHz.\n",
+		modname, hw->pclk)
+	;
+
+	/* Setup adapter dual-port memory window and test memory */
+	if (hw->dpmbase == 0)
+	{
+		err = sdla_autodpm(hw);
+		if (err)
+		{
+			printk(KERN_ERR
+				"%s: can't find available memory region!\n",
+				modname)
+			;
+ 			return err;
+		}
+	}
+	else if (!get_option_index(dpmbase_opt, virt_to_phys(hw->dpmbase)))
+	{
+		printk(KERN_ERR "%s: memory address 0x%lX is illegal!\n",
+			modname, virt_to_phys(hw->dpmbase))
+		;
+		return -EINVAL;
+	} 
+	else if (sdla_setdpm(hw))
+	{
+		printk(KERN_ERR
+			"%s: 8K memory region at 0x%lX is not available!\n",
+			modname, virt_to_phys(hw->dpmbase));
+		return -EINVAL;
+	} 
+	printk(KERN_INFO "%s: dual-port memory window is set at 0x%lX.\n",
+		modname, virt_to_phys(hw->dpmbase));
+
+	printk(KERN_INFO "%s: found %luK bytes of on-board memory.\n",
+		modname, hw->memory / 1024);
+
+	/* Load firmware. If loader fails then shut down adapter */
+	err = sdla_load(hw, sfm, len);
+	if (err) sdla_down(hw);		/* shutdown adapter */
+	return err;
+} 
+
+/*============================================================================
+ * Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc.
+ */
+
+EXPORT_SYMBOL(sdla_down);
+
+int sdla_down (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+	int i;
+
+	if (!port) return -EFAULT;
+
+	switch (hw->type)
+	{
+	case SDLA_S502A:
+		_OUTB(port, 0x08);		/* halt CPU */
+		_OUTB(port, 0x08);
+		_OUTB(port, 0x08);
+		hw->regs[0] = 0x08;
+		_OUTB(port + 1, 0xFF);		/* close memory window */
+		hw->regs[1] = 0xFF;
+		break;
+
+	case SDLA_S502E:
+		_OUTB(port + 3, 0);		/* stop CPU */
+		_OUTB(port, 0);			/* reset board */
+		for (i = 0; i < S502E_IORANGE; ++i)
+			hw->regs[i] = 0
+		;
+		break;
+
+	case SDLA_S503:
+	case SDLA_S507:
+	case SDLA_S508:
+		_OUTB(port, 0);			/* reset board logic */
+		hw->regs[0] = 0;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Map shared memory window into SDLA address space.
+ */
+
+EXPORT_SYMBOL(sdla_mapmem);
+
+int sdla_mapmem (sdlahw_t* hw, unsigned long addr)
+{
+	unsigned port = hw->port;
+	register int tmp;
+
+	switch (hw->type)
+	{
+	case SDLA_S502A:
+	case SDLA_S502E:
+		if (addr < S502_MAXMEM)	/* verify parameter */
+		{
+			tmp = addr >> 13;	/* convert to register mask */
+			_OUTB(port + 2, tmp);
+			hw->regs[2] = tmp;
+		}
+		else return -EINVAL;
+		break;
+
+	case SDLA_S503:
+		if (addr < S503_MAXMEM)	/* verify parameter */
+		{
+			tmp = (hw->regs[0] & 0x8F) | ((addr >> 9) & 0x70);
+			_OUTB(port, tmp);
+			hw->regs[0] = tmp;
+		}
+		else return -EINVAL;
+		break;
+
+	case SDLA_S507:
+		if (addr < S507_MAXMEM)
+		{
+			if (!(_INB(port) & 0x02))
+				return -EIO
+			;
+			tmp = addr >> 13;	/* convert to register mask */
+			_OUTB(port + 2, tmp);
+			hw->regs[2] = tmp;
+		}
+		else return -EINVAL;
+		break;
+
+	case SDLA_S508:
+		if (addr < S508_MAXMEM)
+		{
+			tmp = addr >> 13;	/* convert to register mask */
+			_OUTB(port + 2, tmp);
+			hw->regs[2] = tmp;
+		}
+		else return -EINVAL;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	hw->vector = addr & 0xFFFFE000L;
+	return 0;
+}
+
+/*============================================================================
+ * Enable interrupt generation.
+ */
+ 
+EXPORT_SYMBOL(sdla_inten);
+
+int sdla_inten (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+	int tmp, i;
+
+	switch (hw->type)
+	{
+	case SDLA_S502E:
+		/* Note thar interrupt control operations on S502E are allowed
+		 * only if CPU is enabled (bit 0 of status register is set).
+		 */
+		if (_INB(port) & 0x01)
+		{
+			_OUTB(port, 0x02);	/* bit1 = 1, bit2 = 0 */
+			_OUTB(port, 0x06);	/* bit1 = 1, bit2 = 1 */
+			hw->regs[0] = 0x06;
+		}
+		else return -EIO;
+		break;
+
+	case SDLA_S503:
+		tmp = hw->regs[0] | 0x04;
+		_OUTB(port, tmp);
+		hw->regs[0] = tmp;		/* update mirror */
+		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+		if (!(_INB(port) & 0x02))		/* verify */
+			return -EIO
+		;
+		break;
+
+	case SDLA_S508:
+		tmp = hw->regs[0] | 0x10;
+		_OUTB(port, tmp);
+		hw->regs[0] = tmp;		/* update mirror */
+		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+		if (!(_INB(port + 1) & 0x10))		/* verify */
+			return -EIO
+		;
+		break;
+
+	case SDLA_S502A:
+	case SDLA_S507:
+		break;
+
+	default:
+		return -EINVAL;
+
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Disable interrupt generation.
+ */
+
+EXPORT_SYMBOL(sdla_intde);
+
+int sdla_intde (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+	int tmp, i;
+
+	switch (hw->type)
+	{
+	case SDLA_S502E:
+		/* Notes:
+		 *  1) interrupt control operations are allowed only if CPU is
+		 *     enabled (bit 0 of status register is set).
+		 *  2) disabling interrupts using bit 1 of control register
+		 *     causes IRQ line go high, therefore we are going to use
+		 *     0x04 instead: lower it to inhibit interrupts to PC.
+		 */
+		if (_INB(port) & 0x01)
+		{
+			_OUTB(port, hw->regs[0] & ~0x04);
+			hw->regs[0] &= ~0x04;
+		}
+		else return -EIO;
+		break;
+
+	case SDLA_S503:
+		tmp = hw->regs[0] & ~0x04;
+		_OUTB(port, tmp);
+		hw->regs[0] = tmp;			/* update mirror */
+		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+		if (_INB(port) & 0x02)			/* verify */
+			return -EIO
+		;
+		break;
+
+	case SDLA_S508:
+		tmp = hw->regs[0] & ~0x10;
+		_OUTB(port, tmp);
+		hw->regs[0] = tmp;			/* update mirror */
+		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+		if (_INB(port) & 0x10)			/* verify */
+			return -EIO
+		;
+		break;
+
+	case SDLA_S502A:
+	case SDLA_S507:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Acknowledge SDLA hardware interrupt.
+ */
+
+EXPORT_SYMBOL(sdla_intack);
+
+int sdla_intack (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+	int tmp;
+
+	switch (hw->type)
+	{
+	case SDLA_S502E:
+		/* To acknoledge hardware interrupt we have to toggle bit 3 of
+		 * control register: \_/
+		 * Note that interrupt control operations on S502E are allowed
+		 * only if CPU is enabled (bit 1 of status register is set).
+		 */
+		if (_INB(port) & 0x01)
+		{
+			tmp = hw->regs[0] & ~0x04;
+			_OUTB(port, tmp);
+			tmp |= 0x04;
+			_OUTB(port, tmp);
+			hw->regs[0] = tmp;
+		}
+		else return -EIO;
+		break;
+
+	case SDLA_S503:
+		if (_INB(port) & 0x04)
+		{
+			tmp = hw->regs[0] & ~0x08;
+			_OUTB(port, tmp);
+			tmp |= 0x08;
+			_OUTB(port, tmp);
+			hw->regs[0] = tmp;
+		}
+		break;
+
+	case SDLA_S502A:
+	case SDLA_S507:
+	case SDLA_S508:
+	break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Generate an interrupt to adapter's CPU.
+ */
+
+EXPORT_SYMBOL(sdla_intr);
+
+int sdla_intr (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+
+	switch (hw->type)
+	{
+	case SDLA_S502A:
+		if (!(_INB(port) & 0x40))
+		{
+			_OUTB(port, 0x10);		/* issue NMI to CPU */
+			hw->regs[0] = 0x10;
+		}
+		else return -EIO;
+		break;
+
+	case SDLA_S507:
+		if ((_INB(port) & 0x06) == 0x06)
+		{
+			_OUTB(port + 3, 0);
+		}
+		else return -EIO;
+		break;
+
+	case SDLA_S508:
+		if (_INB(port + 1) & 0x02)
+		{
+			_OUTB(port, 0x08);
+		}
+		else return -EIO;
+		break;
+
+	case SDLA_S502E:
+	case SDLA_S503:
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Execute Adapter Command.
+ * o Set exec flag.
+ * o Busy-wait until flag is reset.
+ * o Return number of loops made, or 0 if command timed out.
+ */
+
+EXPORT_SYMBOL(sdla_exec);
+
+int sdla_exec (void* opflag)
+{
+	volatile unsigned char* flag = opflag;
+	unsigned long tstop;
+	int nloops;
+
+	if (*flag) return 0;	/* ???? */
+
+	*flag = 1;
+	tstop = SYSTEM_TICK + EXEC_TIMEOUT;
+	for (nloops = 1; *flag; ++nloops)
+	{
+		unsigned delay = exec_idle;
+		while (--delay);			/* delay */
+		if (SYSTEM_TICK > tstop) return 0;	/* time is up! */
+	}
+	return nloops;
+}
+
+/*============================================================================
+ * Read absolute adapter memory.
+ * Transfer data from adapter's memory to data buffer.
+ *
+ * Note:
+ * Care should be taken when crossing dual-port memory window boundary.
+ * This function is not atomic, so caller must disable interrupt if
+ * interrupt routines are accessing adapter shared memory.
+ */
+ 
+EXPORT_SYMBOL(sdla_peek);
+
+int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len)
+{
+	unsigned long oldvec = hw->vector;
+	unsigned winsize = hw->dpmsize;
+	unsigned curpos, curlen;	/* current offset and block size */
+	unsigned long curvec;		/* current DPM window vector */
+	int err = 0;
+
+	if (addr + len > hw->memory)	/* verify arguments */
+		return -EINVAL
+	;
+	while (len && !err)
+	{
+		curpos = addr % winsize;	/* current window offset */
+		curvec = addr - curpos;		/* current window vector */
+		curlen = (len > (winsize - curpos)) ? (winsize - curpos) : len;
+
+		/* Relocate window and copy block of data */
+		err = sdla_mapmem(hw, curvec);
+		memcpy(buf, (void *)((u8 *)hw->dpmbase + curpos), curlen);
+		addr       += curlen;
+		(char*)buf += curlen;
+		len        -= curlen;
+	}
+
+	/* Restore DPM window position */
+	sdla_mapmem(hw, oldvec);
+	return err;
+}
+
+/*============================================================================
+ * Write Absolute Adapter Memory.
+ * Transfer data from data buffer to adapter's memory.
+ *
+ * Note:
+ * Care should be taken when crossing dual-port memory window boundary.
+ * This function is not atomic, so caller must disable interrupt if
+ * interrupt routines are accessing adapter shared memory.
+ */
+ 
+EXPORT_SYMBOL(sdla_poke);
+ 
+int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len)
+{
+	unsigned long oldvec = hw->vector;
+	unsigned winsize = hw->dpmsize;
+	unsigned curpos, curlen;	/* current offset and block size */
+	unsigned long curvec;		/* current DPM window vector */
+	int err = 0;
+
+	if (addr + len > hw->memory)	/* verify arguments */
+		return -EINVAL
+	;
+	while (len && !err)
+	{
+		curpos = addr % winsize;	/* current window offset */
+		curvec = addr - curpos;		/* current window vector */
+		curlen = (len > (winsize - curpos)) ? (winsize - curpos) : len;
+
+		/* Relocate window and copy block of data */
+		sdla_mapmem(hw, curvec);
+		memcpy((void*)((u8 *)hw->dpmbase + curpos), buf, curlen);
+		addr       += curlen;
+		(char*)buf += curlen;
+		len        -= curlen;
+	}
+
+	/* Restore DPM window position */
+	sdla_mapmem(hw, oldvec);
+	return err;
+}
+
+#ifdef	DONT_COMPIPLE_THIS
+#endif	/* DONT_COMPIPLE_THIS */
+
+/****** Hardware-Specific Functions *****************************************/
+
+/*============================================================================
+ * Detect adapter type.
+ * o if adapter type is specified then call detection routine for that adapter
+ *   type.  Otherwise call detection routines for every adapter types until
+ *   adapter is detected.
+ *
+ * Notes:
+ * 1) Detection tests are destructive! Adapter will be left in shutdown state
+ *    after the test.
+ */
+static int sdla_detect (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+	int err = 0;
+
+	if (!port)
+		return -EFAULT
+	;
+	switch (hw->type)
+	{
+	case SDLA_S502A:
+		if (!detect_s502a(port)) err = -ENODEV;
+		break;
+
+	case SDLA_S502E:
+		if (!detect_s502e(port)) err = -ENODEV;
+		break;
+
+	case SDLA_S503:
+		if (!detect_s503(port)) err = -ENODEV;
+		break;
+
+	case SDLA_S507:
+		if (!detect_s507(port)) err = -ENODEV;
+		break;
+
+	case SDLA_S508:
+		if (!detect_s508(port)) err = -ENODEV;
+		break;
+
+	default:
+		if (detect_s502a(port))
+			hw->type = SDLA_S502A
+		;
+		else if (detect_s502e(port))
+			hw->type = SDLA_S502E
+		;
+		else if (detect_s503(port))
+			hw->type = SDLA_S503
+		;
+		else if (detect_s507(port))
+			hw->type = SDLA_S507
+		;
+		else if (detect_s508(port))
+			hw->type = SDLA_S508
+		;
+		else err = -ENODEV;
+	}
+	return err;
+}
+
+/*============================================================================
+ * Autoselect memory region. 
+ * o try all available DMP address options from the top down until success.
+ */
+static int sdla_autodpm (sdlahw_t* hw)
+{
+	int i, err = -EINVAL;
+	unsigned* opt;
+
+	switch (hw->type)
+	{
+	case SDLA_S502A:
+		opt = s502a_dpmbase_options;
+		break;
+
+	case SDLA_S502E:
+	case SDLA_S503:
+	case SDLA_S508:
+		opt = s508_dpmbase_options;
+		break;
+
+	case SDLA_S507:
+		opt = s507_dpmbase_options;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	for (i = opt[0]; i && err; --i)
+	{
+		hw->dpmbase = phys_to_virt(opt[i]);
+		err = sdla_setdpm(hw);
+	}
+	return err;
+}
+
+/*============================================================================
+ * Set up adapter dual-port memory window. 
+ * o shut down adapter
+ * o make sure that no physical memory exists in this region, i.e entire
+ *   region reads 0xFF and is not writable when adapter is shut down.
+ * o initialize adapter hardware
+ * o make sure that region is usable with SDLA card, i.e. we can write to it
+ *   when adapter is configured.
+ */
+static int sdla_setdpm (sdlahw_t* hw)
+{
+	int err;
+
+	/* Shut down card and verify memory region */
+	sdla_down(hw);
+	if (check_memregion(hw->dpmbase, hw->dpmsize))
+		return -EINVAL
+	;
+
+	/* Initialize adapter and test on-board memory segment by segment.
+	 * If memory size appears to be less than shared memory window size,
+	 * assume that memory region is unusable.
+	 */
+	err = sdla_init(hw);
+	if (err) return err;
+
+	if (sdla_memtest(hw) < hw->dpmsize)	/* less than window size */
+	{
+		sdla_down(hw);
+		return -EIO;
+	}
+	sdla_mapmem(hw, 0L);	/* set window vector at bottom */
+	return 0;
+}
+
+/*============================================================================
+ * Load adapter from the memory image of the SDLA firmware module. 
+ * o verify firmware integrity and compatibility
+ * o start adapter up
+ */
+static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len)
+{
+	int i;
+
+	/* Verify firmware signature */
+	if (strcmp(sfm->signature, SFM_SIGNATURE))
+	{
+		printk(KERN_ERR "%s: not SDLA firmware!\n",
+			modname)
+		;
+		return -EINVAL;
+	}
+
+	/* Verify firmware module format version */
+	if (sfm->version != SFM_VERSION)
+	{
+		printk(KERN_ERR
+			"%s: firmware format %u rejected! Expecting %u.\n",
+			modname, sfm->version, SFM_VERSION)
+		;
+		return -EINVAL;
+	}
+
+	/* Verify firmware module length and checksum */
+	if ((len - offsetof(sfm_t, image) != sfm->info.codesize) ||
+		(checksum((void*)&sfm->info,
+		sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum))
+	{
+		printk(KERN_ERR "%s: firmware corrupted!\n", modname);
+		return -EINVAL;
+	}
+
+	/* Announce */
+	printk(KERN_INFO "%s: loading %s (ID=%u)...\n", modname,
+		(sfm->descr[0] != '\0') ? sfm->descr : "unknown firmware",
+		sfm->info.codeid)
+	;
+
+	/* Scan through the list of compatible adapters and make sure our
+	 * adapter type is listed.
+	 */
+	for (i = 0;
+	     (i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hw->type);
+	     ++i)
+	;
+	if (i == SFM_MAX_SDLA)
+	{
+		printk(KERN_ERR "%s: firmware is not compatible with S%u!\n",
+			modname, hw->type)
+		;
+		return -EINVAL;
+	}
+
+	/* Make sure there is enough on-board memory */
+	if (hw->memory < sfm->info.memsize)
+	{
+		printk(KERN_ERR
+			"%s: firmware needs %lu bytes of on-board memory!\n",
+			modname, sfm->info.memsize)
+		;
+		return -EINVAL;
+	}
+
+	/* Move code onto adapter */
+	if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize))
+	{
+		printk(KERN_ERR "%s: failed to load code segment!\n",
+			modname)
+		;
+		return -EIO;
+	}
+
+	/* Prepare boot-time configuration data and kick-off CPU */
+	sdla_bootcfg(hw, &sfm->info);
+	if (sdla_start(hw, sfm->info.startoffs))
+	{
+		printk(KERN_ERR "%s: Damn... Adapter won't start!\n",
+			modname)
+		;
+		return -EIO;
+	}
+
+	/* position DPM window over the mailbox and enable interrupts */
+        if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw))
+	{
+		printk(KERN_ERR "%s: adapter hardware failure!\n",
+			modname)
+		;
+		return -EIO;
+	}
+	hw->fwid = sfm->info.codeid;		/* set firmware ID */
+	return 0;
+}
+
+/*============================================================================
+ * Initialize SDLA hardware: setup memory window, IRQ, etc.
+ */
+static int sdla_init (sdlahw_t* hw)
+{
+	int i;
+
+	for (i = 0; i < SDLA_MAXIORANGE; ++i)
+		hw->regs[i] = 0
+	;
+	switch (hw->type)
+	{
+	case SDLA_S502A: return init_s502a(hw);
+	case SDLA_S502E: return init_s502e(hw);
+	case SDLA_S503:  return init_s503(hw);
+	case SDLA_S507:  return init_s507(hw);
+	case SDLA_S508:  return init_s508(hw);
+	}
+	return -EINVAL;
+}
+
+/*============================================================================
+ * Test adapter on-board memory.
+ * o slide DPM window from the bottom up and test adapter memory segment by
+ *   segment.
+ * Return adapter memory size.
+ */
+static unsigned long sdla_memtest (sdlahw_t* hw)
+{
+	unsigned long memsize;
+	unsigned winsize;
+
+	for (memsize = 0, winsize = hw->dpmsize;
+	     !sdla_mapmem(hw, memsize) &&
+		(test_memregion(hw->dpmbase, winsize) == winsize)
+	     ;
+	     memsize += winsize)
+	;
+	hw->memory = memsize;
+	return memsize;
+}
+
+/*============================================================================
+ * Prepare boot-time firmware configuration data.
+ * o position DPM window
+ * o initialize configuration data area
+ */
+static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo)
+{
+	unsigned char* data;
+
+	if (!sfminfo->datasize) return 0;	/* nothing to do */
+
+	if (sdla_mapmem(hw, sfminfo->dataoffs) != 0)
+		return -EIO
+	;
+	data = (void*)((u8 *)hw->dpmbase + (sfminfo->dataoffs - hw->vector));
+	memset(data, 0, sfminfo->datasize);
+
+	data[0x00] = make_config_byte(hw);
+	switch (sfminfo->codeid)
+	{
+	case SFID_X25_502:
+	case SFID_X25_508:
+		data[0x01] = 3;			/* T1 timer */
+		data[0x03] = 10;		/* N2 */
+		data[0x06] = 7;			/* HDLC window size */
+		data[0x0B] = 1;			/* DTE */
+		data[0x0C] = 2;			/* X.25 packet window size */
+		*(short*)&data[0x0D] = 128;	/* default X.25 data size */
+		*(short*)&data[0x0F] = 128;	/* maximum X.25 data size */
+		break;
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Prepare configuration byte identifying adapter type and CPU clock rate.
+ */
+static unsigned char make_config_byte (sdlahw_t* hw)
+{
+	unsigned char byte = 0;
+
+	switch (hw->pclk)
+	{
+		case 5000:  byte = 0x01; break;
+		case 7200:  byte = 0x02; break;
+		case 8000:  byte = 0x03; break;
+		case 10000: byte = 0x04; break;
+		case 16000: byte = 0x05; break;
+	}
+	switch (hw->type)
+	{
+		case SDLA_S502E: byte |= 0x80; break;
+		case SDLA_S503:  byte |= 0x40; break;
+	}
+	return byte;
+}
+
+/*============================================================================
+ * Start adapter's CPU.
+ * o calculate a pointer to adapter's cold boot entry point
+ * o position DPM window
+ * o place boot instruction (jp addr) at cold boot entry point
+ * o start CPU
+ */
+static int sdla_start (sdlahw_t* hw, unsigned addr)
+{
+	unsigned port = hw->port;
+	unsigned char *bootp;
+	int err, tmp, i;
+
+	if (!port) return -EFAULT;
+
+	switch (hw->type)
+	{
+	case SDLA_S502A:
+		bootp = hw->dpmbase;
+		bootp += 0x66;
+		break;
+
+	case SDLA_S502E:
+	case SDLA_S503:
+	case SDLA_S507:
+	case SDLA_S508:
+		bootp = hw->dpmbase;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	err = sdla_mapmem(hw, 0);
+	if (err) return err;
+
+	*bootp = 0xC3;	 /* Z80: 'jp' opcode */
+	bootp++;
+	*((unsigned short*)(bootp)) = addr;
+
+	switch (hw->type)
+	{
+	case SDLA_S502A:
+		_OUTB(port, 0x10);		/* issue NMI to CPU */
+		hw->regs[0] = 0x10;
+		break;
+
+	case SDLA_S502E:
+		_OUTB(port + 3, 0x01);		/* start CPU */
+		hw->regs[3] = 0x01;
+		for (i = 0; i < SDLA_IODELAY; ++i);
+		if (_INB(port) & 0x01)		/* verify */
+		{
+			/*
+			 * Enabling CPU changes functionality of the
+			 * control register, so we have to reset its
+			 * mirror.
+			 */
+			_OUTB(port, 0);		/* disable interrupts */
+			hw->regs[0] = 0;
+		}
+		else return -EIO;
+		break;
+
+	case SDLA_S503:
+		tmp = hw->regs[0] | 0x09;	/* set bits 0 and 3 */
+		_OUTB(port, tmp);
+		hw->regs[0] = tmp;		/* update mirror */
+		for (i = 0; i < SDLA_IODELAY; ++i);
+		if (!(_INB(port) & 0x01))	/* verify */
+			return -EIO
+		;
+		break;
+
+	case SDLA_S507:
+		tmp = hw->regs[0] | 0x02;
+		_OUTB(port, tmp);
+		hw->regs[0] = tmp;		/* update mirror */
+		for (i = 0; i < SDLA_IODELAY; ++i);
+		if (!(_INB(port) & 0x04))	/* verify */
+			return -EIO
+		;
+		break;
+
+	case SDLA_S508:
+		tmp = hw->regs[0] | 0x02;
+		_OUTB(port, tmp);
+		hw->regs[0] = tmp;	/* update mirror */
+		for (i = 0; i < SDLA_IODELAY; ++i);
+		if (!(_INB(port + 1) & 0x02))	/* verify */
+			return -EIO
+		;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Initialize S502A adapter.
+ */
+static int init_s502a (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+	int tmp, i;
+
+	if (!detect_s502a(port))
+		return -ENODEV
+	;
+	hw->regs[0] = 0x08;
+	hw->regs[1] = 0xFF;
+
+	/* Verify configuration options */
+	i = get_option_index(s502a_dpmbase_options, virt_to_phys(hw->dpmbase));
+	if (i == 0)
+		return -EINVAL
+	;
+
+	tmp = s502a_hmcr[i - 1];
+	switch (hw->dpmsize)
+	{
+	case 0x2000:
+		tmp |= 0x01;
+		break;
+
+	case 0x10000L:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Setup dual-port memory window (this also enables memory access) */
+	_OUTB(port + 1, tmp);
+	hw->regs[1] = tmp;
+	hw->regs[0] = 0x08;
+	return 0;
+}
+
+/*============================================================================
+ * Initialize S502E adapter.
+ */
+static int init_s502e (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+	int tmp, i;
+
+	if (!detect_s502e(port))
+		return -ENODEV
+	;
+
+	/* Verify configuration options */
+	i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase));
+	if (i == 0)
+		return -EINVAL
+	;
+
+	tmp = s502e_hmcr[i - 1];
+	switch (hw->dpmsize)
+	{
+	case 0x2000:
+		tmp |= 0x01;
+		break;
+
+	case 0x10000L:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Setup dual-port memory window */
+	_OUTB(port + 1, tmp);
+	hw->regs[1] = tmp;
+
+	/* Enable memory access */
+	_OUTB(port, 0x02);
+	hw->regs[0] = 0x02;
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	return (_INB(port) & 0x02) ? 0 : -EIO;
+}
+
+/*============================================================================
+ * Initialize S503 adapter.
+ * ---------------------------------------------------------------------------
+ */
+static int init_s503 (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+	int tmp, i;
+
+	if (!detect_s503(port))
+		return -ENODEV
+	;
+
+	/* Verify configuration options */
+	i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase));
+	if (i == 0)
+		return -EINVAL
+	;
+
+	tmp = s502e_hmcr[i - 1];
+	switch (hw->dpmsize)
+	{
+	case 0x2000:
+		tmp |= 0x01;
+		break;
+
+	case 0x10000L:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Setup dual-port memory window */
+	_OUTB(port + 1, tmp);
+	hw->regs[1] = tmp;
+
+	/* Enable memory access */
+	_OUTB(port, 0x02);
+	hw->regs[0] = 0x02;	/* update mirror */
+	return 0;
+}
+
+/*============================================================================
+ * Initialize S507 adapter.
+ */
+static int init_s507 (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+	int tmp, i;
+
+	if (!detect_s507(port))
+		return -ENODEV
+	;
+
+	/* Verify configuration options */
+	i = get_option_index(s507_dpmbase_options, virt_to_phys(hw->dpmbase));
+	if (i == 0)
+		return -EINVAL
+	;
+
+	tmp = s507_hmcr[i - 1];
+	switch (hw->dpmsize)
+	{
+	case 0x2000:
+		tmp |= 0x01;
+		break;
+
+	case 0x10000L:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Enable adapter's logic */
+	_OUTB(port, 0x01);
+	hw->regs[0] = 0x01;
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if (!(_INB(port) & 0x20))
+		return -EIO
+	;
+
+	/* Setup dual-port memory window */
+	_OUTB(port + 1, tmp);
+	hw->regs[1] = tmp;
+
+	/* Enable memory access */
+	tmp = hw->regs[0] | 0x04;
+	if (hw->irq)
+	{
+		i = get_option_index(s508_irq_options, hw->irq);
+		if (i) tmp |= s507_irqmask[i - 1];
+	}
+	_OUTB(port, tmp);
+	hw->regs[0] = tmp;		/* update mirror */
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	return (_INB(port) & 0x08) ? 0 : -EIO;
+}
+
+/*============================================================================
+ * Initialize S508 adapter.
+ */
+static int init_s508 (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+	int tmp, i;
+
+	if (!detect_s508(port))
+		return -ENODEV
+	;
+
+	/* Verify configuration options */
+	i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase));
+	if (i == 0)
+		return -EINVAL
+	;
+
+	/* Setup memory configuration */
+	tmp = s508_hmcr[i - 1];
+	_OUTB(port + 1, tmp);
+	hw->regs[1] = tmp;
+
+	/* Enable memory access */
+	_OUTB(port, 0x04);
+	hw->regs[0] = 0x04;		/* update mirror */
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	return (_INB(port + 1) & 0x04) ? 0 : -EIO;
+}
+
+/*============================================================================
+ * Detect S502A adapter.
+ *	Following tests are used to detect S502A adapter:
+ *	1. All registers other than status (BASE) should read 0xFF
+ *	2. After writing 00001000b to control register, status register should
+ *	   read 01000000b.
+ *	3. After writing 0 to control register, status register should still
+ *	   read  01000000b.
+ *	4. After writing 00000100b to control register, status register should
+ *	   read 01000100b.
+ *	Return 1 if detected o.k. or 0 if failed.
+ *	Note:	This test is destructive! Adapter will be left in shutdown
+ *		state after the test.
+ */
+static int detect_s502a (int port)
+{
+	int i, j;
+
+	if (!get_option_index(s502_port_options, port))
+		return 0
+	;
+	for (j = 1; j < SDLA_MAXIORANGE; ++j)
+	{
+		if (_INB(port + j) != 0xFF)
+			return 0
+		;
+		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	}
+
+	_OUTB(port, 0x08);			/* halt CPU */
+	_OUTB(port, 0x08);
+	_OUTB(port, 0x08);
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if (_INB(port) != 0x40)
+		return 0
+	;
+	_OUTB(port, 0x00);
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if (_INB(port) != 0x40)
+		return 0
+	;
+	_OUTB(port, 0x04);
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if (_INB(port) != 0x44)
+		return 0
+	;
+
+	/* Reset adapter */
+	_OUTB(port, 0x08);
+	_OUTB(port, 0x08);
+	_OUTB(port, 0x08);
+	_OUTB(port + 1, 0xFF);
+	return 1;
+}
+
+/*============================================================================
+ * Detect S502E adapter.
+ *	Following tests are used to verify adapter presence:
+ *	1. All registers other than status (BASE) should read 0xFF.
+ *	2. After writing 0 to CPU control register (BASE+3), status register
+ *	   (BASE) should read 11111000b.
+ *	3. After writing 00000100b to port BASE (set bit 2), status register
+ *	   (BASE) should read 11111100b.
+ *	Return 1 if detected o.k. or 0 if failed.
+ *	Note:	This test is destructive! Adapter will be left in shutdown
+ *		state after the test.
+ */
+static int detect_s502e (int port)
+{
+	int i, j;
+
+	if (!get_option_index(s502_port_options, port))
+		return 0
+	;
+	for (j = 1; j < SDLA_MAXIORANGE; ++j)
+	{
+		if (_INB(port + j) != 0xFF)
+			return 0
+		;
+		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	}
+
+	_OUTB(port + 3, 0);			/* CPU control reg. */
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if (_INB(port) != 0xF8)			/* read status */
+		return 0
+	;
+	_OUTB(port, 0x04);			/* set bit 2 */
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if (_INB(port) != 0xFC)			/* verify */
+		return 0
+	;
+
+	/* Reset adapter */
+	_OUTB(port, 0);
+	return 1;
+}
+
+/*============================================================================
+ * Detect s503 adapter.
+ *	Following tests are used to verify adapter presence:
+ *	1. All registers other than status (BASE) should read 0xFF.
+ *	2. After writing 0 to control register (BASE), status register (BASE)
+ *	   should read 11110000b.
+ *	3. After writing 00000100b (set bit 2) to control register (BASE),
+ *	   status register should read 11110010b.
+ *	Return 1 if detected o.k. or 0 if failed.
+ *	Note:	This test is destructive! Adapter will be left in shutdown
+ *		state after the test.
+ */
+static int detect_s503 (int port)
+{
+	int i, j;
+
+	if (!get_option_index(s503_port_options, port))
+		return 0
+	;
+	for (j = 1; j < SDLA_MAXIORANGE; ++j)
+	{
+		if (_INB(port + j) != 0xFF)
+			return 0
+		;
+		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	}
+
+	_OUTB(port, 0);				/* reset control reg.*/
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if (_INB(port) != 0xF0)			/* read status */
+		return 0
+	;
+	_OUTB(port, 0x04);			/* set bit 2 */
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if (_INB(port) != 0xF2)			/* verify */
+		return 0
+	;
+
+	/* Reset adapter */
+	_OUTB(port, 0);
+	return 1;
+}
+
+/*============================================================================
+ * Detect s507 adapter.
+ *	Following tests are used to detect s507 adapter:
+ *	1. All ports should read the same value.
+ *	2. After writing 0x00 to control register, status register should read
+ *	   ?011000?b.
+ *	3. After writing 0x01 to control register, status register should read
+ *	   ?011001?b.
+ *	Return 1 if detected o.k. or 0 if failed.
+ *	Note:	This test is destructive! Adapter will be left in shutdown
+ *		state after the test.
+ */
+static int detect_s507 (int port)
+{
+	int tmp, i, j;
+
+	if (!get_option_index(s508_port_options, port))
+		return 0
+	;
+	tmp = _INB(port);
+	for (j = 1; j < S507_IORANGE; ++j)
+	{
+		if (_INB(port + j) != tmp)
+			return 0
+		;
+		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	}
+
+	_OUTB(port, 0x00);
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if ((_INB(port) & 0x7E) != 0x30)
+		return 0
+	;
+	_OUTB(port, 0x01);
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if ((_INB(port) & 0x7E) != 0x32)
+		return 0
+	;
+
+	/* Reset adapter */
+	_OUTB(port, 0x00);
+	return 1;
+}
+
+/*============================================================================
+ * Detect s508 adapter.
+ *	Following tests are used to detect s508 adapter:
+ *	1. After writing 0x00 to control register, status register should read
+ *	   ??000000b.
+ *	2. After writing 0x10 to control register, status register should read
+ *	   ??010000b
+ *	Return 1 if detected o.k. or 0 if failed.
+ *	Note:	This test is destructive! Adapter will be left in shutdown
+ *		state after the test.
+ */
+static int detect_s508 (int port)
+{
+	int i;
+
+	if (!get_option_index(s508_port_options, port))
+		return 0
+	;
+	_OUTB(port, 0x00);
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if ((_INB(port + 1) & 0x3F) != 0x00)
+		return 0
+	;
+	_OUTB(port, 0x10);
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if ((_INB(port + 1) & 0x3F) != 0x10)
+		return 0
+	;
+
+	/* Reset adapter */
+	_OUTB(port, 0x00);
+	return 1;
+}
+
+/******* Miscellaneous ******************************************************/
+
+/*============================================================================
+ * Calibrate SDLA memory access delay.
+ * Count number of idle loops made within 1 second and then calculate the
+ * number of loops that should be made to achive desired delay.
+ */
+static int calibrate_delay (int mks)
+{
+	unsigned int delay;
+	unsigned long stop;
+
+	for (delay = 0, stop = SYSTEM_TICK + HZ; SYSTEM_TICK < stop; ++delay);
+	return (delay/(1000000L/mks) + 1);
+}
+
+/*============================================================================
+ * Get option's index into the options list.
+ *	Return option's index (1 .. N) or zero if option is invalid.
+ */
+static int get_option_index (unsigned* optlist, unsigned optval)
+{
+	int i;
+
+	for (i = 1; i <= optlist[0]; ++i)
+		if ( optlist[i] == optval) return i
+	;
+	return 0;
+}
+
+/*============================================================================
+ * Check memory region to see if it's available. 
+ * Return:	0	ok.
+ */
+static unsigned check_memregion (void* ptr, unsigned len)
+{
+	volatile unsigned char* p = ptr;
+
+	for (; len && (*p == 0xFF); --len, ++p)
+	{
+		*p = 0;			/* attempt to write 0 */
+		if (*p != 0xFF)		/* still has to read 0xFF */
+		{
+			*p = 0xFF;	/* restore original value */
+			break;		/* not good */
+		}
+	}
+	return len;
+}
+
+/*============================================================================
+ * Test memory region.
+ * Return:	size of the region that passed the test.
+ * Note:	Region size must be multiple of 2 !
+ */
+static unsigned test_memregion (void* ptr, unsigned len)
+{
+	volatile unsigned short* w_ptr;
+	unsigned len_w = len >> 1;	/* region len in words */
+	unsigned i;
+
+	for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
+		*w_ptr = 0xAA55
+	;
+	for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
+		if (*w_ptr != 0xAA55)
+		{
+			len_w = i;
+			break;
+		}
+	;
+	for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
+		*w_ptr = 0x55AA
+	;
+	for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
+		if (*w_ptr != 0x55AA)
+		{
+			len_w = i;
+			break;
+		}
+	;
+	for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) *w_ptr = 0;
+	return len_w << 1;
+}
+
+/*============================================================================
+ * Calculate 16-bit CRC using CCITT polynomial.
+ */
+static unsigned short checksum (unsigned char* buf, unsigned len)
+{
+	unsigned short crc = 0;
+	unsigned mask, flag;
+
+	for (; len; --len, ++buf)
+	{
+		for (mask = 0x80; mask; mask >>= 1)
+		{
+			flag = (crc & 0x8000);
+			crc <<= 1;
+			crc |= ((*buf & mask) ? 1 : 0);
+			if (flag) crc ^= 0x1021;
+		}
+	}
+	return crc;
+}
+
+
+/****** End *****************************************************************/
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/sdlamain.c linux/drivers/net/wan/sdlamain.c
--- v2.3.20/linux/drivers/net/wan/sdlamain.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/sdlamain.c	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,628 @@
+/*****************************************************************************
+* sdlamain.c	WANPIPE(tm) Multiprotocol WAN Link Driver.  Main module.
+*
+* Author:	Gene Kozin	<genek@compuserve.com>
+*		Jaspreet Singh	<jaspreet@sangoma.com>
+* Fixes:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+*
+* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
+*
+*		This program is free software; you can redistribute it and/or
+*		modify it under the terms of the GNU General Public License
+*		as published by the Free Software Foundation; either version
+*		2 of the License, or (at your option) any later version.
+* ============================================================================
+* May 19, 1999  Arnaldo Melo    __init for wanpipe_init
+* Nov 28, 1997	Jaspreet Singh	Changed DRV_RELEASE to 1
+* Nov 10, 1997	Jaspreet Singh	Changed sti() to restore_flags();
+* Nov 06, 1997 	Jaspreet Singh	Changed DRV_VERSION to 4 and DRV_RELEASE to 0
+* Oct 20, 1997 	Jaspreet Singh	Modified sdla_isr routine so that card->in_isr
+*				assignments are taken out and placed in the
+*				sdla_ppp.c, sdla_fr.c and sdla_x25.c isr
+*				routines. Took out 'wandev->tx_int_enabled' and
+*				replaced it with 'wandev->enable_tx_int'. 
+* May 29, 1997	Jaspreet Singh	Flow Control Problem
+*				added "wandev->tx_int_enabled=1" line in the
+*				init module. This line intializes the flag for 
+*				preventing Interrupt disabled with device set to
+*				busy
+* Jan 15, 1997	Gene Kozin	Version 3.1.0
+*				 o added UDP management stuff
+* Jan 02, 1997	Gene Kozin	Initial version.
+*****************************************************************************/
+
+#include <linux/config.h>	/* OS configuration options */
+#include <linux/stddef.h>	/* offsetof(), etc. */
+#include <linux/errno.h>	/* return codes */
+#include <linux/string.h>	/* inline memset(), etc. */
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
+#include <linux/kernel.h>	/* printk(), and other useful stuff */
+#include <linux/module.h>	/* support for loadable modules */
+#include <linux/ioport.h>	/* request_region(), release_region() */
+#include <linux/tqueue.h>	/* for kernel task queues */
+#include <linux/wanrouter.h>	/* WAN router definitions */
+#include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
+#include <asm/uaccess.h>	/* kernel <-> user copy */
+#include <asm/io.h>		/* phys_to_virt() */
+#include <linux/init.h>         /* __init (when not using as a module) */
+
+
+/****** Defines & Macros ****************************************************/
+
+#ifdef	_DEBUG_
+#define	STATIC
+#else
+#define	STATIC		static
+#endif
+
+#define	DRV_VERSION	4		/* version number */
+#define	DRV_RELEASE	1		/* release (minor version) number */
+#define	MAX_CARDS	8		/* max number of adapters */
+
+#ifndef	CONFIG_WANPIPE_CARDS		/* configurable option */
+#define	CONFIG_WANPIPE_CARDS 1
+#endif
+
+#define	CMD_OK		0		/* normal firmware return code */
+#define	CMD_TIMEOUT	0xFF		/* firmware command timed out */
+#define	MAX_CMD_RETRY	10		/* max number of firmware retries */
+
+/****** Function Prototypes *************************************************/
+
+/* Module entry points */
+int init_module (void);
+void cleanup_module (void);
+
+/* WAN link driver entry points */
+static int setup    (wan_device_t* wandev, wandev_conf_t* conf);
+static int shutdown (wan_device_t* wandev);
+static int ioctl    (wan_device_t* wandev, unsigned cmd, unsigned long arg);
+
+/* IOCTL hanlers */
+static int ioctl_dump	(sdla_t* card, sdla_dump_t* u_dump);
+static int ioctl_exec	(sdla_t* card, sdla_exec_t* u_exec);
+
+/* Miscellaneous functions */
+STATIC void sdla_isr	(int irq, void* dev_id, struct pt_regs *regs);
+STATIC void sdla_poll	(void* data);
+
+/****** Global Data **********************************************************
+ * Note: All data must be explicitly initialized!!!
+ */
+
+/* private data */
+static char drvname[]	= "wanpipe";
+static char fullname[]	= "WANPIPE(tm) Multiprotocol Driver";
+static char copyright[]	= "(c) 1995-1996 Sangoma Technologies Inc.";
+static int ncards = CONFIG_WANPIPE_CARDS;
+static int active = 0;			/* number of active cards */
+static sdla_t* card_array = NULL;	/* adapter data space */
+
+/* Task queue element for creating a 'thread' */
+static struct tq_struct sdla_tq =
+{
+	NULL,		/* .next */
+	0,		/* .sync */
+	&sdla_poll,	/* .routine */
+	NULL		/* .data */
+}; 
+
+/******* Kernel Loadable Module Entry Points ********************************/
+
+/*============================================================================
+ * Module 'insert' entry point.
+ * o print announcement
+ * o allocate adapter data space
+ * o initialize static data
+ * o register all cards with WAN router
+ * o calibrate SDLA shared memory access delay.
+ *
+ * Return:	0	Ok
+ *		< 0	error.
+ * Context:	process
+ */
+ 
+#ifdef MODULE
+int init_module (void)
+#else
+int __init wanpipe_init(void)
+#endif
+{
+	int cnt, err = 0;
+
+	printk(KERN_INFO "%s v%u.%u %s\n",
+		fullname, DRV_VERSION, DRV_RELEASE, copyright)
+	;
+
+	/* Verify number of cards and allocate adapter data space */
+	ncards = min(ncards, MAX_CARDS);
+	ncards = max(ncards, 1);
+	card_array = kmalloc(sizeof(sdla_t) * ncards, GFP_KERNEL);
+	if (card_array == NULL)
+		return -ENOMEM
+	;
+	memset(card_array, 0, sizeof(sdla_t) * ncards);
+
+	/* Register adapters with WAN router */
+	for (cnt = 0; cnt < ncards; ++cnt)
+	{
+		sdla_t* card = &card_array[cnt];
+		wan_device_t* wandev = &card->wandev;
+
+		sprintf(card->devname, "%s%d", drvname, cnt + 1);
+		wandev->magic    = ROUTER_MAGIC;
+		wandev->name     = card->devname;
+		wandev->private  = card;
+		wandev->enable_tx_int = 0;
+		wandev->setup    = &setup;
+		wandev->shutdown = &shutdown;
+		wandev->ioctl    = &ioctl;
+		err = register_wan_device(wandev);
+		if (err)
+		{
+			printk(KERN_ERR
+				"%s: %s registration failed with error %d!\n",
+				drvname, card->devname, err)
+			;
+			break;
+		}
+	}
+	if (cnt)
+		ncards = cnt;	/* adjust actual number of cards */
+	else
+	{
+		kfree(card_array);
+		err = -ENODEV;
+	}
+	return err;
+}
+
+#ifdef MODULE
+/*============================================================================
+ * Module 'remove' entry point.
+ * o unregister all adapters from the WAN router
+ * o release all remaining system resources
+ */
+void cleanup_module (void)
+{
+	int i;
+
+	for (i = 0; i < ncards; ++i)
+	{
+		sdla_t* card = &card_array[i];
+		unregister_wan_device(card->devname);
+	}
+	kfree(card_array);
+}
+
+#endif
+
+/******* WAN Device Driver Entry Points *************************************/
+
+/*============================================================================
+ * Setup/confugure WAN link driver.
+ * o check adapter state
+ * o make sure firmware is present in configuration
+ * o make sure I/O port and IRQ are specified
+ * o make sure I/O region is available
+ * o allocate interrupt vector
+ * o setup SDLA hardware
+ * o call appropriate routine to perform protocol-specific initialization
+ * o mark I/O region as used
+ * o if this is the first active card, then schedule background task
+ *
+ * This function is called when router handles ROUTER_SETUP IOCTL. The
+ * configuration structure is in kernel memory (including extended data, if
+ * any).
+ */
+ 
+static int setup (wan_device_t* wandev, wandev_conf_t* conf)
+{
+	sdla_t* card;
+	int err = 0;
+	int irq;
+
+	/* Sanity checks */
+	if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL))
+		return -EFAULT;
+		
+	card = wandev->private;
+	if (wandev->state != WAN_UNCONFIGURED)
+		return -EBUSY;		/* already configured */
+
+	if (!conf->data_size || (conf->data == NULL))
+	{
+		printk(KERN_ERR
+			"%s: firmware not found in configuration data!\n",
+			wandev->name);
+		return -EINVAL;
+	}
+	if (conf->ioport <= 0)
+	{
+		printk(KERN_ERR
+			"%s: can't configure without I/O port address!\n",
+			wandev->name);
+		return -EINVAL;
+	}
+	
+	if (conf->irq <= 0)
+	{
+		printk(KERN_ERR "%s: can't configure without IRQ!\n",
+			wandev->name);
+		return -EINVAL;
+	}
+
+	/* Make sure I/O port region is available */
+	if (check_region(conf->ioport, SDLA_MAXIORANGE))
+	{
+		printk(KERN_ERR "%s: I/O region 0x%X - 0x%X is in use!\n",
+			wandev->name, conf->ioport,
+			conf->ioport + SDLA_MAXIORANGE);
+		return -EINVAL;
+	}
+
+	/* Allocate IRQ */
+	irq = (conf->irq == 2) ? 9 : conf->irq;	/* IRQ2 -> IRQ9 */
+	if (request_irq(irq, sdla_isr, 0, wandev->name, card))
+	{
+		printk(KERN_ERR "%s: can't reserve IRQ %d!\n",
+			wandev->name, irq);
+		return -EINVAL;
+	}
+
+	/* Configure hardware, load firmware, etc. */
+	memset(&card->hw, 0, sizeof(sdlahw_t));
+	card->hw.port    = conf->ioport;
+	card->hw.irq     = (conf->irq == 9) ? 2 : conf->irq;
+	/* Compute the virtual address of the card in kernel space */
+	if(conf->maddr)
+		card->hw.dpmbase = phys_to_virt(conf->maddr);
+	else	/* But 0 means NULL */
+		card->hw.dpmbase = (void *)conf->maddr;
+
+	card->hw.dpmsize = SDLA_WINDOWSIZE;
+	card->hw.type    = conf->hw_opt[0];
+	card->hw.pclk    = conf->hw_opt[1];
+	err = sdla_setup(&card->hw, conf->data, conf->data_size);
+	if (err)
+	{
+		free_irq(irq, card);
+		return err;
+	}
+
+	/* Intialize WAN device data space */
+	wandev->irq       = irq;
+	wandev->dma       = 0;
+	wandev->ioport    = card->hw.port;
+	wandev->maddr     = card->hw.dpmbase;
+	wandev->msize     = card->hw.dpmsize;
+	wandev->hw_opt[0] = card->hw.type;
+	wandev->hw_opt[1] = card->hw.pclk;
+	wandev->hw_opt[2] = card->hw.memory;
+	wandev->hw_opt[3] = card->hw.fwid;
+
+	/* Protocol-specific initialization */
+	switch (card->hw.fwid)
+	{
+#ifdef	CONFIG_WANPIPE_X25
+	case SFID_X25_502:
+	case SFID_X25_508:
+		err = wpx_init(card, conf);
+		break;
+#endif
+
+#ifdef	CONFIG_WANPIPE_FR
+	case SFID_FR502:
+	case SFID_FR508:
+		err = wpf_init(card, conf);
+		break;
+#endif
+
+#ifdef	CONFIG_WANPIPE_PPP
+	case SFID_PPP502:
+	case SFID_PPP508:
+		err = wpp_init(card, conf);
+		break;
+#endif
+
+	default:
+		printk(KERN_ERR "%s: this firmware is not supported!\n",
+			wandev->name)
+		;
+		err = -EINVAL;
+	}
+	if (err)
+	{
+		sdla_down(&card->hw);
+		free_irq(irq, card);
+		return err;
+	}
+  	/* Reserve I/O region and schedule background task */
+/*	printk(KERN_INFO "about to request\n");*/
+	request_region(card->hw.port, card->hw.io_range, wandev->name);
+/*	printk(KERN_INFO "request done\n");*/
+	if (++active == 1)
+		queue_task(&sdla_tq, &tq_scheduler);
+		
+	wandev->critical = 0;
+	return 0;
+}
+
+/*============================================================================
+ * Shut down WAN link driver. 
+ * o shut down adapter hardware
+ * o release system resources.
+ *
+ * This function is called by the router when device is being unregistered or
+ * when it handles ROUTER_DOWN IOCTL.
+ */
+static int shutdown (wan_device_t* wandev)
+{
+	sdla_t* card;
+
+	/* sanity checks */
+	if ((wandev == NULL) || (wandev->private == NULL))
+		return -EFAULT;
+		
+	if (wandev->state == WAN_UNCONFIGURED)
+		return 0;
+		
+	/* If wee are in a critical section we lose */
+	if (test_and_set_bit(0, (void*)&wandev->critical))
+		return -EAGAIN;
+		
+	card = wandev->private;
+	wandev->state = WAN_UNCONFIGURED;
+
+	if (--active == 0)
+		schedule();	/* stop background thread */
+	
+/*	printk(KERN_INFO "active now %d\n", active);
+
+	printk(KERN_INFO "About to call sdla_down\n");*/
+	sdla_down(&card->hw);
+/*	printk(KERN_INFO "sdla_down done\n");
+	printk(KERN_INFO "About to call free_irq\n");*/
+	free_irq(wandev->irq, card);
+/*	printk(KERN_INFO "free_irq done\n");
+	printk(KERN_INFO "About to call release_region\n");*/
+	release_region(card->hw.port, card->hw.io_range);
+/*	printk(KERN_INFO "release_region done\n");*/
+	wandev->critical = 0;
+	return 0;
+}
+
+/*============================================================================
+ * Driver I/O control. 
+ * o verify arguments
+ * o perform requested action
+ *
+ * This function is called when router handles one of the reserved user
+ * IOCTLs.  Note that 'arg' stil points to user address space.
+ */
+static int ioctl (wan_device_t* wandev, unsigned cmd, unsigned long arg)
+{
+	int err;
+
+	/* sanity checks */
+	if ((wandev == NULL) || (wandev->private == NULL))
+		return -EFAULT
+	;
+	if (wandev->state == WAN_UNCONFIGURED)
+		return -ENODEV
+	;
+	if (test_and_set_bit(0, (void*)&wandev->critical))
+		return -EAGAIN
+	;
+	switch (cmd)
+	{
+	case WANPIPE_DUMP:
+		err = ioctl_dump(wandev->private, (void*)arg);
+		break;
+
+	case WANPIPE_EXEC:
+		err = ioctl_exec(wandev->private, (void*)arg);
+		break;
+
+	default:
+		err = -EINVAL;
+	}
+	wandev->critical = 0;
+	return err;
+}
+
+/****** Driver IOCTL Hanlers ************************************************/
+
+/*============================================================================
+ * Dump adapter memory to user buffer.
+ * o verify request structure
+ * o copy request structure to kernel data space
+ * o verify length/offset
+ * o verify user buffer
+ * o copy adapter memory image to user buffer
+ *
+ * Note: when dumping memory, this routine switches curent dual-port memory
+ *	 vector, so care must be taken to avoid racing conditions.
+ */
+static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump)
+{
+	sdla_dump_t dump;
+	unsigned winsize;
+	unsigned long oldvec;	/* DPM window vector */
+	unsigned long flags;
+	int err = 0;
+
+	if(copy_from_user((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t)))
+		return -EFAULT;
+		
+	if ((dump.magic != WANPIPE_MAGIC) ||
+	    (dump.offset + dump.length > card->hw.memory))
+		return -EINVAL;
+		
+	winsize = card->hw.dpmsize;
+	save_flags(flags);
+        cli();				/* >>> critical section start <<< */
+	oldvec = card->hw.vector;
+	while (dump.length)
+	{
+		unsigned pos = dump.offset % winsize;	/* current offset */
+		unsigned long vec = dump.offset - pos;	/* current vector */
+		unsigned len = (dump.length > (winsize - pos)) ?
+			(winsize - pos) : dump.length
+		;
+		if (sdla_mapmem(&card->hw, vec) != 0)	/* relocate window */
+		{
+			err = -EIO;
+			break;
+		}
+		/* FIXME::: COPY TO KERNEL BUFFER FIRST ?? */
+		sti();	/* Not ideal but tough we have to do this */
+		if(copy_to_user((void *)dump.ptr,
+			(u8 *)card->hw.dpmbase + pos, len))	
+			return -EFAULT;
+		cli();
+		dump.length     -= len;
+		dump.offset     += len;
+		(char*)dump.ptr += len;
+	}
+	sdla_mapmem(&card->hw, oldvec);	/* restore DPM window position */
+	restore_flags(flags);		/* >>> critical section end <<< */
+	return err;
+}
+
+/*============================================================================
+ * Execute adapter firmware command.
+ * o verify request structure
+ * o copy request structure to kernel data space
+ * o call protocol-specific 'exec' function
+ */
+static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec)
+{
+	sdla_exec_t exec;
+
+	if (card->exec == NULL)
+		return -ENODEV;
+		
+	if(copy_from_user((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t)))
+		return -EFAULT;
+	if ((exec.magic != WANPIPE_MAGIC) || (exec.cmd == NULL))
+		return -EINVAL;
+	return card->exec(card, exec.cmd, exec.data);
+}
+
+/******* Miscellaneous ******************************************************/
+
+/*============================================================================
+ * SDLA Interrupt Service Routine.
+ * o acknowledge SDLA hardware interrupt.
+ * o call protocol-specific interrupt service routine, if any.
+ */
+STATIC void sdla_isr (int irq, void* dev_id, struct pt_regs *regs)
+{
+#define	card	((sdla_t*)dev_id)
+
+	if (!card || (card->wandev.state == WAN_UNCONFIGURED))
+		return
+	;
+	if (card->in_isr)
+	{
+		printk(KERN_WARNING "%s: interrupt re-entrancy on IRQ %d!\n",
+			card->devname, card->wandev.irq)
+		;
+		return;
+	}
+
+	sdla_intack(&card->hw);
+	if (card->isr) 
+		card->isr(card);
+
+#undef	card
+}
+
+/*============================================================================
+ * SDLA polling routine.
+ * This routine simulates kernel thread to perform various housekeeping job.
+ *
+ * o for each configured device call its poll() routine
+ * o if there is at least one active card, then reschedule itself once again
+ */
+STATIC void sdla_poll (void* data)
+{
+	int i;
+
+	for (i = 0; i < ncards; ++i)
+	{
+		sdla_t* card = &card_array[i];
+
+		if ((card->wandev.state != WAN_UNCONFIGURED) && card->poll &&
+		    !card->wandev.critical)
+		{
+			card->poll(card);
+		}
+	}
+	if (active)
+		queue_task(&sdla_tq, &tq_scheduler);
+}
+
+/*============================================================================
+ * This routine is called by the protocol-specific modules when network
+ * interface is being open.  The only reason we need this, is because we
+ * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's
+ * defined more than once into the same kernel module.
+ */
+void wanpipe_open (sdla_t* card)
+{
+	++card->open_cnt;
+	MOD_INC_USE_COUNT;
+}
+
+/*============================================================================
+ * This routine is called by the protocol-specific modules when network
+ * interface is being closed.  The only reason we need this, is because we
+ * have to call MOD_DEC_USE_COUNT, but cannot include 'module.h' where it's
+ * defined more than once into the same kernel module.
+ */
+void wanpipe_close (sdla_t* card)
+{
+	--card->open_cnt;
+	MOD_DEC_USE_COUNT;
+}
+
+/*============================================================================
+ * Set WAN device state.
+ */
+void wanpipe_set_state (sdla_t* card, int state)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	if (card->wandev.state != state)
+	{
+		switch (state)
+		{
+		case WAN_CONNECTED:
+			printk (KERN_INFO "%s: link connected!\n",
+				card->devname)
+			;
+			break;
+
+		case WAN_CONNECTING:
+			printk (KERN_INFO "%s: link connecting...\n",
+				card->devname)
+			;
+			break;
+
+		case WAN_DISCONNECTED:
+			printk (KERN_INFO "%s: link disconnected!\n",
+				card->devname)
+			;
+			break;
+		}
+		card->wandev.state = state;
+	}
+	card->state_tick = jiffies;
+	restore_flags(flags);
+}
+
+/****** End *****************************************************************/
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/sealevel.c linux/drivers/net/wan/sealevel.c
--- v2.3.20/linux/drivers/net/wan/sealevel.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/sealevel.c	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,471 @@
+#define LINUX_21
+
+/*
+ *	Sealevel Systems 4021 driver.
+ *
+ *	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.
+ *
+ *	(c) Copyright 1999 Building Number Three Ltd
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <net/arp.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/byteorder.h>
+#include "syncppp.h"
+#include "z85230.h"
+
+
+struct slvl_device
+{
+	struct z8530_channel *chan;
+	struct ppp_device netdev;
+	char name[16];
+	int channel;
+};
+
+
+struct slvl_board
+{
+	struct slvl_device dev[2];
+	struct z8530_dev board;
+	int iobase;
+};
+
+/*
+ *	Network driver support routines
+ */
+
+/*
+ *	Frame receive. Simple for our card as we do sync ppp and there
+ *	is no funny garbage involved
+ */
+ 
+static void sealevel_input(struct z8530_channel *c, struct sk_buff *skb)
+{
+	/* Drop the CRC - its not a good idea to try and negotiate it ;) */
+	skb_trim(skb, skb->len-2);
+	skb->protocol=htons(ETH_P_WAN_PPP);
+	skb->mac.raw=skb->data;
+	skb->dev=c->netdevice;
+	/*
+	 *	Send it to the PPP layer. We dont have time to process
+	 *	it right now.
+	 */
+	netif_rx(skb);
+}
+ 
+/*
+ *	We've been placed in the UP state
+ */ 
+ 
+static int sealevel_open(struct net_device *d)
+{
+	struct slvl_device *slvl=d->priv;
+	int err = -1;
+	int unit = slvl->channel;
+	
+	/*
+	 *	Link layer up. 
+	 */
+
+	switch(unit)
+	{
+		case 0:
+			err=z8530_sync_dma_open(d, slvl->chan);
+			break;
+		case 1:
+			err=z8530_sync_open(d, slvl->chan);
+			break;
+	}
+	
+	if(err)
+		return err;
+	/*
+	 *	Begin PPP
+	 */
+	err=sppp_open(d);
+	if(err)
+	{
+		switch(unit)
+		{
+			case 0:
+				z8530_sync_dma_close(d, slvl->chan);
+				break;
+			case 1:
+				z8530_sync_close(d, slvl->chan);
+				break;
+		}				
+		return err;
+	}
+	
+	slvl->chan->rx_function=sealevel_input;
+	
+	/*
+	 *	Go go go
+	 */
+	d->tbusy=0;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int sealevel_close(struct net_device *d)
+{
+	struct slvl_device *slvl=d->priv;
+	int unit = slvl->channel;
+	
+	/*
+	 *	Discard new frames
+	 */
+	
+	slvl->chan->rx_function=z8530_null_rx;
+		
+	/*
+	 *	PPP off
+	 */
+	sppp_close(d);
+	/*
+	 *	Link layer down
+	 */
+	d->tbusy=1;
+	
+	switch(unit)
+	{
+		case 0:
+			z8530_sync_dma_close(d, slvl->chan);
+			break;
+		case 1:
+			z8530_sync_close(d, slvl->chan);
+			break;
+	}
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int sealevel_ioctl(struct net_device *d, struct ifreq *ifr, int cmd)
+{
+	/* struct slvl_device *slvl=d->priv;
+	   z8530_ioctl(d,&slvl->sync.chanA,ifr,cmd) */
+	return sppp_do_ioctl(d, ifr,cmd);
+}
+
+static struct enet_statistics *sealevel_get_stats(struct net_device *d)
+{
+	struct slvl_device *slvl=d->priv;
+	if(slvl)
+		return z8530_get_stats(slvl->chan);
+	else
+		return NULL;
+}
+
+/*
+ *	Passed PPP frames, fire them downwind.
+ */
+ 
+static int sealevel_queue_xmit(struct sk_buff *skb, struct net_device *d)
+{
+	struct slvl_device *slvl=d->priv;
+	return z8530_queue_xmit(slvl->chan, skb);
+}
+
+#ifdef LINUX_21
+static int sealevel_neigh_setup(struct neighbour *n)
+{
+	if (n->nud_state == NUD_NONE) {
+		n->ops = &arp_broken_ops;
+		n->output = n->ops->output;
+	}
+	return 0;
+}
+
+static int sealevel_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p)
+{
+	if (p->tbl->family == AF_INET) {
+		p->neigh_setup = sealevel_neigh_setup;
+		p->ucast_probes = 0;
+		p->mcast_probes = 0;
+	}
+	return 0;
+}
+
+#else
+
+static int return_0(struct net_device *d)
+{
+	return 0;
+}
+
+#endif
+
+/*
+ *	Description block for a Comtrol Hostess SV11 card
+ */
+ 
+static struct slvl_board *slvl_init(int iobase, int irq, int txdma, int rxdma, int slow)
+{
+	struct z8530_dev *dev;
+	struct slvl_device *sv;
+	struct slvl_board *b;
+	
+	int i;
+	unsigned long flags;
+	int u;
+	
+	/*
+	 *	Get the needed I/O space
+	 */
+	 
+	if(check_region(iobase, 8))
+	{	
+		printk(KERN_WARNING "sealevel: I/O 0x%X already in use.\n", iobase);
+		return NULL;
+	}
+	request_region(iobase, 8, "Sealevel 4021");
+	
+	b=(struct slvl_board *)kmalloc(sizeof(struct slvl_board), GFP_KERNEL);
+	if(!b)
+		goto fail3;
+			
+	memset(b, 0, sizeof(*sv));
+
+	b->dev[0].chan = &b->board.chanA;	
+	b->dev[1].chan = &b->board.chanB;
+	
+	dev=&b->board;
+	
+	/*
+	 *	Stuff in the I/O addressing
+	 */
+	 
+	dev->active = 0;
+
+	b->iobase = iobase;
+	
+	/*
+	 *	Select 8530 delays for the old board
+	 */
+	 
+	if(slow)
+		iobase |= Z8530_PORT_SLEEP;
+		
+	dev->chanA.ctrlio=iobase+1;
+	dev->chanA.dataio=iobase;
+	dev->chanB.ctrlio=iobase+3;
+	dev->chanB.dataio=iobase+2;
+	
+	dev->chanA.irqs=&z8530_nop;
+	dev->chanB.irqs=&z8530_nop;
+	
+	/*
+	 *	Assert DTR enable DMA
+	 */
+	 
+	outb(3|(1<<7), b->iobase+4);	
+	
+
+	/* We want a fast IRQ for this device. Actually we'd like an even faster
+	   IRQ ;) - This is one driver RtLinux is made for */
+   
+	if(request_irq(irq, &z8530_interrupt, SA_INTERRUPT, "SeaLevel", dev)<0)
+	{
+		printk(KERN_WARNING "sealevel: IRQ %d already in use.\n", irq);
+		goto fail2;
+	}
+	
+	dev->irq=irq;
+	dev->chanA.private=&b->dev[0];
+	dev->chanB.private=&b->dev[1];
+	dev->chanA.netdevice=&b->dev[0].netdev.dev;
+	dev->chanB.netdevice=&b->dev[1].netdev.dev;
+	dev->chanA.dev=dev;
+	dev->chanB.dev=dev;
+	dev->name=b->dev[0].name;
+
+	dev->chanA.txdma=3;
+	dev->chanA.rxdma=1;
+	if(request_dma(dev->chanA.txdma, "SeaLevel (TX)")!=0)
+		goto fail;
+		
+	if(request_dma(dev->chanA.rxdma, "SeaLevel (RX)")!=0)
+		goto dmafail;
+	
+	save_flags(flags);
+	cli();
+	
+	/*
+	 *	Begin normal initialise
+	 */
+	 
+	if(z8530_init(dev)!=0)
+	{
+		printk(KERN_ERR "Z8530 series device not found.\n");
+		goto dmafail2;
+	}
+	if(dev->type==Z85C30)
+	{
+		z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream);
+		z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream);
+	}
+	else
+	{
+		z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream_85230);
+		z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream_85230);
+	}
+
+	/*
+	 *	Now we can take the IRQ
+	 */
+	
+	restore_flags(flags);
+
+	for(u=0; u<2; u++)
+	{
+		sv=&b->dev[u];
+		sv->channel = u;
+	
+		for(i=0;i<999;i++)
+		{
+			sprintf(sv->name,"hdlc%d", i);
+			if(dev_get(sv->name)==0)
+			{
+				struct net_device *d=sv->chan->netdevice;
+	
+				/* 
+				 *	Initialise the PPP components
+				 */
+				sppp_attach(&sv->netdev);
+			
+				/*
+				 *	Local fields
+				 */	
+				sprintf(sv->name,"hdlc%d", i);
+				
+				d->name = sv->name;
+				d->base_addr = iobase;
+				d->irq = irq;
+				d->priv = sv;
+				d->init = NULL;
+			
+				d->open = sealevel_open;
+				d->stop = sealevel_close;
+				d->hard_start_xmit = sealevel_queue_xmit;
+				d->get_stats = sealevel_get_stats;
+				d->set_multicast_list = NULL;
+				d->do_ioctl = sealevel_ioctl;
+#ifdef LINUX_21			
+				d->neigh_setup = sealevel_neigh_setup_dev;
+				dev_init_buffers(d);
+#else
+				d->init = return_0;
+#endif
+				d->set_mac_address = NULL;
+			
+				if(register_netdev(d)==-1)
+				{
+					printk(KERN_ERR "%s: unable to register device.\n",
+						sv->name);
+					goto fail_unit;
+				}				
+
+				break;
+			}
+		}
+	}
+	z8530_describe(dev, "I/O", iobase);
+	dev->active=1;
+	return b;
+
+fail_unit:
+	if(u==1)
+		unregister_netdev(b->dev[0].chan->netdevice);
+	
+dmafail2:
+	free_dma(dev->chanA.rxdma);
+dmafail:
+	free_dma(dev->chanA.txdma);
+fail:
+	free_irq(irq, dev);
+fail2:
+	kfree(b);
+fail3:
+	release_region(iobase,8);
+	return NULL;
+}
+
+static void slvl_shutdown(struct slvl_board *b)
+{
+	int u;
+
+	z8530_shutdown(&b->board);
+	
+	for(u=0; u<2; u++)
+	{
+		sppp_detach(&b->dev[u].netdev.dev);
+		unregister_netdev(&b->dev[u].netdev.dev);
+	}
+	
+	free_irq(b->board.irq, &b->board);
+	free_dma(b->board.chanA.rxdma);
+	free_dma(b->board.chanA.txdma);
+	/* DMA off on the card, drop DTR */
+	outb(0, b->iobase);
+	release_region(b->iobase, 8);
+}
+
+#ifdef MODULE
+
+static int io=0x238;
+static int txdma=1;
+static int rxdma=3;
+static int irq=5;
+static int slow=0;
+
+#ifdef LINUX_21
+MODULE_PARM(io,"i");
+MODULE_PARM_DESC(io, "The I/O base of the Sealevel card");
+MODULE_PARM(txdma,"i");
+MODULE_PARM_DESC(txdma, "Transmit DMA channel");
+MODULE_PARM(rxdma,"i");
+MODULE_PARM_DESC(rxdma, "Receive DMA channel");
+MODULE_PARM(irq,"i");
+MODULE_PARM_DESC(irq, "The interrupt line setting for the SeaLevel card");
+MODULE_PARM(slow,"i");
+MODULE_PARM_DESC(slow, "Set this for an older Sealevel card such as the 4012");
+
+MODULE_AUTHOR("Bulding Number Three Ltd");
+MODULE_DESCRIPTION("Modular driver for the SeaLevel 4021");
+#endif
+
+static struct slvl_board *slvl_unit;
+
+int init_module(void)
+{
+	printk(KERN_INFO "SeaLevel Z85230 Synchronous Driver v 0.01.\n");
+	printk(KERN_INFO "(c) Copyright 1998, Building Number Three Ltd.\n");	
+	if((slvl_unit=slvl_init(io,irq, txdma, rxdma, slow))==NULL)
+		return -ENODEV;
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	if(slvl_unit)
+		slvl_shutdown(slvl_unit);
+}
+
+#endif
+
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/syncppp.c linux/drivers/net/wan/syncppp.c
--- v2.3.20/linux/drivers/net/wan/syncppp.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/syncppp.c	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,1315 @@
+/*
+ *	NET3:	A (fairly minimal) implementation of synchronous PPP for Linux
+ *		as well as a CISCO HDLC implementation. See the copyright 
+ *		message below for the original source.
+ *
+ *	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.
+ *
+ *	Note however. This code is also used in a different form by FreeBSD.
+ *	Therefore when making any non OS specific change please consider
+ *	contributing it back to the original author under the terms
+ *	below in addition.
+ *		-- Alan
+ *
+ *	Port for Linux-2.1 by Jan "Yenya" Kasprzak <kas@fi.muni.cz>
+ */
+
+/*
+ * Synchronous PPP/Cisco link level subroutines.
+ * Keepalive protocol implemented in both Cisco and PPP modes.
+ *
+ * Copyright (C) 1994 Cronyx Ltd.
+ * Author: Serge Vakulenko, <vak@zebub.msk.su>
+ *
+ * This software is distributed with NO WARRANTIES, not even the implied
+ * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Authors grant any other persons or organisations permission to use
+ * or modify this software as long as this message is kept with the software,
+ * all derivative works or modified versions.
+ *
+ * Version 1.9, Wed Oct  4 18:58:15 MSK 1995
+ *
+ * $Id: if_spppsubr.c,v 1.12 1996/06/10 23:17:45 gpalmer Exp $
+ */
+#undef DEBUG
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/if_arp.h>
+#include <linux/skbuff.h>
+#include <linux/route.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/random.h>
+#include <linux/pkt_sched.h>
+#include <asm/byteorder.h>
+#include "syncppp.h"
+
+#define MAXALIVECNT     6               /* max. alive packets */
+
+#define PPP_ALLSTATIONS 0xff            /* All-Stations broadcast address */
+#define PPP_UI          0x03            /* Unnumbered Information */
+#define PPP_IP          0x0021          /* Internet Protocol */
+#define PPP_ISO         0x0023          /* ISO OSI Protocol */
+#define PPP_XNS         0x0025          /* Xerox NS Protocol */
+#define PPP_IPX         0x002b          /* Novell IPX Protocol */
+#define PPP_LCP         0xc021          /* Link Control Protocol */
+#define PPP_IPCP        0x8021          /* Internet Protocol Control Protocol */
+
+#define LCP_CONF_REQ    1               /* PPP LCP configure request */
+#define LCP_CONF_ACK    2               /* PPP LCP configure acknowledge */
+#define LCP_CONF_NAK    3               /* PPP LCP configure negative ack */
+#define LCP_CONF_REJ    4               /* PPP LCP configure reject */
+#define LCP_TERM_REQ    5               /* PPP LCP terminate request */
+#define LCP_TERM_ACK    6               /* PPP LCP terminate acknowledge */
+#define LCP_CODE_REJ    7               /* PPP LCP code reject */
+#define LCP_PROTO_REJ   8               /* PPP LCP protocol reject */
+#define LCP_ECHO_REQ    9               /* PPP LCP echo request */
+#define LCP_ECHO_REPLY  10              /* PPP LCP echo reply */
+#define LCP_DISC_REQ    11              /* PPP LCP discard request */
+
+#define LCP_OPT_MRU             1       /* maximum receive unit */
+#define LCP_OPT_ASYNC_MAP       2       /* async control character map */
+#define LCP_OPT_AUTH_PROTO      3       /* authentication protocol */
+#define LCP_OPT_QUAL_PROTO      4       /* quality protocol */
+#define LCP_OPT_MAGIC           5       /* magic number */
+#define LCP_OPT_RESERVED        6       /* reserved */
+#define LCP_OPT_PROTO_COMP      7       /* protocol field compression */
+#define LCP_OPT_ADDR_COMP       8       /* address/control field compression */
+
+#define IPCP_CONF_REQ   LCP_CONF_REQ    /* PPP IPCP configure request */
+#define IPCP_CONF_ACK   LCP_CONF_ACK    /* PPP IPCP configure acknowledge */
+#define IPCP_CONF_NAK   LCP_CONF_NAK    /* PPP IPCP configure negative ack */
+#define IPCP_CONF_REJ   LCP_CONF_REJ    /* PPP IPCP configure reject */
+#define IPCP_TERM_REQ   LCP_TERM_REQ    /* PPP IPCP terminate request */
+#define IPCP_TERM_ACK   LCP_TERM_ACK    /* PPP IPCP terminate acknowledge */
+#define IPCP_CODE_REJ   LCP_CODE_REJ    /* PPP IPCP code reject */
+
+#define CISCO_MULTICAST         0x8f    /* Cisco multicast address */
+#define CISCO_UNICAST           0x0f    /* Cisco unicast address */
+#define CISCO_KEEPALIVE         0x8035  /* Cisco keepalive protocol */
+#define CISCO_ADDR_REQ          0       /* Cisco address request */
+#define CISCO_ADDR_REPLY        1       /* Cisco address reply */
+#define CISCO_KEEPALIVE_REQ     2       /* Cisco keepalive request */
+
+struct ppp_header {
+	u8 address;
+	u8 control;
+	u16 protocol;
+};
+#define PPP_HEADER_LEN          sizeof (struct ppp_header)
+
+struct lcp_header {
+	u8 type;
+	u8 ident;
+	u16 len;
+};
+#define LCP_HEADER_LEN          sizeof (struct lcp_header)
+
+struct cisco_packet {
+	u32 type;
+	u32 par1;
+	u32 par2;
+	u16 rel;
+	u16 time0;
+	u16 time1;
+};
+#define CISCO_PACKET_LEN 18
+#define CISCO_BIG_PACKET_LEN 20
+
+static struct sppp *spppq;
+static struct timer_list sppp_keepalive_timer;
+
+static void sppp_keepalive (unsigned long dummy);
+static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type,
+	u8 ident, u16 len, void *data);
+static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2);
+static void sppp_lcp_input (struct sppp *sp, struct sk_buff *m);
+static void sppp_cisco_input (struct sppp *sp, struct sk_buff *m);
+static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *m);
+static void sppp_lcp_open (struct sppp *sp);
+static void sppp_ipcp_open (struct sppp *sp);
+static int sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h,
+	int len, u32 *magic);
+static void sppp_cp_timeout (unsigned long arg);
+static char *sppp_lcp_type_name (u8 type);
+static char *sppp_ipcp_type_name (u8 type);
+static void sppp_print_bytes (u8 *p, u16 len);
+
+static int debug = 0;
+
+/*
+ *	Interface down stub
+ */	
+
+static void if_down(struct net_device *dev)
+{
+	;
+}
+
+/*
+ * Timeout routine activations.
+ */
+
+static void sppp_set_timeout(struct sppp *p,int s) 
+{
+	if (! (p->pp_flags & PP_TIMO)) 
+	{
+		init_timer(&p->pp_timer);
+		p->pp_timer.function=sppp_cp_timeout;
+		p->pp_timer.expires=jiffies+s*HZ;
+		p->pp_timer.data=(unsigned long)p;
+		p->pp_flags |= PP_TIMO;
+		add_timer(&p->pp_timer);
+	}
+}
+
+static void sppp_clear_timeout(struct sppp *p)
+{
+	if (p->pp_flags & PP_TIMO) 
+	{
+		del_timer(&p->pp_timer);
+		p->pp_flags &= ~PP_TIMO; 
+	}
+}
+
+/*
+ * Process the received packet.
+ */
+ 
+void sppp_input (struct net_device *dev, struct sk_buff *skb)
+{
+	struct ppp_header *h;
+	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
+	
+	skb->dev=dev;
+	skb->mac.raw=skb->data;
+	
+	if (dev->flags & IFF_UP)
+	{
+		/* Count received bytes, add FCS and one flag */
+		sp->ibytes+= skb->len + 3;
+		sp->ipkts++;
+	}
+
+	if (skb->len <= PPP_HEADER_LEN) {
+		/* Too small packet, drop it. */
+		if (sp->pp_flags & PP_DEBUG)
+			printk (KERN_DEBUG "%s: input packet is too small, %d bytes\n",
+				dev->name, skb->len);
+drop:           kfree_skb(skb);
+		return;
+	}
+
+	/* Get PPP header. */
+	h = (struct ppp_header *)skb->data;
+	skb_pull(skb,sizeof(struct ppp_header));
+
+	switch (h->address) {
+	default:        /* Invalid PPP packet. */
+invalid:        if (sp->pp_flags & PP_DEBUG)
+			printk (KERN_WARNING "%s: invalid input packet <0x%x 0x%x 0x%x>\n",
+				dev->name,
+				h->address, h->control, ntohs (h->protocol));
+		goto drop;
+	case PPP_ALLSTATIONS:
+		if (h->control != PPP_UI)
+			goto invalid;
+		if (sp->pp_flags & PP_CISCO) {
+			if (sp->pp_flags & PP_DEBUG)
+				printk (KERN_WARNING "%s: PPP packet in Cisco mode <0x%x 0x%x 0x%x>\n",
+					dev->name,
+					h->address, h->control, ntohs (h->protocol));
+			goto drop;
+		}
+		switch (ntohs (h->protocol)) {
+		default:
+			if (sp->lcp.state == LCP_STATE_OPENED)
+				sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ,
+					++sp->pp_seq, skb->len + 2,
+					&h->protocol);
+			if (sp->pp_flags & PP_DEBUG)
+				printk (KERN_WARNING "%s: invalid input protocol <0x%x 0x%x 0x%x>\n",
+					dev->name,
+					h->address, h->control, ntohs (h->protocol));
+			goto drop;
+		case PPP_LCP:
+			sppp_lcp_input (sp, skb);
+			kfree_skb(skb);
+			return;
+		case PPP_IPCP:
+			if (sp->lcp.state == LCP_STATE_OPENED)
+				sppp_ipcp_input (sp, skb);
+			else
+				printk(KERN_DEBUG "IPCP when still waiting LCP finish.\n");
+			kfree_skb(skb);
+			return;
+		case PPP_IP:
+			if (sp->ipcp.state == IPCP_STATE_OPENED) {
+				if(sp->pp_flags&PP_DEBUG)
+					printk(KERN_DEBUG "Yow an IP frame.\n");
+				skb->protocol=htons(ETH_P_IP);
+				netif_rx(skb);
+				return;
+			}
+			break;
+#ifdef IPX
+		case PPP_IPX:
+			/* IPX IPXCP not implemented yet */
+			if (sp->lcp.state == LCP_STATE_OPENED) {
+				skb->protocol=htons(ETH_P_IPX);
+				netif_rx(skb);
+				return;
+			}
+			break;
+#endif
+		}
+		break;
+	case CISCO_MULTICAST:
+	case CISCO_UNICAST:
+		/* Don't check the control field here (RFC 1547). */
+		if (! (sp->pp_flags & PP_CISCO)) {
+			if (sp->pp_flags & PP_DEBUG)
+				printk (KERN_WARNING "%s: Cisco packet in PPP mode <0x%x 0x%x 0x%x>\n",
+					dev->name,
+					h->address, h->control, ntohs (h->protocol));
+			goto drop;
+		}
+		switch (ntohs (h->protocol)) {
+		default:
+			goto invalid;
+		case CISCO_KEEPALIVE:
+			sppp_cisco_input (sp, skb);
+			kfree_skb(skb);
+			return;
+#ifdef CONFIG_INET
+		case ETH_P_IP:
+			skb->protocol=htons(ETH_P_IP);
+			netif_rx(skb);
+			return;
+#endif
+#ifdef CONFIG_IPX
+		case ETH_P_IPX:
+			skb->protocol=htons(ETH_P_IPX);
+			netif_rx(skb);
+			return;
+#endif
+		}
+		break;
+	}
+	kfree_skb(skb);
+}
+
+EXPORT_SYMBOL(sppp_input);
+
+/*
+ *	Handle transmit packets.
+ */
+ 
+static int sppp_hard_header(struct sk_buff *skb, struct net_device *dev, __u16 type,
+		void *daddr, void *saddr, unsigned int len)
+{
+	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
+	struct ppp_header *h;
+	skb_push(skb,sizeof(struct ppp_header));
+	h=(struct ppp_header *)skb->data;
+	if(sp->pp_flags&PP_CISCO)
+	{
+		h->address = CISCO_MULTICAST;
+		h->control = 0;
+	}
+	else
+	{
+		h->address = PPP_ALLSTATIONS;
+		h->control = PPP_UI;
+	}
+	if(sp->pp_flags & PP_CISCO)
+	{
+		h->protocol = htons(type);
+	}
+	else switch(type)
+	{
+		case ETH_P_IP:
+			h->protocol = htons(PPP_IP);
+			break;
+		case ETH_P_IPX:
+			h->protocol = htons(PPP_IPX);
+			break;
+	}
+	return sizeof(struct ppp_header);
+}
+
+static int sppp_rebuild_header(struct sk_buff *skb)
+{
+	return 0;
+}
+
+/*
+ * Send keepalive packets, every 10 seconds.
+ */
+
+static void sppp_keepalive (unsigned long dummy)
+{
+	struct sppp *sp;
+	unsigned long flags;
+	save_flags(flags);
+	cli();
+
+	for (sp=spppq; sp; sp=sp->pp_next) 
+	{
+		struct net_device *dev = sp->pp_if;
+
+		/* Keepalive mode disabled or channel down? */
+		if (! (sp->pp_flags & PP_KEEPALIVE) ||
+		    ! (dev->flags & IFF_RUNNING))
+			continue;
+
+		/* No keepalive in PPP mode if LCP not opened yet. */
+		if (! (sp->pp_flags & PP_CISCO) &&
+		    sp->lcp.state != LCP_STATE_OPENED)
+			continue;
+
+		if (sp->pp_alivecnt == MAXALIVECNT) {
+			/* No keepalive packets got.  Stop the interface. */
+			printk (KERN_WARNING "%s: down\n", dev->name);
+			if_down (dev);
+			if (! (sp->pp_flags & PP_CISCO)) {
+				/* Shut down the PPP link. */
+				sp->lcp.magic = jiffies;
+				sp->lcp.state = LCP_STATE_CLOSED;
+				sp->ipcp.state = IPCP_STATE_CLOSED;
+				sppp_clear_timeout (sp);
+				/* Initiate negotiation. */
+				sppp_lcp_open (sp);
+			}
+		}
+		if (sp->pp_alivecnt <= MAXALIVECNT)
+			++sp->pp_alivecnt;
+		if (sp->pp_flags & PP_CISCO)
+			sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq,
+				sp->pp_rseq);
+		else if (sp->lcp.state == LCP_STATE_OPENED) {
+			long nmagic = htonl (sp->lcp.magic);
+			sp->lcp.echoid = ++sp->pp_seq;
+			sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ,
+				sp->lcp.echoid, 4, &nmagic);
+		}
+	}
+	restore_flags(flags);
+	sppp_keepalive_timer.expires=jiffies+10*HZ;
+	add_timer(&sppp_keepalive_timer);
+}
+
+/*
+ * Handle incoming PPP Link Control Protocol packets.
+ */
+ 
+static void sppp_lcp_input (struct sppp *sp, struct sk_buff *skb)
+{
+	struct lcp_header *h;
+	struct net_device *dev = sp->pp_if;
+	int len = skb->len;
+	u8 *p, opt[6];
+	u32 rmagic;
+
+	if (len < 4) {
+		if (sp->pp_flags & PP_DEBUG)
+			printk (KERN_WARNING "%s: invalid lcp packet length: %d bytes\n",
+				dev->name, len);
+		return;
+	}
+	h = (struct lcp_header *)skb->data;
+	skb_pull(skb,sizeof(struct lcp_header *));
+	
+	if (sp->pp_flags & PP_DEBUG) 
+	{
+		char state = '?';
+		switch (sp->lcp.state) {
+		case LCP_STATE_CLOSED:   state = 'C'; break;
+		case LCP_STATE_ACK_RCVD: state = 'R'; break;
+		case LCP_STATE_ACK_SENT: state = 'S'; break;
+		case LCP_STATE_OPENED:   state = 'O'; break;
+		}
+		printk (KERN_WARNING "%s: lcp input(%c): %d bytes <%s id=%xh len=%xh",
+			dev->name, state, len,
+			sppp_lcp_type_name (h->type), h->ident, ntohs (h->len));
+		if (len > 4)
+			sppp_print_bytes ((u8*) (h+1), len-4);
+		printk (">\n");
+	}
+	if (len > ntohs (h->len))
+		len = ntohs (h->len);
+	switch (h->type) {
+	default:
+		/* Unknown packet type -- send Code-Reject packet. */
+		sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq,
+			skb->len, h);
+		break;
+	case LCP_CONF_REQ:
+		if (len < 4) {
+			if (sp->pp_flags & PP_DEBUG)
+				printk (KERN_DEBUG"%s: invalid lcp configure request packet length: %d bytes\n",
+					dev->name, len);
+			break;
+		}
+		if (len>4 && !sppp_lcp_conf_parse_options (sp, h, len, &rmagic))
+			goto badreq;
+		if (rmagic == sp->lcp.magic) {
+			/* Local and remote magics equal -- loopback? */
+			if (sp->pp_loopcnt >= MAXALIVECNT*5) {
+				printk (KERN_WARNING "%s: loopback\n",
+					dev->name);
+				sp->pp_loopcnt = 0;
+				if (dev->flags & IFF_UP) {
+					if_down (dev);
+				}
+			} else if (sp->pp_flags & PP_DEBUG)
+				printk (KERN_DEBUG "%s: conf req: magic glitch\n",
+					dev->name);
+			++sp->pp_loopcnt;
+
+			/* MUST send Conf-Nack packet. */
+			rmagic = ~sp->lcp.magic;
+			opt[0] = LCP_OPT_MAGIC;
+			opt[1] = sizeof (opt);
+			opt[2] = rmagic >> 24;
+			opt[3] = rmagic >> 16;
+			opt[4] = rmagic >> 8;
+			opt[5] = rmagic;
+			sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK,
+				h->ident, sizeof (opt), &opt);
+badreq:
+			switch (sp->lcp.state) {
+			case LCP_STATE_OPENED:
+				/* Initiate renegotiation. */
+				sppp_lcp_open (sp);
+				/* fall through... */
+			case LCP_STATE_ACK_SENT:
+				/* Go to closed state. */
+				sp->lcp.state = LCP_STATE_CLOSED;
+				sp->ipcp.state = IPCP_STATE_CLOSED;
+			}
+			break;
+		}
+		/* Send Configure-Ack packet. */
+		sp->pp_loopcnt = 0;
+		sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK,
+				h->ident, len-4, h+1);
+		/* Change the state. */
+		switch (sp->lcp.state) {
+		case LCP_STATE_CLOSED:
+			sp->lcp.state = LCP_STATE_ACK_SENT;
+			break;
+		case LCP_STATE_ACK_RCVD:
+			sp->lcp.state = LCP_STATE_OPENED;
+			sppp_ipcp_open (sp);
+			break;
+		case LCP_STATE_OPENED:
+#if 0		
+			/* Remote magic changed -- close session. */
+			sp->lcp.state = LCP_STATE_CLOSED;
+			sp->ipcp.state = IPCP_STATE_CLOSED;
+			/* Initiate renegotiation. */
+			sppp_lcp_open (sp);
+			/* An ACK has already been sent. */
+			sp->lcp.state = LCP_STATE_ACK_SENT;
+#endif			
+			break;
+		}
+		break;
+	case LCP_CONF_ACK:
+		if (h->ident != sp->lcp.confid)
+			break;
+		sppp_clear_timeout (sp);
+		if (! (dev->flags & IFF_UP) &&
+		    (dev->flags & IFF_RUNNING)) {
+			/* Coming out of loopback mode. */
+			dev->flags |= IFF_UP;
+			printk (KERN_INFO "%s: up\n", dev->name);
+		}
+		switch (sp->lcp.state) {
+		case LCP_STATE_CLOSED:
+			sp->lcp.state = LCP_STATE_ACK_RCVD;
+			sppp_set_timeout (sp, 5);
+			break;
+		case LCP_STATE_ACK_SENT:
+			sp->lcp.state = LCP_STATE_OPENED;
+			sppp_ipcp_open (sp);
+			break;
+		}
+		break;
+	case LCP_CONF_NAK:
+		if (h->ident != sp->lcp.confid)
+			break;
+		p = (u8*) (h+1);
+		if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) {
+			rmagic = (u32)p[2] << 24 |
+				(u32)p[3] << 16 | p[4] << 8 | p[5];
+			if (rmagic == ~sp->lcp.magic) {
+				int newmagic;
+				if (sp->pp_flags & PP_DEBUG)
+					printk (KERN_DEBUG "%s: conf nak: magic glitch\n",
+						dev->name);
+				get_random_bytes(&newmagic, sizeof(newmagic));
+				sp->lcp.magic += newmagic;
+			} else
+				sp->lcp.magic = rmagic;
+			}
+		if (sp->lcp.state != LCP_STATE_ACK_SENT) {
+			/* Go to closed state. */
+			sp->lcp.state = LCP_STATE_CLOSED;
+			sp->ipcp.state = IPCP_STATE_CLOSED;
+		}
+		/* The link will be renegotiated after timeout,
+		 * to avoid endless req-nack loop. */
+		sppp_clear_timeout (sp);
+		sppp_set_timeout (sp, 2);
+		break;
+	case LCP_CONF_REJ:
+		if (h->ident != sp->lcp.confid)
+			break;
+		sppp_clear_timeout (sp);
+		/* Initiate renegotiation. */
+		sppp_lcp_open (sp);
+		if (sp->lcp.state != LCP_STATE_ACK_SENT) {
+			/* Go to closed state. */
+			sp->lcp.state = LCP_STATE_CLOSED;
+			sp->ipcp.state = IPCP_STATE_CLOSED;
+		}
+		break;
+	case LCP_TERM_REQ:
+		sppp_clear_timeout (sp);
+		/* Send Terminate-Ack packet. */
+		sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, 0);
+		/* Go to closed state. */
+		sp->lcp.state = LCP_STATE_CLOSED;
+		sp->ipcp.state = IPCP_STATE_CLOSED;
+		/* Initiate renegotiation. */
+		sppp_lcp_open (sp);
+		break;
+	case LCP_TERM_ACK:
+	case LCP_CODE_REJ:
+	case LCP_PROTO_REJ:
+		/* Ignore for now. */
+		break;
+	case LCP_DISC_REQ:
+		/* Discard the packet. */
+		break;
+	case LCP_ECHO_REQ:
+		if (sp->lcp.state != LCP_STATE_OPENED)
+			break;
+		if (len < 8) {
+			if (sp->pp_flags & PP_DEBUG)
+				printk (KERN_WARNING "%s: invalid lcp echo request packet length: %d bytes\n",
+					dev->name, len);
+			break;
+		}
+		if (ntohl (*(long*)(h+1)) == sp->lcp.magic) {
+			/* Line loopback mode detected. */
+			printk (KERN_WARNING "%s: loopback\n", dev->name);
+			if_down (dev);
+
+			/* Shut down the PPP link. */
+			sp->lcp.state = LCP_STATE_CLOSED;
+			sp->ipcp.state = IPCP_STATE_CLOSED;
+			sppp_clear_timeout (sp);
+			/* Initiate negotiation. */
+			sppp_lcp_open (sp);
+			break;
+		}
+		*(long*)(h+1) = htonl (sp->lcp.magic);
+		sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REPLY, h->ident, len-4, h+1);
+		break;
+	case LCP_ECHO_REPLY:
+		if (h->ident != sp->lcp.echoid)
+			break;
+		if (len < 8) {
+			if (sp->pp_flags & PP_DEBUG)
+				printk (KERN_WARNING "%s: invalid lcp echo reply packet length: %d bytes\n",
+					dev->name, len);
+			break;
+		}
+		if (ntohl (*(long*)(h+1)) != sp->lcp.magic)
+		sp->pp_alivecnt = 0;
+		break;
+	}
+}
+
+/*
+ * Handle incoming Cisco keepalive protocol packets.
+ */
+
+static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb)
+{
+	struct cisco_packet *h;
+	struct net_device *dev = sp->pp_if;
+
+	if (skb->len != CISCO_PACKET_LEN && skb->len != CISCO_BIG_PACKET_LEN) {
+		if (sp->pp_flags & PP_DEBUG)
+			printk (KERN_WARNING "%s: invalid cisco packet length: %d bytes\n",
+				dev->name,  skb->len);
+		return;
+	}
+	h = (struct cisco_packet *)skb->data;
+	skb_pull(skb, sizeof(struct cisco_packet*));
+	if (sp->pp_flags & PP_DEBUG)
+		printk (KERN_WARNING "%s: cisco input: %d bytes <%lxh %xh %xh %xh %xh-%xh>\n",
+			dev->name,  skb->len,
+			ntohl (h->type), h->par1, h->par2, h->rel,
+			h->time0, h->time1);
+	switch (ntohl (h->type)) {
+	default:
+		if (sp->pp_flags & PP_DEBUG)
+			printk (KERN_WARNING "%s: unknown cisco packet type: 0x%lx\n",
+				dev->name,  ntohl (h->type));
+		break;
+	case CISCO_ADDR_REPLY:
+		/* Reply on address request, ignore */
+		break;
+	case CISCO_KEEPALIVE_REQ:
+		sp->pp_alivecnt = 0;
+		sp->pp_rseq = ntohl (h->par1);
+		if (sp->pp_seq == sp->pp_rseq) {
+			/* Local and remote sequence numbers are equal.
+			 * Probably, the line is in loopback mode. */
+			int newseq;
+			if (sp->pp_loopcnt >= MAXALIVECNT) {
+				printk (KERN_WARNING "%s: loopback\n",
+					dev->name);
+				sp->pp_loopcnt = 0;
+				if (dev->flags & IFF_UP) {
+					if_down (dev);
+				}
+			}
+			++sp->pp_loopcnt;
+
+			/* Generate new local sequence number */
+			get_random_bytes(&newseq, sizeof(newseq));
+			sp->pp_seq ^= newseq;
+			break;
+		}
+		sp->pp_loopcnt = 0;
+		if (! (dev->flags & IFF_UP) &&
+		    (dev->flags & IFF_RUNNING)) {
+			dev->flags |= IFF_UP;
+			printk (KERN_INFO "%s: up\n", dev->name);
+		}
+		break;
+	case CISCO_ADDR_REQ:
+		/* Stolen from net/ipv4/devinet.c -- SIOCGIFADDR ioctl */
+		{
+		struct in_device *in_dev;
+		struct in_ifaddr *ifa;
+		u32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */
+
+		if ((in_dev=in_dev_get(dev)) != NULL)
+		{
+			read_lock(&in_dev->lock);
+			for (ifa=in_dev->ifa_list; ifa != NULL;
+				ifa=ifa->ifa_next) {
+				if (strcmp(dev->name, ifa->ifa_label) == 0) 
+				{
+					addr = ifa->ifa_local;
+					mask = ifa->ifa_mask;
+					break;
+				}
+			}
+			read_unlock(&in_dev->lock);
+			in_dev_put(in_dev);
+		}
+		/* I hope both addr and mask are in the net order */
+		sppp_cisco_send (sp, CISCO_ADDR_REPLY, addr, mask);
+		break;
+		}
+	}
+}
+
+/*
+ * Send PPP LCP packet.
+ */
+
+static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type,
+	u8 ident, u16 len, void *data)
+{
+	struct ppp_header *h;
+	struct lcp_header *lh;
+	struct sk_buff *skb;
+	struct net_device *dev = sp->pp_if;
+
+	skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+LCP_HEADER_LEN+len,
+		GFP_ATOMIC);
+	if (skb==NULL)
+		return;
+
+	skb_reserve(skb,dev->hard_header_len);
+	
+	h = (struct ppp_header *)skb_put(skb, sizeof(struct ppp_header));
+	h->address = PPP_ALLSTATIONS;        /* broadcast address */
+	h->control = PPP_UI;                 /* Unnumbered Info */
+	h->protocol = htons (proto);         /* Link Control Protocol */
+
+	lh = (struct lcp_header *)skb_put(skb, sizeof(struct lcp_header));
+	lh->type = type;
+	lh->ident = ident;
+	lh->len = htons (LCP_HEADER_LEN + len);
+
+	if (len)
+		memcpy(skb_put(skb,len),data, len);
+
+	if (sp->pp_flags & PP_DEBUG) {
+		printk (KERN_WARNING "%s: %s output <%s id=%xh len=%xh",
+			dev->name, 
+			proto==PPP_LCP ? "lcp" : "ipcp",
+			proto==PPP_LCP ? sppp_lcp_type_name (lh->type) :
+			sppp_ipcp_type_name (lh->type), lh->ident,
+			ntohs (lh->len));
+		if (len)
+			sppp_print_bytes ((u8*) (lh+1), len);
+		printk (">\n");
+	}
+	sp->obytes += skb->len;
+	/* Control is high priority so it doesnt get queued behind data */
+	skb->priority=TC_PRIO_CONTROL;
+	skb->dev = dev;
+	dev_queue_xmit(skb);
+}
+
+/*
+ * Send Cisco keepalive packet.
+ */
+
+static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2)
+{
+	struct ppp_header *h;
+	struct cisco_packet *ch;
+	struct sk_buff *skb;
+	struct net_device *dev = sp->pp_if;
+	u32 t = jiffies * 1000/HZ;
+
+	skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+CISCO_PACKET_LEN,
+		GFP_ATOMIC);
+
+	if(skb==NULL)
+		return;
+		
+	skb_reserve(skb, dev->hard_header_len);
+	h = (struct ppp_header *)skb_put (skb, sizeof(struct ppp_header));
+	h->address = CISCO_MULTICAST;
+	h->control = 0;
+	h->protocol = htons (CISCO_KEEPALIVE);
+
+	ch = (struct cisco_packet*)skb_put(skb, CISCO_PACKET_LEN);
+	ch->type = htonl (type);
+	ch->par1 = htonl (par1);
+	ch->par2 = htonl (par2);
+	ch->rel = -1;
+	ch->time0 = htons ((u16) (t >> 16));
+	ch->time1 = htons ((u16) t);
+
+	if (sp->pp_flags & PP_DEBUG)
+		printk (KERN_WARNING "%s: cisco output: <%lxh %xh %xh %xh %xh-%xh>\n",
+			dev->name,  ntohl (ch->type), ch->par1,
+			ch->par2, ch->rel, ch->time0, ch->time1);
+	sp->obytes += skb->len;
+	skb->priority=TC_PRIO_CONTROL;
+	skb->dev = dev;
+	dev_queue_xmit(skb);
+}
+
+
+int sppp_close (struct net_device *dev)
+{
+	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
+	dev->flags &= ~IFF_RUNNING;
+	sp->lcp.state = LCP_STATE_CLOSED;
+	sp->ipcp.state = IPCP_STATE_CLOSED;
+	sppp_clear_timeout (sp);
+	return 0;
+}
+
+EXPORT_SYMBOL(sppp_close);
+
+
+int sppp_open (struct net_device *dev)
+{
+	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
+	sppp_close(dev);
+	dev->flags |= IFF_RUNNING;
+	if (!(sp->pp_flags & PP_CISCO))
+		sppp_lcp_open (sp);
+	return 0;
+}
+
+EXPORT_SYMBOL(sppp_open);
+
+int sppp_reopen (struct net_device *dev)
+{
+	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
+	sppp_close(dev);
+	dev->flags |= IFF_RUNNING;
+	if (!(sp->pp_flags & PP_CISCO))
+	{
+		sp->lcp.magic = jiffies;
+		++sp->pp_seq;
+		sp->lcp.state = LCP_STATE_CLOSED;
+		sp->ipcp.state = IPCP_STATE_CLOSED;
+		/* Give it a moment for the line to settle then go */
+		sppp_set_timeout (sp, 1);
+	}
+	return 0;
+}
+
+EXPORT_SYMBOL(sppp_reopen);
+
+int sppp_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if(new_mtu<128||new_mtu>PPP_MTU||(dev->flags&IFF_UP))
+		return -EINVAL;
+	dev->mtu=new_mtu;
+	return 0;
+}
+
+EXPORT_SYMBOL(sppp_change_mtu);
+
+int sppp_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
+
+	if(dev->flags&IFF_UP)
+		return -EBUSY;
+		
+	if(!capable(CAP_NET_ADMIN))
+		return -EPERM;
+	
+	switch(cmd)
+	{
+		case SPPPIOCCISCO:
+			sp->pp_flags|=PP_CISCO;
+			dev->type = ARPHRD_HDLC;
+			break;
+		case SPPPIOCPPP:
+			sp->pp_flags&=~PP_CISCO;
+			dev->type = ARPHRD_PPP;
+			break;
+		case SPPPIOCDEBUG:
+			sp->pp_flags&=~PP_DEBUG;
+			if(ifr->ifr_flags)
+				sp->pp_flags|=PP_DEBUG;
+			break;
+		default:
+			return -EINVAL;
+	}
+	return 0;
+}
+
+EXPORT_SYMBOL(sppp_do_ioctl);
+
+void sppp_attach(struct ppp_device *pd)
+{
+	struct net_device *dev=&pd->dev;
+	struct sppp *sp = &pd->sppp;
+	
+	/* Initialize keepalive handler. */
+	if (! spppq)
+	{
+		init_timer(&sppp_keepalive_timer);
+		sppp_keepalive_timer.expires=jiffies+10*HZ;
+		sppp_keepalive_timer.function=sppp_keepalive;
+		add_timer(&sppp_keepalive_timer);
+	}
+	/* Insert new entry into the keepalive list. */
+	sp->pp_next = spppq;
+	spppq = sp;
+
+	sp->pp_loopcnt = 0;
+	sp->pp_alivecnt = 0;
+	sp->pp_seq = 0;
+	sp->pp_rseq = 0;
+	sp->pp_flags = PP_KEEPALIVE|PP_CISCO|debug;/*PP_DEBUG;*/
+	sp->lcp.magic = 0;
+	sp->lcp.state = LCP_STATE_CLOSED;
+	sp->ipcp.state = IPCP_STATE_CLOSED;
+	sp->pp_if = dev;
+	
+	/* 
+	 *	Device specific setup. All but interrupt handler and
+	 *	hard_start_xmit.
+	 */
+	 
+	dev->hard_header = sppp_hard_header;
+	dev->rebuild_header = sppp_rebuild_header;
+	dev->tx_queue_len = 10;
+	dev->type = ARPHRD_HDLC;
+	dev->addr_len = 0;
+	dev->hard_header_len = sizeof(struct ppp_header);
+	dev->mtu = PPP_MTU;
+	/*
+	 *	These 4 are callers but MUST also call sppp_ functions
+	 */
+	dev->do_ioctl = sppp_do_ioctl;
+#if 0
+	dev->get_stats = NULL;		/* Let the driver override these */
+	dev->open = sppp_open;
+	dev->stop = sppp_close;
+#endif	
+	dev->change_mtu = sppp_change_mtu;
+	dev->hard_header_cache = NULL;
+	dev->header_cache_update = NULL;
+	dev->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP;
+	dev_init_buffers(dev);
+}
+
+EXPORT_SYMBOL(sppp_attach);
+
+void sppp_detach (struct net_device *dev)
+{
+	struct sppp **q, *p, *sp = &((struct ppp_device *)dev)->sppp;
+
+
+	/* Remove the entry from the keepalive list. */
+	for (q = &spppq; (p = *q); q = &p->pp_next)
+		if (p == sp) {
+			*q = p->pp_next;
+			break;
+		}
+
+	/* Stop keepalive handler. */
+	if (! spppq)
+		del_timer(&sppp_keepalive_timer);
+	sppp_clear_timeout (sp);
+}
+
+EXPORT_SYMBOL(sppp_detach);
+
+/*
+ * Analyze the LCP Configure-Request options list
+ * for the presence of unknown options.
+ * If the request contains unknown options, build and
+ * send Configure-reject packet, containing only unknown options.
+ */
+static int
+sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h,
+	int len, u32 *magic)
+{
+	u8 *buf, *r, *p;
+	int rlen;
+
+	len -= 4;
+	buf = r = kmalloc (len, GFP_ATOMIC);
+	if (! buf)
+		return (0);
+
+	p = (void*) (h+1);
+	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
+		switch (*p) {
+		case LCP_OPT_MAGIC:
+			/* Magic number -- extract. */
+			if (len >= 6 && p[1] == 6) {
+				*magic = (u32)p[2] << 24 |
+					(u32)p[3] << 16 | p[4] << 8 | p[5];
+				continue;
+			}
+			break;
+		case LCP_OPT_ASYNC_MAP:
+			/* Async control character map -- check to be zero. */
+			if (len >= 6 && p[1] == 6 && ! p[2] && ! p[3] &&
+			    ! p[4] && ! p[5])
+				continue;
+			break;
+		case LCP_OPT_MRU:
+			/* Maximum receive unit -- always OK. */
+			continue;
+		default:
+			/* Others not supported. */
+			break;
+		}
+		/* Add the option to rejected list. */
+		memcpy(r, p, p[1]);
+		r += p[1];
+		rlen += p[1];
+	}
+	if (rlen)
+		sppp_cp_send (sp, PPP_LCP, LCP_CONF_REJ, h->ident, rlen, buf);
+	kfree(buf);
+	return (rlen == 0);
+}
+
+static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *skb)
+{
+	struct lcp_header *h;
+	struct net_device *dev = sp->pp_if;
+	int len = skb->len;
+
+	if (len < 4) 
+	{
+		if (sp->pp_flags & PP_DEBUG)
+			printk (KERN_WARNING "%s: invalid ipcp packet length: %d bytes\n",
+				dev->name,  len);
+		return;
+	}
+	h = (struct lcp_header *)skb->data;
+	skb_pull(skb,sizeof(struct lcp_header));
+	if (sp->pp_flags & PP_DEBUG) {
+		printk (KERN_WARNING "%s: ipcp input: %d bytes <%s id=%xh len=%xh",
+			dev->name,  len,
+			sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len));
+		if (len > 4)
+			sppp_print_bytes ((u8*) (h+1), len-4);
+		printk (">\n");
+	}
+	if (len > ntohs (h->len))
+		len = ntohs (h->len);
+	switch (h->type) {
+	default:
+		/* Unknown packet type -- send Code-Reject packet. */
+		sppp_cp_send (sp, PPP_IPCP, IPCP_CODE_REJ, ++sp->pp_seq, len, h);
+		break;
+	case IPCP_CONF_REQ:
+		if (len < 4) {
+			if (sp->pp_flags & PP_DEBUG)
+				printk (KERN_WARNING "%s: invalid ipcp configure request packet length: %d bytes\n",
+					dev->name, len);
+			return;
+		}
+		if (len > 4) {
+			sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident,
+				len-4, h+1);
+
+			switch (sp->ipcp.state) {
+			case IPCP_STATE_OPENED:
+				/* Initiate renegotiation. */
+				sppp_ipcp_open (sp);
+				/* fall through... */
+			case IPCP_STATE_ACK_SENT:
+				/* Go to closed state. */
+				sp->ipcp.state = IPCP_STATE_CLOSED;
+			}
+		} else {
+			/* Send Configure-Ack packet. */
+			sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident,
+				0, 0);
+			/* Change the state. */
+			if (sp->ipcp.state == IPCP_STATE_ACK_RCVD)
+				sp->ipcp.state = IPCP_STATE_OPENED;
+			else
+				sp->ipcp.state = IPCP_STATE_ACK_SENT;
+		}
+		break;
+	case IPCP_CONF_ACK:
+		if (h->ident != sp->ipcp.confid)
+			break;
+		sppp_clear_timeout (sp);
+		switch (sp->ipcp.state) {
+		case IPCP_STATE_CLOSED:
+			sp->ipcp.state = IPCP_STATE_ACK_RCVD;
+			sppp_set_timeout (sp, 5);
+			break;
+		case IPCP_STATE_ACK_SENT:
+			sp->ipcp.state = IPCP_STATE_OPENED;
+			break;
+		}
+		break;
+	case IPCP_CONF_NAK:
+	case IPCP_CONF_REJ:
+		if (h->ident != sp->ipcp.confid)
+			break;
+		sppp_clear_timeout (sp);
+			/* Initiate renegotiation. */
+		sppp_ipcp_open (sp);
+		if (sp->ipcp.state != IPCP_STATE_ACK_SENT)
+			/* Go to closed state. */
+			sp->ipcp.state = IPCP_STATE_CLOSED;
+		break;
+	case IPCP_TERM_REQ:
+		/* Send Terminate-Ack packet. */
+		sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, 0);
+		/* Go to closed state. */
+		sp->ipcp.state = IPCP_STATE_CLOSED;
+		/* Initiate renegotiation. */
+		sppp_ipcp_open (sp);
+		break;
+	case IPCP_TERM_ACK:
+		/* Ignore for now. */
+	case IPCP_CODE_REJ:
+		/* Ignore for now. */
+		break;
+	}
+}
+
+static void sppp_lcp_open (struct sppp *sp)
+{
+	char opt[6];
+
+	if (! sp->lcp.magic)
+		sp->lcp.magic = jiffies;
+	opt[0] = LCP_OPT_MAGIC;
+	opt[1] = sizeof (opt);
+	opt[2] = sp->lcp.magic >> 24;
+	opt[3] = sp->lcp.magic >> 16;
+	opt[4] = sp->lcp.magic >> 8;
+	opt[5] = sp->lcp.magic;
+	sp->lcp.confid = ++sp->pp_seq;
+	sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, sp->lcp.confid,
+		sizeof (opt), &opt);
+	sppp_set_timeout (sp, 2);
+}
+
+static void sppp_ipcp_open (struct sppp *sp)
+{
+	sp->ipcp.confid = ++sp->pp_seq;
+	sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0, 0);
+	sppp_set_timeout (sp, 2);
+}
+
+/*
+ * Process PPP control protocol timeouts.
+ */
+ 
+static void sppp_cp_timeout (unsigned long arg)
+{
+	struct sppp *sp = (struct sppp*) arg;
+	unsigned long flags;
+	save_flags(flags);
+	cli();
+
+	sp->pp_flags &= ~PP_TIMO;
+	if (! (sp->pp_if->flags & IFF_RUNNING) || (sp->pp_flags & PP_CISCO)) {
+		restore_flags(flags);
+		return;
+	}
+	switch (sp->lcp.state) {
+	case LCP_STATE_CLOSED:
+		/* No ACK for Configure-Request, retry. */
+		sppp_lcp_open (sp);
+		break;
+	case LCP_STATE_ACK_RCVD:
+		/* ACK got, but no Configure-Request for peer, retry. */
+		sppp_lcp_open (sp);
+		sp->lcp.state = LCP_STATE_CLOSED;
+		break;
+	case LCP_STATE_ACK_SENT:
+		/* ACK sent but no ACK for Configure-Request, retry. */
+		sppp_lcp_open (sp);
+		break;
+	case LCP_STATE_OPENED:
+		/* LCP is already OK, try IPCP. */
+		switch (sp->ipcp.state) {
+		case IPCP_STATE_CLOSED:
+			/* No ACK for Configure-Request, retry. */
+			sppp_ipcp_open (sp);
+			break;
+		case IPCP_STATE_ACK_RCVD:
+			/* ACK got, but no Configure-Request for peer, retry. */
+			sppp_ipcp_open (sp);
+			sp->ipcp.state = IPCP_STATE_CLOSED;
+			break;
+		case IPCP_STATE_ACK_SENT:
+			/* ACK sent but no ACK for Configure-Request, retry. */
+			sppp_ipcp_open (sp);
+			break;
+		case IPCP_STATE_OPENED:
+			/* IPCP is OK. */
+			break;
+		}
+		break;
+	}
+	restore_flags(flags);
+}
+
+static char *sppp_lcp_type_name (u8 type)
+{
+	static char buf [8];
+	switch (type) {
+	case LCP_CONF_REQ:   return ("conf-req");
+	case LCP_CONF_ACK:   return ("conf-ack");
+	case LCP_CONF_NAK:   return ("conf-nack");
+	case LCP_CONF_REJ:   return ("conf-rej");
+	case LCP_TERM_REQ:   return ("term-req");
+	case LCP_TERM_ACK:   return ("term-ack");
+	case LCP_CODE_REJ:   return ("code-rej");
+	case LCP_PROTO_REJ:  return ("proto-rej");
+	case LCP_ECHO_REQ:   return ("echo-req");
+	case LCP_ECHO_REPLY: return ("echo-reply");
+	case LCP_DISC_REQ:   return ("discard-req");
+	}
+	sprintf (buf, "%xh", type);
+	return (buf);
+}
+
+static char *sppp_ipcp_type_name (u8 type)
+{
+	static char buf [8];
+	switch (type) {
+	case IPCP_CONF_REQ:   return ("conf-req");
+	case IPCP_CONF_ACK:   return ("conf-ack");
+	case IPCP_CONF_NAK:   return ("conf-nack");
+	case IPCP_CONF_REJ:   return ("conf-rej");
+	case IPCP_TERM_REQ:   return ("term-req");
+	case IPCP_TERM_ACK:   return ("term-ack");
+	case IPCP_CODE_REJ:   return ("code-rej");
+	}
+	sprintf (buf, "%xh", type);
+	return (buf);
+}
+
+static void sppp_print_bytes (u_char *p, u16 len)
+{
+	printk (" %x", *p++);
+	while (--len > 0)
+		printk ("-%x", *p++);
+}
+
+/*
+ *	Protocol glue. This drives the deferred processing mode the poorer
+ *	cards use.
+ */
+
+int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p)
+{
+	sppp_input(dev,skb);
+	return 0;
+}
+
+EXPORT_SYMBOL(sppp_rcv);
+
+struct packet_type sppp_packet_type=
+{
+	0,
+	NULL,
+	sppp_rcv,
+	NULL,
+	NULL
+};
+
+
+void sync_ppp_init(void)
+{
+	printk(KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n");
+	printk(KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & Jan \"Yenya\" Kasprzak.\n");
+	sppp_packet_type.type=htons(ETH_P_WAN_PPP);	
+	dev_add_pack(&sppp_packet_type);
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+	if(debug)
+		debug=PP_DEBUG;
+	sync_ppp_init();
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	dev_remove_pack(&sppp_packet_type);
+}
+
+#endif
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/syncppp.h linux/drivers/net/wan/syncppp.h
--- v2.3.20/linux/drivers/net/wan/syncppp.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/syncppp.h	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,91 @@
+/*
+ * Defines for synchronous PPP/Cisco link level subroutines.
+ *
+ * Copyright (C) 1994 Cronyx Ltd.
+ * Author: Serge Vakulenko, <vak@zebub.msk.su>
+ *
+ * This software is distributed with NO WARRANTIES, not even the implied
+ * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Authors grant any other persons or organizations permission to use
+ * or modify this software as long as this message is kept with the software,
+ * all derivative works or modified versions.
+ *
+ * Version 1.7, Wed Jun  7 22:12:02 MSD 1995
+ *
+ *
+ *
+ */
+
+#ifndef _SYNCPPP_H_
+#define _SYNCPPP_H_ 1
+
+#ifdef __KERNEL__
+struct slcp {
+	u16	state;          /* state machine */
+	u32	magic;          /* local magic number */
+	u_char	echoid;         /* id of last keepalive echo request */
+	u_char	confid;         /* id of last configuration request */
+};
+
+struct sipcp {
+	u16	state;          /* state machine */
+	u_char  confid;         /* id of last configuration request */
+};
+
+struct sppp 
+{
+	struct sppp *	pp_next;	/* next interface in keepalive list */
+	u32		pp_flags;	/* use Cisco protocol instead of PPP */
+	u16		pp_alivecnt;	/* keepalive packets counter */
+	u16		pp_loopcnt;	/* loopback detection counter */
+	u32		pp_seq;		/* local sequence number */
+	u32		pp_rseq;	/* remote sequence number */
+	struct slcp	lcp;		/* LCP params */
+	struct sipcp	ipcp;		/* IPCP params */
+	u32		ibytes,obytes;	/* Bytes in/out */
+	u32		ipkts,opkts;	/* Packets in/out */
+	struct timer_list	pp_timer;
+	struct net_device	*pp_if;
+};
+
+struct ppp_device
+{	
+	struct net_device dev;	/* Network device */
+	struct sppp sppp;	/* Synchronous PPP */
+};
+
+#define PP_KEEPALIVE    0x01    /* use keepalive protocol */
+#define PP_CISCO        0x02    /* use Cisco protocol instead of PPP */
+#define PP_TIMO         0x04    /* cp_timeout routine active */
+#define PP_DEBUG	0x08
+
+#define PPP_MTU          1500    /* max. transmit unit */
+
+#define LCP_STATE_CLOSED        0       /* LCP state: closed (conf-req sent) */
+#define LCP_STATE_ACK_RCVD      1       /* LCP state: conf-ack received */
+#define LCP_STATE_ACK_SENT      2       /* LCP state: conf-ack sent */
+#define LCP_STATE_OPENED        3       /* LCP state: opened */
+
+#define IPCP_STATE_CLOSED       0       /* IPCP state: closed (conf-req sent) */
+#define IPCP_STATE_ACK_RCVD     1       /* IPCP state: conf-ack received */
+#define IPCP_STATE_ACK_SENT     2       /* IPCP state: conf-ack sent */
+#define IPCP_STATE_OPENED       3       /* IPCP state: opened */
+
+void sppp_attach (struct ppp_device *pd);
+void sppp_detach (struct net_device *dev);
+void sppp_input (struct net_device *dev, struct sk_buff *m);
+int sppp_do_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd);
+struct sk_buff *sppp_dequeue (struct net_device *dev);
+int sppp_isempty (struct net_device *dev);
+void sppp_flush (struct net_device *dev);
+int sppp_open (struct net_device *dev);
+int sppp_reopen (struct net_device *dev);
+int sppp_close (struct net_device *dev);
+#endif
+
+#define SPPPIOCCISCO	(SIOCDEVPRIVATE)
+#define SPPPIOCPPP	(SIOCDEVPRIVATE+1)
+#define SPPPIOCDEBUG	(SIOCDEVPRIVATE+2)
+
+#endif /* _SYNCPPP_H_ */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/x25_asy.c linux/drivers/net/wan/x25_asy.c
--- v2.3.20/linux/drivers/net/wan/x25_asy.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/x25_asy.c	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,943 @@
+/*
+ *	Things to sort out:
+ *
+ *	o	tbusy handling
+ *	o	allow users to set the parameters
+ *	o	sync/async switching ?
+ *
+ *	Note: This does _not_ implement CCITT X.25 asynchronous framing
+ *	recommendations. Its primarily for testing purposes. If you wanted
+ *	to do CCITT then in theory all you need is to nick the HDLC async
+ *	checksum routines from ppp.c
+ */
+
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/x25.h>
+#include <linux/lapb.h>
+#include <linux/init.h>
+#include "x25_asy.h"
+
+typedef struct x25_ctrl {
+	char		if_name[8];	/* "xasy0\0" .. "xasy99999\0"	*/
+	struct x25_asy	ctrl;		/* X.25 things			*/
+	struct net_device	dev;		/* the device			*/
+} x25_asy_ctrl_t;
+
+static x25_asy_ctrl_t	**x25_asy_ctrls = NULL;
+
+int x25_asy_maxdev = SL_NRUNIT;		/* Can be overridden with insmod! */
+MODULE_PARM(x25_asy_maxdev, "i");
+
+static struct tty_ldisc	x25_ldisc;
+
+static int x25_asy_esc(unsigned char *p, unsigned char *d, int len);
+static void x25_asy_unesc(struct x25_asy *sl, unsigned char c);
+
+/* Find a free X.25 channel, and link in this `tty' line. */
+static inline struct x25_asy *x25_asy_alloc(void)
+{
+	x25_asy_ctrl_t *slp = NULL;
+	int i;
+
+	if (x25_asy_ctrls == NULL)
+		return NULL;	/* Master array missing ! */
+
+	for (i = 0; i < x25_asy_maxdev; i++) 
+	{
+		slp = x25_asy_ctrls[i];
+		/* Not allocated ? */
+		if (slp == NULL)
+			break;
+		/* Not in use ? */
+		if (!test_and_set_bit(SLF_INUSE, &slp->ctrl.flags))
+			break;
+	}
+	/* SLP is set.. */
+
+	/* Sorry, too many, all slots in use */
+	if (i >= x25_asy_maxdev)
+		return NULL;
+
+	/* If no channels are available, allocate one */
+	if (!slp &&
+	    (x25_asy_ctrls[i] = (x25_asy_ctrl_t *)kmalloc(sizeof(x25_asy_ctrl_t),
+						    GFP_KERNEL)) != NULL) {
+		slp = x25_asy_ctrls[i];
+		memset(slp, 0, sizeof(x25_asy_ctrl_t));
+
+		/* Initialize channel control data */
+		set_bit(SLF_INUSE, &slp->ctrl.flags);
+		slp->ctrl.tty         = NULL;
+		sprintf(slp->if_name, "x25asy%d", i);
+		slp->dev.name         = slp->if_name;
+		slp->dev.base_addr    = i;
+		slp->dev.priv         = (void*)&(slp->ctrl);
+		slp->dev.next         = NULL;
+		slp->dev.init         = x25_asy_init;
+	}
+	if (slp != NULL) 
+	{
+
+		/* register device so that it can be ifconfig'ed       */
+		/* x25_asy_init() will be called as a side-effect      */
+		/* SIDE-EFFECT WARNING: x25_asy_init() CLEARS slp->ctrl ! */
+
+		if (register_netdev(&(slp->dev)) == 0) 
+		{
+			/* (Re-)Set the INUSE bit.   Very Important! */
+			set_bit(SLF_INUSE, &slp->ctrl.flags);
+			slp->ctrl.dev = &(slp->dev);
+			slp->dev.priv = (void*)&(slp->ctrl);
+			return (&(slp->ctrl));
+		}
+		else
+		{
+			clear_bit(SLF_INUSE,&(slp->ctrl.flags));
+			printk("x25_asy_alloc() - register_netdev() failure.\n");
+		}
+	}
+	return NULL;
+}
+
+
+/* Free an X.25 channel. */
+
+static inline void x25_asy_free(struct x25_asy *sl)
+{
+	/* Free all X.25 frame buffers. */
+	if (sl->rbuff)  {
+		kfree(sl->rbuff);
+	}
+	sl->rbuff = NULL;
+	if (sl->xbuff)  {
+		kfree(sl->xbuff);
+	}
+	sl->xbuff = NULL;
+
+	if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) {
+		printk("%s: x25_asy_free for already free unit.\n", sl->dev->name);
+	}
+}
+
+/* MTU has been changed by the IP layer. Unfortunately we are not told
+   about this, but we spot it ourselves and fix things up. We could be
+   in an upcall from the tty driver, or in an ip packet queue. */
+
+static void x25_asy_changed_mtu(struct x25_asy *sl)
+{
+	struct net_device *dev = sl->dev;
+	unsigned char *xbuff, *rbuff, *oxbuff, *orbuff;
+	int len;
+	unsigned long flags;
+
+	len = dev->mtu * 2;
+
+	xbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
+	rbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
+
+	if (xbuff == NULL || rbuff == NULL)  
+	{
+		printk("%s: unable to grow X.25 buffers, MTU change cancelled.\n",
+		       sl->dev->name);
+		dev->mtu = sl->mtu;
+		if (xbuff != NULL)  
+			kfree(xbuff);
+		if (rbuff != NULL)  
+			kfree(rbuff);
+		return;
+	}
+
+	save_flags(flags); 
+	cli();
+
+	oxbuff    = sl->xbuff;
+	sl->xbuff = xbuff;
+	orbuff    = sl->rbuff;
+	sl->rbuff = rbuff;
+
+	if (sl->xleft)  {
+		if (sl->xleft <= len)  {
+			memcpy(sl->xbuff, sl->xhead, sl->xleft);
+		} else  {
+			sl->xleft = 0;
+			sl->tx_dropped++;
+		}
+	}
+	sl->xhead = sl->xbuff;
+
+	if (sl->rcount)  {
+		if (sl->rcount <= len) {
+			memcpy(sl->rbuff, orbuff, sl->rcount);
+		} else  {
+			sl->rcount = 0;
+			sl->rx_over_errors++;
+			set_bit(SLF_ERROR, &sl->flags);
+		}
+	}
+	sl->mtu      = dev->mtu;
+
+	sl->buffsize = len;
+
+	restore_flags(flags);
+
+	if (oxbuff != NULL) 
+		kfree(oxbuff);
+	if (orbuff != NULL)
+		kfree(orbuff);
+}
+
+
+/* Set the "sending" flag.  This must be atomic, hence the ASM. */
+
+static inline void x25_asy_lock(struct x25_asy *sl)
+{
+	if (test_and_set_bit(0, (void *) &sl->dev->tbusy))
+		printk("%s: trying to lock already locked device!\n", sl->dev->name);
+}
+
+
+/* Clear the "sending" flag.  This must be atomic, hence the ASM. */
+
+static inline void x25_asy_unlock(struct x25_asy *sl)
+{
+	if (!test_and_clear_bit(0, (void *)&sl->dev->tbusy))
+		printk("%s: trying to unlock already unlocked device!\n", sl->dev->name);
+}
+
+/* Send one completely decapsulated IP datagram to the IP layer. */
+
+static void x25_asy_bump(struct x25_asy *sl)
+{
+	struct sk_buff *skb;
+	int count;
+	int err;
+
+	count = sl->rcount;
+	sl->rx_bytes+=count;
+	
+	skb = dev_alloc_skb(count+1);
+	if (skb == NULL)  
+	{
+		printk("%s: memory squeeze, dropping packet.\n", sl->dev->name);
+		sl->rx_dropped++;
+		return;
+	}
+	skb_push(skb,1);	/* LAPB internal control */
+	skb->dev = sl->dev;
+	memcpy(skb_put(skb,count), sl->rbuff, count);
+	skb->mac.raw=skb->data;
+	skb->protocol=htons(ETH_P_X25);
+	if((err=lapb_data_received(sl,skb))!=LAPB_OK)
+	{
+		kfree_skb(skb);
+		printk(KERN_DEBUG "x25_asy: data received err - %d\n",err);
+	}
+	else
+	{
+		netif_rx(skb);
+		sl->rx_packets++;
+	}
+}
+
+/* Encapsulate one IP datagram and stuff into a TTY queue. */
+static void x25_asy_encaps(struct x25_asy *sl, unsigned char *icp, int len)
+{
+	unsigned char *p;
+	int actual, count;
+
+
+	if (sl->mtu != sl->dev->mtu) {	/* Someone has been ifconfigging */
+
+		x25_asy_changed_mtu(sl);
+	}
+
+	if (len > sl->mtu) 
+	{		/* Sigh, shouldn't occur BUT ... */
+		len = sl->mtu;
+		printk ("%s: truncating oversized transmit packet!\n", sl->dev->name);
+		sl->tx_dropped++;
+		x25_asy_unlock(sl);
+		return;
+	}
+
+	p = icp;
+	count = x25_asy_esc(p, (unsigned char *) sl->xbuff, len);
+
+	/* Order of next two lines is *very* important.
+	 * When we are sending a little amount of data,
+	 * the transfer may be completed inside driver.write()
+	 * routine, because it's running with interrupts enabled.
+	 * In this case we *never* got WRITE_WAKEUP event,
+	 * if we did not request it before write operation.
+	 *       14 Oct 1994  Dmitry Gorodchanin.
+	 */
+	sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+	actual = sl->tty->driver.write(sl->tty, 0, sl->xbuff, count);
+	sl->xleft = count - actual;
+	sl->xhead = sl->xbuff + actual;
+	/* VSV */
+	clear_bit(SLF_OUTWAIT, &sl->flags);	/* reset outfill flag */
+}
+
+/*
+ * Called by the driver when there's room for more data.  If we have
+ * more packets to send, we send them here.
+ */
+static void x25_asy_write_wakeup(struct tty_struct *tty)
+{
+	int actual;
+	struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
+
+	/* First make sure we're connected. */
+	if (!sl || sl->magic != X25_ASY_MAGIC || !sl->dev->start)
+		return;
+
+	if (sl->xleft <= 0)  
+	{
+		/* Now serial buffer is almost free & we can start
+		 * transmission of another packet */
+		sl->tx_packets++;
+		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+		x25_asy_unlock(sl);
+		mark_bh(NET_BH);
+		return;
+	}
+
+	actual = tty->driver.write(tty, 0, sl->xhead, sl->xleft);
+	sl->xleft -= actual;
+	sl->xhead += actual;
+}
+
+/* Encapsulate an IP datagram and kick it into a TTY queue. */
+
+static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct x25_asy *sl = (struct x25_asy*)(dev->priv);
+	int err;
+
+	if (!dev->start)  
+	{
+		printk("%s: xmit call when iface is down\n", dev->name);
+		return 1;
+	}
+	
+	switch(skb->data[0])
+	{
+		case 0x00:break;
+		case 0x01: /* Connection request .. do nothing */
+			if((err=lapb_connect_request(sl))!=LAPB_OK)
+				printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err);
+			kfree_skb(skb);
+			return 0;
+		case 0x02: /* Disconnect request .. do nothing - hang up ?? */
+			if((err=lapb_disconnect_request(sl))!=LAPB_OK)
+				printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err);
+		default:
+			kfree_skb(skb);
+			return  0;
+	}
+	skb_pull(skb,1);	/* Remove control byte */
+	/*
+	 * If we are busy already- too bad.  We ought to be able
+	 * to queue things at this point, to allow for a little
+	 * frame buffer.  Oh well...
+	 * -----------------------------------------------------
+	 * I hate queues in X.25 driver. May be it's efficient,
+	 * but for me latency is more important. ;)
+	 * So, no queues !
+	 *        14 Oct 1994  Dmitry Gorodchanin.
+	 */
+	if (dev->tbusy) {
+		/* May be we must check transmitter timeout here ?
+		 *      14 Oct 1994 Dmitry Gorodchanin.
+		 */
+#ifdef SL_CHECK_TRANSMIT
+		if (jiffies - dev->trans_start  < 20 * HZ)  {
+			/* 20 sec timeout not reached */
+			return 1;
+		}
+		printk("%s: transmit timed out, %s?\n", dev->name,
+		       (sl->tty->driver.chars_in_buffer(sl->tty) || sl->xleft) ?
+		       "bad line quality" : "driver error");
+		sl->xleft = 0;
+		sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+		x25_asy_unlock(sl);
+#else
+		return 1;
+#endif
+	}
+	
+	if((err=lapb_data_request(sl,skb))!=LAPB_OK)
+	{
+		printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err);
+		kfree_skb(skb);
+		return 0;
+	}
+	return 0;
+}
+
+
+/*
+ *	LAPB interface boilerplate
+ */
+
+/*
+ *	Called when I frame data arrives. We did the work above - throw it
+ *	at the net layer.
+ */
+  
+static void x25_asy_data_indication(void *token, struct sk_buff *skb)
+{
+	netif_rx(skb);
+}
+
+/*
+ *	Data has emerged from the LAPB protocol machine. We don't handle
+ *	busy cases too well. Its tricky to see how to do this nicely -
+ *	perhaps lapb should allow us to bounce this ?
+ */
+ 
+static void x25_asy_data_transmit(void *token, struct sk_buff *skb)
+{
+	struct x25_asy *sl=token;
+	if(sl->dev->tbusy)
+	{
+		printk(KERN_ERR "x25_asy: tbusy drop\n");
+		kfree_skb(skb);
+		return;
+	}
+	/* We were not busy, so we are now... :-) */
+	if (skb != NULL) 
+	{
+		x25_asy_lock(sl);
+		sl->tx_bytes+=skb->len;
+		x25_asy_encaps(sl, skb->data, skb->len);
+		dev_kfree_skb(skb);
+	}
+}
+
+/*
+ *	LAPB connection establish/down information.
+ */
+ 
+static void x25_asy_connected(void *token, int reason)
+{
+	struct x25_asy *sl = token;
+	struct sk_buff *skb;
+	unsigned char *ptr;
+
+	if ((skb = dev_alloc_skb(1)) == NULL) {
+		printk(KERN_ERR "lapbeth: out of memory\n");
+		return;
+	}
+
+	ptr  = skb_put(skb, 1);
+	*ptr = 0x01;
+
+	skb->dev      = sl->dev;
+	skb->protocol = htons(ETH_P_X25);
+	skb->mac.raw  = skb->data;
+	skb->pkt_type = PACKET_HOST;
+
+	netif_rx(skb);
+}
+
+static void x25_asy_disconnected(void *token, int reason)
+{
+	struct x25_asy *sl = token;
+	struct sk_buff *skb;
+	unsigned char *ptr;
+
+	if ((skb = dev_alloc_skb(1)) == NULL) {
+		printk(KERN_ERR "x25_asy: out of memory\n");
+		return;
+	}
+
+	ptr  = skb_put(skb, 1);
+	*ptr = 0x02;
+
+	skb->dev      = sl->dev;
+	skb->protocol = htons(ETH_P_X25);
+	skb->mac.raw  = skb->data;
+	skb->pkt_type = PACKET_HOST;
+
+	netif_rx(skb);
+}
+
+
+/* Open the low-level part of the X.25 channel. Easy! */
+
+static int x25_asy_open(struct net_device *dev)
+{
+	struct lapb_register_struct x25_asy_callbacks;
+	struct x25_asy *sl = (struct x25_asy*)(dev->priv);
+	unsigned long len;
+	int err;
+
+	if (sl->tty == NULL)
+		return -ENODEV;
+
+	/*
+	 * Allocate the X.25 frame buffers:
+	 *
+	 * rbuff	Receive buffer.
+	 * xbuff	Transmit buffer.
+	 */
+
+	len = dev->mtu * 2;
+
+	sl->rbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
+	if (sl->rbuff == NULL)   {
+		goto norbuff;
+	}
+	sl->xbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
+	if (sl->xbuff == NULL)   {
+		goto noxbuff;
+	}
+	sl->mtu	     = dev->mtu;
+	sl->buffsize = len;
+	sl->rcount   = 0;
+	sl->xleft    = 0;
+	sl->flags   &= (1 << SLF_INUSE);      /* Clear ESCAPE & ERROR flags */
+
+	dev->tbusy  = 0;
+/*	dev->flags |= IFF_UP; */
+	dev->start  = 1;
+	
+	/*
+	 *	Now attach LAPB
+	 */
+	 
+	x25_asy_callbacks.connect_confirmation=x25_asy_connected;
+	x25_asy_callbacks.connect_indication=x25_asy_connected;
+	x25_asy_callbacks.disconnect_confirmation=x25_asy_disconnected;
+	x25_asy_callbacks.disconnect_indication=x25_asy_disconnected;
+	x25_asy_callbacks.data_indication=x25_asy_data_indication;
+	x25_asy_callbacks.data_transmit=x25_asy_data_transmit;
+
+	if((err=lapb_register(sl, &x25_asy_callbacks))==LAPB_OK)
+		return 0;
+
+	/* Cleanup */
+	kfree(sl->xbuff);
+noxbuff:
+	kfree(sl->rbuff);
+norbuff:
+	return -ENOMEM;
+}
+
+
+/* Close the low-level part of the X.25 channel. Easy! */
+static int x25_asy_close(struct net_device *dev)
+{
+	struct x25_asy *sl = (struct x25_asy*)(dev->priv);
+	int err;
+
+	if (sl->tty == NULL)
+		return -EBUSY;
+
+	sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+	dev->tbusy = 1;
+	dev->start = 0;
+	if((err=lapb_unregister(sl))!=LAPB_OK)
+		printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",err);
+
+/*	dev->flags &= ~IFF_UP; */
+	return 0;
+}
+
+static int x25_asy_receive_room(struct tty_struct *tty)
+{
+	return 65536;  /* We can handle an infinite amount of data. :-) */
+}
+
+/*
+ * Handle the 'receiver data ready' interrupt.
+ * This function is called by the 'tty_io' module in the kernel when
+ * a block of X.25 data has been received, which can now be decapsulated
+ * and sent on to some IP layer for further processing.
+ */
+ 
+static void x25_asy_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+{
+	struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
+
+	if (!sl || sl->magic != X25_ASY_MAGIC || !sl->dev->start)
+		return;
+
+	/*
+	 * Argh! mtu change time! - costs us the packet part received
+	 * at the change
+	 */
+	if (sl->mtu != sl->dev->mtu)  {
+
+		x25_asy_changed_mtu(sl);
+	}
+
+	/* Read the characters out of the buffer */
+	while (count--) {
+		if (fp && *fp++) {
+			if (!test_and_set_bit(SLF_ERROR, &sl->flags))  {
+				sl->rx_errors++;
+			}
+			cp++;
+			continue;
+		}
+		x25_asy_unesc(sl, *cp++);
+	}
+}
+
+/*
+ * Open the high-level part of the X.25 channel.
+ * This function is called by the TTY module when the
+ * X.25 line discipline is called for.  Because we are
+ * sure the tty line exists, we only have to link it to
+ * a free X.25 channel...
+ */
+
+static int x25_asy_open_tty(struct tty_struct *tty)
+{
+	struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
+	int err;
+
+	/* First make sure we're not already connected. */
+	if (sl && sl->magic == X25_ASY_MAGIC) {
+		return -EEXIST;
+	}
+
+	/* OK.  Find a free X.25 channel to use. */
+	if ((sl = x25_asy_alloc()) == NULL) {
+		return -ENFILE;
+	}
+
+	sl->tty = tty;
+	tty->disc_data = sl;
+	if (tty->driver.flush_buffer)  {
+		tty->driver.flush_buffer(tty);
+	}
+	if (tty->ldisc.flush_buffer)  {
+		tty->ldisc.flush_buffer(tty);
+	}
+
+	/* Restore default settings */
+	sl->dev->type = ARPHRD_X25;
+	
+	/* Perform the low-level X.25 async init */
+	if ((err = x25_asy_open(sl->dev)))
+		return err;
+
+	MOD_INC_USE_COUNT;
+
+	/* Done.  We have linked the TTY line to a channel. */
+	return sl->dev->base_addr;
+}
+
+
+/*
+ * Close down an X.25 channel.
+ * This means flushing out any pending queues, and then restoring the
+ * TTY line discipline to what it was before it got hooked to X.25
+ * (which usually is TTY again).
+ */
+static void x25_asy_close_tty(struct tty_struct *tty)
+{
+	struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
+
+	/* First make sure we're connected. */
+	if (!sl || sl->magic != X25_ASY_MAGIC)
+		return;
+
+	if (sl->dev->flags & IFF_UP)
+	{
+		(void) dev_close(sl->dev);
+	}
+
+	tty->disc_data = 0;
+	sl->tty = NULL;
+	x25_asy_free(sl);
+	unregister_netdev(sl->dev);
+	MOD_DEC_USE_COUNT;
+}
+
+
+static struct net_device_stats *x25_asy_get_stats(struct net_device *dev)
+{
+	static struct net_device_stats stats;
+	struct x25_asy *sl = (struct x25_asy*)(dev->priv);
+
+	memset(&stats, 0, sizeof(struct net_device_stats));
+
+	stats.rx_packets     = sl->rx_packets;
+	stats.tx_packets     = sl->tx_packets;
+	stats.rx_bytes	     = sl->rx_bytes;
+	stats.tx_bytes	     = sl->tx_bytes;
+	stats.rx_dropped     = sl->rx_dropped;
+	stats.tx_dropped     = sl->tx_dropped;
+	stats.tx_errors      = sl->tx_errors;
+	stats.rx_errors      = sl->rx_errors;
+	stats.rx_over_errors = sl->rx_over_errors;
+	return (&stats);
+}
+
+
+ /************************************************************************
+  *			STANDARD X.25 ENCAPSULATION		  	 *
+  ************************************************************************/
+
+int x25_asy_esc(unsigned char *s, unsigned char *d, int len)
+{
+	unsigned char *ptr = d;
+	unsigned char c;
+
+	/*
+	 * Send an initial END character to flush out any
+	 * data that may have accumulated in the receiver
+	 * due to line noise.
+	 */
+
+	*ptr++ = X25_END;	/* Send 10111110 bit seq */
+
+	/*
+	 * For each byte in the packet, send the appropriate
+	 * character sequence, according to the X.25 protocol.
+	 */
+
+	while (len-- > 0) 
+	{
+		switch(c = *s++) 
+		{
+			case X25_END:
+				*ptr++ = X25_ESC;
+				*ptr++ = X25_ESCAPE(X25_END);
+				break;
+			case X25_ESC:
+				*ptr++ = X25_ESC;
+				*ptr++ = X25_ESCAPE(X25_ESC);
+				break;
+			 default:
+				*ptr++ = c;
+				break;
+		}
+	}
+	*ptr++ = X25_END;
+	return (ptr - d);
+}
+
+static void x25_asy_unesc(struct x25_asy *sl, unsigned char s)
+{
+
+	switch(s) 
+	{
+		case X25_END:
+			if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))  
+			{
+				x25_asy_bump(sl);
+			}
+			clear_bit(SLF_ESCAPE, &sl->flags);
+			sl->rcount = 0;
+			return;
+
+		case X25_ESC:
+			set_bit(SLF_ESCAPE, &sl->flags);
+			return;
+			
+		case X25_ESCAPE(X25_ESC):
+		case X25_ESCAPE(X25_END):
+			if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
+				s = X25_UNESCAPE(s);
+			break;
+	}
+	if (!test_bit(SLF_ERROR, &sl->flags))  
+	{
+		if (sl->rcount < sl->buffsize)  
+		{
+			sl->rbuff[sl->rcount++] = s;
+			return;
+		}
+		sl->rx_over_errors++;
+		set_bit(SLF_ERROR, &sl->flags);
+	}
+}
+
+
+/* Perform I/O control on an active X.25 channel. */
+static int x25_asy_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
+{
+	struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
+
+	/* First make sure we're connected. */
+	if (!sl || sl->magic != X25_ASY_MAGIC) {
+		return -EINVAL;
+	}
+
+	switch(cmd) 
+	{
+		case SIOCGIFNAME:
+			if(copy_to_user(arg, sl->dev->name, strlen(sl->dev->name) + 1))
+				return -EFAULT;
+			return 0;
+
+		case SIOCSIFHWADDR:
+			return -EINVAL;
+
+		/* Allow stty to read, but not set, the serial port */
+		case TCGETS:
+		case TCGETA:
+			return n_tty_ioctl(tty, (struct file *) file, cmd, (unsigned long) arg);
+
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+static int x25_asy_open_dev(struct net_device *dev)
+{
+	struct x25_asy *sl = (struct x25_asy*)(dev->priv);
+	if(sl->tty==NULL)
+		return -ENODEV;
+	return 0;
+}
+
+/* Initialize X.25 control device -- register X.25 line discipline */
+#ifdef MODULE
+static int x25_asy_init_ctrl_dev(void)
+#else	/* !MODULE */
+int __init x25_asy_init_ctrl_dev(struct net_device *dummy)
+#endif	/* !MODULE */
+{
+	int status;
+
+	if (x25_asy_maxdev < 4) x25_asy_maxdev = 4; /* Sanity */
+
+	printk(KERN_INFO "X.25 async: version 0.00 ALPHA (dynamic channels, max=%d).\n",
+		x25_asy_maxdev );
+	x25_asy_ctrls = (x25_asy_ctrl_t **) kmalloc(sizeof(void*)*x25_asy_maxdev, GFP_KERNEL);
+	if (x25_asy_ctrls == NULL)
+	{
+		printk("X25 async: Can't allocate x25_asy_ctrls[] array!  Uaargh! (-> No X.25 available)\n");
+		return -ENOMEM;
+	}
+
+	/* Clear the pointer array, we allocate devices when we need them */
+	memset(x25_asy_ctrls, 0, sizeof(void*)*x25_asy_maxdev); /* Pointers */
+
+	/* Fill in our line protocol discipline, and register it */
+	memset(&x25_ldisc, 0, sizeof(x25_ldisc));
+	x25_ldisc.magic  = TTY_LDISC_MAGIC;
+	x25_ldisc.name   = "X.25";
+	x25_ldisc.flags  = 0;
+	x25_ldisc.open   = x25_asy_open_tty;
+	x25_ldisc.close  = x25_asy_close_tty;
+	x25_ldisc.read   = NULL;
+	x25_ldisc.write  = NULL;
+	x25_ldisc.ioctl  = (int (*)(struct tty_struct *, struct file *,
+				   unsigned int, unsigned long)) x25_asy_ioctl;
+	x25_ldisc.poll   = NULL;
+	x25_ldisc.receive_buf = x25_asy_receive_buf;
+	x25_ldisc.receive_room = x25_asy_receive_room;
+	x25_ldisc.write_wakeup = x25_asy_write_wakeup;
+	if ((status = tty_register_ldisc(N_X25, &x25_ldisc)) != 0)  {
+		printk("X.25 async: can't register line discipline (err = %d)\n", status);
+	}
+
+#ifdef MODULE
+	return status;
+#else
+	/* Return "not found", so that dev_init() will unlink
+	 * the placeholder device entry for us.
+	 */
+	return ENODEV;
+#endif
+      }
+
+
+/* Initialise the X.25 driver.  Called by the device init code */
+
+int x25_asy_init(struct net_device *dev)
+{
+	struct x25_asy *sl = (struct x25_asy*)(dev->priv);
+
+	if (sl == NULL)		/* Allocation failed ?? */
+		return -ENODEV;
+
+	/* Set up the control block. (And clear statistics) */
+
+	memset(sl, 0, sizeof (struct x25_asy));
+	sl->magic  = X25_ASY_MAGIC;
+	sl->dev	   = dev;
+
+	/*
+	 *	Finish setting up the DEVICE info. 
+	 */
+	 
+	dev->mtu		= SL_MTU;
+	dev->hard_start_xmit	= x25_asy_xmit;
+	dev->open		= x25_asy_open_dev;
+	dev->stop		= x25_asy_close;
+	dev->get_stats	        = x25_asy_get_stats;
+	dev->hard_header_len	= 0;
+	dev->addr_len		= 0;
+	dev->type		= ARPHRD_X25;
+	dev->tx_queue_len	= 10;
+
+	dev_init_buffers(dev);
+	
+	/* New-style flags. */
+	dev->flags		= IFF_NOARP;
+
+	return 0;
+}
+#ifdef MODULE
+
+int
+init_module(void)
+{
+	return x25_asy_init_ctrl_dev();
+}
+
+void
+cleanup_module(void)
+{
+	int i;
+
+	if (x25_asy_ctrls != NULL)
+	{
+		for (i = 0; i < x25_asy_maxdev; i++)
+		{
+			if (x25_asy_ctrls[i])
+			{
+				/*
+				 * VSV = if dev->start==0, then device
+				 * unregistered while close proc.
+				 */
+				if (x25_asy_ctrls[i]->dev.start)
+					unregister_netdev(&(x25_asy_ctrls[i]->dev));
+
+				kfree(x25_asy_ctrls[i]);
+				x25_asy_ctrls[i] = NULL;
+			}
+		}
+		kfree(x25_asy_ctrls);
+		x25_asy_ctrls = NULL;
+	}
+	if ((i = tty_register_ldisc(N_X25, NULL)))
+	{
+		printk("X.25 async: can't unregister line discipline (err = %d)\n", i);
+	}
+}
+#endif /* MODULE */
+
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/x25_asy.h linux/drivers/net/wan/x25_asy.h
--- v2.3.20/linux/drivers/net/wan/x25_asy.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/x25_asy.h	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,58 @@
+#ifndef _LINUX_X25_ASY_H
+#define _LINUX_X25_ASY_H
+
+/* X.25 asy configuration. */
+#define SL_NRUNIT	256		/* MAX number of X.25 channels;
+					   This can be overridden with
+					   insmod -ox25_asy_maxdev=nnn	*/
+#define SL_MTU		256	
+
+/* X25 async protocol characters. */
+#define X25_END         0x7E		/* indicates end of frame	*/
+#define X25_ESC         0x7D		/* indicates byte stuffing	*/
+#define X25_ESCAPE(x)	((x)^0x20)
+#define X25_UNESCAPE(x)	((x)^0x20)
+
+
+struct x25_asy {
+  int			magic;
+
+  /* Various fields. */
+  struct tty_struct	*tty;		/* ptr to TTY structure		*/
+  struct net_device		*dev;		/* easy for intr handling	*/
+
+  /* These are pointers to the malloc()ed frame buffers. */
+  unsigned char		*rbuff;		/* receiver buffer		*/
+  int                   rcount;         /* received chars counter       */
+  unsigned char		*xbuff;		/* transmitter buffer		*/
+  unsigned char         *xhead;         /* pointer to next byte to XMIT */
+  int                   xleft;          /* bytes left in XMIT queue     */
+
+  /* X.25 interface statistics. */
+  unsigned long		rx_packets;	/* inbound frames counter	*/
+  unsigned long         tx_packets;     /* outbound frames counter      */
+  unsigned long		rx_bytes;	/* inbound byte counte		*/
+  unsigned long         tx_bytes;       /* outbound byte counter	*/
+  unsigned long         rx_errors;      /* Parity, etc. errors          */
+  unsigned long         tx_errors;      /* Planned stuff                */
+  unsigned long         rx_dropped;     /* No memory for skb            */
+  unsigned long         tx_dropped;     /* When MTU change              */
+  unsigned long         rx_over_errors; /* Frame bigger then X.25 buf.  */
+
+  int			mtu;		/* Our mtu (to spot changes!)   */
+  int                   buffsize;       /* Max buffers sizes            */
+
+  unsigned int		flags;		/* Flag values/ mode etc	*/
+#define SLF_INUSE	0		/* Channel in use               */
+#define SLF_ESCAPE	1               /* ESC received                 */
+#define SLF_ERROR	2               /* Parity, etc. error           */
+#define SLF_OUTWAIT	4		/* Waiting for output		*/
+};
+
+
+
+#define X25_ASY_MAGIC 0x5303
+
+extern int x25_asy_init(struct net_device *dev);
+
+#endif	/* _LINUX_X25_ASY.H */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/z85230.c linux/drivers/net/wan/z85230.c
--- v2.3.20/linux/drivers/net/wan/z85230.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/z85230.c	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,1470 @@
+/*
+ *	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.
+ *
+ *	(c) Copyright 1998 Building Number Three Ltd
+ *
+ *	Development of this driver was funded by Equiinet Ltd
+ *			http://www.equiinet.com
+ *
+ *	ChangeLog:
+ *
+ *	Asynchronous mode dropped for 2.2. For 2.3 we will attempt the
+ *	unification of all the Z85x30 asynchronous drivers for real.
+ *
+ *	To Do:
+ *	
+ *	Finish DMA mode support.
+ *
+ *	Performance
+ *
+ *	Z85230:
+ *	Non DMA you want a 486DX50 or better to do 64Kbits. 9600 baud
+ *	X.25 is not unrealistic on all machines. DMA mode can in theory
+ *	handle T1/E1 quite nicely. In practice the limit seems to be about
+ *	512Kbit->1Mbit depending on motherboard.
+ *
+ *	Z85C30:
+ *	64K will take DMA, 9600 baud X.25 should be ok.
+ *
+ *	Z8530:
+ *	Synchronous mode without DMA is unlikely to pass about 2400 baud.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#define RT_LOCK
+#define RT_UNLOCK
+#include <linux/spinlock.h>
+
+#include "z85230.h"
+#include "syncppp.h"
+
+
+static spinlock_t z8530_buffer_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ *	Provided port access methods. The Comtrol SV11 requires no delays
+ *	between accesses and uses PC I/O. Some drivers may need a 5uS delay
+ */
+
+extern __inline__ int z8530_read_port(int p)
+{
+	u8 r=inb(Z8530_PORT_OF(p));
+	if(p&Z8530_PORT_SLEEP)	/* gcc should figure this out efficiently ! */
+		udelay(5);
+	return r;
+}
+
+extern __inline__ void z8530_write_port(int p, u8 d)
+{
+	outb(d,Z8530_PORT_OF(p));
+	if(p&Z8530_PORT_SLEEP)
+		udelay(5);
+}
+
+
+
+static void z8530_rx_done(struct z8530_channel *c);
+static void z8530_tx_done(struct z8530_channel *c);
+
+
+/*
+ *	Port accesses
+ */
+ 
+extern inline u8 read_zsreg(struct z8530_channel *c, u8 reg)
+{
+	u8 r;
+	unsigned long flags;
+	save_flags(flags);
+	cli();
+	if(reg)
+		z8530_write_port(c->ctrlio, reg);
+	r=z8530_read_port(c->ctrlio);
+	restore_flags(flags);
+	return r;
+}
+
+extern inline u8 read_zsdata(struct z8530_channel *c)
+{
+	u8 r;
+	r=z8530_read_port(c->dataio);
+	return r;
+}
+
+extern inline void write_zsreg(struct z8530_channel *c, u8 reg, u8 val)
+{
+	unsigned long flags;
+	save_flags(flags);
+	cli();
+	if(reg)
+		z8530_write_port(c->ctrlio, reg);
+	z8530_write_port(c->ctrlio, val);
+	restore_flags(flags);
+}
+
+extern inline void write_zsctrl(struct z8530_channel *c, u8 val)
+{
+	z8530_write_port(c->ctrlio, val);
+}
+
+extern inline void write_zsdata(struct z8530_channel *c, u8 val)
+{
+	z8530_write_port(c->dataio, val);
+}
+
+/*
+ *	Register loading parameters for a dead port
+ */
+ 
+u8 z8530_dead_port[]=
+{
+	255
+};
+
+EXPORT_SYMBOL(z8530_dead_port);
+
+/*
+ *	Register loading parameters for currently supported circuit types
+ */
+
+
+/*
+ *	Data clocked by telco end. This is the correct data for the UK
+ *	"kilostream" service, and most other similar services.
+ */
+ 
+u8 z8530_hdlc_kilostream[]=
+{
+	4,	SYNC_ENAB|SDLC|X1CLK,
+	2,	0,	/* No vector */
+	1,	0,
+	3,	ENT_HM|RxCRC_ENAB|Rx8,
+	5,	TxCRC_ENAB|RTS|TxENAB|Tx8|DTR,
+	9,	0,		/* Disable interrupts */
+	6,	0xFF,
+	7,	FLAG,
+	10,	ABUNDER|NRZ|CRCPS,/*MARKIDLE ??*/
+	11,	TCTRxCP,
+	14,	DISDPLL,
+	15,	DCDIE|SYNCIE|CTSIE|TxUIE|BRKIE,
+	1,	EXT_INT_ENAB|TxINT_ENAB|INT_ALL_Rx,
+	9,	NV|MIE|NORESET,
+	255
+};
+
+EXPORT_SYMBOL(z8530_hdlc_kilostream);
+
+/*
+ *	As above but for enhanced chips.
+ */
+
+u8 z8530_hdlc_kilostream_85230[]=
+{
+	4,	SYNC_ENAB|SDLC|X1CLK,
+	2,	0,	/* No vector */
+	1,	0,
+	3,	ENT_HM|RxCRC_ENAB|Rx8,
+	5,	TxCRC_ENAB|RTS|TxENAB|Tx8|DTR,
+	9,	0,		/* Disable interrupts */
+	6,	0xFF,
+	7,	FLAG,
+	10,	ABUNDER|NRZ|CRCPS,	/* MARKIDLE?? */
+	11,	TCTRxCP,
+	14,	DISDPLL,
+	15,	DCDIE|SYNCIE|CTSIE|TxUIE|BRKIE,
+	1,	EXT_INT_ENAB|TxINT_ENAB|INT_ALL_Rx,
+	9,	NV|MIE|NORESET,
+	23,	3,		/* Extended mode AUTO TX and EOM*/
+	
+	255
+};
+
+EXPORT_SYMBOL(z8530_hdlc_kilostream_85230);
+
+/*
+ *	Flush the FIFO
+ */
+ 
+static void z8530_flush_fifo(struct z8530_channel *c)
+{
+	read_zsreg(c, R1);
+	read_zsreg(c, R1);
+	read_zsreg(c, R1);
+	read_zsreg(c, R1);
+	if(c->dev->type==Z85230)
+	{
+		read_zsreg(c, R1);
+		read_zsreg(c, R1);
+		read_zsreg(c, R1);
+		read_zsreg(c, R1);
+	}
+}	
+
+/* Sets or clears DTR/RTS on the requested line */
+
+static void z8530_rtsdtr(struct z8530_channel *c, int set)
+{
+	if (set)
+		c->regs[5] |= (RTS | DTR);
+	else
+		c->regs[5] &= ~(RTS | DTR);
+	write_zsreg(c, R5, c->regs[5]);
+}
+
+/*
+ *	Receive handler. This is much like the async one but not quite the
+ *	same or as complex
+ *
+ *	Note: Its intended that this handler can easily be separated from
+ *	the main code to run realtime. That'll be needed for some machines
+ *	(eg to ever clock 64kbits on a sparc ;)).
+ *
+ *	The RT_LOCK macros don't do anything now. Keep the code covered
+ *	by them as short as possible in all circumstances - clocks cost
+ *	baud. The interrupt handler is assumed to be atomic w.r.t. to
+ *	other code - this is true in the RT case too.
+ *
+ *	We only cover the sync cases for this. If you want 2Mbit async
+ *	do it yourself but consider medical assistance first.
+ *
+ *	This non DMA synchronous mode is portable code.
+ */
+ 
+static void z8530_rx(struct z8530_channel *c)
+{
+	u8 ch,stat;
+	 
+	while(1)
+	{
+		/* FIFO empty ? */
+		if(!(read_zsreg(c, R0)&1))
+			break;
+		ch=read_zsdata(c);
+		stat=read_zsreg(c, R1);
+	
+		/*
+		 *	Overrun ?
+		 */
+		if(c->count < c->max)
+		{
+			*c->dptr++=ch;
+			c->count++;
+		}
+
+		if(stat&END_FR)
+		{
+		
+			/*
+			 *	Error ?
+			 */
+			if(stat&(Rx_OVR|CRC_ERR))
+			{
+				/* Rewind the buffer and return */
+				if(c->skb)
+					c->dptr=c->skb->data;
+				c->count=0;
+				if(stat&Rx_OVR)
+				{
+					printk(KERN_WARNING "%s: overrun\n", c->dev->name);
+					c->rx_overrun++;
+				}
+				if(stat&CRC_ERR)
+				{
+					c->rx_crc_err++;
+					/* printk("crc error\n"); */
+				}
+				/* Shove the frame upstream */
+			}
+			else
+			{
+				z8530_rx_done(c);
+				write_zsctrl(c, RES_Rx_CRC);
+			}
+		}
+	}
+	/*
+	 *	Clear irq
+	 */
+	write_zsctrl(c, ERR_RES);
+	write_zsctrl(c, RES_H_IUS);
+}
+
+
+/*
+ *	Z8530 transmit interrupt handler
+ */
+ 
+static void z8530_tx(struct z8530_channel *c)
+{
+	while(c->txcount)
+	{
+		/* FIFO full ? */
+		if(!(read_zsreg(c, R0)&4))
+			break;
+		c->txcount--;
+		/*
+		 *	Shovel out the byte
+		 */
+		write_zsreg(c, R8, *c->tx_ptr++);
+		write_zsctrl(c, RES_H_IUS);
+		/* We are about to underflow */
+		if(c->txcount==0)
+		{
+			write_zsctrl(c, RES_EOM_L);
+			write_zsreg(c, R10, c->regs[10]&~ABUNDER);
+		}
+		return;
+	}
+	
+	/*
+	 *	End of frame TX - fire another one
+	 */
+	 
+	write_zsctrl(c, RES_Tx_P);
+
+	z8530_tx_done(c);	 
+/*	write_zsreg(c, R8, *c->tx_ptr++); */
+	write_zsctrl(c, RES_H_IUS);
+}
+
+static void z8530_status(struct z8530_channel *chan)
+{
+	u8 status=read_zsreg(chan, R0);
+	u8 altered=chan->status^status;
+	
+	chan->status=status;
+	
+	if(status&TxEOM)
+	{
+/*		printk("%s: Tx underrun.\n", chan->dev->name); */
+		chan->stats.tx_fifo_errors++;
+		write_zsctrl(chan, ERR_RES);
+		z8530_tx_done(chan);
+	}
+		
+	if(altered&DCD)
+	{
+		if(status&DCD)
+		{
+			printk(KERN_INFO "%s: DCD raised\n", chan->dev->name);
+			write_zsreg(chan, R3, chan->regs[3]|RxENABLE);
+			if(chan->netdevice)
+				sppp_reopen(chan->netdevice);
+		}
+		else
+		{
+			printk(KERN_INFO "%s: DCD lost\n", chan->dev->name);
+			write_zsreg(chan, R3, chan->regs[3]&~RxENABLE);
+			z8530_flush_fifo(chan);
+		}
+		
+	}	
+	write_zsctrl(chan, RES_EXT_INT);
+	write_zsctrl(chan, RES_H_IUS);
+}
+
+struct z8530_irqhandler z8530_sync=
+{
+	z8530_rx,
+	z8530_tx,
+	z8530_status
+};
+
+EXPORT_SYMBOL(z8530_sync);
+
+/*
+ *	Non bus mastering DMA interfaces for the Z8x30 devices. This
+ *	is really pretty PC specific.
+ */
+ 
+static void z8530_dma_rx(struct z8530_channel *chan)
+{
+	if(chan->rxdma_on)
+	{
+		/* Special condition check only */
+		u8 status;
+
+		read_zsreg(chan, R7);
+		read_zsreg(chan, R6);
+		
+		status=read_zsreg(chan, R1);
+		if(status&END_FR)
+		{
+			z8530_rx_done(chan);	/* Fire up the next one */
+		}		
+		write_zsctrl(chan, ERR_RES);
+		write_zsctrl(chan, RES_H_IUS);
+	}
+	else
+	{
+		/* DMA is off right now, drain the slow way */
+		z8530_rx(chan);
+	}	
+}
+
+static void z8530_dma_tx(struct z8530_channel *chan)
+{
+	if(!chan->dma_tx)
+	{
+		printk("Hey who turned the DMA off?\n");
+		z8530_tx(chan);
+		return;
+	}
+	/* This shouldnt occur in DMA mode */
+	printk(KERN_ERR "DMA tx ??\n");
+	z8530_tx(chan);
+}
+
+static void z8530_dma_status(struct z8530_channel *chan)
+{
+	unsigned long flags;
+	u8 status=read_zsreg(chan, R0);
+	u8 altered=chan->status^status;
+	
+	chan->status=status;
+
+	if(chan->dma_tx)
+	{
+		if(status&TxEOM)
+		{
+			flags=claim_dma_lock();
+			/* Transmit underrun */
+			disable_dma(chan->txdma);
+			clear_dma_ff(chan->txdma);	
+			chan->txdma_on=0;
+			release_dma_lock(flags);
+			z8530_tx_done(chan);
+		}
+	}
+	if(altered&DCD)
+	{
+		if(status&DCD)
+		{
+			printk(KERN_INFO "%s: DCD raised\n", chan->dev->name);
+			write_zsreg(chan, R3, chan->regs[3]|RxENABLE);
+			if(chan->netdevice)
+				sppp_reopen(chan->netdevice);
+		}
+		else
+		{
+			printk(KERN_INFO "%s:DCD lost\n", chan->dev->name);
+			write_zsreg(chan, R3, chan->regs[3]&~RxENABLE);
+			z8530_flush_fifo(chan);
+		}
+	}	
+	write_zsctrl(chan, RES_EXT_INT);
+	write_zsctrl(chan, RES_H_IUS);
+}
+
+struct z8530_irqhandler z8530_dma_sync=
+{
+	z8530_dma_rx,
+	z8530_dma_tx,
+	z8530_dma_status
+};
+
+EXPORT_SYMBOL(z8530_dma_sync);
+
+struct z8530_irqhandler z8530_txdma_sync=
+{
+	z8530_rx,
+	z8530_dma_tx,
+	z8530_dma_status
+};
+
+EXPORT_SYMBOL(z8530_txdma_sync);
+
+/*
+ *	Interrupt vectors for a Z8530 that is in 'parked' mode.
+ *	For machines with PCI Z85x30 cards, or level triggered interrupts
+ *	(eg the MacII) we must clear the interrupt cause or die.
+ */
+
+
+static void z8530_rx_clear(struct z8530_channel *c)
+{
+	/*
+	 *	Data and status bytes
+	 */
+	u8 stat;
+
+	read_zsdata(c);
+	stat=read_zsreg(c, R1);
+	
+	if(stat&END_FR)
+		write_zsctrl(c, RES_Rx_CRC);
+	/*
+	 *	Clear irq
+	 */
+	write_zsctrl(c, ERR_RES);
+	write_zsctrl(c, RES_H_IUS);
+}
+
+static void z8530_tx_clear(struct z8530_channel *c)
+{
+	write_zsctrl(c, RES_Tx_P);
+	write_zsctrl(c, RES_H_IUS);
+}
+
+static void z8530_status_clear(struct z8530_channel *chan)
+{
+	u8 status=read_zsreg(chan, R0);
+	if(status&TxEOM)
+		write_zsctrl(chan, ERR_RES);
+	write_zsctrl(chan, RES_EXT_INT);
+	write_zsctrl(chan, RES_H_IUS);
+}
+
+struct z8530_irqhandler z8530_nop=
+{
+	z8530_rx_clear,
+	z8530_tx_clear,
+	z8530_status_clear
+};
+
+
+EXPORT_SYMBOL(z8530_nop);
+
+/*
+ *	A Z85[2]30 device has stuck its hand in the air for attention
+ */
+
+void z8530_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct z8530_dev *dev=dev_id;
+	u8 intr;
+	static volatile int locker=0;
+	int work=0;
+	
+	if(locker)
+	{
+		printk(KERN_ERR "IRQ re-enter\n");
+		return;
+	}
+	locker=1;
+	
+	while(++work<5000)
+	{
+		struct z8530_irqhandler *irqs=dev->chanA.irqs;
+		
+		intr = read_zsreg(&dev->chanA, R3);
+		if(!(intr & (CHARxIP|CHATxIP|CHAEXT|CHBRxIP|CHBTxIP|CHBEXT)))
+			break;
+	
+		/* This holds the IRQ status. On the 8530 you must read it from chan 
+		   A even though it applies to the whole chip */
+		
+		/* Now walk the chip and see what it is wanting - it may be
+		   an IRQ for someone else remember */
+		   
+		if(intr & (CHARxIP|CHATxIP|CHAEXT))
+		{
+			if(intr&CHARxIP)
+				irqs->rx(&dev->chanA);
+			if(intr&CHATxIP)
+				irqs->tx(&dev->chanA);
+			if(intr&CHAEXT)
+				irqs->status(&dev->chanA);
+		}
+
+		irqs=dev->chanB.irqs;
+
+		if(intr & (CHBRxIP|CHBTxIP|CHBEXT))
+		{
+			if(intr&CHBRxIP)
+				irqs->rx(&dev->chanB);
+			if(intr&CHBTxIP)
+				irqs->tx(&dev->chanB);
+			if(intr&CHBEXT)
+				irqs->status(&dev->chanB);
+		}
+	}
+	if(work==5000)
+		printk(KERN_ERR "%s: interrupt jammed - abort(0x%X)!\n", dev->name, intr);
+	/* Ok all done */
+	locker=0;
+}
+
+EXPORT_SYMBOL(z8530_interrupt);
+
+static char reg_init[16]=
+{
+	0,0,0,0,
+	0,0,0,0,
+	0,0,0,0,
+	0x55,0,0,0
+};
+
+
+int z8530_sync_open(struct net_device *dev, struct z8530_channel *c)
+{
+	c->sync = 1;
+	c->mtu = dev->mtu+64;
+	c->count = 0;
+	c->skb = NULL;
+	c->skb2 = NULL;
+	c->irqs = &z8530_sync;
+	/* This loads the double buffer up */
+	z8530_rx_done(c);	/* Load the frame ring */
+	z8530_rx_done(c);	/* Load the backup frame */
+	z8530_rtsdtr(c,1);
+	c->dma_tx = 0;
+	c->regs[R1]|=TxINT_ENAB;
+	write_zsreg(c, R1, c->regs[R1]);
+	write_zsreg(c, R3, c->regs[R3]|RxENABLE);
+	return 0;
+}
+
+
+EXPORT_SYMBOL(z8530_sync_open);
+
+int z8530_sync_close(struct net_device *dev, struct z8530_channel *c)
+{
+	u8 chk;
+	c->irqs = &z8530_nop;
+	c->max = 0;
+	c->sync = 0;
+	
+	chk=read_zsreg(c,R0);
+	write_zsreg(c, R3, c->regs[R3]);
+	z8530_rtsdtr(c,0);
+	return 0;
+}
+
+EXPORT_SYMBOL(z8530_sync_close);
+
+int z8530_sync_dma_open(struct net_device *dev, struct z8530_channel *c)
+{
+	unsigned long flags;
+	
+	c->sync = 1;
+	c->mtu = dev->mtu+64;
+	c->count = 0;
+	c->skb = NULL;
+	c->skb2 = NULL;
+	/*
+	 *	Load the DMA interfaces up
+	 */
+	c->rxdma_on = 0;
+	c->txdma_on = 0;
+	
+	/*
+	 *	Allocate the DMA flip buffers
+	 */
+	 
+	c->rx_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
+	if(c->rx_buf[0]==NULL)
+		return -ENOBUFS;
+	c->rx_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
+	if(c->rx_buf[1]==NULL)
+	{
+		kfree(c->rx_buf[0]);
+		c->rx_buf[0]=NULL;
+		return -ENOBUFS;
+	}
+	
+	c->tx_dma_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
+	if(c->tx_dma_buf[0]==NULL)
+	{
+		kfree(c->rx_buf[0]);
+		kfree(c->rx_buf[1]);
+		c->rx_buf[0]=NULL;
+		return -ENOBUFS;
+	}
+	c->tx_dma_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
+	if(c->tx_dma_buf[1]==NULL)
+	{
+		kfree(c->tx_dma_buf[0]);
+		kfree(c->rx_buf[0]);
+		kfree(c->rx_buf[1]);
+		c->rx_buf[0]=NULL;
+		c->rx_buf[1]=NULL;
+		c->tx_dma_buf[0]=NULL;
+		return -ENOBUFS;
+	}
+	c->tx_dma_used=0;
+	c->dma_tx = 1;
+	c->dma_num=0;
+	c->dma_ready=1;
+	
+	/*
+	 *	Enable DMA control mode
+	 */
+	 
+	/*
+	 *	TX DMA via DIR/REQ
+	 */
+	 
+	c->regs[R14]|= DTRREQ;
+	write_zsreg(c, R14, c->regs[R14]);     
+
+	c->regs[R1]&= ~TxINT_ENAB;
+	write_zsreg(c, R1, c->regs[R1]);
+	
+	/*
+	 *	RX DMA via W/Req
+	 */	 
+
+	c->regs[R1]|= WT_FN_RDYFN;
+	c->regs[R1]|= WT_RDY_RT;
+	c->regs[R1]|= INT_ERR_Rx;
+	c->regs[R1]&= ~TxINT_ENAB;
+	write_zsreg(c, R1, c->regs[R1]);
+	c->regs[R1]|= WT_RDY_ENAB;
+	write_zsreg(c, R1, c->regs[R1]);            
+	
+	/*
+	 *	DMA interrupts
+	 */
+	 
+	/*
+	 *	Set up the DMA configuration
+	 */	
+	 
+	flags=claim_dma_lock();
+	 
+	disable_dma(c->rxdma);
+	clear_dma_ff(c->rxdma);
+	set_dma_mode(c->rxdma, DMA_MODE_READ|0x10);
+	set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[0]));
+	set_dma_count(c->rxdma, c->mtu);
+	enable_dma(c->rxdma);
+
+	disable_dma(c->txdma);
+	clear_dma_ff(c->txdma);
+	set_dma_mode(c->txdma, DMA_MODE_WRITE);
+	disable_dma(c->txdma);
+	
+	release_dma_lock(flags);
+	
+	/*
+	 *	Select the DMA interrupt handlers
+	 */
+
+	c->rxdma_on = 1;
+	c->txdma_on = 1;
+	c->tx_dma_used = 1;
+	 
+	c->irqs = &z8530_dma_sync;
+	z8530_rtsdtr(c,1);
+	write_zsreg(c, R3, c->regs[R3]|RxENABLE);
+	return 0;
+}
+
+EXPORT_SYMBOL(z8530_sync_dma_open);
+
+int z8530_sync_dma_close(struct net_device *dev, struct z8530_channel *c)
+{
+	u8 chk;
+	unsigned long flags;
+	
+	c->irqs = &z8530_nop;
+	c->max = 0;
+	c->sync = 0;
+	
+	/*
+	 *	Disable the PC DMA channels
+	 */
+	
+	flags=claim_dma_lock(); 
+	disable_dma(c->rxdma);
+	clear_dma_ff(c->rxdma);
+	
+	c->rxdma_on = 0;
+	
+	disable_dma(c->txdma);
+	clear_dma_ff(c->txdma);
+	release_dma_lock(flags);
+	
+	c->txdma_on = 0;
+	c->tx_dma_used = 0;
+
+	/*
+	 *	Disable DMA control mode
+	 */
+	 
+	c->regs[R1]&= ~WT_RDY_ENAB;
+	write_zsreg(c, R1, c->regs[R1]);            
+	c->regs[R1]&= ~(WT_RDY_RT|WT_FN_RDYFN|INT_ERR_Rx);
+	c->regs[R1]|= INT_ALL_Rx;
+	write_zsreg(c, R1, c->regs[R1]);
+	c->regs[R14]&= ~DTRREQ;
+	write_zsreg(c, R14, c->regs[R14]);   
+	
+	if(c->rx_buf[0])
+	{
+		kfree(c->rx_buf[0]);
+		c->rx_buf[0]=NULL;
+	}
+	if(c->rx_buf[1])
+	{
+		kfree(c->rx_buf[1]);
+		c->rx_buf[1]=NULL;
+	}
+	if(c->tx_dma_buf[0])
+	{
+		kfree(c->tx_dma_buf[0]);
+		c->tx_dma_buf[0]=NULL;
+	}
+	if(c->tx_dma_buf[1])
+	{
+		kfree(c->tx_dma_buf[1]);
+		c->tx_dma_buf[1]=NULL;
+	}
+	chk=read_zsreg(c,R0);
+	write_zsreg(c, R3, c->regs[R3]);
+	z8530_rtsdtr(c,0);
+	return 0;
+}
+
+EXPORT_SYMBOL(z8530_sync_dma_close);
+
+int z8530_sync_txdma_open(struct net_device *dev, struct z8530_channel *c)
+{
+	unsigned long flags;
+
+	printk("Opening sync interface for TX-DMA\n");
+	c->sync = 1;
+	c->mtu = dev->mtu+64;
+	c->count = 0;
+	c->skb = NULL;
+	c->skb2 = NULL;
+	
+	/*
+	 *	Load the PIO receive ring
+	 */
+
+	z8530_rx_done(c);
+	z8530_rx_done(c);
+
+ 	/*
+	 *	Load the DMA interfaces up
+	 */
+
+	c->rxdma_on = 0;
+	c->txdma_on = 0;
+	
+	c->tx_dma_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
+	if(c->tx_dma_buf[0]==NULL)
+	{
+		kfree(c->rx_buf[0]);
+		kfree(c->rx_buf[1]);
+		c->rx_buf[0]=NULL;
+		return -ENOBUFS;
+	}
+	c->tx_dma_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
+	if(c->tx_dma_buf[1]==NULL)
+	{
+		kfree(c->tx_dma_buf[0]);
+		kfree(c->rx_buf[0]);
+		kfree(c->rx_buf[1]);
+		c->rx_buf[0]=NULL;
+		c->rx_buf[1]=NULL;
+		c->tx_dma_buf[0]=NULL;
+		return -ENOBUFS;
+	}
+	c->tx_dma_used=0;
+	c->dma_num=0;
+	c->dma_ready=1;
+	c->dma_tx = 1;
+
+ 	/*
+	 *	Enable DMA control mode
+	 */
+
+ 	/*
+	 *	TX DMA via DIR/REQ
+ 	 */
+	c->regs[R14]|= DTRREQ;
+	write_zsreg(c, R14, c->regs[R14]);     
+	
+	c->regs[R1]&= ~TxINT_ENAB;
+	write_zsreg(c, R1, c->regs[R1]);
+	
+	/*
+	 *	Set up the DMA configuration
+	 */	
+	 
+	flags = claim_dma_lock();
+
+	disable_dma(c->txdma);
+	clear_dma_ff(c->txdma);
+	set_dma_mode(c->txdma, DMA_MODE_WRITE);
+	disable_dma(c->txdma);
+
+	release_dma_lock(flags);
+	
+	/*
+	 *	Select the DMA interrupt handlers
+	 */
+
+	c->rxdma_on = 0;
+	c->txdma_on = 1;
+	c->tx_dma_used = 1;
+	 
+	c->irqs = &z8530_txdma_sync;
+	printk("Loading RX\n");
+	z8530_rtsdtr(c,1);
+	printk("Rx interrupts ON\n");	
+	write_zsreg(c, R3, c->regs[R3]|RxENABLE);
+	return 0;
+}
+
+EXPORT_SYMBOL(z8530_sync_txdma_open);
+	
+int z8530_sync_txdma_close(struct net_device *dev, struct z8530_channel *c)
+{
+	unsigned long flags;
+	u8 chk;
+	c->irqs = &z8530_nop;
+	c->max = 0;
+	c->sync = 0;
+	
+	/*
+	 *	Disable the PC DMA channels
+	 */
+	 
+	flags = claim_dma_lock();
+
+	disable_dma(c->txdma);
+	clear_dma_ff(c->txdma);
+	c->txdma_on = 0;
+	c->tx_dma_used = 0;
+
+	release_dma_lock(flags);
+
+	/*
+	 *	Disable DMA control mode
+	 */
+	 
+	c->regs[R1]&= ~WT_RDY_ENAB;
+	write_zsreg(c, R1, c->regs[R1]);            
+	c->regs[R1]&= ~(WT_RDY_RT|WT_FN_RDYFN|INT_ERR_Rx);
+	c->regs[R1]|= INT_ALL_Rx;
+	write_zsreg(c, R1, c->regs[R1]);
+	c->regs[R14]&= ~DTRREQ;
+	write_zsreg(c, R14, c->regs[R14]);   
+	
+	if(c->tx_dma_buf[0])
+	{
+		kfree(c->tx_dma_buf[0]);
+		c->tx_dma_buf[0]=NULL;
+	}
+	if(c->tx_dma_buf[1])
+	{
+		kfree(c->tx_dma_buf[1]);
+		c->tx_dma_buf[1]=NULL;
+	}
+	chk=read_zsreg(c,R0);
+	write_zsreg(c, R3, c->regs[R3]);
+	z8530_rtsdtr(c,0);
+	return 0;
+}
+
+
+EXPORT_SYMBOL(z8530_sync_txdma_close);
+
+/*
+ *	Describe a Z8530 in a standard format. We must pass the I/O as
+ *	the port offset isnt predictable. The main reason for this function
+ *	is to try and get a common format of report.
+ */
+
+static char *z8530_type_name[]={
+	"Z8530",
+	"Z85C30",
+	"Z85230"
+};
+
+void z8530_describe(struct z8530_dev *dev, char *mapping, int io)
+{
+	printk(KERN_INFO "%s: %s found at %s 0x%X, IRQ %d.\n",
+		dev->name, 
+		z8530_type_name[dev->type],
+		mapping,
+		Z8530_PORT_OF(io),
+		dev->irq);
+}
+
+EXPORT_SYMBOL(z8530_describe);
+
+/*
+ *	Configure up a Z8530
+ */
+
+ 
+int z8530_init(struct z8530_dev *dev)
+{
+	/* NOP the interrupt handlers first - we might get a
+	   floating IRQ transition when we reset the chip */
+	dev->chanA.irqs=&z8530_nop;
+	dev->chanB.irqs=&z8530_nop;
+	/* Reset the chip */
+	write_zsreg(&dev->chanA, R9, 0xC0);
+	udelay(200);
+	/* Now check its valid */
+	write_zsreg(&dev->chanA, R12, 0xAA);
+	if(read_zsreg(&dev->chanA, R12)!=0xAA)
+		return -ENODEV;
+	write_zsreg(&dev->chanA, R12, 0x55);
+	if(read_zsreg(&dev->chanA, R12)!=0x55)
+		return -ENODEV;
+		
+	dev->type=Z8530;
+	
+	/*
+	 *	See the application note.
+	 */
+	 
+	write_zsreg(&dev->chanA, R15, 0x01);
+	
+	/*
+	 *	If we can set the low bit of R15 then
+	 *	the chip is enhanced.
+	 */
+	 
+	if(read_zsreg(&dev->chanA, R15)==0x01)
+	{
+		/* This C30 versus 230 detect is from Klaus Kudielka's dmascc */
+		/* Put a char in the fifo */
+		write_zsreg(&dev->chanA, R8, 0);
+		if(read_zsreg(&dev->chanA, R0)&Tx_BUF_EMP)
+			dev->type = Z85230;	/* Has a FIFO */
+		else
+			dev->type = Z85C30;	/* Z85C30, 1 byte FIFO */
+	}
+		
+	/*
+	 *	The code assumes R7' and friends are
+	 *	off. Use write_zsext() for these and keep
+	 *	this bit clear.
+	 */
+	 
+	write_zsreg(&dev->chanA, R15, 0);
+		
+	/*
+	 *	At this point it looks like the chip is behaving
+	 */
+	 
+	memcpy(dev->chanA.regs, reg_init, 16);
+	memcpy(dev->chanB.regs, reg_init ,16);
+	
+	return 0;
+}
+
+
+EXPORT_SYMBOL(z8530_init);
+
+int z8530_shutdown(struct z8530_dev *dev)
+{
+	/* Reset the chip */
+	dev->chanA.irqs=&z8530_nop;
+	dev->chanB.irqs=&z8530_nop;
+	write_zsreg(&dev->chanA, R9, 0xC0);
+	udelay(100);
+	return 0;
+}
+
+EXPORT_SYMBOL(z8530_shutdown);
+
+/*
+ *	Load a Z8530 channel up from the system data
+ *	We use +16 to indicate the 'prime' registers
+ */
+
+int z8530_channel_load(struct z8530_channel *c, u8 *rtable)
+{
+	while(*rtable!=255)
+	{
+		int reg=*rtable++;
+		if(reg>0x0F)
+			write_zsreg(c, R15, c->regs[15]|1);
+		write_zsreg(c, reg&0x0F, *rtable);
+		if(reg>0x0F)
+			write_zsreg(c, R15, c->regs[15]&~1);
+		c->regs[reg]=*rtable++;
+	}
+	c->rx_function=z8530_null_rx;
+	c->skb=NULL;
+	c->tx_skb=NULL;
+	c->tx_next_skb=NULL;
+	c->mtu=1500;
+	c->max=0;
+	c->count=0;
+	c->status=0;	/* Fixme - check DCD now */
+	c->sync=1;
+	write_zsreg(c, R3, c->regs[R3]|RxENABLE);
+	return 0;
+}
+
+EXPORT_SYMBOL(z8530_channel_load);
+
+
+/*
+ *	Higher level shovelling - transmit chains
+ */
+
+static void z8530_tx_begin(struct z8530_channel *c)
+{
+	unsigned long flags;
+	if(c->tx_skb)
+		return;
+		
+	c->tx_skb=c->tx_next_skb;
+	c->tx_next_skb=NULL;
+	c->tx_ptr=c->tx_next_ptr;
+	
+	mark_bh(NET_BH);
+	if(c->tx_skb==NULL)
+	{
+		/* Idle on */
+		if(c->dma_tx)
+		{
+			flags=claim_dma_lock();
+			disable_dma(c->txdma);
+			/*
+			 *	Check if we crapped out.
+			 */
+			if(get_dma_residue(c->txdma))
+			{
+				c->stats.tx_dropped++;
+				c->stats.tx_fifo_errors++;
+			}
+			release_dma_lock(flags);
+		}
+		c->txcount=0;
+	}
+	else
+	{
+		c->txcount=c->tx_skb->len;
+		
+		
+		if(c->dma_tx)
+		{
+			/*
+			 *	FIXME. DMA is broken for the original 8530,
+			 *	on the older parts we need to set a flag and
+			 *	wait for a further TX interrupt to fire this
+			 *	stage off	
+			 */
+			 
+			flags=claim_dma_lock();
+			disable_dma(c->txdma);
+
+			/*
+			 *	These two are needed by the 8530/85C30
+			 *	and must be issued when idling.
+			 */
+			 
+			if(c->dev->type!=Z85230)
+			{
+				write_zsctrl(c, RES_Tx_CRC);
+				write_zsctrl(c, RES_EOM_L);
+			}	
+			write_zsreg(c, R10, c->regs[10]&~ABUNDER);
+			clear_dma_ff(c->txdma);
+			set_dma_addr(c->txdma, virt_to_bus(c->tx_ptr));
+			set_dma_count(c->txdma, c->txcount);
+			enable_dma(c->txdma);
+			release_dma_lock(flags);
+			write_zsctrl(c, RES_EOM_L);
+			write_zsreg(c, R5, c->regs[R5]|TxENAB);
+		}
+		else
+		{
+			save_flags(flags);
+			cli();
+			/* ABUNDER off */
+			write_zsreg(c, R10, c->regs[10]);
+			write_zsctrl(c, RES_Tx_CRC);
+//???			write_zsctrl(c, RES_EOM_L);
+	
+			while(c->txcount && (read_zsreg(c,R0)&Tx_BUF_EMP))
+			{		
+				write_zsreg(c, R8, *c->tx_ptr++);
+				c->txcount--;
+			}
+			restore_flags(flags);
+		}
+	}
+}
+ 
+ 
+static void z8530_tx_done(struct z8530_channel *c)
+{
+	unsigned long flags;
+	struct sk_buff *skb;
+
+	spin_lock_irqsave(&z8530_buffer_lock, flags);
+	c->netdevice->tbusy=0;
+	/* Actually this can happen.*/
+	if(c->tx_skb==NULL)
+	{
+		spin_unlock_irqrestore(&z8530_buffer_lock, flags);
+		return;
+	}
+	skb=c->tx_skb;
+	c->tx_skb=NULL;
+	z8530_tx_begin(c);
+	spin_unlock_irqrestore(&z8530_buffer_lock, flags);
+	c->stats.tx_packets++;
+	c->stats.tx_bytes+=skb->len;
+	dev_kfree_skb(skb);
+}
+
+/*
+ *	Higher level shovelling - receive chains
+ */
+ 
+void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb)
+{
+	kfree_skb(skb);
+}
+
+EXPORT_SYMBOL(z8530_null_rx);
+
+static void z8530_rx_done(struct z8530_channel *c)
+{
+	struct sk_buff *skb;
+	int ct;
+	
+	/*
+	 *	Is our receive engine in DMA mode
+	 */
+	 
+	if(c->rxdma_on)
+	{
+		/*
+		 *	Save the ready state and the buffer currently
+		 *	being used as the DMA target
+		 */
+
+		int ready=c->dma_ready;
+		unsigned char *rxb=c->rx_buf[c->dma_num];
+		unsigned long flags;
+		
+		/*
+		 *	Complete this DMA. Neccessary to find the length
+		 */		
+		 
+		flags=claim_dma_lock();
+		
+		disable_dma(c->rxdma);
+		clear_dma_ff(c->rxdma);
+		c->rxdma_on=0;
+		ct=c->mtu-get_dma_residue(c->rxdma);
+		if(ct<0)
+			ct=2;	/* Shit happens.. */
+		c->dma_ready=0;
+		
+		/*
+		 *	Normal case: the other slot is free, start the next DMA
+		 *	into it immediately.
+		 */
+		 
+		if(ready)
+		{
+			c->dma_num^=1;
+			set_dma_mode(c->rxdma, DMA_MODE_READ|0x10);
+			set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[c->dma_num]));
+			set_dma_count(c->rxdma, c->mtu);
+			c->rxdma_on = 1;
+			enable_dma(c->rxdma);
+			/* Stop any frames that we missed the head of 
+			   from passing */
+			write_zsreg(c, R0, RES_Rx_CRC);
+		}
+		else
+			/* Can't occur as we dont reenable the DMA irq until
+			   after the flip is done */
+			printk("DMA flip overrun!\n");
+			
+		release_dma_lock(flags);
+		
+		/*
+		 *	Shove the old buffer into an sk_buff. We can't DMA
+		 *	directly into one on a PC - it might be above the 16Mb
+		 *	boundary. Optimisation - we could check to see if we
+		 *	can avoid the copy. Optimisation 2 - make the memcpy
+		 *	a copychecksum.
+		 */
+		 
+		skb=dev_alloc_skb(ct);
+		if(skb==NULL)
+		{
+			c->stats.rx_dropped++;
+			printk(KERN_WARNING "%s: Memory squeeze.\n", c->netdevice->name);
+		}
+		else
+		{
+			skb_put(skb, ct);
+			memcpy(skb->data, rxb, ct);
+			c->stats.rx_packets++;
+			c->stats.rx_bytes+=ct;
+		}
+		c->dma_ready=1;
+	}
+	else
+	{
+		RT_LOCK;	
+		skb=c->skb;
+		
+		/*
+		 *	The game we play for non DMA is similar. We want to
+		 *	get the controller set up for the next packet as fast
+		 *	as possible. We potentially only have one byte + the
+		 *	fifo length for this. Thus we want to flip to the new
+		 *	buffer and then mess around copying and allocating
+		 *	things. For the current case it doesn't matter but
+		 *	if you build a system where the sync irq isnt blocked
+		 *	by the kernel IRQ disable then you need only block the
+		 *	sync IRQ for the RT_LOCK area.
+		 *	
+		 */
+		ct=c->count;
+		
+		c->skb = c->skb2;
+		c->count = 0;
+		c->max = c->mtu;
+		if(c->skb)
+		{
+			c->dptr = c->skb->data;
+			c->max = c->mtu;
+		}
+		else
+		{
+			c->count= 0;
+			c->max = 0;
+		}
+		RT_UNLOCK;
+
+		c->skb2 = dev_alloc_skb(c->mtu);
+		if(c->skb2==NULL)
+			printk(KERN_WARNING "%s: memory squeeze.\n",
+				c->netdevice->name);
+		else
+		{
+			skb_put(c->skb2,c->mtu);
+		}
+		c->stats.rx_packets++;
+		c->stats.rx_bytes+=ct;
+		
+	}
+	/*
+	 *	If we received a frame we must now process it.
+	 */
+	if(skb)
+	{
+		skb_trim(skb, ct);
+		c->rx_function(c,skb);
+	}
+	else
+	{
+		c->stats.rx_dropped++;
+		printk(KERN_ERR "%s: Lost a frame\n", c->netdevice->name);
+	}
+}
+
+/*
+ *	Cannot DMA over a 64K boundary on a PC
+ */
+ 
+extern inline int spans_boundary(struct sk_buff *skb)
+{
+	unsigned long a=(unsigned long)skb->data;
+	a^=(a+skb->len);
+	if(a&0x00010000)	/* If the 64K bit is different.. */
+	{
+		printk("spanner\n");
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ *	Queue a packet for transmission. Because we have rather
+ *	hard to hit interrupt latencies for the Z85230 per packet 
+ *	even in DMA mode we do the flip to DMA buffer if needed here
+ *	not in the IRQ.
+ */
+
+int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb)
+{
+	unsigned long flags;
+	if(c->tx_next_skb)
+	{
+		skb->dev->tbusy=1;
+		return 1;
+	}
+	
+	/* PC SPECIFIC - DMA limits */
+	
+	/*
+	 *	If we will DMA the transmit and its gone over the ISA bus
+	 *	limit, then copy to the flip buffer
+	 */
+	 
+	if(c->dma_tx && ((unsigned long)(virt_to_bus(skb->data+skb->len))>=16*1024*1024 || spans_boundary(skb)))
+	{
+		/* 
+		 *	Send the flip buffer, and flip the flippy bit.
+		 *	We don't care which is used when just so long as
+		 *	we never use the same buffer twice in a row. Since
+		 *	only one buffer can be going out at a time the other
+		 *	has to be safe.
+		 */
+		c->tx_next_ptr=c->tx_dma_buf[c->tx_dma_used];
+		c->tx_dma_used^=1;	/* Flip temp buffer */
+		memcpy(c->tx_next_ptr, skb->data, skb->len);
+	}
+	else
+		c->tx_next_ptr=skb->data;	
+	RT_LOCK;
+	c->tx_next_skb=skb;
+	RT_UNLOCK;
+	
+	spin_lock_irqsave(&z8530_buffer_lock, flags);
+	z8530_tx_begin(c);
+	spin_unlock_irqrestore(&z8530_buffer_lock, flags);
+	return 0;
+}
+
+EXPORT_SYMBOL(z8530_queue_xmit);
+
+struct net_device_stats *z8530_get_stats(struct z8530_channel *c)
+{
+	return &c->stats;
+}
+
+EXPORT_SYMBOL(z8530_get_stats);
+
+#ifdef MODULE
+
+/*
+ *	Module support
+ */
+ 
+int init_module(void)
+{
+	printk(KERN_INFO "Generic Z85C30/Z85230 interface driver v0.02\n");
+	return 0;
+}
+
+void cleanup_module(void)
+{
+}
+
+#endif
diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/z85230.h linux/drivers/net/wan/z85230.h
--- v2.3.20/linux/drivers/net/wan/z85230.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/z85230.h	Mon Oct 11 10:13:25 1999
@@ -0,0 +1,446 @@
+/*
+ *	Description of Z8530 Z85C30 and Z85230 communications chips
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Alan Cox <alan@redhat.com>
+ */
+
+#ifndef _Z8530_H
+#define _Z8530_H
+
+/* Conversion routines to/from brg time constants from/to bits
+ * per second.
+ */
+#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/* The Zilog register set */
+
+#define	FLAG	0x7e
+
+/* Write Register 0 */
+#define	R0	0		/* Register selects */
+#define	R1	1
+#define	R2	2
+#define	R3	3
+#define	R4	4
+#define	R5	5
+#define	R6	6
+#define	R7	7
+#define	R8	8
+#define	R9	9
+#define	R10	10
+#define	R11	11
+#define	R12	12
+#define	R13	13
+#define	R14	14
+#define	R15	15
+
+#define RPRIME	16		/* Indicate a prime register access on 230 */
+
+#define	NULLCODE	0	/* Null Code */
+#define	POINT_HIGH	0x8	/* Select upper half of registers */
+#define	RES_EXT_INT	0x10	/* Reset Ext. Status Interrupts */
+#define	SEND_ABORT	0x18	/* HDLC Abort */
+#define	RES_RxINT_FC	0x20	/* Reset RxINT on First Character */
+#define	RES_Tx_P	0x28	/* Reset TxINT Pending */
+#define	ERR_RES		0x30	/* Error Reset */
+#define	RES_H_IUS	0x38	/* Reset highest IUS */
+
+#define	RES_Rx_CRC	0x40	/* Reset Rx CRC Checker */
+#define	RES_Tx_CRC	0x80	/* Reset Tx CRC Checker */
+#define	RES_EOM_L	0xC0	/* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define	EXT_INT_ENAB	0x1	/* Ext Int Enable */
+#define	TxINT_ENAB	0x2	/* Tx Int Enable */
+#define	PAR_SPEC	0x4	/* Parity is special condition */
+
+#define	RxINT_DISAB	0	/* Rx Int Disable */
+#define	RxINT_FCERR	0x8	/* Rx Int on First Character Only or Error */
+#define	INT_ALL_Rx	0x10	/* Int on all Rx Characters or error */
+#define	INT_ERR_Rx	0x18	/* Int on error only */
+
+#define	WT_RDY_RT	0x20	/* Wait/Ready on R/T */
+#define	WT_FN_RDYFN	0x40	/* Wait/FN/Ready FN */
+#define	WT_RDY_ENAB	0x80	/* Wait/Ready Enable */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define	RxENABLE	0x1	/* Rx Enable */
+#define	SYNC_L_INH	0x2	/* Sync Character Load Inhibit */
+#define	ADD_SM		0x4	/* Address Search Mode (SDLC) */
+#define	RxCRC_ENAB	0x8	/* Rx CRC Enable */
+#define	ENT_HM		0x10	/* Enter Hunt Mode */
+#define	AUTO_ENAB	0x20	/* Auto Enables */
+#define	Rx5		0x0	/* Rx 5 Bits/Character */
+#define	Rx7		0x40	/* Rx 7 Bits/Character */
+#define	Rx6		0x80	/* Rx 6 Bits/Character */
+#define	Rx8		0xc0	/* Rx 8 Bits/Character */
+
+/* Write Register 4 */
+
+#define	PAR_ENA		0x1	/* Parity Enable */
+#define	PAR_EVEN	0x2	/* Parity Even/Odd* */
+
+#define	SYNC_ENAB	0	/* Sync Modes Enable */
+#define	SB1		0x4	/* 1 stop bit/char */
+#define	SB15		0x8	/* 1.5 stop bits/char */
+#define	SB2		0xc	/* 2 stop bits/char */
+
+#define	MONSYNC		0	/* 8 Bit Sync character */
+#define	BISYNC		0x10	/* 16 bit sync character */
+#define	SDLC		0x20	/* SDLC Mode (01111110 Sync Flag) */
+#define	EXTSYNC		0x30	/* External Sync Mode */
+
+#define	X1CLK		0x0	/* x1 clock mode */
+#define	X16CLK		0x40	/* x16 clock mode */
+#define	X32CLK		0x80	/* x32 clock mode */
+#define	X64CLK		0xC0	/* x64 clock mode */
+
+/* Write Register 5 */
+
+#define	TxCRC_ENAB	0x1	/* Tx CRC Enable */
+#define	RTS		0x2	/* RTS */
+#define	SDLC_CRC	0x4	/* SDLC/CRC-16 */
+#define	TxENAB		0x8	/* Tx Enable */
+#define	SND_BRK		0x10	/* Send Break */
+#define	Tx5		0x0	/* Tx 5 bits (or less)/character */
+#define	Tx7		0x20	/* Tx 7 bits/character */
+#define	Tx6		0x40	/* Tx 6 bits/character */
+#define	Tx8		0x60	/* Tx 8 bits/character */
+#define	DTR		0x80	/* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define	VIS	1	/* Vector Includes Status */
+#define	NV	2	/* No Vector */
+#define	DLC	4	/* Disable Lower Chain */
+#define	MIE	8	/* Master Interrupt Enable */
+#define	STATHI	0x10	/* Status high */
+#define	NORESET	0	/* No reset on write to R9 */
+#define	CHRB	0x40	/* Reset channel B */
+#define	CHRA	0x80	/* Reset channel A */
+#define	FHWRES	0xc0	/* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define	BIT6	1	/* 6 bit/8bit sync */
+#define	LOOPMODE 2	/* SDLC Loop mode */
+#define	ABUNDER	4	/* Abort/flag on SDLC xmit underrun */
+#define	MARKIDLE 8	/* Mark/flag on idle */
+#define	GAOP	0x10	/* Go active on poll */
+#define	NRZ	0	/* NRZ mode */
+#define	NRZI	0x20	/* NRZI mode */
+#define	FM1	0x40	/* FM1 (transition = 1) */
+#define	FM0	0x60	/* FM0 (transition = 0) */
+#define	CRCPS	0x80	/* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define	TRxCXT	0	/* TRxC = Xtal output */
+#define	TRxCTC	1	/* TRxC = Transmit clock */
+#define	TRxCBR	2	/* TRxC = BR Generator Output */
+#define	TRxCDP	3	/* TRxC = DPLL output */
+#define	TRxCOI	4	/* TRxC O/I */
+#define	TCRTxCP	0	/* Transmit clock = RTxC pin */
+#define	TCTRxCP	8	/* Transmit clock = TRxC pin */
+#define	TCBR	0x10	/* Transmit clock = BR Generator output */
+#define	TCDPLL	0x18	/* Transmit clock = DPLL output */
+#define	RCRTxCP	0	/* Receive clock = RTxC pin */
+#define	RCTRxCP	0x20	/* Receive clock = TRxC pin */
+#define	RCBR	0x40	/* Receive clock = BR Generator output */
+#define	RCDPLL	0x60	/* Receive clock = DPLL output */
+#define	RTxCX	0x80	/* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* Write Register 13 (upper byte of baud rate generator time constant) */
+
+/* Write Register 14 (Misc control bits) */
+#define	BRENABL	1	/* Baud rate generator enable */
+#define	BRSRC	2	/* Baud rate generator source */
+#define	DTRREQ	4	/* DTR/Request function */
+#define	AUTOECHO 8	/* Auto Echo */
+#define	LOOPBAK	0x10	/* Local loopback */
+#define	SEARCH	0x20	/* Enter search mode */
+#define	RMC	0x40	/* Reset missing clock */
+#define	DISDPLL	0x60	/* Disable DPLL */
+#define	SSBR	0x80	/* Set DPLL source = BR generator */
+#define	SSRTxC	0xa0	/* Set DPLL source = RTxC */
+#define	SFMM	0xc0	/* Set FM mode */
+#define	SNRZI	0xe0	/* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define PRIME	1	/* R5' etc register access (Z85C30/230 only) */
+#define	ZCIE	2	/* Zero count IE */
+#define FIFOE	4	/* Z85230 only */
+#define	DCDIE	8	/* DCD IE */
+#define	SYNCIE	0x10	/* Sync/hunt IE */
+#define	CTSIE	0x20	/* CTS IE */
+#define	TxUIE	0x40	/* Tx Underrun/EOM IE */
+#define	BRKIE	0x80	/* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define	Rx_CH_AV	0x1	/* Rx Character Available */
+#define	ZCOUNT		0x2	/* Zero count */
+#define	Tx_BUF_EMP	0x4	/* Tx Buffer empty */
+#define	DCD		0x8	/* DCD */
+#define	SYNC_HUNT	0x10	/* Sync/hunt */
+#define	CTS		0x20	/* CTS */
+#define	TxEOM		0x40	/* Tx underrun */
+#define	BRK_ABRT	0x80	/* Break/Abort */
+
+/* Read Register 1 */
+#define	ALL_SNT		0x1	/* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define	RES3		0x8	/* 0/3 */
+#define	RES4		0x4	/* 0/4 */
+#define	RES5		0xc	/* 0/5 */
+#define	RES6		0x2	/* 0/6 */
+#define	RES7		0xa	/* 0/7 */
+#define	RES8		0x6	/* 0/8 */
+#define	RES18		0xe	/* 1/8 */
+#define	RES28		0x0	/* 2/8 */
+/* Special Rx Condition Interrupts */
+#define	PAR_ERR		0x10	/* Parity error */
+#define	Rx_OVR		0x20	/* Rx Overrun Error */
+#define	CRC_ERR		0x40	/* CRC/Framing Error */
+#define	END_FR		0x80	/* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define	CHBEXT	0x1		/* Channel B Ext/Stat IP */
+#define	CHBTxIP	0x2		/* Channel B Tx IP */
+#define	CHBRxIP	0x4		/* Channel B Rx IP */
+#define	CHAEXT	0x8		/* Channel A Ext/Stat IP */
+#define	CHATxIP	0x10		/* Channel A Tx IP */
+#define	CHARxIP	0x20		/* Channel A Rx IP */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10  (misc status bits) */
+#define	ONLOOP	2		/* On loop */
+#define	LOOPSEND 0x10		/* Loop sending */
+#define	CLK2MIS	0x40		/* Two clocks missing */
+#define	CLK1MIS	0x80		/* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */
+
+
+/*
+ *	Interrupt handling functions for this SCC
+ */
+
+struct z8530_channel;
+ 
+struct z8530_irqhandler
+{
+	void (*rx)(struct z8530_channel *);
+	void (*tx)(struct z8530_channel *);
+	void (*status)(struct z8530_channel *);
+};
+
+/*
+ *	A channel of the Z8530
+ */
+
+struct z8530_channel
+{
+	struct		z8530_irqhandler *irqs;		/* IRQ handlers */
+	/*
+	 *	Synchronous
+	 */
+	u16		count;		/* Buyes received */
+	u16		max;		/* Most we can receive this frame */
+	u16		mtu;		/* MTU of the device */
+	u8		*dptr;		/* Pointer into rx buffer */
+	struct sk_buff	*skb;		/* Buffer dptr points into */
+	struct sk_buff	*skb2;		/* Pending buffer */
+	u8		status;		/* Current DCD */
+	u8		sync;		/* Set if in sync mode */
+
+	u8		regs[32];	/* Register map for the chip */
+	u8		pendregs[32];	/* Pending register values */
+	
+	struct sk_buff 	*tx_skb;	/* Buffer being transmitted */
+	struct sk_buff  *tx_next_skb;	/* Next transmit buffer */
+	u8		*tx_ptr;	/* Byte pointer into the buffer */
+	u8		*tx_next_ptr;	/* Next pointer to use */
+	u8		*tx_dma_buf[2];	/* TX flip buffers for DMA */
+	u8		tx_dma_used;	/* Flip buffer usage toggler */
+	u16		txcount;	/* Count of bytes to transmit */
+	
+	void		(*rx_function)(struct z8530_channel *, struct sk_buff *);
+	
+	/*
+	 *	Sync DMA
+	 */
+	
+	u8		rxdma;		/* DMA channels */
+	u8		txdma;		
+	u8		rxdma_on;	/* DMA active if flag set */
+	u8		txdma_on;
+	u8		dma_num;	/* Buffer we are DMAing into */
+	u8		dma_ready;	/* Is the other buffer free */
+	u8		dma_tx;		/* TX is to use DMA */
+	u8		*rx_buf[2];	/* The flip buffers */
+	
+	/*
+	 *	System
+	 */
+	 
+	struct z8530_dev *dev;		/* Z85230 chip instance we are from */
+	int		ctrlio;		/* I/O ports */
+	int		dataio;
+
+	/*
+	 *	For PC we encode this way.
+	 */	
+#define Z8530_PORT_SLEEP	0x80000000
+#define Z8530_PORT_OF(x)	((x)&0xFFFF)
+
+	u32		rx_overrun;		/* Overruns - not done yet */
+	u32		rx_crc_err;
+
+	/*
+	 *	Bound device pointers
+	 */
+
+	void		*private;	/* For our owner */
+	struct net_device	*netdevice;	/* Network layer device */
+	struct net_device_stats stats;	/* Network layer statistics */
+
+	/*
+	 *	Async features
+	 */
+
+	struct tty_struct 	*tty;		/* Attached terminal */
+	int			line;		/* Minor number */
+	struct termios		normal_termios;	/* Terminal settings */
+	struct termios		callout_termios;
+	wait_queue_head_t	open_wait;	/* Tasks waiting to open */
+	wait_queue_head_t	close_wait;	/* and for close to end */
+	unsigned long		event;		/* Pending events */
+	int			fdcount;    	/* # of fd on device */
+	int			blocked_open;	/* # of blocked opens */
+	long			session; 	/* Session of opening process */
+	long			pgrp; 		/* pgrp of opening process */
+	int			x_char;		/* XON/XOF char */
+	unsigned char 		*xmit_buf;	/* Transmit pointer */
+	int			xmit_head;	/* Transmit ring */
+	int			xmit_tail;
+	int			xmit_cnt;
+	int			flags;	
+	int			timeout;
+	int			xmit_fifo_size;	/* Transmit FIFO info */
+
+	int			close_delay;	/* Do we wait for drain on close ? */
+	unsigned short		closing_wait;
+
+	/* We need to know the current clock divisor
+	 * to read the bps rate the chip has currently
+	 * loaded.
+	 */
+
+	unsigned char		clk_divisor;  /* May be 1, 16, 32, or 64 */
+	int			zs_baud;
+
+	int			magic;
+	int			baud_base;		/* Baud parameters */
+	int			custom_divisor;
+
+
+	unsigned char		tx_active; /* character is being xmitted */
+	unsigned char		tx_stopped; /* output is suspended */
+};	
+
+/*
+ *	Each Z853x0 device.
+ */	
+ 
+struct z8530_dev
+{
+	char *name;	/* Device instance name */
+	struct z8530_channel chanA;	/* SCC channel A */
+	struct z8530_channel chanB;	/* SCC channel B */
+	int type;
+#define Z8530	0	/* NMOS dinosaur */	
+#define Z85C30	1	/* CMOS - better */
+#define Z85230	2	/* CMOS with real FIFO */
+	int irq;	/* Interrupt for the device */
+	int active;	/* Soft interrupt enable - the Mac doesn't 
+			   always have a hard disable on its 8530s... */
+};
+
+
+/*
+ *	Functions
+ */
+ 
+extern u8 z8530_dead_port[];
+extern u8 z8530_hdlc_kilostream_85230[];
+extern u8 z8530_hdlc_kilostream[];
+extern void z8530_interrupt(int, void *, struct pt_regs *);
+extern void z8530_describe(struct z8530_dev *, char *mapping,int io);
+extern int z8530_init(struct z8530_dev *);
+extern int z8530_shutdown(struct z8530_dev *);
+extern int z8530_sync_open(struct net_device *, struct z8530_channel *);
+extern int z8530_sync_close(struct net_device *, struct z8530_channel *);
+extern int z8530_sync_dma_open(struct net_device *, struct z8530_channel *);
+extern int z8530_sync_dma_close(struct net_device *, struct z8530_channel *);
+extern int z8530_sync_txdma_open(struct net_device *, struct z8530_channel *);
+extern int z8530_sync_txdma_close(struct net_device *, struct z8530_channel *);
+extern int z8530_channel_load(struct z8530_channel *, u8 *);
+extern int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb);
+extern struct net_device_stats *z8530_get_stats(struct z8530_channel *c);
+extern void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb);
+
+
+/*
+ *	Standard interrupt vector sets
+ */
+ 
+struct z8530_irqhandler z8530_sync, z8530_async, z8530_nop;
+
+/*
+ *	Asynchronous Interfacing
+ */
+
+#define SERIAL_MAGIC 0x5301
+
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+
+#define SERIAL_XMIT_SIZE 4096
+#define WAKEUP_CHARS	256
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP	0
+
+/* Internal flags used only by kernel/chr_drv/serial.c */
+#define ZILOG_INITIALIZED	0x80000000 /* Serial port was initialized */
+#define ZILOG_CALLOUT_ACTIVE	0x40000000 /* Call out device is active */
+#define ZILOG_NORMAL_ACTIVE	0x20000000 /* Normal device is active */
+#define ZILOG_BOOT_AUTOCONF	0x10000000 /* Autoconfigure port on bootup */
+#define ZILOG_CLOSING		0x08000000 /* Serial port is closing */
+#define ZILOG_CTS_FLOW		0x04000000 /* Do CTS flow control */
+#define ZILOG_CHECK_CD		0x02000000 /* i.e., CLOCAL */
+
+#endif /* !(_Z8530_H) */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/x25_asy.c linux/drivers/net/x25_asy.c
--- v2.3.20/linux/drivers/net/x25_asy.c	Thu Aug 26 13:05:38 1999
+++ linux/drivers/net/x25_asy.c	Wed Dec 31 16:00:00 1969
@@ -1,943 +0,0 @@
-/*
- *	Things to sort out:
- *
- *	o	tbusy handling
- *	o	allow users to set the parameters
- *	o	sync/async switching ?
- *
- *	Note: This does _not_ implement CCITT X.25 asynchronous framing
- *	recommendations. Its primarily for testing purposes. If you wanted
- *	to do CCITT then in theory all you need is to nick the HDLC async
- *	checksum routines from ppp.c
- */
-
-#include <linux/module.h>
-
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/bitops.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/tty.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/x25.h>
-#include <linux/lapb.h>
-#include <linux/init.h>
-#include "x25_asy.h"
-
-typedef struct x25_ctrl {
-	char		if_name[8];	/* "xasy0\0" .. "xasy99999\0"	*/
-	struct x25_asy	ctrl;		/* X.25 things			*/
-	struct net_device	dev;		/* the device			*/
-} x25_asy_ctrl_t;
-
-static x25_asy_ctrl_t	**x25_asy_ctrls = NULL;
-
-int x25_asy_maxdev = SL_NRUNIT;		/* Can be overridden with insmod! */
-MODULE_PARM(x25_asy_maxdev, "i");
-
-static struct tty_ldisc	x25_ldisc;
-
-static int x25_asy_esc(unsigned char *p, unsigned char *d, int len);
-static void x25_asy_unesc(struct x25_asy *sl, unsigned char c);
-
-/* Find a free X.25 channel, and link in this `tty' line. */
-static inline struct x25_asy *x25_asy_alloc(void)
-{
-	x25_asy_ctrl_t *slp = NULL;
-	int i;
-
-	if (x25_asy_ctrls == NULL)
-		return NULL;	/* Master array missing ! */
-
-	for (i = 0; i < x25_asy_maxdev; i++) 
-	{
-		slp = x25_asy_ctrls[i];
-		/* Not allocated ? */
-		if (slp == NULL)
-			break;
-		/* Not in use ? */
-		if (!test_and_set_bit(SLF_INUSE, &slp->ctrl.flags))
-			break;
-	}
-	/* SLP is set.. */
-
-	/* Sorry, too many, all slots in use */
-	if (i >= x25_asy_maxdev)
-		return NULL;
-
-	/* If no channels are available, allocate one */
-	if (!slp &&
-	    (x25_asy_ctrls[i] = (x25_asy_ctrl_t *)kmalloc(sizeof(x25_asy_ctrl_t),
-						    GFP_KERNEL)) != NULL) {
-		slp = x25_asy_ctrls[i];
-		memset(slp, 0, sizeof(x25_asy_ctrl_t));
-
-		/* Initialize channel control data */
-		set_bit(SLF_INUSE, &slp->ctrl.flags);
-		slp->ctrl.tty         = NULL;
-		sprintf(slp->if_name, "x25asy%d", i);
-		slp->dev.name         = slp->if_name;
-		slp->dev.base_addr    = i;
-		slp->dev.priv         = (void*)&(slp->ctrl);
-		slp->dev.next         = NULL;
-		slp->dev.init         = x25_asy_init;
-	}
-	if (slp != NULL) 
-	{
-
-		/* register device so that it can be ifconfig'ed       */
-		/* x25_asy_init() will be called as a side-effect      */
-		/* SIDE-EFFECT WARNING: x25_asy_init() CLEARS slp->ctrl ! */
-
-		if (register_netdev(&(slp->dev)) == 0) 
-		{
-			/* (Re-)Set the INUSE bit.   Very Important! */
-			set_bit(SLF_INUSE, &slp->ctrl.flags);
-			slp->ctrl.dev = &(slp->dev);
-			slp->dev.priv = (void*)&(slp->ctrl);
-			return (&(slp->ctrl));
-		}
-		else
-		{
-			clear_bit(SLF_INUSE,&(slp->ctrl.flags));
-			printk("x25_asy_alloc() - register_netdev() failure.\n");
-		}
-	}
-	return NULL;
-}
-
-
-/* Free an X.25 channel. */
-
-static inline void x25_asy_free(struct x25_asy *sl)
-{
-	/* Free all X.25 frame buffers. */
-	if (sl->rbuff)  {
-		kfree(sl->rbuff);
-	}
-	sl->rbuff = NULL;
-	if (sl->xbuff)  {
-		kfree(sl->xbuff);
-	}
-	sl->xbuff = NULL;
-
-	if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) {
-		printk("%s: x25_asy_free for already free unit.\n", sl->dev->name);
-	}
-}
-
-/* MTU has been changed by the IP layer. Unfortunately we are not told
-   about this, but we spot it ourselves and fix things up. We could be
-   in an upcall from the tty driver, or in an ip packet queue. */
-
-static void x25_asy_changed_mtu(struct x25_asy *sl)
-{
-	struct net_device *dev = sl->dev;
-	unsigned char *xbuff, *rbuff, *oxbuff, *orbuff;
-	int len;
-	unsigned long flags;
-
-	len = dev->mtu * 2;
-
-	xbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
-	rbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
-
-	if (xbuff == NULL || rbuff == NULL)  
-	{
-		printk("%s: unable to grow X.25 buffers, MTU change cancelled.\n",
-		       sl->dev->name);
-		dev->mtu = sl->mtu;
-		if (xbuff != NULL)  
-			kfree(xbuff);
-		if (rbuff != NULL)  
-			kfree(rbuff);
-		return;
-	}
-
-	save_flags(flags); 
-	cli();
-
-	oxbuff    = sl->xbuff;
-	sl->xbuff = xbuff;
-	orbuff    = sl->rbuff;
-	sl->rbuff = rbuff;
-
-	if (sl->xleft)  {
-		if (sl->xleft <= len)  {
-			memcpy(sl->xbuff, sl->xhead, sl->xleft);
-		} else  {
-			sl->xleft = 0;
-			sl->tx_dropped++;
-		}
-	}
-	sl->xhead = sl->xbuff;
-
-	if (sl->rcount)  {
-		if (sl->rcount <= len) {
-			memcpy(sl->rbuff, orbuff, sl->rcount);
-		} else  {
-			sl->rcount = 0;
-			sl->rx_over_errors++;
-			set_bit(SLF_ERROR, &sl->flags);
-		}
-	}
-	sl->mtu      = dev->mtu;
-
-	sl->buffsize = len;
-
-	restore_flags(flags);
-
-	if (oxbuff != NULL) 
-		kfree(oxbuff);
-	if (orbuff != NULL)
-		kfree(orbuff);
-}
-
-
-/* Set the "sending" flag.  This must be atomic, hence the ASM. */
-
-static inline void x25_asy_lock(struct x25_asy *sl)
-{
-	if (test_and_set_bit(0, (void *) &sl->dev->tbusy))
-		printk("%s: trying to lock already locked device!\n", sl->dev->name);
-}
-
-
-/* Clear the "sending" flag.  This must be atomic, hence the ASM. */
-
-static inline void x25_asy_unlock(struct x25_asy *sl)
-{
-	if (!test_and_clear_bit(0, (void *)&sl->dev->tbusy))
-		printk("%s: trying to unlock already unlocked device!\n", sl->dev->name);
-}
-
-/* Send one completely decapsulated IP datagram to the IP layer. */
-
-static void x25_asy_bump(struct x25_asy *sl)
-{
-	struct sk_buff *skb;
-	int count;
-	int err;
-
-	count = sl->rcount;
-	sl->rx_bytes+=count;
-	
-	skb = dev_alloc_skb(count+1);
-	if (skb == NULL)  
-	{
-		printk("%s: memory squeeze, dropping packet.\n", sl->dev->name);
-		sl->rx_dropped++;
-		return;
-	}
-	skb_push(skb,1);	/* LAPB internal control */
-	skb->dev = sl->dev;
-	memcpy(skb_put(skb,count), sl->rbuff, count);
-	skb->mac.raw=skb->data;
-	skb->protocol=htons(ETH_P_X25);
-	if((err=lapb_data_received(sl,skb))!=LAPB_OK)
-	{
-		kfree_skb(skb);
-		printk(KERN_DEBUG "x25_asy: data received err - %d\n",err);
-	}
-	else
-	{
-		netif_rx(skb);
-		sl->rx_packets++;
-	}
-}
-
-/* Encapsulate one IP datagram and stuff into a TTY queue. */
-static void x25_asy_encaps(struct x25_asy *sl, unsigned char *icp, int len)
-{
-	unsigned char *p;
-	int actual, count;
-
-
-	if (sl->mtu != sl->dev->mtu) {	/* Someone has been ifconfigging */
-
-		x25_asy_changed_mtu(sl);
-	}
-
-	if (len > sl->mtu) 
-	{		/* Sigh, shouldn't occur BUT ... */
-		len = sl->mtu;
-		printk ("%s: truncating oversized transmit packet!\n", sl->dev->name);
-		sl->tx_dropped++;
-		x25_asy_unlock(sl);
-		return;
-	}
-
-	p = icp;
-	count = x25_asy_esc(p, (unsigned char *) sl->xbuff, len);
-
-	/* Order of next two lines is *very* important.
-	 * When we are sending a little amount of data,
-	 * the transfer may be completed inside driver.write()
-	 * routine, because it's running with interrupts enabled.
-	 * In this case we *never* got WRITE_WAKEUP event,
-	 * if we did not request it before write operation.
-	 *       14 Oct 1994  Dmitry Gorodchanin.
-	 */
-	sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
-	actual = sl->tty->driver.write(sl->tty, 0, sl->xbuff, count);
-	sl->xleft = count - actual;
-	sl->xhead = sl->xbuff + actual;
-	/* VSV */
-	clear_bit(SLF_OUTWAIT, &sl->flags);	/* reset outfill flag */
-}
-
-/*
- * Called by the driver when there's room for more data.  If we have
- * more packets to send, we send them here.
- */
-static void x25_asy_write_wakeup(struct tty_struct *tty)
-{
-	int actual;
-	struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
-
-	/* First make sure we're connected. */
-	if (!sl || sl->magic != X25_ASY_MAGIC || !sl->dev->start)
-		return;
-
-	if (sl->xleft <= 0)  
-	{
-		/* Now serial buffer is almost free & we can start
-		 * transmission of another packet */
-		sl->tx_packets++;
-		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-		x25_asy_unlock(sl);
-		mark_bh(NET_BH);
-		return;
-	}
-
-	actual = tty->driver.write(tty, 0, sl->xhead, sl->xleft);
-	sl->xleft -= actual;
-	sl->xhead += actual;
-}
-
-/* Encapsulate an IP datagram and kick it into a TTY queue. */
-
-static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct x25_asy *sl = (struct x25_asy*)(dev->priv);
-	int err;
-
-	if (!dev->start)  
-	{
-		printk("%s: xmit call when iface is down\n", dev->name);
-		return 1;
-	}
-	
-	switch(skb->data[0])
-	{
-		case 0x00:break;
-		case 0x01: /* Connection request .. do nothing */
-			if((err=lapb_connect_request(sl))!=LAPB_OK)
-				printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err);
-			kfree_skb(skb);
-			return 0;
-		case 0x02: /* Disconnect request .. do nothing - hang up ?? */
-			if((err=lapb_disconnect_request(sl))!=LAPB_OK)
-				printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err);
-		default:
-			kfree_skb(skb);
-			return  0;
-	}
-	skb_pull(skb,1);	/* Remove control byte */
-	/*
-	 * If we are busy already- too bad.  We ought to be able
-	 * to queue things at this point, to allow for a little
-	 * frame buffer.  Oh well...
-	 * -----------------------------------------------------
-	 * I hate queues in X.25 driver. May be it's efficient,
-	 * but for me latency is more important. ;)
-	 * So, no queues !
-	 *        14 Oct 1994  Dmitry Gorodchanin.
-	 */
-	if (dev->tbusy) {
-		/* May be we must check transmitter timeout here ?
-		 *      14 Oct 1994 Dmitry Gorodchanin.
-		 */
-#ifdef SL_CHECK_TRANSMIT
-		if (jiffies - dev->trans_start  < 20 * HZ)  {
-			/* 20 sec timeout not reached */
-			return 1;
-		}
-		printk("%s: transmit timed out, %s?\n", dev->name,
-		       (sl->tty->driver.chars_in_buffer(sl->tty) || sl->xleft) ?
-		       "bad line quality" : "driver error");
-		sl->xleft = 0;
-		sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-		x25_asy_unlock(sl);
-#else
-		return 1;
-#endif
-	}
-	
-	if((err=lapb_data_request(sl,skb))!=LAPB_OK)
-	{
-		printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err);
-		kfree_skb(skb);
-		return 0;
-	}
-	return 0;
-}
-
-
-/*
- *	LAPB interface boilerplate
- */
-
-/*
- *	Called when I frame data arrives. We did the work above - throw it
- *	at the net layer.
- */
-  
-static void x25_asy_data_indication(void *token, struct sk_buff *skb)
-{
-	netif_rx(skb);
-}
-
-/*
- *	Data has emerged from the LAPB protocol machine. We don't handle
- *	busy cases too well. Its tricky to see how to do this nicely -
- *	perhaps lapb should allow us to bounce this ?
- */
- 
-static void x25_asy_data_transmit(void *token, struct sk_buff *skb)
-{
-	struct x25_asy *sl=token;
-	if(sl->dev->tbusy)
-	{
-		printk(KERN_ERR "x25_asy: tbusy drop\n");
-		kfree_skb(skb);
-		return;
-	}
-	/* We were not busy, so we are now... :-) */
-	if (skb != NULL) 
-	{
-		x25_asy_lock(sl);
-		sl->tx_bytes+=skb->len;
-		x25_asy_encaps(sl, skb->data, skb->len);
-		dev_kfree_skb(skb);
-	}
-}
-
-/*
- *	LAPB connection establish/down information.
- */
- 
-static void x25_asy_connected(void *token, int reason)
-{
-	struct x25_asy *sl = token;
-	struct sk_buff *skb;
-	unsigned char *ptr;
-
-	if ((skb = dev_alloc_skb(1)) == NULL) {
-		printk(KERN_ERR "lapbeth: out of memory\n");
-		return;
-	}
-
-	ptr  = skb_put(skb, 1);
-	*ptr = 0x01;
-
-	skb->dev      = sl->dev;
-	skb->protocol = htons(ETH_P_X25);
-	skb->mac.raw  = skb->data;
-	skb->pkt_type = PACKET_HOST;
-
-	netif_rx(skb);
-}
-
-static void x25_asy_disconnected(void *token, int reason)
-{
-	struct x25_asy *sl = token;
-	struct sk_buff *skb;
-	unsigned char *ptr;
-
-	if ((skb = dev_alloc_skb(1)) == NULL) {
-		printk(KERN_ERR "x25_asy: out of memory\n");
-		return;
-	}
-
-	ptr  = skb_put(skb, 1);
-	*ptr = 0x02;
-
-	skb->dev      = sl->dev;
-	skb->protocol = htons(ETH_P_X25);
-	skb->mac.raw  = skb->data;
-	skb->pkt_type = PACKET_HOST;
-
-	netif_rx(skb);
-}
-
-
-/* Open the low-level part of the X.25 channel. Easy! */
-
-static int x25_asy_open(struct net_device *dev)
-{
-	struct lapb_register_struct x25_asy_callbacks;
-	struct x25_asy *sl = (struct x25_asy*)(dev->priv);
-	unsigned long len;
-	int err;
-
-	if (sl->tty == NULL)
-		return -ENODEV;
-
-	/*
-	 * Allocate the X.25 frame buffers:
-	 *
-	 * rbuff	Receive buffer.
-	 * xbuff	Transmit buffer.
-	 */
-
-	len = dev->mtu * 2;
-
-	sl->rbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
-	if (sl->rbuff == NULL)   {
-		goto norbuff;
-	}
-	sl->xbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
-	if (sl->xbuff == NULL)   {
-		goto noxbuff;
-	}
-	sl->mtu	     = dev->mtu;
-	sl->buffsize = len;
-	sl->rcount   = 0;
-	sl->xleft    = 0;
-	sl->flags   &= (1 << SLF_INUSE);      /* Clear ESCAPE & ERROR flags */
-
-	dev->tbusy  = 0;
-/*	dev->flags |= IFF_UP; */
-	dev->start  = 1;
-	
-	/*
-	 *	Now attach LAPB
-	 */
-	 
-	x25_asy_callbacks.connect_confirmation=x25_asy_connected;
-	x25_asy_callbacks.connect_indication=x25_asy_connected;
-	x25_asy_callbacks.disconnect_confirmation=x25_asy_disconnected;
-	x25_asy_callbacks.disconnect_indication=x25_asy_disconnected;
-	x25_asy_callbacks.data_indication=x25_asy_data_indication;
-	x25_asy_callbacks.data_transmit=x25_asy_data_transmit;
-
-	if((err=lapb_register(sl, &x25_asy_callbacks))==LAPB_OK)
-		return 0;
-
-	/* Cleanup */
-	kfree(sl->xbuff);
-noxbuff:
-	kfree(sl->rbuff);
-norbuff:
-	return -ENOMEM;
-}
-
-
-/* Close the low-level part of the X.25 channel. Easy! */
-static int x25_asy_close(struct net_device *dev)
-{
-	struct x25_asy *sl = (struct x25_asy*)(dev->priv);
-	int err;
-
-	if (sl->tty == NULL)
-		return -EBUSY;
-
-	sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-	dev->tbusy = 1;
-	dev->start = 0;
-	if((err=lapb_unregister(sl))!=LAPB_OK)
-		printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",err);
-
-/*	dev->flags &= ~IFF_UP; */
-	return 0;
-}
-
-static int x25_asy_receive_room(struct tty_struct *tty)
-{
-	return 65536;  /* We can handle an infinite amount of data. :-) */
-}
-
-/*
- * Handle the 'receiver data ready' interrupt.
- * This function is called by the 'tty_io' module in the kernel when
- * a block of X.25 data has been received, which can now be decapsulated
- * and sent on to some IP layer for further processing.
- */
- 
-static void x25_asy_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
-{
-	struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
-
-	if (!sl || sl->magic != X25_ASY_MAGIC || !sl->dev->start)
-		return;
-
-	/*
-	 * Argh! mtu change time! - costs us the packet part received
-	 * at the change
-	 */
-	if (sl->mtu != sl->dev->mtu)  {
-
-		x25_asy_changed_mtu(sl);
-	}
-
-	/* Read the characters out of the buffer */
-	while (count--) {
-		if (fp && *fp++) {
-			if (!test_and_set_bit(SLF_ERROR, &sl->flags))  {
-				sl->rx_errors++;
-			}
-			cp++;
-			continue;
-		}
-		x25_asy_unesc(sl, *cp++);
-	}
-}
-
-/*
- * Open the high-level part of the X.25 channel.
- * This function is called by the TTY module when the
- * X.25 line discipline is called for.  Because we are
- * sure the tty line exists, we only have to link it to
- * a free X.25 channel...
- */
-
-static int x25_asy_open_tty(struct tty_struct *tty)
-{
-	struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
-	int err;
-
-	/* First make sure we're not already connected. */
-	if (sl && sl->magic == X25_ASY_MAGIC) {
-		return -EEXIST;
-	}
-
-	/* OK.  Find a free X.25 channel to use. */
-	if ((sl = x25_asy_alloc()) == NULL) {
-		return -ENFILE;
-	}
-
-	sl->tty = tty;
-	tty->disc_data = sl;
-	if (tty->driver.flush_buffer)  {
-		tty->driver.flush_buffer(tty);
-	}
-	if (tty->ldisc.flush_buffer)  {
-		tty->ldisc.flush_buffer(tty);
-	}
-
-	/* Restore default settings */
-	sl->dev->type = ARPHRD_X25;
-	
-	/* Perform the low-level X.25 async init */
-	if ((err = x25_asy_open(sl->dev)))
-		return err;
-
-	MOD_INC_USE_COUNT;
-
-	/* Done.  We have linked the TTY line to a channel. */
-	return sl->dev->base_addr;
-}
-
-
-/*
- * Close down an X.25 channel.
- * This means flushing out any pending queues, and then restoring the
- * TTY line discipline to what it was before it got hooked to X.25
- * (which usually is TTY again).
- */
-static void x25_asy_close_tty(struct tty_struct *tty)
-{
-	struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
-
-	/* First make sure we're connected. */
-	if (!sl || sl->magic != X25_ASY_MAGIC)
-		return;
-
-	if (sl->dev->flags & IFF_UP)
-	{
-		(void) dev_close(sl->dev);
-	}
-
-	tty->disc_data = 0;
-	sl->tty = NULL;
-	x25_asy_free(sl);
-	unregister_netdev(sl->dev);
-	MOD_DEC_USE_COUNT;
-}
-
-
-static struct net_device_stats *x25_asy_get_stats(struct net_device *dev)
-{
-	static struct net_device_stats stats;
-	struct x25_asy *sl = (struct x25_asy*)(dev->priv);
-
-	memset(&stats, 0, sizeof(struct net_device_stats));
-
-	stats.rx_packets     = sl->rx_packets;
-	stats.tx_packets     = sl->tx_packets;
-	stats.rx_bytes	     = sl->rx_bytes;
-	stats.tx_bytes	     = sl->tx_bytes;
-	stats.rx_dropped     = sl->rx_dropped;
-	stats.tx_dropped     = sl->tx_dropped;
-	stats.tx_errors      = sl->tx_errors;
-	stats.rx_errors      = sl->rx_errors;
-	stats.rx_over_errors = sl->rx_over_errors;
-	return (&stats);
-}
-
-
- /************************************************************************
-  *			STANDARD X.25 ENCAPSULATION		  	 *
-  ************************************************************************/
-
-int x25_asy_esc(unsigned char *s, unsigned char *d, int len)
-{
-	unsigned char *ptr = d;
-	unsigned char c;
-
-	/*
-	 * Send an initial END character to flush out any
-	 * data that may have accumulated in the receiver
-	 * due to line noise.
-	 */
-
-	*ptr++ = X25_END;	/* Send 10111110 bit seq */
-
-	/*
-	 * For each byte in the packet, send the appropriate
-	 * character sequence, according to the X.25 protocol.
-	 */
-
-	while (len-- > 0) 
-	{
-		switch(c = *s++) 
-		{
-			case X25_END:
-				*ptr++ = X25_ESC;
-				*ptr++ = X25_ESCAPE(X25_END);
-				break;
-			case X25_ESC:
-				*ptr++ = X25_ESC;
-				*ptr++ = X25_ESCAPE(X25_ESC);
-				break;
-			 default:
-				*ptr++ = c;
-				break;
-		}
-	}
-	*ptr++ = X25_END;
-	return (ptr - d);
-}
-
-static void x25_asy_unesc(struct x25_asy *sl, unsigned char s)
-{
-
-	switch(s) 
-	{
-		case X25_END:
-			if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))  
-			{
-				x25_asy_bump(sl);
-			}
-			clear_bit(SLF_ESCAPE, &sl->flags);
-			sl->rcount = 0;
-			return;
-
-		case X25_ESC:
-			set_bit(SLF_ESCAPE, &sl->flags);
-			return;
-			
-		case X25_ESCAPE(X25_ESC):
-		case X25_ESCAPE(X25_END):
-			if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
-				s = X25_UNESCAPE(s);
-			break;
-	}
-	if (!test_bit(SLF_ERROR, &sl->flags))  
-	{
-		if (sl->rcount < sl->buffsize)  
-		{
-			sl->rbuff[sl->rcount++] = s;
-			return;
-		}
-		sl->rx_over_errors++;
-		set_bit(SLF_ERROR, &sl->flags);
-	}
-}
-
-
-/* Perform I/O control on an active X.25 channel. */
-static int x25_asy_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
-{
-	struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
-
-	/* First make sure we're connected. */
-	if (!sl || sl->magic != X25_ASY_MAGIC) {
-		return -EINVAL;
-	}
-
-	switch(cmd) 
-	{
-		case SIOCGIFNAME:
-			if(copy_to_user(arg, sl->dev->name, strlen(sl->dev->name) + 1))
-				return -EFAULT;
-			return 0;
-
-		case SIOCSIFHWADDR:
-			return -EINVAL;
-
-		/* Allow stty to read, but not set, the serial port */
-		case TCGETS:
-		case TCGETA:
-			return n_tty_ioctl(tty, (struct file *) file, cmd, (unsigned long) arg);
-
-		default:
-			return -ENOIOCTLCMD;
-	}
-}
-
-static int x25_asy_open_dev(struct net_device *dev)
-{
-	struct x25_asy *sl = (struct x25_asy*)(dev->priv);
-	if(sl->tty==NULL)
-		return -ENODEV;
-	return 0;
-}
-
-/* Initialize X.25 control device -- register X.25 line discipline */
-#ifdef MODULE
-static int x25_asy_init_ctrl_dev(void)
-#else	/* !MODULE */
-int __init x25_asy_init_ctrl_dev(struct net_device *dummy)
-#endif	/* !MODULE */
-{
-	int status;
-
-	if (x25_asy_maxdev < 4) x25_asy_maxdev = 4; /* Sanity */
-
-	printk(KERN_INFO "X.25 async: version 0.00 ALPHA (dynamic channels, max=%d).\n",
-		x25_asy_maxdev );
-	x25_asy_ctrls = (x25_asy_ctrl_t **) kmalloc(sizeof(void*)*x25_asy_maxdev, GFP_KERNEL);
-	if (x25_asy_ctrls == NULL)
-	{
-		printk("X25 async: Can't allocate x25_asy_ctrls[] array!  Uaargh! (-> No X.25 available)\n");
-		return -ENOMEM;
-	}
-
-	/* Clear the pointer array, we allocate devices when we need them */
-	memset(x25_asy_ctrls, 0, sizeof(void*)*x25_asy_maxdev); /* Pointers */
-
-	/* Fill in our line protocol discipline, and register it */
-	memset(&x25_ldisc, 0, sizeof(x25_ldisc));
-	x25_ldisc.magic  = TTY_LDISC_MAGIC;
-	x25_ldisc.name   = "X.25";
-	x25_ldisc.flags  = 0;
-	x25_ldisc.open   = x25_asy_open_tty;
-	x25_ldisc.close  = x25_asy_close_tty;
-	x25_ldisc.read   = NULL;
-	x25_ldisc.write  = NULL;
-	x25_ldisc.ioctl  = (int (*)(struct tty_struct *, struct file *,
-				   unsigned int, unsigned long)) x25_asy_ioctl;
-	x25_ldisc.poll   = NULL;
-	x25_ldisc.receive_buf = x25_asy_receive_buf;
-	x25_ldisc.receive_room = x25_asy_receive_room;
-	x25_ldisc.write_wakeup = x25_asy_write_wakeup;
-	if ((status = tty_register_ldisc(N_X25, &x25_ldisc)) != 0)  {
-		printk("X.25 async: can't register line discipline (err = %d)\n", status);
-	}
-
-#ifdef MODULE
-	return status;
-#else
-	/* Return "not found", so that dev_init() will unlink
-	 * the placeholder device entry for us.
-	 */
-	return ENODEV;
-#endif
-      }
-
-
-/* Initialise the X.25 driver.  Called by the device init code */
-
-int x25_asy_init(struct net_device *dev)
-{
-	struct x25_asy *sl = (struct x25_asy*)(dev->priv);
-
-	if (sl == NULL)		/* Allocation failed ?? */
-		return -ENODEV;
-
-	/* Set up the control block. (And clear statistics) */
-
-	memset(sl, 0, sizeof (struct x25_asy));
-	sl->magic  = X25_ASY_MAGIC;
-	sl->dev	   = dev;
-
-	/*
-	 *	Finish setting up the DEVICE info. 
-	 */
-	 
-	dev->mtu		= SL_MTU;
-	dev->hard_start_xmit	= x25_asy_xmit;
-	dev->open		= x25_asy_open_dev;
-	dev->stop		= x25_asy_close;
-	dev->get_stats	        = x25_asy_get_stats;
-	dev->hard_header_len	= 0;
-	dev->addr_len		= 0;
-	dev->type		= ARPHRD_X25;
-	dev->tx_queue_len	= 10;
-
-	dev_init_buffers(dev);
-	
-	/* New-style flags. */
-	dev->flags		= IFF_NOARP;
-
-	return 0;
-}
-#ifdef MODULE
-
-int
-init_module(void)
-{
-	return x25_asy_init_ctrl_dev();
-}
-
-void
-cleanup_module(void)
-{
-	int i;
-
-	if (x25_asy_ctrls != NULL)
-	{
-		for (i = 0; i < x25_asy_maxdev; i++)
-		{
-			if (x25_asy_ctrls[i])
-			{
-				/*
-				 * VSV = if dev->start==0, then device
-				 * unregistered while close proc.
-				 */
-				if (x25_asy_ctrls[i]->dev.start)
-					unregister_netdev(&(x25_asy_ctrls[i]->dev));
-
-				kfree(x25_asy_ctrls[i]);
-				x25_asy_ctrls[i] = NULL;
-			}
-		}
-		kfree(x25_asy_ctrls);
-		x25_asy_ctrls = NULL;
-	}
-	if ((i = tty_register_ldisc(N_X25, NULL)))
-	{
-		printk("X.25 async: can't unregister line discipline (err = %d)\n", i);
-	}
-}
-#endif /* MODULE */
-
diff -u --recursive --new-file v2.3.20/linux/drivers/net/x25_asy.h linux/drivers/net/x25_asy.h
--- v2.3.20/linux/drivers/net/x25_asy.h	Wed Aug 18 11:36:45 1999
+++ linux/drivers/net/x25_asy.h	Wed Dec 31 16:00:00 1969
@@ -1,58 +0,0 @@
-#ifndef _LINUX_X25_ASY_H
-#define _LINUX_X25_ASY_H
-
-/* X.25 asy configuration. */
-#define SL_NRUNIT	256		/* MAX number of X.25 channels;
-					   This can be overridden with
-					   insmod -ox25_asy_maxdev=nnn	*/
-#define SL_MTU		256	
-
-/* X25 async protocol characters. */
-#define X25_END         0x7E		/* indicates end of frame	*/
-#define X25_ESC         0x7D		/* indicates byte stuffing	*/
-#define X25_ESCAPE(x)	((x)^0x20)
-#define X25_UNESCAPE(x)	((x)^0x20)
-
-
-struct x25_asy {
-  int			magic;
-
-  /* Various fields. */
-  struct tty_struct	*tty;		/* ptr to TTY structure		*/
-  struct net_device		*dev;		/* easy for intr handling	*/
-
-  /* These are pointers to the malloc()ed frame buffers. */
-  unsigned char		*rbuff;		/* receiver buffer		*/
-  int                   rcount;         /* received chars counter       */
-  unsigned char		*xbuff;		/* transmitter buffer		*/
-  unsigned char         *xhead;         /* pointer to next byte to XMIT */
-  int                   xleft;          /* bytes left in XMIT queue     */
-
-  /* X.25 interface statistics. */
-  unsigned long		rx_packets;	/* inbound frames counter	*/
-  unsigned long         tx_packets;     /* outbound frames counter      */
-  unsigned long		rx_bytes;	/* inbound byte counte		*/
-  unsigned long         tx_bytes;       /* outbound byte counter	*/
-  unsigned long         rx_errors;      /* Parity, etc. errors          */
-  unsigned long         tx_errors;      /* Planned stuff                */
-  unsigned long         rx_dropped;     /* No memory for skb            */
-  unsigned long         tx_dropped;     /* When MTU change              */
-  unsigned long         rx_over_errors; /* Frame bigger then X.25 buf.  */
-
-  int			mtu;		/* Our mtu (to spot changes!)   */
-  int                   buffsize;       /* Max buffers sizes            */
-
-  unsigned int		flags;		/* Flag values/ mode etc	*/
-#define SLF_INUSE	0		/* Channel in use               */
-#define SLF_ESCAPE	1               /* ESC received                 */
-#define SLF_ERROR	2               /* Parity, etc. error           */
-#define SLF_OUTWAIT	4		/* Waiting for output		*/
-};
-
-
-
-#define X25_ASY_MAGIC 0x5303
-
-extern int x25_asy_init(struct net_device *dev);
-
-#endif	/* _LINUX_X25_ASY.H */
diff -u --recursive --new-file v2.3.20/linux/drivers/net/z85230.c linux/drivers/net/z85230.c
--- v2.3.20/linux/drivers/net/z85230.c	Fri Sep 10 23:57:30 1999
+++ linux/drivers/net/z85230.c	Wed Dec 31 16:00:00 1969
@@ -1,1470 +0,0 @@
-/*
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License
- *	as published by the Free Software Foundation; either version
- *	2 of the License, or (at your option) any later version.
- *
- *	(c) Copyright 1998 Building Number Three Ltd
- *
- *	Development of this driver was funded by Equiinet Ltd
- *			http://www.equiinet.com
- *
- *	ChangeLog:
- *
- *	Asynchronous mode dropped for 2.2. For 2.3 we will attempt the
- *	unification of all the Z85x30 asynchronous drivers for real.
- *
- *	To Do:
- *	
- *	Finish DMA mode support.
- *
- *	Performance
- *
- *	Z85230:
- *	Non DMA you want a 486DX50 or better to do 64Kbits. 9600 baud
- *	X.25 is not unrealistic on all machines. DMA mode can in theory
- *	handle T1/E1 quite nicely. In practice the limit seems to be about
- *	512Kbit->1Mbit depending on motherboard.
- *
- *	Z85C30:
- *	64K will take DMA, 9600 baud X.25 should be ok.
- *
- *	Z8530:
- *	Synchronous mode without DMA is unlikely to pass about 2400 baud.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/net.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#define RT_LOCK
-#define RT_UNLOCK
-#include <linux/spinlock.h>
-
-#include "z85230.h"
-#include "syncppp.h"
-
-
-static spinlock_t z8530_buffer_lock = SPIN_LOCK_UNLOCKED;
-
-/*
- *	Provided port access methods. The Comtrol SV11 requires no delays
- *	between accesses and uses PC I/O. Some drivers may need a 5uS delay
- */
-
-extern __inline__ int z8530_read_port(int p)
-{
-	u8 r=inb(Z8530_PORT_OF(p));
-	if(p&Z8530_PORT_SLEEP)	/* gcc should figure this out efficiently ! */
-		udelay(5);
-	return r;
-}
-
-extern __inline__ void z8530_write_port(int p, u8 d)
-{
-	outb(d,Z8530_PORT_OF(p));
-	if(p&Z8530_PORT_SLEEP)
-		udelay(5);
-}
-
-
-
-static void z8530_rx_done(struct z8530_channel *c);
-static void z8530_tx_done(struct z8530_channel *c);
-
-
-/*
- *	Port accesses
- */
- 
-extern inline u8 read_zsreg(struct z8530_channel *c, u8 reg)
-{
-	u8 r;
-	unsigned long flags;
-	save_flags(flags);
-	cli();
-	if(reg)
-		z8530_write_port(c->ctrlio, reg);
-	r=z8530_read_port(c->ctrlio);
-	restore_flags(flags);
-	return r;
-}
-
-extern inline u8 read_zsdata(struct z8530_channel *c)
-{
-	u8 r;
-	r=z8530_read_port(c->dataio);
-	return r;
-}
-
-extern inline void write_zsreg(struct z8530_channel *c, u8 reg, u8 val)
-{
-	unsigned long flags;
-	save_flags(flags);
-	cli();
-	if(reg)
-		z8530_write_port(c->ctrlio, reg);
-	z8530_write_port(c->ctrlio, val);
-	restore_flags(flags);
-}
-
-extern inline void write_zsctrl(struct z8530_channel *c, u8 val)
-{
-	z8530_write_port(c->ctrlio, val);
-}
-
-extern inline void write_zsdata(struct z8530_channel *c, u8 val)
-{
-	z8530_write_port(c->dataio, val);
-}
-
-/*
- *	Register loading parameters for a dead port
- */
- 
-u8 z8530_dead_port[]=
-{
-	255
-};
-
-EXPORT_SYMBOL(z8530_dead_port);
-
-/*
- *	Register loading parameters for currently supported circuit types
- */
-
-
-/*
- *	Data clocked by telco end. This is the correct data for the UK
- *	"kilostream" service, and most other similar services.
- */
- 
-u8 z8530_hdlc_kilostream[]=
-{
-	4,	SYNC_ENAB|SDLC|X1CLK,
-	2,	0,	/* No vector */
-	1,	0,
-	3,	ENT_HM|RxCRC_ENAB|Rx8,
-	5,	TxCRC_ENAB|RTS|TxENAB|Tx8|DTR,
-	9,	0,		/* Disable interrupts */
-	6,	0xFF,
-	7,	FLAG,
-	10,	ABUNDER|NRZ|CRCPS,/*MARKIDLE ??*/
-	11,	TCTRxCP,
-	14,	DISDPLL,
-	15,	DCDIE|SYNCIE|CTSIE|TxUIE|BRKIE,
-	1,	EXT_INT_ENAB|TxINT_ENAB|INT_ALL_Rx,
-	9,	NV|MIE|NORESET,
-	255
-};
-
-EXPORT_SYMBOL(z8530_hdlc_kilostream);
-
-/*
- *	As above but for enhanced chips.
- */
-
-u8 z8530_hdlc_kilostream_85230[]=
-{
-	4,	SYNC_ENAB|SDLC|X1CLK,
-	2,	0,	/* No vector */
-	1,	0,
-	3,	ENT_HM|RxCRC_ENAB|Rx8,
-	5,	TxCRC_ENAB|RTS|TxENAB|Tx8|DTR,
-	9,	0,		/* Disable interrupts */
-	6,	0xFF,
-	7,	FLAG,
-	10,	ABUNDER|NRZ|CRCPS,	/* MARKIDLE?? */
-	11,	TCTRxCP,
-	14,	DISDPLL,
-	15,	DCDIE|SYNCIE|CTSIE|TxUIE|BRKIE,
-	1,	EXT_INT_ENAB|TxINT_ENAB|INT_ALL_Rx,
-	9,	NV|MIE|NORESET,
-	23,	3,		/* Extended mode AUTO TX and EOM*/
-	
-	255
-};
-
-EXPORT_SYMBOL(z8530_hdlc_kilostream_85230);
-
-/*
- *	Flush the FIFO
- */
- 
-static void z8530_flush_fifo(struct z8530_channel *c)
-{
-	read_zsreg(c, R1);
-	read_zsreg(c, R1);
-	read_zsreg(c, R1);
-	read_zsreg(c, R1);
-	if(c->dev->type==Z85230)
-	{
-		read_zsreg(c, R1);
-		read_zsreg(c, R1);
-		read_zsreg(c, R1);
-		read_zsreg(c, R1);
-	}
-}	
-
-/* Sets or clears DTR/RTS on the requested line */
-
-static void z8530_rtsdtr(struct z8530_channel *c, int set)
-{
-	if (set)
-		c->regs[5] |= (RTS | DTR);
-	else
-		c->regs[5] &= ~(RTS | DTR);
-	write_zsreg(c, R5, c->regs[5]);
-}
-
-/*
- *	Receive handler. This is much like the async one but not quite the
- *	same or as complex
- *
- *	Note: Its intended that this handler can easily be separated from
- *	the main code to run realtime. That'll be needed for some machines
- *	(eg to ever clock 64kbits on a sparc ;)).
- *
- *	The RT_LOCK macros don't do anything now. Keep the code covered
- *	by them as short as possible in all circumstances - clocks cost
- *	baud. The interrupt handler is assumed to be atomic w.r.t. to
- *	other code - this is true in the RT case too.
- *
- *	We only cover the sync cases for this. If you want 2Mbit async
- *	do it yourself but consider medical assistance first.
- *
- *	This non DMA synchronous mode is portable code.
- */
- 
-static void z8530_rx(struct z8530_channel *c)
-{
-	u8 ch,stat;
-	 
-	while(1)
-	{
-		/* FIFO empty ? */
-		if(!(read_zsreg(c, R0)&1))
-			break;
-		ch=read_zsdata(c);
-		stat=read_zsreg(c, R1);
-	
-		/*
-		 *	Overrun ?
-		 */
-		if(c->count < c->max)
-		{
-			*c->dptr++=ch;
-			c->count++;
-		}
-
-		if(stat&END_FR)
-		{
-		
-			/*
-			 *	Error ?
-			 */
-			if(stat&(Rx_OVR|CRC_ERR))
-			{
-				/* Rewind the buffer and return */
-				if(c->skb)
-					c->dptr=c->skb->data;
-				c->count=0;
-				if(stat&Rx_OVR)
-				{
-					printk(KERN_WARNING "%s: overrun\n", c->dev->name);
-					c->rx_overrun++;
-				}
-				if(stat&CRC_ERR)
-				{
-					c->rx_crc_err++;
-					/* printk("crc error\n"); */
-				}
-				/* Shove the frame upstream */
-			}
-			else
-			{
-				z8530_rx_done(c);
-				write_zsctrl(c, RES_Rx_CRC);
-			}
-		}
-	}
-	/*
-	 *	Clear irq
-	 */
-	write_zsctrl(c, ERR_RES);
-	write_zsctrl(c, RES_H_IUS);
-}
-
-
-/*
- *	Z8530 transmit interrupt handler
- */
- 
-static void z8530_tx(struct z8530_channel *c)
-{
-	while(c->txcount)
-	{
-		/* FIFO full ? */
-		if(!(read_zsreg(c, R0)&4))
-			break;
-		c->txcount--;
-		/*
-		 *	Shovel out the byte
-		 */
-		write_zsreg(c, R8, *c->tx_ptr++);
-		write_zsctrl(c, RES_H_IUS);
-		/* We are about to underflow */
-		if(c->txcount==0)
-		{
-			write_zsctrl(c, RES_EOM_L);
-			write_zsreg(c, R10, c->regs[10]&~ABUNDER);
-		}
-		return;
-	}
-	
-	/*
-	 *	End of frame TX - fire another one
-	 */
-	 
-	write_zsctrl(c, RES_Tx_P);
-
-	z8530_tx_done(c);	 
-/*	write_zsreg(c, R8, *c->tx_ptr++); */
-	write_zsctrl(c, RES_H_IUS);
-}
-
-static void z8530_status(struct z8530_channel *chan)
-{
-	u8 status=read_zsreg(chan, R0);
-	u8 altered=chan->status^status;
-	
-	chan->status=status;
-	
-	if(status&TxEOM)
-	{
-/*		printk("%s: Tx underrun.\n", chan->dev->name); */
-		chan->stats.tx_fifo_errors++;
-		write_zsctrl(chan, ERR_RES);
-		z8530_tx_done(chan);
-	}
-		
-	if(altered&DCD)
-	{
-		if(status&DCD)
-		{
-			printk(KERN_INFO "%s: DCD raised\n", chan->dev->name);
-			write_zsreg(chan, R3, chan->regs[3]|RxENABLE);
-			if(chan->netdevice)
-				sppp_reopen(chan->netdevice);
-		}
-		else
-		{
-			printk(KERN_INFO "%s: DCD lost\n", chan->dev->name);
-			write_zsreg(chan, R3, chan->regs[3]&~RxENABLE);
-			z8530_flush_fifo(chan);
-		}
-		
-	}	
-	write_zsctrl(chan, RES_EXT_INT);
-	write_zsctrl(chan, RES_H_IUS);
-}
-
-struct z8530_irqhandler z8530_sync=
-{
-	z8530_rx,
-	z8530_tx,
-	z8530_status
-};
-
-EXPORT_SYMBOL(z8530_sync);
-
-/*
- *	Non bus mastering DMA interfaces for the Z8x30 devices. This
- *	is really pretty PC specific.
- */
- 
-static void z8530_dma_rx(struct z8530_channel *chan)
-{
-	if(chan->rxdma_on)
-	{
-		/* Special condition check only */
-		u8 status;
-
-		read_zsreg(chan, R7);
-		read_zsreg(chan, R6);
-		
-		status=read_zsreg(chan, R1);
-		if(status&END_FR)
-		{
-			z8530_rx_done(chan);	/* Fire up the next one */
-		}		
-		write_zsctrl(chan, ERR_RES);
-		write_zsctrl(chan, RES_H_IUS);
-	}
-	else
-	{
-		/* DMA is off right now, drain the slow way */
-		z8530_rx(chan);
-	}	
-}
-
-static void z8530_dma_tx(struct z8530_channel *chan)
-{
-	if(!chan->dma_tx)
-	{
-		printk("Hey who turned the DMA off?\n");
-		z8530_tx(chan);
-		return;
-	}
-	/* This shouldnt occur in DMA mode */
-	printk(KERN_ERR "DMA tx ??\n");
-	z8530_tx(chan);
-}
-
-static void z8530_dma_status(struct z8530_channel *chan)
-{
-	unsigned long flags;
-	u8 status=read_zsreg(chan, R0);
-	u8 altered=chan->status^status;
-	
-	chan->status=status;
-
-	if(chan->dma_tx)
-	{
-		if(status&TxEOM)
-		{
-			flags=claim_dma_lock();
-			/* Transmit underrun */
-			disable_dma(chan->txdma);
-			clear_dma_ff(chan->txdma);	
-			chan->txdma_on=0;
-			release_dma_lock(flags);
-			z8530_tx_done(chan);
-		}
-	}
-	if(altered&DCD)
-	{
-		if(status&DCD)
-		{
-			printk(KERN_INFO "%s: DCD raised\n", chan->dev->name);
-			write_zsreg(chan, R3, chan->regs[3]|RxENABLE);
-			if(chan->netdevice)
-				sppp_reopen(chan->netdevice);
-		}
-		else
-		{
-			printk(KERN_INFO "%s:DCD lost\n", chan->dev->name);
-			write_zsreg(chan, R3, chan->regs[3]&~RxENABLE);
-			z8530_flush_fifo(chan);
-		}
-	}	
-	write_zsctrl(chan, RES_EXT_INT);
-	write_zsctrl(chan, RES_H_IUS);
-}
-
-struct z8530_irqhandler z8530_dma_sync=
-{
-	z8530_dma_rx,
-	z8530_dma_tx,
-	z8530_dma_status
-};
-
-EXPORT_SYMBOL(z8530_dma_sync);
-
-struct z8530_irqhandler z8530_txdma_sync=
-{
-	z8530_rx,
-	z8530_dma_tx,
-	z8530_dma_status
-};
-
-EXPORT_SYMBOL(z8530_txdma_sync);
-
-/*
- *	Interrupt vectors for a Z8530 that is in 'parked' mode.
- *	For machines with PCI Z85x30 cards, or level triggered interrupts
- *	(eg the MacII) we must clear the interrupt cause or die.
- */
-
-
-static void z8530_rx_clear(struct z8530_channel *c)
-{
-	/*
-	 *	Data and status bytes
-	 */
-	u8 stat;
-
-	read_zsdata(c);
-	stat=read_zsreg(c, R1);
-	
-	if(stat&END_FR)
-		write_zsctrl(c, RES_Rx_CRC);
-	/*
-	 *	Clear irq
-	 */
-	write_zsctrl(c, ERR_RES);
-	write_zsctrl(c, RES_H_IUS);
-}
-
-static void z8530_tx_clear(struct z8530_channel *c)
-{
-	write_zsctrl(c, RES_Tx_P);
-	write_zsctrl(c, RES_H_IUS);
-}
-
-static void z8530_status_clear(struct z8530_channel *chan)
-{
-	u8 status=read_zsreg(chan, R0);
-	if(status&TxEOM)
-		write_zsctrl(chan, ERR_RES);
-	write_zsctrl(chan, RES_EXT_INT);
-	write_zsctrl(chan, RES_H_IUS);
-}
-
-struct z8530_irqhandler z8530_nop=
-{
-	z8530_rx_clear,
-	z8530_tx_clear,
-	z8530_status_clear
-};
-
-
-EXPORT_SYMBOL(z8530_nop);
-
-/*
- *	A Z85[2]30 device has stuck its hand in the air for attention
- */
-
-void z8530_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct z8530_dev *dev=dev_id;
-	u8 intr;
-	static volatile int locker=0;
-	int work=0;
-	
-	if(locker)
-	{
-		printk(KERN_ERR "IRQ re-enter\n");
-		return;
-	}
-	locker=1;
-	
-	while(++work<5000)
-	{
-		struct z8530_irqhandler *irqs=dev->chanA.irqs;
-		
-		intr = read_zsreg(&dev->chanA, R3);
-		if(!(intr & (CHARxIP|CHATxIP|CHAEXT|CHBRxIP|CHBTxIP|CHBEXT)))
-			break;
-	
-		/* This holds the IRQ status. On the 8530 you must read it from chan 
-		   A even though it applies to the whole chip */
-		
-		/* Now walk the chip and see what it is wanting - it may be
-		   an IRQ for someone else remember */
-		   
-		if(intr & (CHARxIP|CHATxIP|CHAEXT))
-		{
-			if(intr&CHARxIP)
-				irqs->rx(&dev->chanA);
-			if(intr&CHATxIP)
-				irqs->tx(&dev->chanA);
-			if(intr&CHAEXT)
-				irqs->status(&dev->chanA);
-		}
-
-		irqs=dev->chanB.irqs;
-
-		if(intr & (CHBRxIP|CHBTxIP|CHBEXT))
-		{
-			if(intr&CHBRxIP)
-				irqs->rx(&dev->chanB);
-			if(intr&CHBTxIP)
-				irqs->tx(&dev->chanB);
-			if(intr&CHBEXT)
-				irqs->status(&dev->chanB);
-		}
-	}
-	if(work==5000)
-		printk(KERN_ERR "%s: interrupt jammed - abort(0x%X)!\n", dev->name, intr);
-	/* Ok all done */
-	locker=0;
-}
-
-EXPORT_SYMBOL(z8530_interrupt);
-
-static char reg_init[16]=
-{
-	0,0,0,0,
-	0,0,0,0,
-	0,0,0,0,
-	0x55,0,0,0
-};
-
-
-int z8530_sync_open(struct net_device *dev, struct z8530_channel *c)
-{
-	c->sync = 1;
-	c->mtu = dev->mtu+64;
-	c->count = 0;
-	c->skb = NULL;
-	c->skb2 = NULL;
-	c->irqs = &z8530_sync;
-	/* This loads the double buffer up */
-	z8530_rx_done(c);	/* Load the frame ring */
-	z8530_rx_done(c);	/* Load the backup frame */
-	z8530_rtsdtr(c,1);
-	c->dma_tx = 0;
-	c->regs[R1]|=TxINT_ENAB;
-	write_zsreg(c, R1, c->regs[R1]);
-	write_zsreg(c, R3, c->regs[R3]|RxENABLE);
-	return 0;
-}
-
-
-EXPORT_SYMBOL(z8530_sync_open);
-
-int z8530_sync_close(struct net_device *dev, struct z8530_channel *c)
-{
-	u8 chk;
-	c->irqs = &z8530_nop;
-	c->max = 0;
-	c->sync = 0;
-	
-	chk=read_zsreg(c,R0);
-	write_zsreg(c, R3, c->regs[R3]);
-	z8530_rtsdtr(c,0);
-	return 0;
-}
-
-EXPORT_SYMBOL(z8530_sync_close);
-
-int z8530_sync_dma_open(struct net_device *dev, struct z8530_channel *c)
-{
-	unsigned long flags;
-	
-	c->sync = 1;
-	c->mtu = dev->mtu+64;
-	c->count = 0;
-	c->skb = NULL;
-	c->skb2 = NULL;
-	/*
-	 *	Load the DMA interfaces up
-	 */
-	c->rxdma_on = 0;
-	c->txdma_on = 0;
-	
-	/*
-	 *	Allocate the DMA flip buffers
-	 */
-	 
-	c->rx_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
-	if(c->rx_buf[0]==NULL)
-		return -ENOBUFS;
-	c->rx_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
-	if(c->rx_buf[1]==NULL)
-	{
-		kfree(c->rx_buf[0]);
-		c->rx_buf[0]=NULL;
-		return -ENOBUFS;
-	}
-	
-	c->tx_dma_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
-	if(c->tx_dma_buf[0]==NULL)
-	{
-		kfree(c->rx_buf[0]);
-		kfree(c->rx_buf[1]);
-		c->rx_buf[0]=NULL;
-		return -ENOBUFS;
-	}
-	c->tx_dma_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
-	if(c->tx_dma_buf[1]==NULL)
-	{
-		kfree(c->tx_dma_buf[0]);
-		kfree(c->rx_buf[0]);
-		kfree(c->rx_buf[1]);
-		c->rx_buf[0]=NULL;
-		c->rx_buf[1]=NULL;
-		c->tx_dma_buf[0]=NULL;
-		return -ENOBUFS;
-	}
-	c->tx_dma_used=0;
-	c->dma_tx = 1;
-	c->dma_num=0;
-	c->dma_ready=1;
-	
-	/*
-	 *	Enable DMA control mode
-	 */
-	 
-	/*
-	 *	TX DMA via DIR/REQ
-	 */
-	 
-	c->regs[R14]|= DTRREQ;
-	write_zsreg(c, R14, c->regs[R14]);     
-
-	c->regs[R1]&= ~TxINT_ENAB;
-	write_zsreg(c, R1, c->regs[R1]);
-	
-	/*
-	 *	RX DMA via W/Req
-	 */	 
-
-	c->regs[R1]|= WT_FN_RDYFN;
-	c->regs[R1]|= WT_RDY_RT;
-	c->regs[R1]|= INT_ERR_Rx;
-	c->regs[R1]&= ~TxINT_ENAB;
-	write_zsreg(c, R1, c->regs[R1]);
-	c->regs[R1]|= WT_RDY_ENAB;
-	write_zsreg(c, R1, c->regs[R1]);            
-	
-	/*
-	 *	DMA interrupts
-	 */
-	 
-	/*
-	 *	Set up the DMA configuration
-	 */	
-	 
-	flags=claim_dma_lock();
-	 
-	disable_dma(c->rxdma);
-	clear_dma_ff(c->rxdma);
-	set_dma_mode(c->rxdma, DMA_MODE_READ|0x10);
-	set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[0]));
-	set_dma_count(c->rxdma, c->mtu);
-	enable_dma(c->rxdma);
-
-	disable_dma(c->txdma);
-	clear_dma_ff(c->txdma);
-	set_dma_mode(c->txdma, DMA_MODE_WRITE);
-	disable_dma(c->txdma);
-	
-	release_dma_lock(flags);
-	
-	/*
-	 *	Select the DMA interrupt handlers
-	 */
-
-	c->rxdma_on = 1;
-	c->txdma_on = 1;
-	c->tx_dma_used = 1;
-	 
-	c->irqs = &z8530_dma_sync;
-	z8530_rtsdtr(c,1);
-	write_zsreg(c, R3, c->regs[R3]|RxENABLE);
-	return 0;
-}
-
-EXPORT_SYMBOL(z8530_sync_dma_open);
-
-int z8530_sync_dma_close(struct net_device *dev, struct z8530_channel *c)
-{
-	u8 chk;
-	unsigned long flags;
-	
-	c->irqs = &z8530_nop;
-	c->max = 0;
-	c->sync = 0;
-	
-	/*
-	 *	Disable the PC DMA channels
-	 */
-	
-	flags=claim_dma_lock(); 
-	disable_dma(c->rxdma);
-	clear_dma_ff(c->rxdma);
-	
-	c->rxdma_on = 0;
-	
-	disable_dma(c->txdma);
-	clear_dma_ff(c->txdma);
-	release_dma_lock(flags);
-	
-	c->txdma_on = 0;
-	c->tx_dma_used = 0;
-
-	/*
-	 *	Disable DMA control mode
-	 */
-	 
-	c->regs[R1]&= ~WT_RDY_ENAB;
-	write_zsreg(c, R1, c->regs[R1]);            
-	c->regs[R1]&= ~(WT_RDY_RT|WT_FN_RDYFN|INT_ERR_Rx);
-	c->regs[R1]|= INT_ALL_Rx;
-	write_zsreg(c, R1, c->regs[R1]);
-	c->regs[R14]&= ~DTRREQ;
-	write_zsreg(c, R14, c->regs[R14]);   
-	
-	if(c->rx_buf[0])
-	{
-		kfree(c->rx_buf[0]);
-		c->rx_buf[0]=NULL;
-	}
-	if(c->rx_buf[1])
-	{
-		kfree(c->rx_buf[1]);
-		c->rx_buf[1]=NULL;
-	}
-	if(c->tx_dma_buf[0])
-	{
-		kfree(c->tx_dma_buf[0]);
-		c->tx_dma_buf[0]=NULL;
-	}
-	if(c->tx_dma_buf[1])
-	{
-		kfree(c->tx_dma_buf[1]);
-		c->tx_dma_buf[1]=NULL;
-	}
-	chk=read_zsreg(c,R0);
-	write_zsreg(c, R3, c->regs[R3]);
-	z8530_rtsdtr(c,0);
-	return 0;
-}
-
-EXPORT_SYMBOL(z8530_sync_dma_close);
-
-int z8530_sync_txdma_open(struct net_device *dev, struct z8530_channel *c)
-{
-	unsigned long flags;
-
-	printk("Opening sync interface for TX-DMA\n");
-	c->sync = 1;
-	c->mtu = dev->mtu+64;
-	c->count = 0;
-	c->skb = NULL;
-	c->skb2 = NULL;
-	
-	/*
-	 *	Load the PIO receive ring
-	 */
-
-	z8530_rx_done(c);
-	z8530_rx_done(c);
-
- 	/*
-	 *	Load the DMA interfaces up
-	 */
-
-	c->rxdma_on = 0;
-	c->txdma_on = 0;
-	
-	c->tx_dma_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
-	if(c->tx_dma_buf[0]==NULL)
-	{
-		kfree(c->rx_buf[0]);
-		kfree(c->rx_buf[1]);
-		c->rx_buf[0]=NULL;
-		return -ENOBUFS;
-	}
-	c->tx_dma_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
-	if(c->tx_dma_buf[1]==NULL)
-	{
-		kfree(c->tx_dma_buf[0]);
-		kfree(c->rx_buf[0]);
-		kfree(c->rx_buf[1]);
-		c->rx_buf[0]=NULL;
-		c->rx_buf[1]=NULL;
-		c->tx_dma_buf[0]=NULL;
-		return -ENOBUFS;
-	}
-	c->tx_dma_used=0;
-	c->dma_num=0;
-	c->dma_ready=1;
-	c->dma_tx = 1;
-
- 	/*
-	 *	Enable DMA control mode
-	 */
-
- 	/*
-	 *	TX DMA via DIR/REQ
- 	 */
-	c->regs[R14]|= DTRREQ;
-	write_zsreg(c, R14, c->regs[R14]);     
-	
-	c->regs[R1]&= ~TxINT_ENAB;
-	write_zsreg(c, R1, c->regs[R1]);
-	
-	/*
-	 *	Set up the DMA configuration
-	 */	
-	 
-	flags = claim_dma_lock();
-
-	disable_dma(c->txdma);
-	clear_dma_ff(c->txdma);
-	set_dma_mode(c->txdma, DMA_MODE_WRITE);
-	disable_dma(c->txdma);
-
-	release_dma_lock(flags);
-	
-	/*
-	 *	Select the DMA interrupt handlers
-	 */
-
-	c->rxdma_on = 0;
-	c->txdma_on = 1;
-	c->tx_dma_used = 1;
-	 
-	c->irqs = &z8530_txdma_sync;
-	printk("Loading RX\n");
-	z8530_rtsdtr(c,1);
-	printk("Rx interrupts ON\n");	
-	write_zsreg(c, R3, c->regs[R3]|RxENABLE);
-	return 0;
-}
-
-EXPORT_SYMBOL(z8530_sync_txdma_open);
-	
-int z8530_sync_txdma_close(struct net_device *dev, struct z8530_channel *c)
-{
-	unsigned long flags;
-	u8 chk;
-	c->irqs = &z8530_nop;
-	c->max = 0;
-	c->sync = 0;
-	
-	/*
-	 *	Disable the PC DMA channels
-	 */
-	 
-	flags = claim_dma_lock();
-
-	disable_dma(c->txdma);
-	clear_dma_ff(c->txdma);
-	c->txdma_on = 0;
-	c->tx_dma_used = 0;
-
-	release_dma_lock(flags);
-
-	/*
-	 *	Disable DMA control mode
-	 */
-	 
-	c->regs[R1]&= ~WT_RDY_ENAB;
-	write_zsreg(c, R1, c->regs[R1]);            
-	c->regs[R1]&= ~(WT_RDY_RT|WT_FN_RDYFN|INT_ERR_Rx);
-	c->regs[R1]|= INT_ALL_Rx;
-	write_zsreg(c, R1, c->regs[R1]);
-	c->regs[R14]&= ~DTRREQ;
-	write_zsreg(c, R14, c->regs[R14]);   
-	
-	if(c->tx_dma_buf[0])
-	{
-		kfree(c->tx_dma_buf[0]);
-		c->tx_dma_buf[0]=NULL;
-	}
-	if(c->tx_dma_buf[1])
-	{
-		kfree(c->tx_dma_buf[1]);
-		c->tx_dma_buf[1]=NULL;
-	}
-	chk=read_zsreg(c,R0);
-	write_zsreg(c, R3, c->regs[R3]);
-	z8530_rtsdtr(c,0);
-	return 0;
-}
-
-
-EXPORT_SYMBOL(z8530_sync_txdma_close);
-
-/*
- *	Describe a Z8530 in a standard format. We must pass the I/O as
- *	the port offset isnt predictable. The main reason for this function
- *	is to try and get a common format of report.
- */
-
-static char *z8530_type_name[]={
-	"Z8530",
-	"Z85C30",
-	"Z85230"
-};
-
-void z8530_describe(struct z8530_dev *dev, char *mapping, int io)
-{
-	printk(KERN_INFO "%s: %s found at %s 0x%X, IRQ %d.\n",
-		dev->name, 
-		z8530_type_name[dev->type],
-		mapping,
-		Z8530_PORT_OF(io),
-		dev->irq);
-}
-
-EXPORT_SYMBOL(z8530_describe);
-
-/*
- *	Configure up a Z8530
- */
-
- 
-int z8530_init(struct z8530_dev *dev)
-{
-	/* NOP the interrupt handlers first - we might get a
-	   floating IRQ transition when we reset the chip */
-	dev->chanA.irqs=&z8530_nop;
-	dev->chanB.irqs=&z8530_nop;
-	/* Reset the chip */
-	write_zsreg(&dev->chanA, R9, 0xC0);
-	udelay(200);
-	/* Now check its valid */
-	write_zsreg(&dev->chanA, R12, 0xAA);
-	if(read_zsreg(&dev->chanA, R12)!=0xAA)
-		return -ENODEV;
-	write_zsreg(&dev->chanA, R12, 0x55);
-	if(read_zsreg(&dev->chanA, R12)!=0x55)
-		return -ENODEV;
-		
-	dev->type=Z8530;
-	
-	/*
-	 *	See the application note.
-	 */
-	 
-	write_zsreg(&dev->chanA, R15, 0x01);
-	
-	/*
-	 *	If we can set the low bit of R15 then
-	 *	the chip is enhanced.
-	 */
-	 
-	if(read_zsreg(&dev->chanA, R15)==0x01)
-	{
-		/* This C30 versus 230 detect is from Klaus Kudielka's dmascc */
-		/* Put a char in the fifo */
-		write_zsreg(&dev->chanA, R8, 0);
-		if(read_zsreg(&dev->chanA, R0)&Tx_BUF_EMP)
-			dev->type = Z85230;	/* Has a FIFO */
-		else
-			dev->type = Z85C30;	/* Z85C30, 1 byte FIFO */
-	}
-		
-	/*
-	 *	The code assumes R7' and friends are
-	 *	off. Use write_zsext() for these and keep
-	 *	this bit clear.
-	 */
-	 
-	write_zsreg(&dev->chanA, R15, 0);
-		
-	/*
-	 *	At this point it looks like the chip is behaving
-	 */
-	 
-	memcpy(dev->chanA.regs, reg_init, 16);
-	memcpy(dev->chanB.regs, reg_init ,16);
-	
-	return 0;
-}
-
-
-EXPORT_SYMBOL(z8530_init);
-
-int z8530_shutdown(struct z8530_dev *dev)
-{
-	/* Reset the chip */
-	dev->chanA.irqs=&z8530_nop;
-	dev->chanB.irqs=&z8530_nop;
-	write_zsreg(&dev->chanA, R9, 0xC0);
-	udelay(100);
-	return 0;
-}
-
-EXPORT_SYMBOL(z8530_shutdown);
-
-/*
- *	Load a Z8530 channel up from the system data
- *	We use +16 to indicate the 'prime' registers
- */
-
-int z8530_channel_load(struct z8530_channel *c, u8 *rtable)
-{
-	while(*rtable!=255)
-	{
-		int reg=*rtable++;
-		if(reg>0x0F)
-			write_zsreg(c, R15, c->regs[15]|1);
-		write_zsreg(c, reg&0x0F, *rtable);
-		if(reg>0x0F)
-			write_zsreg(c, R15, c->regs[15]&~1);
-		c->regs[reg]=*rtable++;
-	}
-	c->rx_function=z8530_null_rx;
-	c->skb=NULL;
-	c->tx_skb=NULL;
-	c->tx_next_skb=NULL;
-	c->mtu=1500;
-	c->max=0;
-	c->count=0;
-	c->status=0;	/* Fixme - check DCD now */
-	c->sync=1;
-	write_zsreg(c, R3, c->regs[R3]|RxENABLE);
-	return 0;
-}
-
-EXPORT_SYMBOL(z8530_channel_load);
-
-
-/*
- *	Higher level shovelling - transmit chains
- */
-
-static void z8530_tx_begin(struct z8530_channel *c)
-{
-	unsigned long flags;
-	if(c->tx_skb)
-		return;
-		
-	c->tx_skb=c->tx_next_skb;
-	c->tx_next_skb=NULL;
-	c->tx_ptr=c->tx_next_ptr;
-	
-	mark_bh(NET_BH);
-	if(c->tx_skb==NULL)
-	{
-		/* Idle on */
-		if(c->dma_tx)
-		{
-			flags=claim_dma_lock();
-			disable_dma(c->txdma);
-			/*
-			 *	Check if we crapped out.
-			 */
-			if(get_dma_residue(c->txdma))
-			{
-				c->stats.tx_dropped++;
-				c->stats.tx_fifo_errors++;
-			}
-			release_dma_lock(flags);
-		}
-		c->txcount=0;
-	}
-	else
-	{
-		c->txcount=c->tx_skb->len;
-		
-		
-		if(c->dma_tx)
-		{
-			/*
-			 *	FIXME. DMA is broken for the original 8530,
-			 *	on the older parts we need to set a flag and
-			 *	wait for a further TX interrupt to fire this
-			 *	stage off	
-			 */
-			 
-			flags=claim_dma_lock();
-			disable_dma(c->txdma);
-
-			/*
-			 *	These two are needed by the 8530/85C30
-			 *	and must be issued when idling.
-			 */
-			 
-			if(c->dev->type!=Z85230)
-			{
-				write_zsctrl(c, RES_Tx_CRC);
-				write_zsctrl(c, RES_EOM_L);
-			}	
-			write_zsreg(c, R10, c->regs[10]&~ABUNDER);
-			clear_dma_ff(c->txdma);
-			set_dma_addr(c->txdma, virt_to_bus(c->tx_ptr));
-			set_dma_count(c->txdma, c->txcount);
-			enable_dma(c->txdma);
-			release_dma_lock(flags);
-			write_zsctrl(c, RES_EOM_L);
-			write_zsreg(c, R5, c->regs[R5]|TxENAB);
-		}
-		else
-		{
-			save_flags(flags);
-			cli();
-			/* ABUNDER off */
-			write_zsreg(c, R10, c->regs[10]);
-			write_zsctrl(c, RES_Tx_CRC);
-//???			write_zsctrl(c, RES_EOM_L);
-	
-			while(c->txcount && (read_zsreg(c,R0)&Tx_BUF_EMP))
-			{		
-				write_zsreg(c, R8, *c->tx_ptr++);
-				c->txcount--;
-			}
-			restore_flags(flags);
-		}
-	}
-}
- 
- 
-static void z8530_tx_done(struct z8530_channel *c)
-{
-	unsigned long flags;
-	struct sk_buff *skb;
-
-	spin_lock_irqsave(&z8530_buffer_lock, flags);
-	c->netdevice->tbusy=0;
-	/* Actually this can happen.*/
-	if(c->tx_skb==NULL)
-	{
-		spin_unlock_irqrestore(&z8530_buffer_lock, flags);
-		return;
-	}
-	skb=c->tx_skb;
-	c->tx_skb=NULL;
-	z8530_tx_begin(c);
-	spin_unlock_irqrestore(&z8530_buffer_lock, flags);
-	c->stats.tx_packets++;
-	c->stats.tx_bytes+=skb->len;
-	dev_kfree_skb(skb);
-}
-
-/*
- *	Higher level shovelling - receive chains
- */
- 
-void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb)
-{
-	kfree_skb(skb);
-}
-
-EXPORT_SYMBOL(z8530_null_rx);
-
-static void z8530_rx_done(struct z8530_channel *c)
-{
-	struct sk_buff *skb;
-	int ct;
-	
-	/*
-	 *	Is our receive engine in DMA mode
-	 */
-	 
-	if(c->rxdma_on)
-	{
-		/*
-		 *	Save the ready state and the buffer currently
-		 *	being used as the DMA target
-		 */
-
-		int ready=c->dma_ready;
-		unsigned char *rxb=c->rx_buf[c->dma_num];
-		unsigned long flags;
-		
-		/*
-		 *	Complete this DMA. Neccessary to find the length
-		 */		
-		 
-		flags=claim_dma_lock();
-		
-		disable_dma(c->rxdma);
-		clear_dma_ff(c->rxdma);
-		c->rxdma_on=0;
-		ct=c->mtu-get_dma_residue(c->rxdma);
-		if(ct<0)
-			ct=2;	/* Shit happens.. */
-		c->dma_ready=0;
-		
-		/*
-		 *	Normal case: the other slot is free, start the next DMA
-		 *	into it immediately.
-		 */
-		 
-		if(ready)
-		{
-			c->dma_num^=1;
-			set_dma_mode(c->rxdma, DMA_MODE_READ|0x10);
-			set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[c->dma_num]));
-			set_dma_count(c->rxdma, c->mtu);
-			c->rxdma_on = 1;
-			enable_dma(c->rxdma);
-			/* Stop any frames that we missed the head of 
-			   from passing */
-			write_zsreg(c, R0, RES_Rx_CRC);
-		}
-		else
-			/* Can't occur as we dont reenable the DMA irq until
-			   after the flip is done */
-			printk("DMA flip overrun!\n");
-			
-		release_dma_lock(flags);
-		
-		/*
-		 *	Shove the old buffer into an sk_buff. We can't DMA
-		 *	directly into one on a PC - it might be above the 16Mb
-		 *	boundary. Optimisation - we could check to see if we
-		 *	can avoid the copy. Optimisation 2 - make the memcpy
-		 *	a copychecksum.
-		 */
-		 
-		skb=dev_alloc_skb(ct);
-		if(skb==NULL)
-		{
-			c->stats.rx_dropped++;
-			printk(KERN_WARNING "%s: Memory squeeze.\n", c->netdevice->name);
-		}
-		else
-		{
-			skb_put(skb, ct);
-			memcpy(skb->data, rxb, ct);
-			c->stats.rx_packets++;
-			c->stats.rx_bytes+=ct;
-		}
-		c->dma_ready=1;
-	}
-	else
-	{
-		RT_LOCK;	
-		skb=c->skb;
-		
-		/*
-		 *	The game we play for non DMA is similar. We want to
-		 *	get the controller set up for the next packet as fast
-		 *	as possible. We potentially only have one byte + the
-		 *	fifo length for this. Thus we want to flip to the new
-		 *	buffer and then mess around copying and allocating
-		 *	things. For the current case it doesn't matter but
-		 *	if you build a system where the sync irq isnt blocked
-		 *	by the kernel IRQ disable then you need only block the
-		 *	sync IRQ for the RT_LOCK area.
-		 *	
-		 */
-		ct=c->count;
-		
-		c->skb = c->skb2;
-		c->count = 0;
-		c->max = c->mtu;
-		if(c->skb)
-		{
-			c->dptr = c->skb->data;
-			c->max = c->mtu;
-		}
-		else
-		{
-			c->count= 0;
-			c->max = 0;
-		}
-		RT_UNLOCK;
-
-		c->skb2 = dev_alloc_skb(c->mtu);
-		if(c->skb2==NULL)
-			printk(KERN_WARNING "%s: memory squeeze.\n",
-				c->netdevice->name);
-		else
-		{
-			skb_put(c->skb2,c->mtu);
-		}
-		c->stats.rx_packets++;
-		c->stats.rx_bytes+=ct;
-		
-	}
-	/*
-	 *	If we received a frame we must now process it.
-	 */
-	if(skb)
-	{
-		skb_trim(skb, ct);
-		c->rx_function(c,skb);
-	}
-	else
-	{
-		c->stats.rx_dropped++;
-		printk(KERN_ERR "%s: Lost a frame\n", c->netdevice->name);
-	}
-}
-
-/*
- *	Cannot DMA over a 64K boundary on a PC
- */
- 
-extern inline int spans_boundary(struct sk_buff *skb)
-{
-	unsigned long a=(unsigned long)skb->data;
-	a^=(a+skb->len);
-	if(a&0x00010000)	/* If the 64K bit is different.. */
-	{
-		printk("spanner\n");
-		return 1;
-	}
-	return 0;
-}
-
-/*
- *	Queue a packet for transmission. Because we have rather
- *	hard to hit interrupt latencies for the Z85230 per packet 
- *	even in DMA mode we do the flip to DMA buffer if needed here
- *	not in the IRQ.
- */
-
-int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb)
-{
-	unsigned long flags;
-	if(c->tx_next_skb)
-	{
-		skb->dev->tbusy=1;
-		return 1;
-	}
-	
-	/* PC SPECIFIC - DMA limits */
-	
-	/*
-	 *	If we will DMA the transmit and its gone over the ISA bus
-	 *	limit, then copy to the flip buffer
-	 */
-	 
-	if(c->dma_tx && ((unsigned long)(virt_to_bus(skb->data+skb->len))>=16*1024*1024 || spans_boundary(skb)))
-	{
-		/* 
-		 *	Send the flip buffer, and flip the flippy bit.
-		 *	We don't care which is used when just so long as
-		 *	we never use the same buffer twice in a row. Since
-		 *	only one buffer can be going out at a time the other
-		 *	has to be safe.
-		 */
-		c->tx_next_ptr=c->tx_dma_buf[c->tx_dma_used];
-		c->tx_dma_used^=1;	/* Flip temp buffer */
-		memcpy(c->tx_next_ptr, skb->data, skb->len);
-	}
-	else
-		c->tx_next_ptr=skb->data;	
-	RT_LOCK;
-	c->tx_next_skb=skb;
-	RT_UNLOCK;
-	
-	spin_lock_irqsave(&z8530_buffer_lock, flags);
-	z8530_tx_begin(c);
-	spin_unlock_irqrestore(&z8530_buffer_lock, flags);
-	return 0;
-}
-
-EXPORT_SYMBOL(z8530_queue_xmit);
-
-struct net_device_stats *z8530_get_stats(struct z8530_channel *c)
-{
-	return &c->stats;
-}
-
-EXPORT_SYMBOL(z8530_get_stats);
-
-#ifdef MODULE
-
-/*
- *	Module support
- */
- 
-int init_module(void)
-{
-	printk(KERN_INFO "Generic Z85C30/Z85230 interface driver v0.02\n");
-	return 0;
-}
-
-void cleanup_module(void)
-{
-}
-
-#endif
diff -u --recursive --new-file v2.3.20/linux/drivers/net/z85230.h linux/drivers/net/z85230.h
--- v2.3.20/linux/drivers/net/z85230.h	Wed Aug 18 11:36:45 1999
+++ linux/drivers/net/z85230.h	Wed Dec 31 16:00:00 1969
@@ -1,446 +0,0 @@
-/*
- *	Description of Z8530 Z85C30 and Z85230 communications chips
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1998 Alan Cox <alan@redhat.com>
- */
-
-#ifndef _Z8530_H
-#define _Z8530_H
-
-/* Conversion routines to/from brg time constants from/to bits
- * per second.
- */
-#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
-#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
-
-/* The Zilog register set */
-
-#define	FLAG	0x7e
-
-/* Write Register 0 */
-#define	R0	0		/* Register selects */
-#define	R1	1
-#define	R2	2
-#define	R3	3
-#define	R4	4
-#define	R5	5
-#define	R6	6
-#define	R7	7
-#define	R8	8
-#define	R9	9
-#define	R10	10
-#define	R11	11
-#define	R12	12
-#define	R13	13
-#define	R14	14
-#define	R15	15
-
-#define RPRIME	16		/* Indicate a prime register access on 230 */
-
-#define	NULLCODE	0	/* Null Code */
-#define	POINT_HIGH	0x8	/* Select upper half of registers */
-#define	RES_EXT_INT	0x10	/* Reset Ext. Status Interrupts */
-#define	SEND_ABORT	0x18	/* HDLC Abort */
-#define	RES_RxINT_FC	0x20	/* Reset RxINT on First Character */
-#define	RES_Tx_P	0x28	/* Reset TxINT Pending */
-#define	ERR_RES		0x30	/* Error Reset */
-#define	RES_H_IUS	0x38	/* Reset highest IUS */
-
-#define	RES_Rx_CRC	0x40	/* Reset Rx CRC Checker */
-#define	RES_Tx_CRC	0x80	/* Reset Tx CRC Checker */
-#define	RES_EOM_L	0xC0	/* Reset EOM latch */
-
-/* Write Register 1 */
-
-#define	EXT_INT_ENAB	0x1	/* Ext Int Enable */
-#define	TxINT_ENAB	0x2	/* Tx Int Enable */
-#define	PAR_SPEC	0x4	/* Parity is special condition */
-
-#define	RxINT_DISAB	0	/* Rx Int Disable */
-#define	RxINT_FCERR	0x8	/* Rx Int on First Character Only or Error */
-#define	INT_ALL_Rx	0x10	/* Int on all Rx Characters or error */
-#define	INT_ERR_Rx	0x18	/* Int on error only */
-
-#define	WT_RDY_RT	0x20	/* Wait/Ready on R/T */
-#define	WT_FN_RDYFN	0x40	/* Wait/FN/Ready FN */
-#define	WT_RDY_ENAB	0x80	/* Wait/Ready Enable */
-
-/* Write Register #2 (Interrupt Vector) */
-
-/* Write Register 3 */
-
-#define	RxENABLE	0x1	/* Rx Enable */
-#define	SYNC_L_INH	0x2	/* Sync Character Load Inhibit */
-#define	ADD_SM		0x4	/* Address Search Mode (SDLC) */
-#define	RxCRC_ENAB	0x8	/* Rx CRC Enable */
-#define	ENT_HM		0x10	/* Enter Hunt Mode */
-#define	AUTO_ENAB	0x20	/* Auto Enables */
-#define	Rx5		0x0	/* Rx 5 Bits/Character */
-#define	Rx7		0x40	/* Rx 7 Bits/Character */
-#define	Rx6		0x80	/* Rx 6 Bits/Character */
-#define	Rx8		0xc0	/* Rx 8 Bits/Character */
-
-/* Write Register 4 */
-
-#define	PAR_ENA		0x1	/* Parity Enable */
-#define	PAR_EVEN	0x2	/* Parity Even/Odd* */
-
-#define	SYNC_ENAB	0	/* Sync Modes Enable */
-#define	SB1		0x4	/* 1 stop bit/char */
-#define	SB15		0x8	/* 1.5 stop bits/char */
-#define	SB2		0xc	/* 2 stop bits/char */
-
-#define	MONSYNC		0	/* 8 Bit Sync character */
-#define	BISYNC		0x10	/* 16 bit sync character */
-#define	SDLC		0x20	/* SDLC Mode (01111110 Sync Flag) */
-#define	EXTSYNC		0x30	/* External Sync Mode */
-
-#define	X1CLK		0x0	/* x1 clock mode */
-#define	X16CLK		0x40	/* x16 clock mode */
-#define	X32CLK		0x80	/* x32 clock mode */
-#define	X64CLK		0xC0	/* x64 clock mode */
-
-/* Write Register 5 */
-
-#define	TxCRC_ENAB	0x1	/* Tx CRC Enable */
-#define	RTS		0x2	/* RTS */
-#define	SDLC_CRC	0x4	/* SDLC/CRC-16 */
-#define	TxENAB		0x8	/* Tx Enable */
-#define	SND_BRK		0x10	/* Send Break */
-#define	Tx5		0x0	/* Tx 5 bits (or less)/character */
-#define	Tx7		0x20	/* Tx 7 bits/character */
-#define	Tx6		0x40	/* Tx 6 bits/character */
-#define	Tx8		0x60	/* Tx 8 bits/character */
-#define	DTR		0x80	/* DTR */
-
-/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
-
-/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
-
-/* Write Register 8 (transmit buffer) */
-
-/* Write Register 9 (Master interrupt control) */
-#define	VIS	1	/* Vector Includes Status */
-#define	NV	2	/* No Vector */
-#define	DLC	4	/* Disable Lower Chain */
-#define	MIE	8	/* Master Interrupt Enable */
-#define	STATHI	0x10	/* Status high */
-#define	NORESET	0	/* No reset on write to R9 */
-#define	CHRB	0x40	/* Reset channel B */
-#define	CHRA	0x80	/* Reset channel A */
-#define	FHWRES	0xc0	/* Force hardware reset */
-
-/* Write Register 10 (misc control bits) */
-#define	BIT6	1	/* 6 bit/8bit sync */
-#define	LOOPMODE 2	/* SDLC Loop mode */
-#define	ABUNDER	4	/* Abort/flag on SDLC xmit underrun */
-#define	MARKIDLE 8	/* Mark/flag on idle */
-#define	GAOP	0x10	/* Go active on poll */
-#define	NRZ	0	/* NRZ mode */
-#define	NRZI	0x20	/* NRZI mode */
-#define	FM1	0x40	/* FM1 (transition = 1) */
-#define	FM0	0x60	/* FM0 (transition = 0) */
-#define	CRCPS	0x80	/* CRC Preset I/O */
-
-/* Write Register 11 (Clock Mode control) */
-#define	TRxCXT	0	/* TRxC = Xtal output */
-#define	TRxCTC	1	/* TRxC = Transmit clock */
-#define	TRxCBR	2	/* TRxC = BR Generator Output */
-#define	TRxCDP	3	/* TRxC = DPLL output */
-#define	TRxCOI	4	/* TRxC O/I */
-#define	TCRTxCP	0	/* Transmit clock = RTxC pin */
-#define	TCTRxCP	8	/* Transmit clock = TRxC pin */
-#define	TCBR	0x10	/* Transmit clock = BR Generator output */
-#define	TCDPLL	0x18	/* Transmit clock = DPLL output */
-#define	RCRTxCP	0	/* Receive clock = RTxC pin */
-#define	RCTRxCP	0x20	/* Receive clock = TRxC pin */
-#define	RCBR	0x40	/* Receive clock = BR Generator output */
-#define	RCDPLL	0x60	/* Receive clock = DPLL output */
-#define	RTxCX	0x80	/* RTxC Xtal/No Xtal */
-
-/* Write Register 12 (lower byte of baud rate generator time constant) */
-
-/* Write Register 13 (upper byte of baud rate generator time constant) */
-
-/* Write Register 14 (Misc control bits) */
-#define	BRENABL	1	/* Baud rate generator enable */
-#define	BRSRC	2	/* Baud rate generator source */
-#define	DTRREQ	4	/* DTR/Request function */
-#define	AUTOECHO 8	/* Auto Echo */
-#define	LOOPBAK	0x10	/* Local loopback */
-#define	SEARCH	0x20	/* Enter search mode */
-#define	RMC	0x40	/* Reset missing clock */
-#define	DISDPLL	0x60	/* Disable DPLL */
-#define	SSBR	0x80	/* Set DPLL source = BR generator */
-#define	SSRTxC	0xa0	/* Set DPLL source = RTxC */
-#define	SFMM	0xc0	/* Set FM mode */
-#define	SNRZI	0xe0	/* Set NRZI mode */
-
-/* Write Register 15 (external/status interrupt control) */
-#define PRIME	1	/* R5' etc register access (Z85C30/230 only) */
-#define	ZCIE	2	/* Zero count IE */
-#define FIFOE	4	/* Z85230 only */
-#define	DCDIE	8	/* DCD IE */
-#define	SYNCIE	0x10	/* Sync/hunt IE */
-#define	CTSIE	0x20	/* CTS IE */
-#define	TxUIE	0x40	/* Tx Underrun/EOM IE */
-#define	BRKIE	0x80	/* Break/Abort IE */
-
-
-/* Read Register 0 */
-#define	Rx_CH_AV	0x1	/* Rx Character Available */
-#define	ZCOUNT		0x2	/* Zero count */
-#define	Tx_BUF_EMP	0x4	/* Tx Buffer empty */
-#define	DCD		0x8	/* DCD */
-#define	SYNC_HUNT	0x10	/* Sync/hunt */
-#define	CTS		0x20	/* CTS */
-#define	TxEOM		0x40	/* Tx underrun */
-#define	BRK_ABRT	0x80	/* Break/Abort */
-
-/* Read Register 1 */
-#define	ALL_SNT		0x1	/* All sent */
-/* Residue Data for 8 Rx bits/char programmed */
-#define	RES3		0x8	/* 0/3 */
-#define	RES4		0x4	/* 0/4 */
-#define	RES5		0xc	/* 0/5 */
-#define	RES6		0x2	/* 0/6 */
-#define	RES7		0xa	/* 0/7 */
-#define	RES8		0x6	/* 0/8 */
-#define	RES18		0xe	/* 1/8 */
-#define	RES28		0x0	/* 2/8 */
-/* Special Rx Condition Interrupts */
-#define	PAR_ERR		0x10	/* Parity error */
-#define	Rx_OVR		0x20	/* Rx Overrun Error */
-#define	CRC_ERR		0x40	/* CRC/Framing Error */
-#define	END_FR		0x80	/* End of Frame (SDLC) */
-
-/* Read Register 2 (channel b only) - Interrupt vector */
-
-/* Read Register 3 (interrupt pending register) ch a only */
-#define	CHBEXT	0x1		/* Channel B Ext/Stat IP */
-#define	CHBTxIP	0x2		/* Channel B Tx IP */
-#define	CHBRxIP	0x4		/* Channel B Rx IP */
-#define	CHAEXT	0x8		/* Channel A Ext/Stat IP */
-#define	CHATxIP	0x10		/* Channel A Tx IP */
-#define	CHARxIP	0x20		/* Channel A Rx IP */
-
-/* Read Register 8 (receive data register) */
-
-/* Read Register 10  (misc status bits) */
-#define	ONLOOP	2		/* On loop */
-#define	LOOPSEND 0x10		/* Loop sending */
-#define	CLK2MIS	0x40		/* Two clocks missing */
-#define	CLK1MIS	0x80		/* One clock missing */
-
-/* Read Register 12 (lower byte of baud rate generator constant) */
-
-/* Read Register 13 (upper byte of baud rate generator constant) */
-
-/* Read Register 15 (value of WR 15) */
-
-
-/*
- *	Interrupt handling functions for this SCC
- */
-
-struct z8530_channel;
- 
-struct z8530_irqhandler
-{
-	void (*rx)(struct z8530_channel *);
-	void (*tx)(struct z8530_channel *);
-	void (*status)(struct z8530_channel *);
-};
-
-/*
- *	A channel of the Z8530
- */
-
-struct z8530_channel
-{
-	struct		z8530_irqhandler *irqs;		/* IRQ handlers */
-	/*
-	 *	Synchronous
-	 */
-	u16		count;		/* Buyes received */
-	u16		max;		/* Most we can receive this frame */
-	u16		mtu;		/* MTU of the device */
-	u8		*dptr;		/* Pointer into rx buffer */
-	struct sk_buff	*skb;		/* Buffer dptr points into */
-	struct sk_buff	*skb2;		/* Pending buffer */
-	u8		status;		/* Current DCD */
-	u8		sync;		/* Set if in sync mode */
-
-	u8		regs[32];	/* Register map for the chip */
-	u8		pendregs[32];	/* Pending register values */
-	
-	struct sk_buff 	*tx_skb;	/* Buffer being transmitted */
-	struct sk_buff  *tx_next_skb;	/* Next transmit buffer */
-	u8		*tx_ptr;	/* Byte pointer into the buffer */
-	u8		*tx_next_ptr;	/* Next pointer to use */
-	u8		*tx_dma_buf[2];	/* TX flip buffers for DMA */
-	u8		tx_dma_used;	/* Flip buffer usage toggler */
-	u16		txcount;	/* Count of bytes to transmit */
-	
-	void		(*rx_function)(struct z8530_channel *, struct sk_buff *);
-	
-	/*
-	 *	Sync DMA
-	 */
-	
-	u8		rxdma;		/* DMA channels */
-	u8		txdma;		
-	u8		rxdma_on;	/* DMA active if flag set */
-	u8		txdma_on;
-	u8		dma_num;	/* Buffer we are DMAing into */
-	u8		dma_ready;	/* Is the other buffer free */
-	u8		dma_tx;		/* TX is to use DMA */
-	u8		*rx_buf[2];	/* The flip buffers */
-	
-	/*
-	 *	System
-	 */
-	 
-	struct z8530_dev *dev;		/* Z85230 chip instance we are from */
-	int		ctrlio;		/* I/O ports */
-	int		dataio;
-
-	/*
-	 *	For PC we encode this way.
-	 */	
-#define Z8530_PORT_SLEEP	0x80000000
-#define Z8530_PORT_OF(x)	((x)&0xFFFF)
-
-	u32		rx_overrun;		/* Overruns - not done yet */
-	u32		rx_crc_err;
-
-	/*
-	 *	Bound device pointers
-	 */
-
-	void		*private;	/* For our owner */
-	struct net_device	*netdevice;	/* Network layer device */
-	struct net_device_stats stats;	/* Network layer statistics */
-
-	/*
-	 *	Async features
-	 */
-
-	struct tty_struct 	*tty;		/* Attached terminal */
-	int			line;		/* Minor number */
-	struct termios		normal_termios;	/* Terminal settings */
-	struct termios		callout_termios;
-	wait_queue_head_t	open_wait;	/* Tasks waiting to open */
-	wait_queue_head_t	close_wait;	/* and for close to end */
-	unsigned long		event;		/* Pending events */
-	int			fdcount;    	/* # of fd on device */
-	int			blocked_open;	/* # of blocked opens */
-	long			session; 	/* Session of opening process */
-	long			pgrp; 		/* pgrp of opening process */
-	int			x_char;		/* XON/XOF char */
-	unsigned char 		*xmit_buf;	/* Transmit pointer */
-	int			xmit_head;	/* Transmit ring */
-	int			xmit_tail;
-	int			xmit_cnt;
-	int			flags;	
-	int			timeout;
-	int			xmit_fifo_size;	/* Transmit FIFO info */
-
-	int			close_delay;	/* Do we wait for drain on close ? */
-	unsigned short		closing_wait;
-
-	/* We need to know the current clock divisor
-	 * to read the bps rate the chip has currently
-	 * loaded.
-	 */
-
-	unsigned char		clk_divisor;  /* May be 1, 16, 32, or 64 */
-	int			zs_baud;
-
-	int			magic;
-	int			baud_base;		/* Baud parameters */
-	int			custom_divisor;
-
-
-	unsigned char		tx_active; /* character is being xmitted */
-	unsigned char		tx_stopped; /* output is suspended */
-};	
-
-/*
- *	Each Z853x0 device.
- */	
- 
-struct z8530_dev
-{
-	char *name;	/* Device instance name */
-	struct z8530_channel chanA;	/* SCC channel A */
-	struct z8530_channel chanB;	/* SCC channel B */
-	int type;
-#define Z8530	0	/* NMOS dinosaur */	
-#define Z85C30	1	/* CMOS - better */
-#define Z85230	2	/* CMOS with real FIFO */
-	int irq;	/* Interrupt for the device */
-	int active;	/* Soft interrupt enable - the Mac doesn't 
-			   always have a hard disable on its 8530s... */
-};
-
-
-/*
- *	Functions
- */
- 
-extern u8 z8530_dead_port[];
-extern u8 z8530_hdlc_kilostream_85230[];
-extern u8 z8530_hdlc_kilostream[];
-extern void z8530_interrupt(int, void *, struct pt_regs *);
-extern void z8530_describe(struct z8530_dev *, char *mapping,int io);
-extern int z8530_init(struct z8530_dev *);
-extern int z8530_shutdown(struct z8530_dev *);
-extern int z8530_sync_open(struct net_device *, struct z8530_channel *);
-extern int z8530_sync_close(struct net_device *, struct z8530_channel *);
-extern int z8530_sync_dma_open(struct net_device *, struct z8530_channel *);
-extern int z8530_sync_dma_close(struct net_device *, struct z8530_channel *);
-extern int z8530_sync_txdma_open(struct net_device *, struct z8530_channel *);
-extern int z8530_sync_txdma_close(struct net_device *, struct z8530_channel *);
-extern int z8530_channel_load(struct z8530_channel *, u8 *);
-extern int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb);
-extern struct net_device_stats *z8530_get_stats(struct z8530_channel *c);
-extern void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb);
-
-
-/*
- *	Standard interrupt vector sets
- */
- 
-struct z8530_irqhandler z8530_sync, z8530_async, z8530_nop;
-
-/*
- *	Asynchronous Interfacing
- */
-
-#define SERIAL_MAGIC 0x5301
-
-/*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-
-#define SERIAL_XMIT_SIZE 4096
-#define WAKEUP_CHARS	256
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP	0
-
-/* Internal flags used only by kernel/chr_drv/serial.c */
-#define ZILOG_INITIALIZED	0x80000000 /* Serial port was initialized */
-#define ZILOG_CALLOUT_ACTIVE	0x40000000 /* Call out device is active */
-#define ZILOG_NORMAL_ACTIVE	0x20000000 /* Normal device is active */
-#define ZILOG_BOOT_AUTOCONF	0x10000000 /* Autoconfigure port on bootup */
-#define ZILOG_CLOSING		0x08000000 /* Serial port is closing */
-#define ZILOG_CTS_FLOW		0x04000000 /* Do CTS flow control */
-#define ZILOG_CHECK_CD		0x02000000 /* i.e., CLOCAL */
-
-#endif /* !(_Z8530_H) */
diff -u --recursive --new-file v2.3.20/linux/drivers/pnp/Config.in linux/drivers/pnp/Config.in
--- v2.3.20/linux/drivers/pnp/Config.in	Sun Aug 15 11:50:35 1999
+++ linux/drivers/pnp/Config.in	Mon Oct 11 10:13:24 1999
@@ -6,6 +6,6 @@
 
 tristate 'Plug and Play support' CONFIG_PNP
 
-dep_tristate 'ISA Plug and Play support' CONFIG_ISAPNP $CONFIG_PNP
+dep_tristate '  ISA Plug and Play support' CONFIG_ISAPNP $CONFIG_PNP
 
 endmenu
diff -u --recursive --new-file v2.3.20/linux/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c
--- v2.3.20/linux/drivers/sbus/char/pcikbd.c	Fri Sep 10 23:57:30 1999
+++ linux/drivers/sbus/char/pcikbd.c	Mon Oct 11 10:13:25 1999
@@ -764,7 +764,7 @@
 	queue->head = head;
 	aux_ready = 1;
 	if (queue->fasync)
-		kill_fasync(queue->fasync, SIGIO);
+		kill_fasync(queue->fasync, SIGIO, POLL_IN);
 	wake_up_interruptible(&queue->proc_list);
 }
 
diff -u --recursive --new-file v2.3.20/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c
--- v2.3.20/linux/drivers/sbus/char/sunkbd.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/sbus/char/sunkbd.c	Mon Oct 11 10:13:25 1999
@@ -1273,7 +1273,7 @@
 		kbd_head = next;
 	}
 	if (kb_fasync)
-		kill_fasync (kb_fasync, SIGIO);
+		kill_fasync (kb_fasync, SIGIO, POLL_IN);
 	wake_up_interruptible (&kbd_wait);
 }
 
diff -u --recursive --new-file v2.3.20/linux/drivers/sbus/char/sunmouse.c linux/drivers/sbus/char/sunmouse.c
--- v2.3.20/linux/drivers/sbus/char/sunmouse.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/sbus/char/sunmouse.c	Mon Oct 11 10:13:25 1999
@@ -137,7 +137,7 @@
 	}
 	sunmouse.ready = 1;
 	if (sunmouse.fasync)
-		kill_fasync (sunmouse.fasync, SIGIO);
+		kill_fasync (sunmouse.fasync, SIGIO, POLL_IN);
 	wake_up_interruptible (&sunmouse.proc_list);
 }
 
@@ -334,7 +334,7 @@
 		 */
 		sunmouse.ready = 1;
 		if (sunmouse.fasync)
-			kill_fasync (sunmouse.fasync, SIGIO);
+			kill_fasync (sunmouse.fasync, SIGIO, POLL_IN);
 		wake_up_interruptible(&sunmouse.proc_list);
 	}
 	return;
diff -u --recursive --new-file v2.3.20/linux/drivers/sbus/char/uctrl.c linux/drivers/sbus/char/uctrl.c
--- v2.3.20/linux/drivers/sbus/char/uctrl.c	Fri Sep 10 23:57:30 1999
+++ linux/drivers/sbus/char/uctrl.c	Mon Oct 11 10:13:25 1999
@@ -92,7 +92,7 @@
 #ifdef MODULE
 int init_module(void)
 #else
-__initfunc(int uctrl_init(void))
+int __init uctrl_init(void)
 #endif
 {
 	struct uctrl_driver *driver = &drv;
diff -u --recursive --new-file v2.3.20/linux/drivers/scsi/imm.c linux/drivers/scsi/imm.c
--- v2.3.20/linux/drivers/scsi/imm.c	Fri May  7 10:57:42 1999
+++ linux/drivers/scsi/imm.c	Mon Oct 11 14:48:00 1999
@@ -166,15 +166,8 @@
 	 */
 	imm_hosts[i].mode = IMM_NIBBLE;
 
-	if (modes & PARPORT_MODE_PCPS2)
+	if (modes & PARPORT_MODE_TRISTATE)
 	    imm_hosts[i].mode = IMM_PS2;
-
-	if (modes & PARPORT_MODE_PCECPPS2) {
-	    w_ecr(ppb, 0x20);
-	    imm_hosts[i].mode = IMM_PS2;
-	}
-	if (modes & PARPORT_MODE_PCECPEPP)
-	    w_ecr(ppb, 0x80);
 
 	/* Done configuration */
 	imm_pb_release(i);
diff -u --recursive --new-file v2.3.20/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v2.3.20/linux/drivers/scsi/sg.c	Sat Oct  9 11:47:50 1999
+++ linux/drivers/scsi/sg.c	Mon Oct 11 10:13:25 1999
@@ -815,7 +815,7 @@
 /* Now wake up any sg_read() that is waiting for this packet. */
     wake_up_interruptible(&sfp->read_wait);
     if ((sfp->async_qp) && (! closed))
-        kill_fasync(sfp->async_qp, SIGPOLL);
+        kill_fasync(sfp->async_qp, SIGPOLL, POLL_IN);
 }
 
 static void sg_debug_all(const Sg_fd * sfp)
diff -u --recursive --new-file v2.3.20/linux/drivers/sgi/char/shmiq.c linux/drivers/sgi/char/shmiq.c
--- v2.3.20/linux/drivers/sgi/char/shmiq.c	Thu Aug 26 13:05:39 1999
+++ linux/drivers/sgi/char/shmiq.c	Mon Oct 11 10:13:25 1999
@@ -118,7 +118,7 @@
 	s->tail = tail_next;
 	shmiqs [device].tail = tail_next;
 	if (shmiqs [device].fasync)
-		kill_fasync (shmiqs [device].fasync, SIGIO);
+		kill_fasync (shmiqs [device].fasync, SIGIO, POLL_IN);
 	wake_up_interruptible (&shmiqs [device].proc_list);
 }
 
diff -u --recursive --new-file v2.3.20/linux/drivers/usb/audio.c linux/drivers/usb/audio.c
--- v2.3.20/linux/drivers/usb/audio.c	Sat Oct  9 11:47:50 1999
+++ linux/drivers/usb/audio.c	Mon Oct 11 10:21:34 1999
@@ -769,7 +769,7 @@
 
 static int usbin_completed(int status, void *__buffer, int rval, void *dev_id)
 {
-#if 0
+#if 1
         struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id;
         struct usb_audiodev *as = (struct usb_audiodev *)id->context;
 #else
@@ -777,10 +777,13 @@
         struct usb_isoc_desc *id;
 #endif
 	struct usbin *u = &as->usbin;
+	unsigned long flags;
 	unsigned int next, idmask;
 
+#if 0
 	printk(KERN_DEBUG "usbin_completed: status %d rval %d flags 0x%x\n", status, rval, u->flags);
-	spin_lock(&as->lock);
+#endif
+	spin_lock_irqsave(&as->lock, flags);
 	next = !(u->flags & FLG_NEXTID);
 	idmask = FLG_ID1RUNNING >> next;
 	u->flags = (u->flags & ~(FLG_NEXTID | idmask)) | next;
@@ -794,7 +797,12 @@
 		u->flags &= ~FLG_RUNNING;
 		printk(KERN_DEBUG "usbin_completed: descriptor not restarted\n");
 	}
-	spin_unlock(&as->lock);
+	if (!(u->flags & idmask)) {
+		printk(KERN_DEBUG "usbin_completed: killing id\n");
+		usb_kill_isoc(id);
+		printk(KERN_DEBUG "usbin_completed: id killed\n");
+	}
+	spin_unlock_irqrestore(&as->lock, flags);
 	return 0;
 }
 
@@ -833,7 +841,7 @@
 
 static int usbin_sync_completed(int status, void *__buffer, int rval, void *dev_id)
 {
-#if 0
+#if 1
         struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id;
         struct usb_audiodev *as = (struct usb_audiodev *)id->context;
 #else
@@ -841,13 +849,16 @@
         struct usb_isoc_desc *id;
 #endif
 	struct usbin *u = &as->usbin;
+	unsigned long flags;
 	unsigned int next, idmask;
 
+#if 0
 	printk(KERN_DEBUG "usbin_sync_completed: status %d rval %d flags 0x%x\n", status, rval, u->flags);
-	spin_lock(&as->lock);
+#endif
+	spin_lock_irqsave(&as->lock, flags);
 	next = !(u->flags & FLG_SYNCNEXTID);
 	idmask = FLG_SYNC1RUNNING >> next;
-	u->flags = (u->flags & ~(FLG_SYNCNEXTID | idmask)) | (-next & FLG_SYNCNEXTID);
+	u->flags = (u->flags & ~(FLG_SYNCNEXTID | idmask)) | ((-next) & FLG_SYNCNEXTID);
 	id = u->synciso[!next];
 	if (!usbin_sync_retire_desc(u, id) &&
 	    u->flags & FLG_RUNNING &&
@@ -858,7 +869,12 @@
 		u->flags &= ~FLG_RUNNING;
 		printk(KERN_DEBUG "usbin_sync_completed: descriptor not restarted\n");
 	}
-	spin_unlock(&as->lock);
+	if (!(u->flags & idmask)) {
+		printk(KERN_DEBUG "usbin_sync_completed: killing id\n");
+		usb_kill_isoc(id);
+		printk(KERN_DEBUG "usbin_sync_completed: id killed\n");
+	}
+	spin_unlock_irqrestore(&as->lock, flags);
 	return 0;
 }
 
@@ -870,8 +886,10 @@
 	unsigned long flags;
 	unsigned int which, i;
 
-	printk(KERN_DEBUG "usbin_start: device %d ufmt %d dfmt %d srate %d\n",
+#if 0
+	printk(KERN_DEBUG "usbin_start: device %d ufmt 0x%08x dfmt 0x%08x srate %d\n",
 	       dev->devnum, u->format, u->dma.format, u->dma.srate);
+#endif
 	/* allocate USB storage if not already done */
 	/* UHCI wants the data to be page aligned - this is silly */
 	if (!u->data[0])
@@ -980,15 +998,18 @@
         unsigned long flags;
 	unsigned int i;
 
+printk(KERN_DEBUG "usb_audio: usbout_stop (1) flags 0x%04x\n", u->flags);
         spin_lock_irqsave(&as->lock, flags);
 	u->flags &= ~FLG_RUNNING;
 	i = u->flags;
         spin_unlock_irqrestore(&as->lock, flags);
+printk(KERN_DEBUG "usb_audio: usbout_stop (2) flags 0x%04x\n", i);
 	while (i & (FLG_ID0RUNNING|FLG_ID1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
 		schedule_timeout(1);
 		spin_lock_irqsave(&as->lock, flags);
 		i = u->flags;
 		spin_unlock_irqrestore(&as->lock, flags);
+printk(KERN_DEBUG "usb_audio: usbout_stop (3) flags 0x%04x\n", i);
 	}
 	if (u->dataiso[0])
 		usb_free_isoc(u->dataiso[0]);
@@ -1219,7 +1240,7 @@
 
 static int usbout_completed(int status, void *__buffer, int rval, void *dev_id)
 {
-#if 0
+#if 1
         struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id;
         struct usb_audiodev *as = (struct usb_audiodev *)id->context;
 #else
@@ -1227,10 +1248,13 @@
 	struct usb_isoc_desc *id;
 #endif
 	struct usbout *u = &as->usbout;
+	unsigned long flags;
 	unsigned int next, idmask;
 
+#if 0
 	printk(KERN_DEBUG "usbout_completed: status %d rval %d flags 0x%x\n", status, rval, u->flags);
-	spin_lock(&as->lock);
+#endif
+	spin_lock_irqsave(&as->lock, flags);
 	next = !(u->flags & FLG_NEXTID);
 	idmask = FLG_ID1RUNNING >> next;
 	u->flags = (u->flags & ~(FLG_NEXTID | idmask)) | next;
@@ -1244,7 +1268,12 @@
 		u->flags &= ~FLG_RUNNING;
 		printk(KERN_DEBUG "usbout_completed: descriptor not restarted\n");
 	}
-	spin_unlock(&as->lock);
+	if (!(u->flags & idmask)) {
+		printk(KERN_DEBUG "usbout_completed: killing id\n");
+		usb_kill_isoc(id);
+		printk(KERN_DEBUG "usbout_completed: id killed\n");
+	}
+	spin_unlock_irqrestore(&as->lock, flags);
 	return 0;
 }
 
@@ -1286,7 +1315,7 @@
 
 static int usbout_sync_completed(int status, void *__buffer, int rval, void *dev_id)
 {
-#if 0
+#if 1
         struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id;
         struct usb_audiodev *as = (struct usb_audiodev *)id->context;
 #else
@@ -1294,13 +1323,16 @@
 	struct usb_isoc_desc *id;
 #endif
 	struct usbout *u = &as->usbout;
+	unsigned long flags;
 	unsigned int next, idmask;
 
+#if 0
 	printk(KERN_DEBUG "usbout_sync_completed: status %d rval %d flags 0x%x\n", status, rval, u->flags);
-	spin_lock(&as->lock);
+#endif
+	spin_lock_irqsave(&as->lock, flags);
 	next = !(u->flags & FLG_SYNCNEXTID);
 	idmask = FLG_SYNC1RUNNING >> next;
-	u->flags = (u->flags & ~(FLG_SYNCNEXTID | idmask)) | (-next & FLG_SYNCNEXTID);
+	u->flags = (u->flags & ~(FLG_SYNCNEXTID | idmask)) | ((-next) & FLG_SYNCNEXTID);
 	id = u->synciso[!next];
 	if (!usbout_sync_retire_desc(u, id) &&
 	    u->flags & FLG_RUNNING &&
@@ -1311,7 +1343,12 @@
 		u->flags &= ~FLG_RUNNING;
 		printk(KERN_DEBUG "usbout_sync_completed: descriptor not restarted\n");
 	}
-	spin_unlock(&as->lock);
+	if (!(u->flags & idmask)) {
+		printk(KERN_DEBUG "usbout_sync_completed: killing id\n");
+		usb_kill_isoc(id);
+		printk(KERN_DEBUG "usbout_sync_completed: id killed\n");
+	}
+	spin_unlock_irqrestore(&as->lock, flags);
 	return 0;
 }
 
@@ -1323,8 +1360,10 @@
 	unsigned long flags;
 	unsigned int which, i;
 
-	printk(KERN_DEBUG "usbout_start: device %d ufmt %d dfmt %d srate %d\n",
+#if 0
+	printk(KERN_DEBUG "usbout_start: device %d ufmt 0x%08x dfmt 0x%08x srate %d\n",
 	       dev->devnum, u->format, u->dma.format, u->dma.srate);
+#endif
 	/* allocate USB storage if not already done */
 	/* UHCI wants the data to be page aligned - this is silly */
 	if (!u->data[0])
@@ -1459,7 +1498,7 @@
 	struct usbin *u = &as->usbin;
 	struct dmabuf *d = &u->dma;
 	struct audioformat *fmt;
-	unsigned int fmtnr;
+	unsigned int fmtnr, ep;
 	unsigned char data[3];
 
 	if (u->interface < 0 || u->interface >= config->bNumInterfaces)
@@ -1474,7 +1513,7 @@
 	if ((alts->endpoint[0].bmAttributes & 0x0c) == 0x08) {
 		if (alts->bNumEndpoints < 2 ||
 		    alts->endpoint[1].bmAttributes != 0x01 ||
-		    alts->endpoint[1].bSynchAddress == 0 ||
+		    alts->endpoint[1].bSynchAddress != 0 ||
 		    alts->endpoint[1].bEndpointAddress != (alts->endpoint[0].bSynchAddress & 0x7f)) {
 			printk(KERN_ERR "usb_audio: device %d interface %d altsetting %d invalid synch pipe\n",
 			       dev->devnum, u->interface, fmt->altsetting);
@@ -1497,18 +1536,21 @@
 	data[0] = d->srate;
 	data[1] = d->srate >> 8;
 	data[2] = d->srate >> 16;
+	ep = usb_pipeendpoint(u->datapipe) | (u->datapipe & USB_DIR_IN);
 	if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
-			    SAMPLING_FREQ_CONTROL << 8, usb_pipeendpoint(u->datapipe), data, 3, HZ) != 3) {
-		printk(KERN_ERR "usbaudio: failure to set sampling frequency device %d endpoint %d\n",
-		       dev->devnum, usb_pipeendpoint(u->datapipe));
+			    SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ) < 0) {
+		printk(KERN_ERR "usbaudio: failure to set input sampling frequency device %d endpoint 0x%x to %u\n",
+		       dev->devnum, ep, d->srate);
 		return -1;
 	}
 	if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
-			    SAMPLING_FREQ_CONTROL << 8, usb_pipeendpoint(u->datapipe), data, 3, HZ) != 3) {
-		printk(KERN_ERR "usbaudio: failure to get sampling frequency device %d endpoint %d\n",
-		       dev->devnum, usb_pipeendpoint(u->datapipe));
+			    SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ) < 0) {
+		printk(KERN_ERR "usbaudio: failure to get input sampling frequency device %d endpoint 0x%x\n",
+		       dev->devnum, ep);
 		return -1;
 	}
+	printk(KERN_DEBUG "usb_audio: set_format_in: device %d interface %d altsetting %d srate req: %u real %u\n",
+	       dev->devnum, u->interface, fmt->altsetting, d->srate, data[0] | (data[1] << 8) | (data[2] << 16));
 	d->srate = data[0] | (data[1] << 8) | (data[2] << 16);
 	return 0;
 }
@@ -1522,7 +1564,7 @@
 	struct usbout *u = &as->usbout;
 	struct dmabuf *d = &u->dma;
 	struct audioformat *fmt;
-	unsigned int fmtnr;
+	unsigned int fmtnr, ep;
 	unsigned char data[3];
 
 	if (u->interface < 0 || u->interface >= config->bNumInterfaces)
@@ -1537,7 +1579,7 @@
 	if ((alts->endpoint[0].bmAttributes & 0x0c) == 0x04) {
 		if (alts->bNumEndpoints < 2 ||
 		    alts->endpoint[1].bmAttributes != 0x01 ||
-		    alts->endpoint[1].bSynchAddress == 0 ||
+		    alts->endpoint[1].bSynchAddress != 0 ||
 		    alts->endpoint[1].bEndpointAddress != (alts->endpoint[0].bSynchAddress | 0x80)) {
 			printk(KERN_ERR "usb_audio: device %d interface %d altsetting %d invalid synch pipe\n",
 			       dev->devnum, u->interface, fmt->altsetting);
@@ -1560,18 +1602,21 @@
 	data[0] = d->srate;
 	data[1] = d->srate >> 8;
 	data[2] = d->srate >> 16;
+	ep = usb_pipeendpoint(u->datapipe) | (u->datapipe & USB_DIR_IN);
 	if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
-			    SAMPLING_FREQ_CONTROL << 8, usb_pipeendpoint(u->datapipe), data, 3, HZ) != 3) {
-		printk(KERN_ERR "usbaudio: failure to set sampling frequency device %d endpoint %d\n",
-		       dev->devnum, usb_pipeendpoint(u->datapipe));
+			    SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ) < 0) {
+		printk(KERN_ERR "usbaudio: failure to set output sampling frequency device %d endpoint 0x%x to %u\n",
+		       dev->devnum, ep, d->srate);
 		return -1;
 	}
 	if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
-			    SAMPLING_FREQ_CONTROL << 8, usb_pipeendpoint(u->datapipe), data, 3, HZ) != 3) {
-		printk(KERN_ERR "usbaudio: failure to get sampling frequency device %d endpoint %d\n",
-		       dev->devnum, usb_pipeendpoint(u->datapipe));
+			    SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ) < 0) {
+		printk(KERN_ERR "usbaudio: failure to get output sampling frequency device %d endpoint 0x%x\n",
+		       dev->devnum, ep);
 		return -1;
 	}
+	printk(KERN_DEBUG "usb_audio: set_format_out: device %d interface %d altsetting %d srate req: %u real %u\n",
+	       dev->devnum, u->interface, fmt->altsetting, d->srate, data[0] | (data[1] << 8) | (data[2] << 16));
 	d->srate = data[0] | (data[1] << 8) | (data[2] << 16);
 	return 0;
 }
@@ -1642,7 +1687,7 @@
 		data[0] = v1;
 		data[1] = v1 >> 8;
                 if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-                                    (ch->chnum << 8) | 1, ms->iface | (ch->unitid << 8), data, 2, HZ) < 2)
+                                    (ch->chnum << 8) | 1, ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
                         goto err;
 		if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
 			return 0;
@@ -1650,7 +1695,7 @@
 		data[1] = v2 >> 8;
 		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
 				    ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)),
-				    ms->iface | (ch->unitid << 8), data, 2, HZ) < 2)
+				    ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
                         goto err;
 		return 0;
 
@@ -1659,14 +1704,14 @@
 		data[0] = v1;
 		data[1] = v1 >> 8;
                 if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-                                    (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 2, HZ) < 2)
+                                    (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
                         goto err;
 		if (ch->chnum == 0)
 			return 0;
 		data[0] = v2;
 		data[1] = v2 >> 8;
 		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 2, HZ) < 2)
+				    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
 			goto err;
 		return 0;
                 
@@ -1675,13 +1720,13 @@
         case TREBLE_CONTROL:
 		data[0] = v1 >> 8;
 		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-                                    (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 1, HZ) < 1)
+                                    (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 1, HZ) < 0)
                         goto err;
 		if (ch->chnum == 0)
 			return 0;
 		data[0] = v2 >> 8;
 		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 1, HZ) < 1)
+				    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 1, HZ) < 0)
 			goto err;
 		return 0;
                
@@ -1839,7 +1884,7 @@
                         for (val = i = 0; i < ms->numch; i++)
 				if (ms->ch[i].flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT))
 					val |= 1 << ms->ch[i].osschannel;
-                        return put_user(0, (int *)arg);
+                        return put_user(val, (int *)arg);
                         
                 case SOUND_MIXER_CAPS:
                         return put_user(0, (int *)arg);
@@ -2778,26 +2823,26 @@
 	if ((state->termtype & 0xff00) == 0x0000 && !(state->mixchmask & SOUND_MASK_VOLUME))
 		return SOUND_MIXER_VOLUME;
 	if ((state->termtype & 0xff00) == 0x0100) {
-		if (!(state->mixchmask & SOUND_MASK_PCM))
+		if (state->mixchmask & SOUND_MASK_PCM)
 			return SOUND_MIXER_PCM;
-		if (!(state->mixchmask & SOUND_MASK_ALTPCM))
+		if (state->mixchmask & SOUND_MASK_ALTPCM)
 			return SOUND_MIXER_ALTPCM;
 	}
-	if ((state->termtype & 0xff00) == 0x0200 && !(state->mixchmask & SOUND_MASK_MIC))
+	if ((state->termtype & 0xff00) == 0x0200 && (state->mixchmask & SOUND_MASK_MIC))
 		return SOUND_MIXER_MIC;
-	if ((state->termtype & 0xff00) == 0x0300 && !(state->mixchmask & SOUND_MASK_SPEAKER))
+	if ((state->termtype & 0xff00) == 0x0300 && (state->mixchmask & SOUND_MASK_SPEAKER))
 		return SOUND_MIXER_SPEAKER;
-	if ((state->termtype & 0xff00) == 0x0300 && !(state->mixchmask & SOUND_MASK_SPEAKER))
+	if ((state->termtype & 0xff00) == 0x0300 && (state->mixchmask & SOUND_MASK_SPEAKER))
 		return SOUND_MIXER_SPEAKER;
 	if ((state->termtype & 0xff00) == 0x0500) {
-		if (!(state->mixchmask & SOUND_MASK_PHONEIN))
+		if (state->mixchmask & SOUND_MASK_PHONEIN)
 			return SOUND_MIXER_PHONEIN;
-		if (!(state->mixchmask & SOUND_MASK_PHONEOUT))
+		if (state->mixchmask & SOUND_MASK_PHONEOUT)
 			return SOUND_MIXER_PHONEOUT;
 	}
-	if (state->termtype >= 0x710 && state->termtype <= 0x711 && !(state->mixchmask & SOUND_MASK_RADIO))
+	if (state->termtype >= 0x710 && state->termtype <= 0x711 && (state->mixchmask & SOUND_MASK_RADIO))
 		return SOUND_MIXER_RADIO;
-	if (state->termtype >= 0x709 && state->termtype <= 0x70f && !(state->mixchmask & SOUND_MASK_VIDEO))
+	if (state->termtype >= 0x709 && state->termtype <= 0x70f && (state->mixchmask & SOUND_MASK_VIDEO))
 		return SOUND_MIXER_VIDEO;
 	u = ffs(state->mixchmask & (SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | SOUND_MASK_LINE3 |
 				    SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 | SOUND_MASK_DIGITAL3));
@@ -2818,18 +2863,18 @@
 	switch (ch->selector) {
 	case 0:  /* mixer unit request */
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
 			goto err;
 		ch->minval = buf[0] | (buf[1] << 8);
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
 			goto err;
 		ch->maxval = buf[0] | (buf[1] << 8);
 		v2 = ch->maxval - ch->minval;
 		if (!v2)
 			v2 = 1;
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
 			goto err;
 		v1 = buf[0] | (buf[1] << 8);
 		v3 = v1 - ch->minval;
@@ -2840,7 +2885,7 @@
 		if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
 			if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
 					    ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)),
-					    state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+					    state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
 			goto err;
 			v1 = buf[0] | (buf[1] << 8);
 			v3 = v1 - ch->minval;
@@ -2854,15 +2899,15 @@
 		/* various feature unit controls */
 	case VOLUME_CONTROL:
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
 			goto err;
 		ch->minval = buf[0] | (buf[1] << 8);
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
 			goto err;
 		ch->maxval = buf[0] | (buf[1] << 8);
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
 			goto err;
 		v1 = buf[0] | (buf[1] << 8);
 		v2 = ch->maxval - ch->minval;
@@ -2875,7 +2920,7 @@
 		ch->value = v3;
 		if (ch->chnum != 0) {
 			if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-					    (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+					    (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
 				goto err;
 			v1 = buf[0] | (buf[1] << 8);
 			v3 = v1 - ch->minval;
@@ -2890,15 +2935,15 @@
 	case MID_CONTROL:
 	case TREBLE_CONTROL:
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 1)
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
 			goto err;
 		ch->minval = buf[0] << 8;
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 1)
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
 			goto err;
 		ch->maxval = buf[0] << 8;
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 1)
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
 			goto err;
 		v1 = buf[0] << 8;
 		v2 = ch->maxval - ch->minval;
@@ -2911,7 +2956,7 @@
 		ch->value = v3;
 		if (ch->chnum != 0) {
 			if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-					    (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 1)
+					    (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
 				goto err;
 			v1 = buf[0] << 8;
 			v3 = v1 - ch->minval;
@@ -2942,12 +2987,12 @@
 	unsigned int idx;
 
 	idx = inidx*numoch;
-	if (!(bmap[idx >> 3] & (1 << (idx & 7))))
+	if (!(bmap[-(idx >> 3)] & (0x80 >> (idx & 7))))
 		return 0;
 	if (!(flg & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
 		return 1;
 	idx = (inidx+!!(flg & MIXFLG_STEREOIN))*numoch+!!(flg & MIXFLG_STEREOOUT);
-	if (!(bmap[idx >> 3] & (1 << (idx & 7))))
+	if (!(bmap[-(idx >> 3)] & (0x80 >> (idx & 7))))
 		return 0;
 	return 1;
 }
@@ -2958,6 +3003,8 @@
 	unsigned int chidx[SOUND_MIXER_NRDEVICES+1];
 	unsigned int termt[SOUND_MIXER_NRDEVICES];
 	unsigned char flg = (nroutch >= 2) ? MIXFLG_STEREOOUT : 0;
+	unsigned char *bmap = &mixer[9+mixer[4]];
+	unsigned int bmapsize;
 	struct mixerchannel *ch;
 	unsigned int i;
 
@@ -2977,7 +3024,9 @@
 	}
 	state->termtype = 0;
 	state->chconfig = mixer[6+mixer[4]] | (mixer[7+mixer[4]] << 8);
-	if (mixer[0] < 10+mixer[4]+((nroutch * chidx[mixer[4]] + 7) >> 3)) {
+	bmapsize = (nroutch * chidx[mixer[4]] + 7) >> 3;
+	bmap += bmapsize - 1;
+	if (mixer[0] < 10+mixer[4]+bmapsize) {
 		printk(KERN_ERR "usb_audio: unit %u invalid MIXER_UNIT descriptor (bitmap too small)\n", mixer[3]);
 		return;
 	}
@@ -2985,7 +3034,7 @@
 		state->termtype = termt[i];
 		if (chidx[i+1]-chidx[i] >= 2) {
 			flg |= MIXFLG_STEREOIN;
-			if (checkmixbmap(&mixer[9+mixer[4]], flg, chidx[i], nroutch)) {
+			if (checkmixbmap(bmap, flg, chidx[i], nroutch)) {
 				ch = getmixchannel(state, getvolchannel(state));
 				if (ch) {
 					ch->unitid = mixer[3];
@@ -2998,7 +3047,7 @@
 			}
 		}
 		flg &= ~MIXFLG_STEREOIN;
-		if (checkmixbmap(&mixer[9+mixer[4]], flg, chidx[i], nroutch)) {
+		if (checkmixbmap(bmap, flg, chidx[i], nroutch)) {
 			ch = getmixchannel(state, getvolchannel(state));
 			if (ch) {
 				ch->unitid = mixer[3];
@@ -3134,6 +3183,7 @@
 static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unitid)
 {
 	unsigned char *p1;
+	unsigned int i, j;
 
 	if (test_and_set_bit(unitid, &state->unitbitmap)) {
 		printk(KERN_ERR "usb_audio: mixer path recursion detected, unit %d!\n", unitid);
@@ -3195,15 +3245,16 @@
 			printk(KERN_ERR "usb_audio: unit %u: invalid EXTENSION_UNIT descriptor\n", unitid);
 			return;
 		}
-		{
-			unsigned int i;
-			
-			for (i = 0; i < p1[6]; i++)
-				usb_audio_recurseunit(state, p1[7+i]);
+		for (j = i = 0; i < p1[6]; i++) {
+			usb_audio_recurseunit(state, p1[7+i]);
+			if (!i)
+				j = state->termtype;
+			else if (j != state->termtype)
+				j = 0;
 		}
 		state->nrchannels = p1[7+p1[6]];
 		state->chconfig = p1[8+p1[6]] | (p1[9+p1[6]] << 8);
-		state->termtype = 0;
+		state->termtype = j;
 		return;
 
 	default:
@@ -3378,6 +3429,10 @@
 	return -1;
 
  configfound:
+        if (usb_set_configuration(dev, config->bConfigurationValue) < 0) {
+		printk(KERN_ERR "usb_audio: set_configuration failed (ConfigValue 0x%x)\n", config->bConfigurationValue);
+		return -1;
+	}
 	ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buf, 8);
 	if (ret) {
 		printk(KERN_ERR "usb_audio: cannot get first 8 bytes of config descriptor %d of device %d\n", i, dev->devnum);
diff -u --recursive --new-file v2.3.20/linux/drivers/usb/mouse.c linux/drivers/usb/mouse.c
--- v2.3.20/linux/drivers/usb/mouse.c	Fri Sep 10 23:57:36 1999
+++ linux/drivers/usb/mouse.c	Mon Oct 11 10:13:25 1999
@@ -120,7 +120,7 @@
 
 	wake_up_interruptible(&mouse->wait);
 	if (mouse->fasync)
-		kill_fasync(mouse->fasync, SIGIO);
+		kill_fasync(mouse->fasync, SIGIO, POLL_IN);
 
 	return 1;
 }
diff -u --recursive --new-file v2.3.20/linux/drivers/video/Config.in linux/drivers/video/Config.in
--- v2.3.20/linux/drivers/video/Config.in	Fri Sep 10 23:57:36 1999
+++ linux/drivers/video/Config.in	Mon Oct 11 10:30:42 1999
@@ -2,350 +2,362 @@
 # Video configuration
 #
 
+mainmenu_option next_comment
+comment 'Frame-buffer support'
+
+bool 'Support for frame buffer devices (EXPERIMENTAL)' CONFIG_FB
+
 if [ "$CONFIG_FB" = "y" ]; then
-  define_bool CONFIG_DUMMY_CONSOLE y
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_PCI" = "y" ]; then
-      tristate 'Cirrus Logic suport (experimental)' CONFIG_FB_CLGEN
-      tristate 'Permedia2 support (experimental)' CONFIG_FB_PM2
-      if [ "$CONFIG_FB_PM2" = "y" ]; then
-        if [ "$CONFIG_PCI" = "y" ]; then
-          bool '  enable FIFO disconnect feature' CONFIG_FB_PM2_FIFO_DISCONNECT
-          bool '  generic Permedia2 PCI board support' CONFIG_FB_PM2_PCI
-        fi
-        if [ "$CONFIG_AMIGA" = "y" ]; then
-          bool '  Phase5 CVisionPPC/BVisionPPC support' CONFIG_FB_PM2_CVPPC
-        fi
-      fi
-    fi
-  fi
-  if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
-    bool 'Acorn VIDC support' CONFIG_FB_ACORN
-  fi
-  if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then
-    tristate 'Cyber2000 support' CONFIG_FB_CYBER2000
-  fi
-  if [ "$CONFIG_APOLLO" = "y" ]; then
-    define_bool CONFIG_FB_APOLLO y
-  fi
-  if [ "$CONFIG_Q40" = "y" ]; then
-    define_bool CONFIG_FB_Q40 y
-  fi
-  if [ "$CONFIG_AMIGA" = "y" ]; then
-    bool 'Amiga native chipset support' CONFIG_FB_AMIGA
-    if [ "$CONFIG_FB_AMIGA" != "n" ]; then
-      bool 'Amiga OCS chipset support' CONFIG_FB_AMIGA_OCS
-      bool 'Amiga ECS chipset support' CONFIG_FB_AMIGA_ECS
-      bool 'Amiga AGA chipset support' CONFIG_FB_AMIGA_AGA
-    fi
-  fi
-  if [ "$CONFIG_ZORRO" = "y" ]; then
-    tristate 'Amiga CyberVision support' CONFIG_FB_CYBER
-    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      bool 'Amiga CyberVision3D support (experimental)' CONFIG_FB_VIRGE
-      tristate 'Amiga RetinaZ3 support' CONFIG_FB_RETINAZ3
-      bool 'Amiga FrameMaster II/Rainbow II support (experimental)' CONFIG_FB_FM2
-    fi
-  fi
-  if [ "$CONFIG_ATARI" = "y" ]; then
-    bool 'Atari native chipset support' CONFIG_FB_ATARI
-    tristate 'ATI Mach64 display support' CONFIG_FB_ATY
-  fi
-  if [ "$CONFIG_PPC" = "y" ]; then
-    bool 'Open Firmware frame buffer device support' CONFIG_FB_OF
-    if [ "$CONFIG_FB_OF" = "y" ]; then
-      bool 'Apple "control" display support' CONFIG_FB_CONTROL
-      bool 'Apple "platinum" display support' CONFIG_FB_PLATINUM
-      bool 'Apple "valkyrie" display support' CONFIG_FB_VALKYRIE
-      tristate 'ATI Mach64 display support' CONFIG_FB_ATY
-      bool 'IMS Twin Turbo display support' CONFIG_FB_IMSTT
-      bool 'Chips 65550 display support' CONFIG_FB_CT65550
-      bool 'S3 Trio display support' CONFIG_FB_S3TRIO
-    fi
-    tristate 'VGA 16-color graphics console' CONFIG_FB_VGA16
-  fi
-  if [ "$CONFIG_MAC" = "y" ]; then
-    define_bool CONFIG_FB_MAC y
-  fi
-  if [ "$CONFIG_HP300" = "y" ]; then
-    define_bool CONFIG_FB_HP300 y
-  fi
-  if [ "$ARCH" = "alpha" ]; then
-    tristate 'TGA framebuffer support' CONFIG_FB_TGA
-  fi
-  if [ "$ARCH" = "i386" ]; then
-    bool 'VESA VGA graphics console' CONFIG_FB_VESA
-    tristate 'VGA 16-color graphics console' CONFIG_FB_VGA16
-    define_bool CONFIG_VIDEO_SELECT y
-  fi
-  if [ "$CONFIG_VISWS" = "y" ]; then
-    tristate 'SGI Visual Workstation framebuffer support' CONFIG_FB_SGIVW
-  fi
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    if [ "$CONFIG_PCI" != "n" ]; then
-      tristate 'Matrox acceleration' CONFIG_FB_MATROX
-      if  [ "$CONFIG_FB_MATROX" != "n" ]; then
-        bool '  Millennium I/II support' CONFIG_FB_MATROX_MILLENIUM
-        bool '  Mystique support' CONFIG_FB_MATROX_MYSTIQUE
-        bool '  G100/G200/G400 support' CONFIG_FB_MATROX_G100
-        bool '  Multihead support' CONFIG_FB_MATROX_MULTIHEAD
-      fi
-      tristate 'ATI Mach64 display support' CONFIG_FB_ATY
-    fi
-  fi
-  if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
-    bool 'SBUS and UPA framebuffers' CONFIG_FB_SBUS
-    if [ "$CONFIG_FB_SBUS" != "n" ]; then
-      if [ "$ARCH" = "sparc64" ]; then
-	bool '  Creator/Creator3D support' CONFIG_FB_CREATOR
-      fi
-      bool '  CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX
-      bool '  BWtwo support' CONFIG_FB_BWTWO
-      bool '  CGthree support' CONFIG_FB_CGTHREE
-      if [ "$ARCH" = "sparc" ]; then
-        bool '  TCX (SS4/SS5 only) support' CONFIG_FB_TCX
-	bool '  CGfourteen (SX) support' CONFIG_FB_CGFOURTEEN
-        bool '  P9100 (Sparcbook 3 only) support' CONFIG_FB_P9100
-      fi
-      bool '  Leo (ZX) support' CONFIG_FB_LEO
-    fi
-  fi
-  if [ "$ARCH" = "sparc" ]; then
-    if [ "$CONFIG_PCI" != "n" ]; then
-      bool 'PCI framebuffers' CONFIG_FB_PCI
-      if [ "$CONFIG_FB_PCI" != "n" ]; then
-        bool '  IGA 168x display support' CONFIG_FB_IGA
-      fi
-    fi
-  fi
-  if [ "$ARCH" = "sparc64" ]; then
-    if [ "$CONFIG_PCI" != "n" ]; then
-      bool 'PCI framebuffers' CONFIG_FB_PCI
-      if [ "$CONFIG_FB_PCI" != "n" ]; then
-        tristate '  ATI Mach64 display support' CONFIG_FB_ATY
-      fi
-    fi
-  fi
-  tristate 'Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL
+   define_bool CONFIG_DUMMY_CONSOLE y
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_PCI" = "y" ]; then
+	 tristate '  Cirrus Logic suport (EXPERIMENTAL)' CONFIG_FB_CLGEN
+	 tristate '  Permedia2 support (EXPERIMENTAL)' CONFIG_FB_PM2
+	 if [ "$CONFIG_FB_PM2" = "y" ]; then
+	    if [ "$CONFIG_PCI" = "y" ]; then
+	       bool '    enable FIFO disconnect feature' CONFIG_FB_PM2_FIFO_DISCONNECT
+	       bool '    generic Permedia2 PCI board support' CONFIG_FB_PM2_PCI
+	    fi
+	    if [ "$CONFIG_AMIGA" = "y" ]; then
+	       bool '    Phase5 CVisionPPC/BVisionPPC support' CONFIG_FB_PM2_CVPPC
+	    fi
+	 fi
+      fi
+   fi
+   if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+      bool '  Acorn VIDC support' CONFIG_FB_ACORN
+   fi
+   if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then
+      tristate '  Cyber2000 support' CONFIG_FB_CYBER2000
+   fi
+   if [ "$CONFIG_APOLLO" = "y" ]; then
+      define_bool CONFIG_FB_APOLLO y
+   fi
+   if [ "$CONFIG_Q40" = "y" ]; then
+      define_bool CONFIG_FB_Q40 y
+   fi
+   if [ "$CONFIG_AMIGA" = "y" ]; then
+      bool '  Amiga native chipset support' CONFIG_FB_AMIGA
+      if [ "$CONFIG_FB_AMIGA" != "n" ]; then
+	 bool '    Amiga OCS chipset support' CONFIG_FB_AMIGA_OCS
+	 bool '    Amiga ECS chipset support' CONFIG_FB_AMIGA_ECS
+	 bool '    Amiga AGA chipset support' CONFIG_FB_AMIGA_AGA
+      fi
+   fi
+   if [ "$CONFIG_ZORRO" = "y" ]; then
+      tristate '  Amiga CyberVision support' CONFIG_FB_CYBER
+      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	 bool '  Amiga CyberVision3D support (EXPERIMENTAL)' CONFIG_FB_VIRGE
+	 tristate '  Amiga RetinaZ3 support (EXPERIMENTAL)' CONFIG_FB_RETINAZ3
+	 bool '  Amiga FrameMaster II/Rainbow II support (EXPERIMENTAL)' CONFIG_FB_FM2
+      fi
+   fi
+   if [ "$CONFIG_ATARI" = "y" ]; then
+      bool '  Atari native chipset support' CONFIG_FB_ATARI
+      tristate '  ATI Mach64 display support' CONFIG_FB_ATY
+   fi
+   if [ "$CONFIG_PPC" = "y" ]; then
+      bool '  Open Firmware frame buffer device support' CONFIG_FB_OF
+      if [ "$CONFIG_FB_OF" = "y" ]; then
+	 bool '    Apple "control" display support' CONFIG_FB_CONTROL
+	 bool '    Apple "platinum" display support' CONFIG_FB_PLATINUM
+	 bool '    Apple "valkyrie" display support' CONFIG_FB_VALKYRIE
+	 bool '    IMS Twin Turbo display support' CONFIG_FB_IMSTT
+	 bool '    Chips 65550 display support' CONFIG_FB_CT65550
+	 bool '    S3 Trio display support' CONFIG_FB_S3TRIO
+      fi
+      tristate '  VGA 16-color graphics console' CONFIG_FB_VGA16
+   fi
+   if [ "$CONFIG_MAC" = "y" ]; then
+      define_bool CONFIG_FB_MAC y
+   fi
+   if [ "$CONFIG_HP300" = "y" ]; then
+      define_bool CONFIG_FB_HP300 y
+   fi
+   if [ "$ARCH" = "alpha" ]; then
+      tristate '  TGA framebuffer support' CONFIG_FB_TGA
+   fi
+   if [ "$ARCH" = "i386" ]; then
+      bool '  VESA VGA graphics console' CONFIG_FB_VESA
+      tristate '  VGA 16-color graphics console' CONFIG_FB_VGA16
+      define_bool CONFIG_VIDEO_SELECT y
+   fi
+   if [ "$CONFIG_VISWS" = "y" ]; then
+      tristate '  SGI Visual Workstation framebuffer support' CONFIG_FB_SGIVW
+      define_bool CONFIG_BUS_I2C y
+   fi
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      if [ "$CONFIG_PCI" != "n" ]; then
+	 tristate '  Matrox acceleration (EXPERIMENTAL)' CONFIG_FB_MATROX
+	 if [ "$CONFIG_FB_MATROX" != "n" ]; then
+	    bool '    Millennium I/II support' CONFIG_FB_MATROX_MILLENIUM
+	    bool '    Mystique support' CONFIG_FB_MATROX_MYSTIQUE
+	    bool '    G100/G200/G400 support' CONFIG_FB_MATROX_G100
+	    bool '    Multihead support' CONFIG_FB_MATROX_MULTIHEAD
+	 fi
+	 tristate '  ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY
+	 bool '  3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX
+      fi
+   fi
+   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+      bool '  SBUS and UPA framebuffers' CONFIG_FB_SBUS
+      if [ "$CONFIG_FB_SBUS" != "n" ]; then
+	 if [ "$ARCH" = "sparc64" ]; then
+	    bool '    Creator/Creator3D support' CONFIG_FB_CREATOR
+	 fi
+	 bool '    CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX
+	 bool '    BWtwo support' CONFIG_FB_BWTWO
+	 bool '    CGthree support' CONFIG_FB_CGTHREE
+	 if [ "$ARCH" = "sparc" ]; then
+	    bool '    TCX (SS4/SS5 only) support' CONFIG_FB_TCX
+	    bool '    CGfourteen (SX) support' CONFIG_FB_CGFOURTEEN
+	    bool '    P9100 (Sparcbook 3 only) support' CONFIG_FB_P9100
+	 fi
+	 bool '    Leo (ZX) support' CONFIG_FB_LEO
+      fi
+   fi
+   if [ "$ARCH" = "sparc" ]; then
+      if [ "$CONFIG_PCI" != "n" ]; then
+	 bool '  PCI framebuffers' CONFIG_FB_PCI
+	 if [ "$CONFIG_FB_PCI" != "n" ]; then
+	    bool '    IGA 168x display support' CONFIG_FB_IGA
+	 fi
+      fi
+   fi
+   if [ "$ARCH" = "sparc64" ]; then
+      if [ "$CONFIG_PCI" != "n" ]; then
+	 bool '  PCI framebuffers' CONFIG_FB_PCI
+	 if [ "$CONFIG_FB_PCI" != "n" ]; then
+	    tristate '    ATI Mach64 display support' CONFIG_FB_ATY
+	 fi
+      fi
+   fi
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate '  Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL
+   fi
 
-  bool 'Advanced low level driver options' CONFIG_FBCON_ADVANCED
-  if [ "$CONFIG_FBCON_ADVANCED" = "y" ]; then
-    tristate 'Monochrome support' CONFIG_FBCON_MFB
-    tristate '2 bpp packed pixels support' CONFIG_FBCON_CFB2
-    tristate '4 bpp packed pixels support' CONFIG_FBCON_CFB4
-    tristate '8 bpp packed pixels support' CONFIG_FBCON_CFB8
-    tristate '16 bpp packed pixels support' CONFIG_FBCON_CFB16
-    tristate '24 bpp packed pixels support' CONFIG_FBCON_CFB24
-    tristate '32 bpp packed pixels support' CONFIG_FBCON_CFB32
-    tristate 'Amiga bitplanes support' CONFIG_FBCON_AFB
-    tristate 'Amiga interleaved bitplanes support' CONFIG_FBCON_ILBM
-    tristate 'Atari interleaved bitplanes (2 planes) support' CONFIG_FBCON_IPLAN2P2
-    tristate 'Atari interleaved bitplanes (4 planes) support' CONFIG_FBCON_IPLAN2P4
-    tristate 'Atari interleaved bitplanes (8 planes) support' CONFIG_FBCON_IPLAN2P8
-#   tristate 'Atari interleaved bitplanes (16 planes) support' CONFIG_FBCON_IPLAN2P16
-    tristate 'Mac variable bpp packed pixels support' CONFIG_FBCON_MAC
-    tristate 'VGA 16-color planar support' CONFIG_FBCON_VGA_PLANES
-    tristate 'VGA characters/attributes support' CONFIG_FBCON_VGA
-  else
-    # Guess what we need
-    if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_AMIGA" = "y" -o \
-	 "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
-	 "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_RETINAZ3" = "y" -o \
-	 "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
-	 "$CONFIG_FB_BWTWO" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then
-      define_bool CONFIG_FBCON_MFB y
-    else
-      if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_AMIGA" = "m" -o \
-	   "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
-	   "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_RETINAZ3" = "m" -o \
-	   "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
-	   "$CONFIG_FB_BWTWO" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then
-	define_bool CONFIG_FBCON_MFB m
-      fi
-    fi
-    if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
-	 "$CONFIG_FB_VIRTUAL" = "y" ]; then
-      define_bool CONFIG_FBCON_CFB2 y
-      define_bool CONFIG_FBCON_CFB4 y
-    else
-      if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_MAC" = "m" -o \
-	   "$CONFIG_FB_VIRTUAL" = "m" ]; then
-	define_bool CONFIG_FBCON_CFB2 m
-	define_bool CONFIG_FBCON_CFB4 m
-      fi
-    fi
-    if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_ATARI" = "y" -o \
-	 "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
-	 "$CONFIG_FB_OF" = "y" -o "$CONFIG_FB_TGA" = "y" -o \
-	 "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
-	 "$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \
-	 "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
-	 "$CONFIG_FB_CGFOURTEEN" = "y" -o "$CONFIG_FB_G364" = "y" -o \
-	 "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
-	 "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
-         "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
-	 "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
-	 "$CONFIG_FB_P9100" = "y" -o \
-	 "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" ]; then
-      define_bool CONFIG_FBCON_CFB8 y
-    else
-      if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
-	   "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_MAC" = "m" -o \
-	   "$CONFIG_FB_OF" = "m" -o "$CONFIG_FB_TGA" = "m" -o \
-	   "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
-	   "$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \
-	   "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
-	   "$CONFIG_FB_CGFOURTEEN" = "m" -o "$CONFIG_FB_G364" = "m" -o \
-	   "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
-	   "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
-           "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
-	   "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
-	   "$CONFIG_FB_P9100" = "m" -o \
-	   "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" ]; then
-	define_bool CONFIG_FBCON_CFB8 m
-      fi
-    fi
-    if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \
-	 "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
-	 "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \
-	 "$CONFIG_FB_Q40" = "y" -o \
-	 "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
-	 "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
-	 "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
-	 "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
-	 "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
-	 "$CONFIG_FB_CYBER2000" = "y" ]; then
-      define_bool CONFIG_FBCON_CFB16 y
-    else
-      if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
-	   "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
-	   "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \
-	 "$CONFIG_FB_Q40" = "m" -o \
-	   "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
-	   "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
- 	   "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
-	   "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
-	   "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "m" -o \
-	   "$CONFIG_FB_CYBER2000" = "m" ]; then
-	define_bool CONFIG_FBCON_CFB16 m
-      fi
-    fi
-    if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
-	 "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
-	  "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
-	 "$CONFIG_FB_CYBER2000" = "y" ]; then
-      define_bool CONFIG_FBCON_CFB24 y
-    else
-      if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
-	   "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
-	   "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
-	   "$CONFIG_FB_CYBER2000" = "m" ]; then
-	define_bool CONFIG_FBCON_CFB24 m
-      fi
-    fi
-    if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \
-	 "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
-	 "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
-	 "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
-	 "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
-	 "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" ]; then
-      define_bool CONFIG_FBCON_CFB32 y
-    else
-      if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
-	   "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
-	   "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
-	   "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
-	   "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
-           "$CONFIG_FB_SGIVW" = "m" ]; then
-	define_bool CONFIG_FBCON_CFB32 m
-      fi
-    fi
-    if [ "$CONFIG_FB_AMIGA" = "y" ]; then
-      define_bool CONFIG_FBCON_AFB y
-      define_bool CONFIG_FBCON_ILBM y
-    else
-      if [ "$CONFIG_FB_AMIGA" = "m" ]; then
-	define_bool CONFIG_FBCON_AFB m
-	define_bool CONFIG_FBCON_ILBM m
-      fi
-    fi
-    if [ "$CONFIG_FB_ATARI" = "y" ]; then
-      define_bool CONFIG_FBCON_IPLAN2P2 y
-      define_bool CONFIG_FBCON_IPLAN2P4 y
-      define_bool CONFIG_FBCON_IPLAN2P8 y
-#     define_bool CONFIG_FBCON_IPLAN2P16 y
-    else
-      if [ "$CONFIG_FB_ATARI" = "m" ]; then
-	define_bool CONFIG_FBCON_IPLAN2P2 m
-	define_bool CONFIG_FBCON_IPLAN2P4 m
-	define_bool CONFIG_FBCON_IPLAN2P8 m
-#	define_bool CONFIG_FBCON_IPLAN2P16 m
-      fi
-    fi
-    if [ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then
-      define_bool CONFIG_FBCON_MAC  y
-    else
-      if [ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
-	define_bool CONFIG_FBCON_MAC  m
-      fi
-    fi
-    if [ "$CONFIG_FB_VGA16" = "y" ]; then
-      define_bool CONFIG_FBCON_VGA_PLANES y
-    else
-      if [ "$CONFIG_FB_VGA16" = "m" ]; then
-	define_bool CONFIG_FBCON_VGA_PLANES m
-      fi
-    fi
-    if [ "$CONFIG_FB_MDA" = "y" -o "$CONFIG_FB_VGA" = "y" ]; then
-      define_bool CONFIG_FBCON_VGA y
-    else
-      if [ "$CONFIG_FB_MDA" = "m" -o "$CONFIG_FB_VGA" = "m" ]; then
-	define_bool CONFIG_FBCON_VGA m
-      fi
-    fi
-  fi
-  bool 'Support only 8 pixels wide fonts' CONFIG_FBCON_FONTWIDTH8_ONLY
-  if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
-    bool 'Sparc console 8x16 font' CONFIG_FONT_SUN8x16
-    if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
-      bool 'Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
-    fi
-    bool 'Select other fonts' CONFIG_FBCON_FONTS
-    if [ "$CONFIG_FBCON_FONTS" = "y" ]; then
-      bool '  VGA 8x8 font' CONFIG_FONT_8x8
-      bool '  VGA 8x16 font' CONFIG_FONT_8x16
-      if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
-        bool '  Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
-      fi
-      bool '  Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8
-      bool '  Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8
-    fi
-  else
-    bool 'Select compiled-in fonts' CONFIG_FBCON_FONTS
-    if [ "$CONFIG_FBCON_FONTS" = "y" ]; then
-      bool '  VGA 8x8 font' CONFIG_FONT_8x8
-      bool '  VGA 8x16 font' CONFIG_FONT_8x16
+   bool '  Advanced low level driver options' CONFIG_FBCON_ADVANCED
+   if [ "$CONFIG_FBCON_ADVANCED" = "y" ]; then
+      tristate '    Monochrome support' CONFIG_FBCON_MFB
+      tristate '    2 bpp packed pixels support' CONFIG_FBCON_CFB2
+      tristate '    4 bpp packed pixels support' CONFIG_FBCON_CFB4
+      tristate '    8 bpp packed pixels support' CONFIG_FBCON_CFB8
+      tristate '    16 bpp packed pixels support' CONFIG_FBCON_CFB16
+      tristate '    24 bpp packed pixels support' CONFIG_FBCON_CFB24
+      tristate '    32 bpp packed pixels support' CONFIG_FBCON_CFB32
+      tristate '    Amiga bitplanes support' CONFIG_FBCON_AFB
+      tristate '    Amiga interleaved bitplanes support' CONFIG_FBCON_ILBM
+      tristate '    Atari interleaved bitplanes (2 planes) support' CONFIG_FBCON_IPLAN2P2
+      tristate '    Atari interleaved bitplanes (4 planes) support' CONFIG_FBCON_IPLAN2P4
+      tristate '    Atari interleaved bitplanes (8 planes) support' CONFIG_FBCON_IPLAN2P8
+#      tristate '    Atari interleaved bitplanes (16 planes) support' CONFIG_FBCON_IPLAN2P16
+      tristate '    Mac variable bpp packed pixels support' CONFIG_FBCON_MAC
+      tristate '    VGA 16-color planar support' CONFIG_FBCON_VGA_PLANES
+      tristate '    VGA characters/attributes support' CONFIG_FBCON_VGA
+   else
+      # Guess what we need
+      if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_AMIGA" = "y" -o \
+	   "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
+	   "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_RETINAZ3" = "y" -o \
+	   "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+	   "$CONFIG_FB_BWTWO" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then
+	 define_bool CONFIG_FBCON_MFB y
+      else
+	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_AMIGA" = "m" -o \
+	      "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
+	      "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_RETINAZ3" = "m" -o \
+	      "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+	      "$CONFIG_FB_BWTWO" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then
+	    define_bool CONFIG_FBCON_MFB m
+	 fi
+      fi
+      if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
+	   "$CONFIG_FB_VIRTUAL" = "y" ]; then
+	 define_bool CONFIG_FBCON_CFB2 y
+	 define_bool CONFIG_FBCON_CFB4 y
+      else
+	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_MAC" = "m" -o \
+	      "$CONFIG_FB_VIRTUAL" = "m" ]; then
+	    define_bool CONFIG_FBCON_CFB2 m
+	    define_bool CONFIG_FBCON_CFB4 m
+	 fi
+      fi
+      if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_ATARI" = "y" -o \
+	   "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
+	   "$CONFIG_FB_OF" = "y" -o "$CONFIG_FB_TGA" = "y" -o \
+	   "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+	   "$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \
+	   "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
+	   "$CONFIG_FB_CGFOURTEEN" = "y" -o "$CONFIG_FB_G364" = "y" -o \
+	   "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
+	   "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
+           "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
+	   "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
+	   "$CONFIG_FB_P9100" = "y" -o \
+	   "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \
+	   "$CONFIG_FB_3DFX" = "y" ]; then
+	 define_bool CONFIG_FBCON_CFB8 y
+      else
+	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
+	      "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_MAC" = "m" -o \
+	      "$CONFIG_FB_OF" = "m" -o "$CONFIG_FB_TGA" = "m" -o \
+	      "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+	      "$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \
+	      "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
+	      "$CONFIG_FB_CGFOURTEEN" = "m" -o "$CONFIG_FB_G364" = "m" -o \
+	      "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
+	      "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
+              "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
+	      "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
+	      "$CONFIG_FB_P9100" = "m" -o \
+	      "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" ]; then
+	    define_bool CONFIG_FBCON_CFB8 m
+	 fi
+      fi
+      if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \
+	   "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
+	   "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \
+	   "$CONFIG_FB_Q40" = "y" -o \
+	   "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
+	   "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
+	   "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
+	   "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
+	   "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
+	   "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y" ]; then
+	 define_bool CONFIG_FBCON_CFB16 y
+      else
+	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
+	      "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
+	      "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \
+	      "$CONFIG_FB_Q40" = "m" -o \
+	      "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
+	      "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
+	      "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
+	      "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
+	      "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "m" -o \
+	      "$CONFIG_FB_CYBER2000" = "m" ]; then
+	    define_bool CONFIG_FBCON_CFB16 m
+	 fi
+      fi
+      if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+	   "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
+	   "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
+	   "$CONFIG_FB_CYBER2000" = "y" ]; then
+	 define_bool CONFIG_FBCON_CFB24 y
+      else
+	 if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+	      "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
+	      "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
+	      "$CONFIG_FB_CYBER2000" = "m" ]; then
+	    define_bool CONFIG_FBCON_CFB24 m
+	 fi
+      fi
+      if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \
+	   "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+	   "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
+	   "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
+	   "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
+	   "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
+	   "$CONFIG_FB_3DFX" = "y" ]; then
+	 define_bool CONFIG_FBCON_CFB32 y
+      else
+	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
+	      "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+	      "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
+	      "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
+	      "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
+              "$CONFIG_FB_SGIVW" = "m" ]; then
+	    define_bool CONFIG_FBCON_CFB32 m
+	 fi
+      fi
+      if [ "$CONFIG_FB_AMIGA" = "y" ]; then
+	 define_bool CONFIG_FBCON_AFB y
+	 define_bool CONFIG_FBCON_ILBM y
+      else
+	 if [ "$CONFIG_FB_AMIGA" = "m" ]; then
+	    define_bool CONFIG_FBCON_AFB m
+	    define_bool CONFIG_FBCON_ILBM m
+	 fi
+      fi
+      if [ "$CONFIG_FB_ATARI" = "y" ]; then
+	 define_bool CONFIG_FBCON_IPLAN2P2 y
+	 define_bool CONFIG_FBCON_IPLAN2P4 y
+	 define_bool CONFIG_FBCON_IPLAN2P8 y
+#	 define_bool CONFIG_FBCON_IPLAN2P16 y
+      else
+	 if [ "$CONFIG_FB_ATARI" = "m" ]; then
+	    define_bool CONFIG_FBCON_IPLAN2P2 m
+	    define_bool CONFIG_FBCON_IPLAN2P4 m
+	    define_bool CONFIG_FBCON_IPLAN2P8 m
+#	    define_bool CONFIG_FBCON_IPLAN2P16 m
+	 fi
+      fi
+      if [ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then
+	 define_bool CONFIG_FBCON_MAC  y
+      else
+	 if [ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
+	    define_bool CONFIG_FBCON_MAC  m
+	 fi
+      fi
+      if [ "$CONFIG_FB_VGA16" = "y" ]; then
+	 define_bool CONFIG_FBCON_VGA_PLANES y
+      else
+	 if [ "$CONFIG_FB_VGA16" = "m" ]; then
+	    define_bool CONFIG_FBCON_VGA_PLANES m
+	 fi
+      fi
+      if [ "$CONFIG_FB_MDA" = "y" -o "$CONFIG_FB_VGA" = "y" ]; then
+	 define_bool CONFIG_FBCON_VGA y
+      else
+	 if [ "$CONFIG_FB_MDA" = "m" -o "$CONFIG_FB_VGA" = "m" ]; then
+	    define_bool CONFIG_FBCON_VGA m
+	 fi
+      fi
+   fi
+   bool '  Support only 8 pixels wide fonts' CONFIG_FBCON_FONTWIDTH8_ONLY
+   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
       bool '  Sparc console 8x16 font' CONFIG_FONT_SUN8x16
       if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
-        bool '  Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
-        bool '  Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
+	 bool '  Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
       fi
-      bool '  Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8
-      bool '  Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8
-    else
-      define_bool CONFIG_FONT_8x8 y
-      define_bool CONFIG_FONT_8x16 y
-      if [ "$CONFIG_MAC" = "y" ]; then
-	if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
-          define_bool CONFIG_FONT_6x11 y
-        fi
+      bool '  Select other fonts' CONFIG_FBCON_FONTS
+      if [ "$CONFIG_FBCON_FONTS" = "y" ]; then
+	 bool '    VGA 8x8 font' CONFIG_FONT_8x8
+	 bool '    VGA 8x16 font' CONFIG_FONT_8x16
+	 if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+	    bool '    Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
+	 fi
+	 bool '    Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8
+	 bool '    Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8
+      fi
+   else
+      bool '  Select compiled-in fonts' CONFIG_FBCON_FONTS
+      if [ "$CONFIG_FBCON_FONTS" = "y" ]; then
+	 bool '    VGA 8x8 font' CONFIG_FONT_8x8
+	 bool '    VGA 8x16 font' CONFIG_FONT_8x16
+	 bool '    Sparc console 8x16 font' CONFIG_FONT_SUN8x16
+	 if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+	    bool '    Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
+	    bool '    Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
+	 fi
+	 bool '    Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8
+	 bool '    Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8
+      else
+	 define_bool CONFIG_FONT_8x8 y
+	 define_bool CONFIG_FONT_8x16 y
+	 if [ "$CONFIG_MAC" = "y" ]; then
+	    if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+	       define_bool CONFIG_FONT_6x11 y
+	    fi
+	 fi
+	 if [ "$CONFIG_AMIGA" = "y" ]; then
+	    define_bool CONFIG_FONT_PEARL_8x8 y
+	 fi
+	 if [ "$CONFIG_ARM" = "y" -a "$CONFIG_ARCH_ACORN" = "y" ]; then
+	    define_bool CONFIG_FONT_ACORN_8x8 y
+	 fi
       fi
-      if [ "$CONFIG_AMIGA" = "y" ]; then
-        define_bool CONFIG_FONT_PEARL_8x8 y
-      fi
-      if [ "$CONFIG_ARM" = "y" -a "$CONFIG_ARCH_ACORN" = "y" ]; then
-        define_bool CONFIG_FONT_ACORN_8x8 y
-      fi
-    fi
-  fi
+   fi
 fi
+
+endmenu
diff -u --recursive --new-file v2.3.20/linux/drivers/video/Makefile linux/drivers/video/Makefile
--- v2.3.20/linux/drivers/video/Makefile	Fri Sep 10 23:57:36 1999
+++ linux/drivers/video/Makefile	Mon Oct 11 10:26:52 1999
@@ -150,11 +150,15 @@
 endif
 
 ifeq ($(CONFIG_FB_SGIVW),y)
-L_OBJS += sgivwfb.o
+LX_OBJS += sgivwfb.o
 else
   ifeq ($(CONFIG_FB_SGIVW),m)
-  M_OBJS += sgivwfb.o
+  MX_OBJS += sgivwfb.o
   endif
+endif
+
+ifeq ($(CONFIG_FB_3DFX),y)
+L_OBJS += tdfxfb.o
 endif
 
 ifeq ($(CONFIG_FB_MAC),y)
diff -u --recursive --new-file v2.3.20/linux/drivers/video/amifb.c linux/drivers/video/amifb.c
--- v2.3.20/linux/drivers/video/amifb.c	Thu Aug 26 13:05:40 1999
+++ linux/drivers/video/amifb.c	Mon Oct 11 10:26:52 1999
@@ -1736,6 +1736,7 @@
 	fb_info.updatevar = &amifbcon_updatevar;
 	fb_info.blank = &amifbcon_blank;
 	fb_info.flags = FBINFO_FLAG_DEFAULT;
+	memset(&var, 0, sizeof(var));
 
 	if (!fb_find_mode(&var, &fb_info, mode_option, ami_modedb,
 			  NUM_TOTAL_MODES, &ami_modedb[defmode], 4))
diff -u --recursive --new-file v2.3.20/linux/drivers/video/aty.h linux/drivers/video/aty.h
--- v2.3.20/linux/drivers/video/aty.h	Mon Aug  9 11:39:37 1999
+++ linux/drivers/video/aty.h	Mon Oct 11 10:26:52 1999
@@ -103,6 +103,8 @@
 
 #define CUSTOM_MACRO_CNTL	0x00D4	/* Dword offset 0_35 */
 
+#define POWER_MANAGEMENT	0x00D8	/* Dword offset 0_36 (LG) */
+
 #define CONFIG_CNTL		0x00DC	/* Dword offset 0_37 (CT, ET, VT) */
 #define CONFIG_CHIP_ID		0x00E0	/* Dword offset 0_38 */
 #define CONFIG_STAT0		0x00E4	/* Dword offset 0_39 */
@@ -950,5 +952,16 @@
 
 #define MACH64_NUM_CLOCKS	16
 #define MACH64_NUM_FREQS	50
+
+/* Power Management register constants (LTG and LT Pro) */
+#define PWR_MGT_ON		0x00000001
+#define PWR_MGT_MODE_MASK	0x00000006
+#define AUTO_PWR_UP		0x00000008
+#define SELF_REFRESH		0x00000080
+#define PWR_BLON		0x02000000
+#define STANDBY_NOW		0x10000000
+#define SUSPEND_NOW		0x20000000
+#define PWR_MGT_STATUS_MASK	0xC0000000
+#define PWR_MGT_STATUS_SUSPEND	0x80000000
 
 #endif /* REGMACH64_H */
diff -u --recursive --new-file v2.3.20/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c
--- v2.3.20/linux/drivers/video/atyfb.c	Fri Sep 10 23:57:36 1999
+++ linux/drivers/video/atyfb.c	Mon Oct 11 10:26:52 1999
@@ -1,4 +1,4 @@
-/*  $Id: atyfb.c,v 1.122 1999/09/06 20:44:08 geert Exp $
+/*  $Id: atyfb.c,v 1.126 1999/09/16 18:46:23 geert Exp $
  *  linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
  *
  *	Copyright (C) 1997-1998  Geert Uytterhoeven
@@ -52,7 +52,6 @@
 #include <linux/console.h>
 #include <linux/init.h>
 #include <linux/pci.h>
-#include <linux/nvram.h>
 #include <linux/kd.h>
 #include <linux/vt_kern.h>
 
@@ -62,12 +61,15 @@
 
 #include <asm/io.h>
 
-#if defined(CONFIG_PPC)
+#ifdef __powerpc__
+#include <linux/adb.h>
+#include <linux/pmu.h>
 #include <asm/prom.h>
 #include <asm/pci-bridge.h>
 #include <video/macmodes.h>
-#include <asm/adb.h>
-#include <asm/pmu.h>
+#endif
+#ifdef CONFIG_NVRAM
+#include <linux/nvram.h>
 #endif
 #ifdef __sparc__
 #include <asm/pbm.h>
@@ -272,8 +274,20 @@
     int vtconsole;
     int consolecnt;
 #endif
+#ifdef CONFIG_PMAC_PBOOK
+    unsigned char *save_framebuffer;
+    unsigned long save_pll[64];
+#endif
 };
 
+#ifdef CONFIG_PMAC_PBOOK
+  int aty_sleep_notify(struct pmu_sleep_notifier *self, int when);
+  static struct pmu_sleep_notifier aty_sleep_notifier = {
+  	aty_sleep_notify, SLEEP_LEVEL_VIDEO,
+  };
+  static struct fb_info_aty* first_display = NULL;
+#endif
+
 
     /*
      *  Frame buffer device API
@@ -446,7 +460,7 @@
 static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 			 u_int transp, struct fb_info *fb);
 static void do_install_cmap(int con, struct fb_info *info);
-#if defined(CONFIG_PPC)
+#ifdef CONFIG_PMAC
 static int read_aty_sense(const struct fb_info_aty *info);
 #endif
 
@@ -488,9 +502,14 @@
 static const char *mode_option __initdata = NULL;
 #endif
 
-#if defined(CONFIG_PPC)
+#ifdef CONFIG_PMAC
+#ifdef CONFIG_NVRAM
 static int default_vmode __initdata = VMODE_NVRAM;
 static int default_cmode __initdata = CMODE_NVRAM;
+#else
+static int default_vmode __initdata = VMODE_CHOOSE;
+static int default_cmode __initdata = CMODE_CHOOSE;
+#endif
 #endif
 
 #ifdef CONFIG_ATARI
@@ -550,58 +569,46 @@
 static inline u32 aty_ld_le32(unsigned int regindex,
 			      const struct fb_info_aty *info)
 {
+#if defined(__powerpc__)
     unsigned long temp;
     u32 val;
 
-#if defined(__powerpc__)
     temp = info->ati_regbase;
     asm volatile("lwbrx %0,%1,%2" : "=r"(val) : "b" (regindex), "r" (temp));
-#elif defined(__sparc_v9__)
-    temp = info->ati_regbase + regindex;
-    val = readl(temp);
+    return val;
+#elif defined(__mc68000__)
+    return le32_to_cpu(*((volatile u32 *)(info->ati_regbase+regindex)));
 #else
-    temp = info->ati_regbase+regindex;
-    val = le32_to_cpu(*((volatile u32 *)(temp)));
+    return readl (info->ati_regbase + regindex);
 #endif
-    return val;
 }
 
 static inline void aty_st_le32(unsigned int regindex, u32 val,
 			       const struct fb_info_aty *info)
 {
+#if defined(__powerpc__)
     unsigned long temp;
 
-#if defined(__powerpc__)
     temp = info->ati_regbase;
     asm volatile("stwbrx %0,%1,%2" : : "r" (val), "b" (regindex), "r" (temp) :
 	"memory");
-#elif defined(__sparc_v9__)
-    temp = info->ati_regbase + regindex;
-    writel(val, temp);
+#elif defined(__mc68000__)
+    *((volatile u32 *)(info->ati_regbase+regindex)) = cpu_to_le32(val);
 #else
-    temp = info->ati_regbase+regindex;
-    *((volatile u32 *)(temp)) = cpu_to_le32(val);
+    writel (val, info->ati_regbase + regindex);
 #endif
 }
 
 static inline u8 aty_ld_8(unsigned int regindex,
 			  const struct fb_info_aty *info)
 {
-#ifdef __sparc_v9__
-    return readb(info->ati_regbase + regindex);
-#else
-    return *(volatile u8 *)(info->ati_regbase+regindex);
-#endif
+    return readb (info->ati_regbase + regindex);
 }
 
 static inline void aty_st_8(unsigned int regindex, u8 val,
 			    const struct fb_info_aty *info)
 {
-#ifdef __sparc_v9__
-    writeb(val, info->ati_regbase + regindex);
-#else
-    *(volatile u8 *)(info->ati_regbase+regindex) = val;
-#endif
+    writeb (val, info->ati_regbase + regindex);
 }
 
 
@@ -791,7 +798,7 @@
     return res;
 }
 
-#if defined(CONFIG_PPC)
+#ifdef CONFIG_PMAC
 
     /*
      *  Apple monitor sense
@@ -831,7 +838,7 @@
     return sense;
 }
 
-#endif /* defined(CONFIG_PPC) */
+#endif /* CONFIG_PMAC */
 
 /* ------------------------------------------------------------------------- */
 
@@ -903,17 +910,19 @@
 		for (x = 0; x < c->size.x >> 2; x++) {
 			m = c->mask[x][y];
 			b = c->bits[x][y];
-			*ram++ = cursor_mask_lookup[m >> 4] |
-				 cursor_bits_lookup[(b & m) >> 4];
-			*ram++ = cursor_mask_lookup[m & 0x0f] |
-				 cursor_bits_lookup[(b & m) & 0x0f];
+			fb_writeb (cursor_mask_lookup[m >> 4] |
+				   cursor_bits_lookup[(b & m) >> 4],
+				   ram++);
+			fb_writeb (cursor_mask_lookup[m & 0x0f] |
+				   cursor_bits_lookup[(b & m) & 0x0f],
+				   ram++);
 		}
 		for ( ; x < 8; x++) {
-			*ram++ = 0xaa;
-			*ram++ = 0xaa;
+			fb_writeb (0xaa, ram++);
+			fb_writeb (0xaa, ram++);
 		}
 	}
-	memset(ram, 0xaa, (64 - c->size.y) * 16);
+	fb_memset (ram, 0xaa, (64 - c->size.y) * 16);
 }
 
 static void
@@ -3239,7 +3248,7 @@
     struct display *disp;
     const char *chipname = NULL, *ramname = NULL, *xtal;
     int pll, mclk, gtb_memsize;
-#if defined(CONFIG_PPC)
+#ifdef CONFIG_PMAC
     int sense;
 #endif
     u8 pll_ref_div;
@@ -3501,16 +3510,22 @@
     var = default_var;
 #else /* !MODULE */
     memset(&var, 0, sizeof(var));
-#if defined(CONFIG_PPC)
+#ifdef CONFIG_PMAC
+    /*
+     *  FIXME: The NVRAM stuff should be put in a Mac-specific file, as it
+     *         applies to all Mac video cards
+     */
     if (mode_option) {
 	if (!mac_find_mode(&var, &info->fb_info, mode_option, 8))
 	    var = default_var;
     } else {
+#ifdef CONFIG_NVRAM
 	if (default_vmode == VMODE_NVRAM) {
 	    default_vmode = nvram_read_byte(NV_VMODE);
 	    if (default_vmode <= 0 || default_vmode > VMODE_MAX)
 		default_vmode = VMODE_CHOOSE;
 	}
+#endif
 	if (default_vmode == VMODE_CHOOSE) {
 	    if (Gx == LG_CHIP_ID)
 		/* G3 PowerBook with 1024x768 LCD */
@@ -3522,14 +3537,16 @@
 	}
 	if (default_vmode <= 0 || default_vmode > VMODE_MAX)
 	    default_vmode = VMODE_640_480_60;
+#ifdef CONFIG_NVRAM
 	if (default_cmode == CMODE_NVRAM)
 	    default_cmode = nvram_read_byte(NV_CMODE);
+#endif
 	if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
 	    default_cmode = CMODE_8;
 	if (mac_vmode_to_var(default_vmode, default_cmode, &var))
 	    var = default_var;
     }
-#else /* !CONFIG_PPC */
+#else /* !CONFIG_PMAC */
 #ifdef __sparc__
     if (mode_option) {
     	if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, NULL, 8))
@@ -3540,7 +3557,7 @@
     if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, NULL, 8))
 	var = default_var;
 #endif /* !__sparc__ */
-#endif /* !CONFIG_PPC */
+#endif /* !CONFIG_PMAC */
 #endif /* !MODULE */
     if (noaccel)
         var.accel_flags &= ~FB_ACCELF_TEXT;
@@ -3964,6 +3981,13 @@
     struct fb_info_aty *info;
     int i;
 
+    if (device_is_compatible(dp, "ATY,264LTPro")) {
+	/* XXX kludge for now */
+	if (dp->name == 0 || strcmp(dp->name, "ATY,264LTProA") != 0
+	    || dp->parent == 0)
+	    return;
+	dp = dp->parent;
+    }
     switch (dp->n_addrs) {
 	case 1:
 	case 2:
@@ -4032,6 +4056,14 @@
 	return;
     }
 
+#ifdef CONFIG_PMAC_PBOOK
+    if (first_display == NULL)
+	pmu_register_sleep_notifier(&aty_sleep_notifier);
+    info->next = first_display;
+    first_display = info;
+#endif
+	
+
 #ifdef CONFIG_FB_COMPAT_XPMAC
     if (!console_fb_info)
 	console_fb_info = &info->fb_info;
@@ -4070,7 +4102,7 @@
 		default_pll = simple_strtoul(this_opt+4, NULL, 0);
 	else if (!strncmp(this_opt, "mclk:", 5))
 		default_mclk = simple_strtoul(this_opt+5, NULL, 0);
-#if defined(CONFIG_PPC)
+#ifdef CONFIG_PMAC
 	else if (!strncmp(this_opt, "vmode:", 6)) {
 	    unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
 	    if (vmode > 0 && vmode <= VMODE_MAX)
@@ -4207,7 +4239,7 @@
     struct fb_info_aty *info = (struct fb_info_aty *)fb;
     u8 gen_cntl;
 
-#if defined(CONFIG_PPC)
+#ifdef CONFIG_PMAC
     if ((_machine == _MACH_Pmac) && blank)
     	pmu_enable_backlight(0);
 #endif
@@ -4232,7 +4264,7 @@
 	gen_cntl &= ~(0x4c);
     aty_st_8(CRTC_GEN_CNTL, gen_cntl, info);
 
-#if defined(CONFIG_PPC)
+#ifdef CONFIG_PMAC
     if ((_machine == _MACH_Pmac) && !blank)
     	pmu_enable_backlight(1);
 #endif
@@ -4735,6 +4767,98 @@
     FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * Save the contents of the frame buffer when we go to sleep,
+ * and restore it when we wake up again.
+ */
+int
+aty_sleep_notify(struct pmu_sleep_notifier *self, int when)
+{
+	struct fb_info_aty *info;
+ 	unsigned int pm;
+ 	
+	for (info = first_display; info != NULL; info = info->next) {
+		struct fb_fix_screeninfo fix;
+		int nb;
+		
+		atyfb_get_fix(&fix, fg_console, (struct fb_info *)info);
+		nb = fb_display[fg_console].var.yres * fix.line_length;
+
+		switch (when) {
+		case PBOOK_SLEEP_NOW:
+			/* Stop accel engine (stop bus mastering) */
+			if (info->current_par.accel_flags & FB_ACCELF_TEXT)
+				reset_engine(info);
+#if 1
+			/* Backup fb content */	
+			info->save_framebuffer = vmalloc(nb);
+			if (info->save_framebuffer)
+				memcpy(info->save_framebuffer,
+				       (void *)info->frame_buffer, nb);
+#endif
+			/* Blank display and LCD */				       
+			atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info);			
+			
+			/* Set chip to "suspend" mode. Note: There's an HW bug in the
+			   chip which prevents proper resync on wakeup with automatic
+			   power management, we handle suspend manually using the
+			   following (weird) sequence described by ATI. Note2:
+			   We could enable this for all Rage LT Pro chip ids */
+			if ((Gx == LG_CHIP_ID) || (Gx == LT_CHIP_ID) || (Gx == LP_CHIP_ID)) {
+				pm = aty_ld_le32(POWER_MANAGEMENT, info);
+				pm &= ~PWR_MGT_ON;
+				aty_st_le32(POWER_MANAGEMENT, pm, info);
+				pm = aty_ld_le32(POWER_MANAGEMENT, info);
+				pm &= ~(PWR_BLON | AUTO_PWR_UP);
+				pm |= SUSPEND_NOW;
+				aty_st_le32(POWER_MANAGEMENT, pm, info);
+				pm = aty_ld_le32(POWER_MANAGEMENT, info);
+				pm |= PWR_MGT_ON;
+				aty_st_le32(POWER_MANAGEMENT, pm, info);
+				do {
+					pm = aty_ld_le32(POWER_MANAGEMENT, info);
+				} while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND);
+				mdelay(500);
+			}
+			break;
+		case PBOOK_WAKE:
+			/* Wakeup chip */
+			if ((Gx == LG_CHIP_ID) || (Gx == LT_CHIP_ID) || (Gx == LP_CHIP_ID)) {
+				pm = aty_ld_le32(POWER_MANAGEMENT, info);
+				pm &= ~PWR_MGT_ON;
+				aty_st_le32(POWER_MANAGEMENT, pm, info);
+				pm = aty_ld_le32(POWER_MANAGEMENT, info);
+				pm |=  (PWR_BLON | AUTO_PWR_UP);
+				pm &= ~SUSPEND_NOW;
+				aty_st_le32(POWER_MANAGEMENT, pm, info);
+				pm = aty_ld_le32(POWER_MANAGEMENT, info);
+				pm |= PWR_MGT_ON;
+				aty_st_le32(POWER_MANAGEMENT, pm, info);
+				do {
+					pm = aty_ld_le32(POWER_MANAGEMENT, info);
+				} while ((pm & PWR_MGT_STATUS_MASK) != 0);
+				mdelay(500);
+			}
+#if 1
+			/* Restore fb content */			
+			if (info->save_framebuffer) {
+				memcpy((void *)info->frame_buffer,
+				       info->save_framebuffer, nb);
+				vfree(info->save_framebuffer);
+				info->save_framebuffer = 0;
+			}
+#endif
+			/* Restore display */			
+			atyfb_set_par(&info->current_par, info);
+			atyfbcon_blank(0, (struct fb_info *)info);
+			break;
+		}
+	}
+	return PBOOK_SLEEP_OK;
+}
+#endif /* CONFIG_PMAC_PBOOK */
 
 #ifdef MODULE
 int __init init_module(void)
diff -u --recursive --new-file v2.3.20/linux/drivers/video/chipsfb.c linux/drivers/video/chipsfb.c
--- v2.3.20/linux/drivers/video/chipsfb.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/video/chipsfb.c	Mon Oct 11 10:26:52 1999
@@ -35,8 +35,8 @@
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/pci-bridge.h>
-#include <asm/adb.h>
-#include <asm/pmu.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
 
 #include <video/fbcon.h>
 #include <video/fbcon-cfb8.h>
@@ -103,9 +103,9 @@
 static struct fb_info_chips *all_chips;
 
 #ifdef CONFIG_PMAC_PBOOK
-int chips_sleep_notify(struct notifier_block *, unsigned long, void *);
-static struct notifier_block chips_sleep_notifier = {
-	chips_sleep_notify, NULL, 0
+int chips_sleep_notify(struct pmu_sleep_notifier *self, int when);
+static struct pmu_sleep_notifier chips_sleep_notifier = {
+	chips_sleep_notify, SLEEP_LEVEL_VIDEO,
 };
 #endif
 
@@ -329,8 +329,9 @@
 	out_8(p->io_base + 0x3c9, blue);
 
 #ifdef FBCON_HAS_CFB16
-	if (regno < 16)	p->fbcon_cfb16_cmap[regno] =
-		((red & 0xf8) << 7) | ((green & 0xf8) << 2) | ((blue & 0xf8) >> 3);
+	if (regno < 16)
+		p->fbcon_cfb16_cmap[regno] = ((red & 0xf8) << 7)
+			| ((green & 0xf8) << 2) | ((blue & 0xf8) >> 3);
 #endif
 
 	return 0;
@@ -638,8 +639,7 @@
 
 #ifdef CONFIG_PMAC_PBOOK
 	if (all_chips == NULL)
-		notifier_chain_register(&sleep_notifier_list,
-					&chips_sleep_notifier);
+		pmu_register_sleep_notifier(&chips_sleep_notifier);
 #endif /* CONFIG_PMAC_PBOOK */
 	p->next = all_chips;
 	all_chips = p;
@@ -705,15 +705,26 @@
  * and restore it when we wake up again.
  */
 int
-chips_sleep_notify(struct notifier_block *this, unsigned long code, void *x)
+chips_sleep_notify(struct pmu_sleep_notifier *self, int when)
 {
 	struct fb_info_chips *p;
 
 	for (p = all_chips; p != NULL; p = p->next) {
 		int nb = p->var.yres * p->fix.line_length;
+		int i;
 
-		switch (code) {
-		case PBOOK_SLEEP:
+		switch (when) {
+		case PBOOK_SLEEP_NOW:
+			chipsfb_blank(1, (struct fb_info *)p);
+			/* get the palette from the chip, Xpmac seems
+			   to set it directly in the chip */
+			for (i = 0; i < 256; ++i) {
+				out_8(p->io_base + 0x3c8, i);
+				udelay(1);
+				p->palette[i].red = in_8(p->io_base + 0x3c9);
+				p->palette[i].green = in_8(p->io_base + 0x3c9);
+				p->palette[i].blue = in_8(p->io_base + 0x3c9);
+			}
 			p->save_framebuffer = vmalloc(nb);
 			if (p->save_framebuffer)
 				memcpy(p->save_framebuffer,
@@ -726,9 +737,10 @@
 				vfree(p->save_framebuffer);
 				p->save_framebuffer = 0;
 			}
+			chipsfb_blank(0, (struct fb_info *)p);
 			break;
 		}
 	}
-	return NOTIFY_DONE;
+	return PBOOK_SLEEP_OK;
 }
 #endif /* CONFIG_PMAC_PBOOK */
diff -u --recursive --new-file v2.3.20/linux/drivers/video/controlfb.c linux/drivers/video/controlfb.c
--- v2.3.20/linux/drivers/video/controlfb.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/video/controlfb.c	Mon Oct 11 10:26:52 1999
@@ -43,11 +43,11 @@
 #ifdef CONFIG_FB_COMPAT_XPMAC
 #include <asm/vc_ioctl.h>
 #endif
+#include <linux/adb.h>
+#include <linux/cuda.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/pgtable.h>
-#include <asm/adb.h>
-#include <asm/cuda.h>
 
 #include <video/fbcon.h>
 #include <video/fbcon-cfb8.h>
@@ -702,26 +702,48 @@
 	p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000);
 
 	/* Work out which banks of VRAM we have installed. */
-	/* danj: I guess the card just ignores writes to nonexistant VRAM... */
+	/* According to Andrew Fyfe <bandr@best.com>, the VRAM behaves like so: */
+	/* afyfe: observations from an 8500:
+	 * - with 2M vram in bank 1, it appears at offsets 0, 2M and 4M
+	 * - with 2M vram in bank 2, it appears only at offset 6M
+	 * - with 4M vram, it appears only as a 4M block at offset 0.
+	 */
+
+	/* We know there is something at 2M if there is something at 0M. */
+	out_8(&p->frame_buffer[0x200000], 0xa5);
+	out_8(&p->frame_buffer[0x200001], 0x38);
+	asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x200000]) : "memory" );
+
 	out_8(&p->frame_buffer[0], 0x5a);
 	out_8(&p->frame_buffer[1], 0xc7);
 	asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0]) : "memory" );
-	bank1 = (in_8(&p->frame_buffer[0]) == 0x5a) && (in_8(&p->frame_buffer[1]) == 0xc7);
 
-	out_8(&p->frame_buffer[0x600000], 0xa5);
-	out_8(&p->frame_buffer[0x600001], 0x38);
-	asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x600000]) : "memory" );
-	bank2 = (in_8(&p->frame_buffer[0x600000]) == 0xa5)
-		&& (in_8(&p->frame_buffer[0x600001]) == 0x38);
-	
-	p->total_vram = (bank1 + bank2) * 0x200000;
-	/* If we don't have bank 1 installed, we hope we have bank 2 :-) */
-	p->control_use_bank2 = !bank1;
-	if (p->control_use_bank2) {
+	bank1 =  (in_8(&p->frame_buffer[0x000000]) == 0x5a)
+		&& (in_8(&p->frame_buffer[0x000001]) == 0xc7);
+	bank2 =  (in_8(&p->frame_buffer[0x200000]) == 0xa5)
+		&& (in_8(&p->frame_buffer[0x200001]) == 0x38);
+
+	if(bank2 && !bank1)
+		printk(KERN_INFO "controlfb: Found memory at 2MB but not at 0!  Please contact dan@debian.org\n");
+
+	if(!bank1) {
+		out_8(&p->frame_buffer[0x600000], 0xa5);
+		out_8(&p->frame_buffer[0x600001], 0x38);
+		asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x600000]) : "memory" );
+		bank2 = (in_8(&p->frame_buffer[0x600000]) == 0xa5)
+			&& (in_8(&p->frame_buffer[0x600001]) == 0x38);
+		/* If we don't have bank 1 installed, we hope we have bank 2 :-) */
+		p->control_use_bank2 = 1;
 		p->frame_buffer += 0x600000;
 		p->frame_buffer_phys += 0x600000;
 	}
 	
+	p->total_vram = (bank1 + bank2) * 0x200000;
+	
+	printk(KERN_INFO "controlfb: Memory bank 1 %s, bank 2 %s, total VRAM %dMB\n",
+		bank1 ? "present" : "absent", bank2 ? "present" : "absent",
+		2 * (bank1 + bank2));
+
 	init_control(p);
 }
 
diff -u --recursive --new-file v2.3.20/linux/drivers/video/fbcon-afb.c linux/drivers/video/fbcon-afb.c
--- v2.3.20/linux/drivers/video/fbcon-afb.c	Thu Feb 25 10:02:12 1999
+++ linux/drivers/video/fbcon-afb.c	Mon Oct 11 10:26:52 1999
@@ -178,7 +178,7 @@
 	dest = p->screen_base+dy*fontheight(p)*width;
 	i = p->var.bits_per_pixel;
 	do {
-	    mymemmove(dest, src, height*fontheight(p)*width);
+	    fb_memmove(dest, src, height*fontheight(p)*width);
 	    src += p->next_plane;
 	    dest += p->next_plane;
 	} while (--i);
@@ -191,7 +191,7 @@
 	    dest = dest0;
 	    j = height*fontheight(p);
 	    do {
-	        mymemmove(dest, src, width);
+	        fb_memmove(dest, src, width);
 	        src += p->next_line;
 	        dest += p->next_line;
 	    } while (--j);
@@ -209,7 +209,7 @@
 	    do {
 	        src -= p->next_line;
 	        dest -= p->next_line;
-	        mymemmove(dest, src, width);
+	        fb_memmove(dest, src, width);
 	    } while (--j);
 	    src0 += p->next_plane;
 	    dest0 += p->next_plane;
@@ -233,9 +233,9 @@
 	j = height*fontheight(p);
 	do {
 	    if (bg & 1)
-	        mymemset(dest, width);
+	        fb_memset255(dest, width);
 	    else
-	        mymemclear(dest, width);
+	        fb_memclear(dest, width);
 	    dest += p->next_line;
 	} while (--j);
 	bg >>= 1;
diff -u --recursive --new-file v2.3.20/linux/drivers/video/fbcon-cfb16.c linux/drivers/video/fbcon-cfb16.c
--- v2.3.20/linux/drivers/video/fbcon-cfb16.c	Thu Feb 25 10:02:12 1999
+++ linux/drivers/video/fbcon-cfb16.c	Mon Oct 11 10:26:52 1999
@@ -14,6 +14,7 @@
 #include <linux/console.h>
 #include <linux/string.h>
 #include <linux/fb.h>
+#include <asm/io.h>
 
 #include <video/fbcon.h>
 #include <video/fbcon-cfb16.h>
@@ -46,7 +47,7 @@
     u8 *src, *dst;
 
     if (sx == 0 && dx == 0 && width * fontwidth(p) * 2 == bytes) {
-	mymemmove(p->screen_base + dy * linesize,
+	fb_memmove(p->screen_base + dy * linesize,
 		  p->screen_base + sy * linesize,
 		  height * linesize);
 	return;
@@ -64,7 +65,7 @@
 	src = p->screen_base + sy * linesize + sx;
 	dst = p->screen_base + dy * linesize + dx;
 	for (rows = height * fontheight(p); rows--;) {
-	    mymemmove(dst, src, width);
+	    fb_memmove(dst, src, width);
 	    src += bytes;
 	    dst += bytes;
 	}
@@ -72,7 +73,7 @@
 	src = p->screen_base + (sy+height) * linesize + sx - bytes;
 	dst = p->screen_base + (dy+height) * linesize + dx - bytes;
 	for (rows = height * fontheight(p); rows--;) {
-	    mymemmove(dst, src, width);
+	    fb_memmove(dst, src, width);
 	    src -= bytes;
 	    dst -= bytes;
 	}
@@ -89,13 +90,13 @@
     while (height-- > 0) {
 	u32 *p = (u32 *)dest;
 	for (i = 0; i < width/4; i++) {
-	    *p++ = data;
-	    *p++ = data;
+	    fb_writel(data, p++);
+	    fb_writel(data, p++);
 	}
 	if (width & 2)
-	    *p++ = data;
+	    fb_writel(data, p++);
 	if (width & 1)
-	    *(u16 *)p = data;
+	    fb_writew(data, (u16*)p);
 	dest += linesize;
     }
 }
@@ -139,11 +140,11 @@
 	cdat = p->fontdata + (c & p->charmask) * fontheight(p);
 	for (rows = fontheight(p); rows--; dest += bytes) {
 	    bits = *cdat++;
-	    ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
-	    ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+	    fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest);
+	    fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest+4);
 	    if (fontwidth(p) == 8) {
-		((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
-		((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+		fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest+8);
+		fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest+12);
 	    }
 	}
 	break;
@@ -152,16 +153,16 @@
 	cdat = p->fontdata + ((c & p->charmask) * fontheight(p) << 1);
 	for (rows = fontheight(p); rows--; dest += bytes) {
 	    bits = *cdat++;
-	    ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
-	    ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
-	    ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
-	    ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+	    fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest);
+	    fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest+4);
+	    fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest+8);
+	    fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest+12);
 	    bits = *cdat++;
-	    ((u32 *)dest)[4] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
-	    ((u32 *)dest)[5] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+	    fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest+16);
+	    fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest+20);
 	    if (fontwidth(p) == 16) {
-		((u32 *)dest)[6] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
-		((u32 *)dest)[7] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+		fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest+24);
+		fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest+28);
 	    }
 	}
 	break;
@@ -191,11 +192,11 @@
 	    cdat = p->fontdata + c * fontheight(p);
 	    for (rows = fontheight(p), dest = dest0; rows--; dest += bytes) {
 		u8 bits = *cdat++;
-		((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
-		((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+	        fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest);
+	        fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest+4);
 		if (fontwidth(p) == 8) {
-		    ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
-		    ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+		    fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest+8);
+		    fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest+12);
 		}
 	    }
 	    dest0 += fontwidth(p)*2;;
@@ -208,16 +209,16 @@
 	    cdat = p->fontdata + (c * fontheight(p) << 1);
 	    for (rows = fontheight(p), dest = dest0; rows--; dest += bytes) {
 		u8 bits = *cdat++;
-		((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
-		((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
-		((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
-		((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+	        fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest);
+	        fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest+4);
+	        fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest+8);
+	        fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest+12);
 		bits = *cdat++;
-		((u32 *)dest)[4] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
-		((u32 *)dest)[5] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+	        fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest+16);
+	        fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest+20);
 		if (fontwidth(p) == 16) {
-		    ((u32 *)dest)[6] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
-		    ((u32 *)dest)[7] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+		    fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest+24);
+		    fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest+28);
 		}
 	    }
 	    dest0 += fontwidth(p)*2;
@@ -235,16 +236,20 @@
     for (rows = fontheight(p); rows--; dest += bytes) {
 	switch (fontwidth(p)) {
 	case 16:
-	    ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff;
+	    fb_writel(fb_readl(dest+24) ^ 0xffffffff, dest+24);
+	    fb_writel(fb_readl(dest+28) ^ 0xffffffff, dest+28);
 	    /* FALL THROUGH */
 	case 12:
-	    ((u32 *)dest)[4] ^= 0xffffffff; ((u32 *)dest)[5] ^= 0xffffffff;
+	    fb_writel(fb_readl(dest+16) ^ 0xffffffff, dest+16);
+	    fb_writel(fb_readl(dest+20) ^ 0xffffffff, dest+20);
 	    /* FALL THROUGH */
 	case 8:
-	    ((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff;
+	    fb_writel(fb_readl(dest+8) ^ 0xffffffff, dest+8);
+	    fb_writel(fb_readl(dest+12) ^ 0xffffffff, dest+12);
 	    /* FALL THROUGH */
 	case 4:
-	    ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
+	    fb_writel(fb_readl(dest+0) ^ 0xffffffff, dest+0);
+	    fb_writel(fb_readl(dest+4) ^ 0xffffffff, dest+4);
 	}
     }
 }
diff -u --recursive --new-file v2.3.20/linux/drivers/video/fbcon-cfb2.c linux/drivers/video/fbcon-cfb2.c
--- v2.3.20/linux/drivers/video/fbcon-cfb2.c	Wed Apr 28 08:48:45 1999
+++ linux/drivers/video/fbcon-cfb2.c	Mon Oct 11 10:26:52 1999
@@ -61,7 +61,7 @@
 	u8 *src,*dst;
 
 	if (sx == 0 && dx == 0 && width * 2 == bytes) {
-		mymemmove(p->screen_base + dy * linesize,
+		fb_memmove(p->screen_base + dy * linesize,
 			  p->screen_base + sy * linesize,
 			  height * linesize);
 	}
@@ -70,7 +70,7 @@
 			src = p->screen_base + sy * linesize + sx * 2;
 			dst = p->screen_base + dy * linesize + dx * 2;
 			for (rows = height * fontheight(p) ; rows-- ;) {
-				mymemmove(dst, src, width * 2);
+				fb_memmove(dst, src, width * 2);
 				src += bytes;
 				dst += bytes;
 			}
@@ -81,7 +81,7 @@
 			dst = p->screen_base + (dy+height) * linesize + dx * 2
 				- bytes;
 			for (rows = height * fontheight(p) ; rows-- ;) {
-				mymemmove(dst, src, width * 2);
+				fb_memmove(dst, src, width * 2);
 				src -= bytes;
 				dst -= bytes;
 			}
@@ -105,7 +105,7 @@
 
 	if (sx == 0 && width * 2 == bytes) {
 		for (i = 0 ; i < lines * width ; i++) {
-			((u16 *)dest)[0]=bgx;
+			fb_writew (bgx, dest);
 			dest+=2;
 		}
 	} else {
@@ -114,7 +114,7 @@
 			dest=dest0;
 			for (i = 0 ; i < width ; i++) {
 				/* memset ?? */
-				((u16 *)dest)[0]=bgx;
+				fb_writew (bgx, dest);
 				dest+=2;
 			}
 		}
@@ -140,10 +140,8 @@
 	eorx = fgx ^ bgx;
 
 	for (rows = fontheight(p) ; rows-- ; dest += bytes) {
-		((u8 *)dest)[0]=
-			(nibbletab_cfb2[*cdat >> 4] & eorx) ^ bgx;
-		((u8 *)dest)[1]=
-			(nibbletab_cfb2[*cdat++ & 0xf] & eorx) ^ bgx;
+		fb_writeb((nibbletab_cfb2[*cdat >> 4] & eorx) ^ bgx, dest+0);
+		fb_writeb((nibbletab_cfb2[*cdat++ & 0xf] & eorx) ^ bgx, dest+1);
 	}
 }
 
@@ -168,10 +166,8 @@
 		cdat = p->fontdata + c * fontheight(p);
 
 		for (rows = fontheight(p), dest = dest0; rows-- ; dest += bytes) {
-			((u8 *)dest)[0]=
-				(nibbletab_cfb2[*cdat >> 4] & eorx) ^ bgx;
-			((u8 *)dest)[1]=
-				(nibbletab_cfb2[*cdat++ & 0xf] & eorx) ^ bgx;
+			fb_writeb((nibbletab_cfb2[*cdat >> 4] & eorx) ^ bgx, dest+0);
+			fb_writeb((nibbletab_cfb2[*cdat++ & 0xf] & eorx) ^ bgx, dest+1);
 		}
 		dest0+=2;
 	}
@@ -184,7 +180,7 @@
 
 	dest = p->screen_base + yy * fontheight(p) * bytes + xx * 2;
 	for (rows = fontheight(p) ; rows-- ; dest += bytes) {
-		((u16 *)dest)[0] ^= 0xffff;
+		fb_writew(fb_readw(dest) ^ 0xffff, dest);
 	}
 }
 
diff -u --recursive --new-file v2.3.20/linux/drivers/video/fbcon-cfb24.c linux/drivers/video/fbcon-cfb24.c
--- v2.3.20/linux/drivers/video/fbcon-cfb24.c	Thu Feb 25 10:02:12 1999
+++ linux/drivers/video/fbcon-cfb24.c	Mon Oct 11 10:26:52 1999
@@ -36,7 +36,7 @@
     u8 *src, *dst;
 
     if (sx == 0 && dx == 0 && width * fontwidth(p) * 3 == bytes) {
-	mymemmove(p->screen_base + dy * linesize,
+	fb_memmove(p->screen_base + dy * linesize,
 		  p->screen_base + sy * linesize,
 		  height * linesize);
 	return;
@@ -55,7 +55,7 @@
 	src = p->screen_base + sy * linesize + sx;
 	dst = p->screen_base + dy * linesize + dx;
 	for (rows = height * fontheight(p); rows--;) {
-	    mymemmove(dst, src, width);
+	    fb_memmove(dst, src, width);
 	    src += bytes;
 	    dst += bytes;
 	}
@@ -63,7 +63,7 @@
 	src = p->screen_base + (sy+height) * linesize + sx - bytes;
 	dst = p->screen_base + (dy+height) * linesize + dx - bytes;
 	for (rows = height * fontheight(p); rows--;) {
-	    mymemmove(dst, src, width);
+	    fb_memmove(dst, src, width);
 	    src -= bytes;
 	    dst -= bytes;
 	}
@@ -90,7 +90,11 @@
 
 static inline void store4pixels(u32 d1, u32 d2, u32 d3, u32 d4, u32 *dest)
 {
-    convert4to3(d1, d2, d3, d4, *dest++, *dest++, *dest++);
+    u32 o1, o2, o3;
+    convert4to3(d1, d2, d3, d4, o1, o2, o3);
+    fb_writel (o1, dest++);
+    fb_writel (o2, dest++);
+    fb_writel (o3, dest);
 }
 
 static inline void rectfill(u8 *dest, int width, int height, u32 data,
@@ -103,9 +107,9 @@
     while (height-- > 0) {
 	u32 *p = (u32 *)dest;
 	for (i = 0; i < width/4; i++) {
-	    *p++ = d1;
-	    *p++ = d2;
-	    *p++ = d3;
+	    fb_writel(d1, p++);
+	    fb_writel(d2, p++);
+	    fb_writel(d3, p++);
 	}
 	dest += linesize;
     }
@@ -174,7 +178,7 @@
 	d2 = (-(bits >> 2 & 1) & eorx) ^ bgx;
 	d3 = (-(bits >> 1 & 1) & eorx) ^ bgx;
 	d4 = (-(bits & 1) & eorx) ^ bgx;
-	store4pixels(d1, d2, d3, d4, (u32 *)(dest+32));
+	store4pixels(d1, d2, d3, d4, (u32 *)(dest+36));
     }
 }
 
@@ -225,7 +229,7 @@
 	    d2 = (-(bits >> 2 & 1) & eorx) ^ bgx;
 	    d3 = (-(bits >> 1 & 1) & eorx) ^ bgx;
 	    d4 = (-(bits & 1) & eorx) ^ bgx;
-	    store4pixels(d1, d2, d3, d4, (u32 *)(dest+32));
+	    store4pixels(d1, d2, d3, d4, (u32 *)(dest+36));
 	}
 	dest0 += fontwidth(p)*3;
     }
@@ -240,17 +244,24 @@
     for (rows = fontheight(p); rows--; dest += bytes) {
 	switch (fontwidth(p)) {
 	case 16:
-	    ((u32 *)dest)[9] ^= 0xffffffff; ((u32 *)dest)[10] ^= 0xffffffff;
-	    ((u32 *)dest)[11] ^= 0xffffffff;	/* FALL THROUGH */
+	    fb_writel(fb_readl(dest+36) ^ 0xffffffff, dest+36);
+	    fb_writel(fb_readl(dest+40) ^ 0xffffffff, dest+40);
+	    fb_writel(fb_readl(dest+44) ^ 0xffffffff, dest+44);
+	    /* FALL THROUGH */
 	case 12:
-	    ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff;
-	    ((u32 *)dest)[8] ^= 0xffffffff;	/* FALL THROUGH */
+	    fb_writel(fb_readl(dest+24) ^ 0xffffffff, dest+24);
+	    fb_writel(fb_readl(dest+28) ^ 0xffffffff, dest+28);
+	    fb_writel(fb_readl(dest+32) ^ 0xffffffff, dest+32);
+	    /* FALL THROUGH */
 	case 8:
-	    ((u32 *)dest)[3] ^= 0xffffffff; ((u32 *)dest)[4] ^= 0xffffffff;
-	    ((u32 *)dest)[5] ^= 0xffffffff;	/* FALL THROUGH */
+	    fb_writel(fb_readl(dest+12) ^ 0xffffffff, dest+12);
+	    fb_writel(fb_readl(dest+16) ^ 0xffffffff, dest+16);
+	    fb_writel(fb_readl(dest+20) ^ 0xffffffff, dest+20);
+	    /* FALL THROUGH */
 	case 4:
-	    ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
-	    ((u32 *)dest)[2] ^= 0xffffffff;
+	    fb_writel(fb_readl(dest+0) ^ 0xffffffff, dest+0);
+	    fb_writel(fb_readl(dest+4) ^ 0xffffffff, dest+4);
+	    fb_writel(fb_readl(dest+8) ^ 0xffffffff, dest+8);
 	}
     }
 }
diff -u --recursive --new-file v2.3.20/linux/drivers/video/fbcon-cfb32.c linux/drivers/video/fbcon-cfb32.c
--- v2.3.20/linux/drivers/video/fbcon-cfb32.c	Thu Feb 25 10:02:12 1999
+++ linux/drivers/video/fbcon-cfb32.c	Mon Oct 11 10:26:52 1999
@@ -36,7 +36,7 @@
     u8 *src, *dst;
 
     if (sx == 0 && dx == 0 && width * fontwidth(p) * 4 == bytes) {
-	mymemmove(p->screen_base + dy * linesize,
+	fb_memmove(p->screen_base + dy * linesize,
 		  p->screen_base + sy * linesize,
 		  height * linesize);
 	return;
@@ -54,7 +54,7 @@
 	src = p->screen_base + sy * linesize + sx;
 	dst = p->screen_base + dy * linesize + dx;
 	for (rows = height * fontheight(p); rows--;) {
-	    mymemmove(dst, src, width);
+	    fb_memmove(dst, src, width);
 	    src += bytes;
 	    dst += bytes;
 	}
@@ -62,7 +62,7 @@
 	src = p->screen_base + (sy+height) * linesize + sx - bytes;
 	dst = p->screen_base + (dy+height) * linesize + dx - bytes;
 	for (rows = height * fontheight(p); rows--;) {
-	    mymemmove(dst, src, width);
+	    fb_memmove(dst, src, width);
 	    src -= bytes;
 	    dst -= bytes;
 	}
@@ -77,17 +77,17 @@
     while (height-- > 0) {
 	u32 *p = (u32 *)dest;
 	for (i = 0; i < width/4; i++) {
-	    *p++ = data;
-	    *p++ = data;
-	    *p++ = data;
-	    *p++ = data;
+	    fb_writel(data, p++);
+	    fb_writel(data, p++);
+	    fb_writel(data, p++);
+	    fb_writel(data, p++);
 	}
 	if (width & 2) {
-	    *p++ = data;
-	    *p++ = data;
+	    fb_writel(data, p++);
+	    fb_writel(data, p++);
 	}
 	if (width & 1)
-	    *p++ = data;
+	    fb_writel(data, p++);
 	dest += linesize;
     }
 }
@@ -115,7 +115,7 @@
 {
     u8 *dest, *cdat, bits;
     int bytes = p->next_line, rows;
-    u32 eorx, fgx, bgx;
+    u32 eorx, fgx, bgx, *pt;
 
     dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 4;
     if (fontwidth(p) <= 8)
@@ -128,29 +128,30 @@
 
     for (rows = fontheight(p); rows--; dest += bytes) {
 	bits = *cdat++;
-	((u32 *)dest)[0] = (-(bits >> 7) & eorx) ^ bgx;
-	((u32 *)dest)[1] = (-(bits >> 6 & 1) & eorx) ^ bgx;
-	((u32 *)dest)[2] = (-(bits >> 5 & 1) & eorx) ^ bgx;
-	((u32 *)dest)[3] = (-(bits >> 4 & 1) & eorx) ^ bgx;
+	pt = (u32 *) dest;
+	fb_writel((-(bits >> 7) & eorx) ^ bgx, pt++);
+	fb_writel((-(bits >> 6 & 1) & eorx) ^ bgx, pt++);
+	fb_writel((-(bits >> 5 & 1) & eorx) ^ bgx, pt++);
+	fb_writel((-(bits >> 4 & 1) & eorx) ^ bgx, pt++);
 	if (fontwidth(p) < 8)
 	    continue;
-	((u32 *)dest)[4] = (-(bits >> 3 & 1) & eorx) ^ bgx;
-	((u32 *)dest)[5] = (-(bits >> 2 & 1) & eorx) ^ bgx;
-	((u32 *)dest)[6] = (-(bits >> 1 & 1) & eorx) ^ bgx;
-	((u32 *)dest)[7] = (-(bits & 1) & eorx) ^ bgx;
+	fb_writel((-(bits >> 3 & 1) & eorx) ^ bgx, pt++);
+	fb_writel((-(bits >> 2 & 1) & eorx) ^ bgx, pt++);
+	fb_writel((-(bits >> 1 & 1) & eorx) ^ bgx, pt++);
+	fb_writel((-(bits & 1) & eorx) ^ bgx, pt++);
 	if (fontwidth(p) < 12)
 	    continue;
 	bits = *cdat++;
-	((u32 *)dest)[8] = (-(bits >> 7) & eorx) ^ bgx;
-	((u32 *)dest)[9] = (-(bits >> 6 & 1) & eorx) ^ bgx;
-	((u32 *)dest)[10] = (-(bits >> 5 & 1) & eorx) ^ bgx;
-	((u32 *)dest)[11] = (-(bits >> 4 & 1) & eorx) ^ bgx;
+	fb_writel((-(bits >> 7) & eorx) ^ bgx, pt++);
+	fb_writel((-(bits >> 6 & 1) & eorx) ^ bgx, pt++);
+	fb_writel((-(bits >> 5 & 1) & eorx) ^ bgx, pt++);
+	fb_writel((-(bits >> 4 & 1) & eorx) ^ bgx, pt++);
 	if (fontwidth(p) < 16)
 	    continue;
-	((u32 *)dest)[12] = (-(bits >> 3 & 1) & eorx) ^ bgx;
-	((u32 *)dest)[13] = (-(bits >> 2 & 1) & eorx) ^ bgx;
-	((u32 *)dest)[14] = (-(bits >> 1 & 1) & eorx) ^ bgx;
-	((u32 *)dest)[15] = (-(bits & 1) & eorx) ^ bgx;
+	fb_writel((-(bits >> 3 & 1) & eorx) ^ bgx, pt++);
+	fb_writel((-(bits >> 2 & 1) & eorx) ^ bgx, pt++);
+	fb_writel((-(bits >> 1 & 1) & eorx) ^ bgx, pt++);
+	fb_writel((-(bits & 1) & eorx) ^ bgx, pt++);
     }
 }
 
@@ -160,7 +161,7 @@
     u8 *cdat, *dest, *dest0, bits;
     u16 c;
     int rows, bytes = p->next_line;
-    u32 eorx, fgx, bgx;
+    u32 eorx, fgx, bgx, *pt;
 
     dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 4;
     fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p, scr_readw(s))];
@@ -174,29 +175,30 @@
 	    cdat = p->fontdata + (c * fontheight(p) << 1);
 	for (rows = fontheight(p), dest = dest0; rows--; dest += bytes) {
 	    bits = *cdat++;
-	    ((u32 *)dest)[0] = (-(bits >> 7) & eorx) ^ bgx;
-	    ((u32 *)dest)[1] = (-(bits >> 6 & 1) & eorx) ^ bgx;
-	    ((u32 *)dest)[2] = (-(bits >> 5 & 1) & eorx) ^ bgx;
-	    ((u32 *)dest)[3] = (-(bits >> 4 & 1) & eorx) ^ bgx;
+	    pt = (u32 *) dest;
+	    fb_writel((-(bits >> 7) & eorx) ^ bgx, pt++);
+	    fb_writel((-(bits >> 6 & 1) & eorx) ^ bgx, pt++);
+	    fb_writel((-(bits >> 5 & 1) & eorx) ^ bgx, pt++);
+	    fb_writel((-(bits >> 4 & 1) & eorx) ^ bgx, pt++);
 	    if (fontwidth(p) < 8)
 		continue;
-	    ((u32 *)dest)[4] = (-(bits >> 3 & 1) & eorx) ^ bgx;
-	    ((u32 *)dest)[5] = (-(bits >> 2 & 1) & eorx) ^ bgx;
-	    ((u32 *)dest)[6] = (-(bits >> 1 & 1) & eorx) ^ bgx;
-	    ((u32 *)dest)[7] = (-(bits & 1) & eorx) ^ bgx;
+	    fb_writel((-(bits >> 3 & 1) & eorx) ^ bgx, pt++);
+	    fb_writel((-(bits >> 2 & 1) & eorx) ^ bgx, pt++);
+	    fb_writel((-(bits >> 1 & 1) & eorx) ^ bgx, pt++);
+	    fb_writel((-(bits & 1) & eorx) ^ bgx, pt++);
 	    if (fontwidth(p) < 12)
 		continue;
 	    bits = *cdat++;
-	    ((u32 *)dest)[8] = (-(bits >> 7) & eorx) ^ bgx;
-	    ((u32 *)dest)[9] = (-(bits >> 6 & 1) & eorx) ^ bgx;
-	    ((u32 *)dest)[10] = (-(bits >> 5 & 1) & eorx) ^ bgx;
-	    ((u32 *)dest)[11] = (-(bits >> 4 & 1) & eorx) ^ bgx;
+	    fb_writel((-(bits >> 7) & eorx) ^ bgx, pt++);
+	    fb_writel((-(bits >> 6 & 1) & eorx) ^ bgx, pt++);
+	    fb_writel((-(bits >> 5 & 1) & eorx) ^ bgx, pt++);
+	    fb_writel((-(bits >> 4 & 1) & eorx) ^ bgx, pt++);
 	    if (fontwidth(p) < 16)
 		continue;
-	    ((u32 *)dest)[12] = (-(bits >> 3 & 1) & eorx) ^ bgx;
-	    ((u32 *)dest)[13] = (-(bits >> 2 & 1) & eorx) ^ bgx;
-	    ((u32 *)dest)[14] = (-(bits >> 1 & 1) & eorx) ^ bgx;
-	    ((u32 *)dest)[15] = (-(bits & 1) & eorx) ^ bgx;
+	    fb_writel((-(bits >> 3 & 1) & eorx) ^ bgx, pt++);
+	    fb_writel((-(bits >> 2 & 1) & eorx) ^ bgx, pt++);
+	    fb_writel((-(bits >> 1 & 1) & eorx) ^ bgx, pt++);
+	    fb_writel((-(bits & 1) & eorx) ^ bgx, pt++);
 	}
 	dest0 += fontwidth(p)*4;
     }
@@ -211,20 +213,28 @@
     for (rows = fontheight(p); rows--; dest += bytes) {
 	switch (fontwidth(p)) {
 	case 16:
-	    ((u32 *)dest)[12] ^= 0xffffffff; ((u32 *)dest)[13] ^= 0xffffffff;
-	    ((u32 *)dest)[14] ^= 0xffffffff; ((u32 *)dest)[15] ^= 0xffffffff;
+	    fb_writel(fb_readl(dest+(4*12)) ^ 0xffffffff, dest+(4*12));
+	    fb_writel(fb_readl(dest+(4*13)) ^ 0xffffffff, dest+(4*13));
+	    fb_writel(fb_readl(dest+(4*14)) ^ 0xffffffff, dest+(4*14));
+	    fb_writel(fb_readl(dest+(4*15)) ^ 0xffffffff, dest+(4*15));
 	    /* FALL THROUGH */
 	case 12:
-	    ((u32 *)dest)[8] ^= 0xffffffff; ((u32 *)dest)[9] ^= 0xffffffff;
-	    ((u32 *)dest)[10] ^= 0xffffffff; ((u32 *)dest)[11] ^= 0xffffffff;
+	    fb_writel(fb_readl(dest+(4*8)) ^ 0xffffffff, dest+(4*8));
+	    fb_writel(fb_readl(dest+(4*9)) ^ 0xffffffff, dest+(4*9));
+	    fb_writel(fb_readl(dest+(4*10)) ^ 0xffffffff, dest+(4*10));
+	    fb_writel(fb_readl(dest+(4*11)) ^ 0xffffffff, dest+(4*11));
 	    /* FALL THROUGH */
 	case 8:
-	    ((u32 *)dest)[4] ^= 0xffffffff; ((u32 *)dest)[5] ^= 0xffffffff;
-	    ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff;
+	    fb_writel(fb_readl(dest+(4*4)) ^ 0xffffffff, dest+(4*4));
+	    fb_writel(fb_readl(dest+(4*5)) ^ 0xffffffff, dest+(4*5));
+	    fb_writel(fb_readl(dest+(4*6)) ^ 0xffffffff, dest+(4*6));
+	    fb_writel(fb_readl(dest+(4*7)) ^ 0xffffffff, dest+(4*7));
 	    /* FALL THROUGH */
 	case 4:
-	    ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
-	    ((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff;
+	    fb_writel(fb_readl(dest+(4*0)) ^ 0xffffffff, dest+(4*0));
+	    fb_writel(fb_readl(dest+(4*1)) ^ 0xffffffff, dest+(4*1));
+	    fb_writel(fb_readl(dest+(4*2)) ^ 0xffffffff, dest+(4*2));
+	    fb_writel(fb_readl(dest+(4*3)) ^ 0xffffffff, dest+(4*3));
 	    /* FALL THROUGH */
 	}
     }
diff -u --recursive --new-file v2.3.20/linux/drivers/video/fbcon-cfb4.c linux/drivers/video/fbcon-cfb4.c
--- v2.3.20/linux/drivers/video/fbcon-cfb4.c	Wed Apr 28 08:48:45 1999
+++ linux/drivers/video/fbcon-cfb4.c	Mon Oct 11 10:26:52 1999
@@ -61,7 +61,7 @@
 	u8 *src,*dst;
 
 	if (sx == 0 && dx == 0 && width * 4 == bytes) {
-		mymemmove(p->screen_base + dy * linesize,
+		fb_memmove(p->screen_base + dy * linesize,
 			  p->screen_base + sy * linesize,
 			  height * linesize);
 	}
@@ -70,7 +70,7 @@
 			src = p->screen_base + sy * linesize + sx * 4;
 			dst = p->screen_base + dy * linesize + dx * 4;
 			for (rows = height * fontheight(p) ; rows-- ;) {
-				mymemmove(dst, src, width * 4);
+				fb_memmove(dst, src, width * 4);
 				src += bytes;
 				dst += bytes;
 			}
@@ -81,7 +81,7 @@
 			dst = p->screen_base + (dy+height) * linesize + dx * 4
 				- bytes;
 			for (rows = height * fontheight(p) ; rows-- ;) {
-				mymemmove(dst, src, width * 4);
+				fb_memmove(dst, src, width * 4);
 				src -= bytes;
 				dst -= bytes;
 			}
@@ -107,7 +107,7 @@
 
 	if (sx == 0 && width * 4 == bytes) {
 		for (i = 0 ; i < lines * width ; i++) {
-			((u32 *)dest)[0]=bgx;
+			fb_writel (bgx, dest);
 			dest+=4;
 		}
 	} else {
@@ -116,7 +116,7 @@
 			dest=dest0;
 			for (i = 0 ; i < width ; i++) {
 				/* memset ?? */
-				((u32 *)dest)[0]=bgx;
+				fb_writel (bgx, dest);
 				dest+=4;
 			}
 		}
@@ -142,10 +142,8 @@
 	eorx = fgx ^ bgx;
 
 	for (rows = fontheight(p) ; rows-- ; dest += bytes) {
-		((u16 *)dest)[0]=
-			(nibbletab_cfb4[*cdat >> 4] & eorx) ^ bgx;
-		((u16 *)dest)[1]=
-			(nibbletab_cfb4[*cdat++ & 0xf] & eorx) ^ bgx;
+		fb_writew((nibbletab_cfb4[*cdat >> 4] & eorx) ^ bgx, dest+0);
+		fb_writew((nibbletab_cfb4[*cdat++ & 0xf] & eorx) ^ bgx, dest+2);
 	}
 }
 
@@ -172,10 +170,8 @@
 		cdat = p->fontdata + c * fontheight(p);
 
 		for (rows = fontheight(p), dest = dest0; rows-- ; dest += bytes) {
-			((u16 *)dest)[0]=
-			(nibbletab_cfb4[*cdat >> 4] & eorx) ^ bgx;
-			((u16 *)dest)[1]=
-			(nibbletab_cfb4[*cdat++ & 0xf] & eorx) ^ bgx;
+			fb_writew((nibbletab_cfb4[*cdat >> 4] & eorx) ^ bgx, dest+0);
+			fb_writew((nibbletab_cfb4[*cdat++ & 0xf] & eorx) ^ bgx, dest+2);
 		}
 		dest0+=4;
 	}
@@ -188,7 +184,7 @@
 
 	dest = p->screen_base + yy * fontheight(p) * bytes + xx * 4;
 	for (rows = fontheight(p) ; rows-- ; dest += bytes) {
-		((u32 *)dest)[0] ^= 0xffffffff;
+		fb_writel(fb_readl(dest+0) ^ 0xffffffff, dest+0);
 	}
 }
 
diff -u --recursive --new-file v2.3.20/linux/drivers/video/fbcon-cfb8.c linux/drivers/video/fbcon-cfb8.c
--- v2.3.20/linux/drivers/video/fbcon-cfb8.c	Thu Feb 25 10:02:12 1999
+++ linux/drivers/video/fbcon-cfb8.c	Mon Oct 11 10:26:52 1999
@@ -52,7 +52,7 @@
     u8 *src,*dst;
 
     if (sx == 0 && dx == 0 && width * fontwidth(p) == bytes) {
-	mymemmove(p->screen_base + dy * linesize,
+	fb_memmove(p->screen_base + dy * linesize,
 		  p->screen_base + sy * linesize,
 		  height * linesize);
 	return;
@@ -66,7 +66,7 @@
 	src = p->screen_base + sy * linesize + sx;
 	dst = p->screen_base + dy * linesize + dx;
 	for (rows = height * fontheight(p) ; rows-- ;) {
-	    mymemmove(dst, src, width);
+	    fb_memmove(dst, src, width);
 	    src += bytes;
 	    dst += bytes;
 	}
@@ -74,7 +74,7 @@
 	src = p->screen_base + (sy+height) * linesize + sx - bytes;
 	dst = p->screen_base + (dy+height) * linesize + dx - bytes;
 	for (rows = height * fontheight(p) ; rows-- ;) {
-	    mymemmove(dst, src, width);
+	    fb_memmove(dst, src, width);
 	    src -= bytes;
 	    dst -= bytes;
 	}
@@ -85,7 +85,7 @@
 			    int linesize)
 {
     while (height-- > 0) {
-	memset(dest, data, width);
+	fb_memset(dest, data, width);
 	dest += linesize;
     }
 }
@@ -132,22 +132,22 @@
     switch (fontwidth(p)) {
     case 4:
 	for (rows = fontheight(p) ; rows-- ; dest += bytes)
-	    ((u32 *)dest)[0]= (nibbletab_cfb8[*cdat++ >> 4] & eorx) ^ bgx;
+	    fb_writel((nibbletab_cfb8[*cdat++ >> 4] & eorx) ^ bgx, dest);
         break;
     case 8:
 	for (rows = fontheight(p) ; rows-- ; dest += bytes) {
-	    ((u32 *)dest)[0]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx;
-	    ((u32 *)dest)[1]= (nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx;
+	    fb_writel((nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx, dest);
+	    fb_writel((nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx, dest+4);
         }
         break;
     case 12:
     case 16:
 	for (rows = fontheight(p) ; rows-- ; dest += bytes) {
-	    ((u32 *)dest)[0]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx;
-	    ((u32 *)dest)[1]= (nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx;
-	    ((u32 *)dest)[2]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx;
+	    fb_writel((nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx, dest);
+	    fb_writel((nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx, dest+4);
+	    fb_writel((nibbletab_cfb8[(*cdat >> 4) & 0xf] & eorx) ^ bgx, dest+8);
 	    if (fontwidth(p) == 16)
-	        ((u32 *)dest)[3]= (nibbletab_cfb8[*cdat & 0xf] & eorx) ^ bgx;
+		fb_writel((nibbletab_cfb8[*cdat & 0xf] & eorx) ^ bgx, dest+12);
 	    cdat++;
         }
         break;
@@ -177,7 +177,7 @@
 	    cdat = p->fontdata + c * fontheight(p);
 
 	    for (rows = fontheight(p), dest = dest0; rows-- ; dest += bytes)
-		((u32 *)dest)[0]= (nibbletab_cfb8[*cdat++ >> 4] & eorx) ^ bgx;
+		fb_writel((nibbletab_cfb8[*cdat++ >> 4] & eorx) ^ bgx, dest);
 	    dest0+=4;
         }
         break;
@@ -187,8 +187,8 @@
 	    cdat = p->fontdata + c * fontheight(p);
 
 	    for (rows = fontheight(p), dest = dest0; rows-- ; dest += bytes) {
-		((u32 *)dest)[0]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx;
-		((u32 *)dest)[1]= (nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx;
+		fb_writel((nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx, dest);
+		fb_writel((nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx, dest+4);
 	    }
 	    dest0+=8;
         }
@@ -200,11 +200,11 @@
 	    cdat = p->fontdata + (c * fontheight(p) << 1);
 
 	    for (rows = fontheight(p), dest = dest0; rows-- ; dest += bytes) {
-		((u32 *)dest)[0]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx;
-		((u32 *)dest)[1]= (nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx;
-		((u32 *)dest)[2]= (nibbletab_cfb8[(*cdat >> 4) & 0xf] & eorx) ^ bgx;
+		fb_writel((nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx, dest);
+		fb_writel((nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx, dest+4);
+		fb_writel((nibbletab_cfb8[(*cdat >> 4) & 0xf] & eorx) ^ bgx, dest+8);
 		if (fontwidth(p) == 16)
-		    ((u32 *)dest)[3]= (nibbletab_cfb8[*cdat & 0xf] & eorx) ^ bgx;
+		   fb_writel((nibbletab_cfb8[*cdat & 0xf] & eorx) ^ bgx, dest+12);
 		cdat++;
 	    }
 	    dest0+=fontwidth(p);
@@ -221,10 +221,10 @@
     dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p);
     for (rows = fontheight(p) ; rows-- ; dest += bytes) {
     	switch (fontwidth(p)) {
-    	case 16: ((u32 *)dest)[3] ^= 0x0f0f0f0f; /* FALL THROUGH */
-    	case 12: ((u32 *)dest)[2] ^= 0x0f0f0f0f; /* FALL THROUGH */
-    	case 8: ((u32 *)dest)[1] ^= 0x0f0f0f0f;  /* FALL THROUGH */
-    	case 4: ((u32 *)dest)[0] ^= 0x0f0f0f0f;  /* FALL THROUGH */
+    	case 16: fb_writel(fb_readl(dest+12) ^ 0x0f0f0f0f, dest+12); /* fall thru */
+    	case 12: fb_writel(fb_readl(dest+8) ^ 0x0f0f0f0f, dest+8); /* fall thru */
+    	case 8: fb_writel(fb_readl(dest+4) ^ 0x0f0f0f0f, dest+4); /* fall thru */
+    	case 4: fb_writel(fb_readl(dest) ^ 0x0f0f0f0f, dest); /* fall thru */
     	default: break;
     	}
     }
diff -u --recursive --new-file v2.3.20/linux/drivers/video/fbcon-ilbm.c linux/drivers/video/fbcon-ilbm.c
--- v2.3.20/linux/drivers/video/fbcon-ilbm.c	Thu Feb 25 10:02:12 1999
+++ linux/drivers/video/fbcon-ilbm.c	Mon Oct 11 10:26:52 1999
@@ -45,7 +45,7 @@
 		      int height, int width)
 {
     if (sx == 0 && dx == 0 && width == p->next_plane)
-	mymemmove(p->screen_base+dy*fontheight(p)*p->next_line,
+	fb_memmove(p->screen_base+dy*fontheight(p)*p->next_line,
 		  p->screen_base+sy*fontheight(p)*p->next_line,
 		  height*fontheight(p)*p->next_line);
     else {
@@ -56,7 +56,7 @@
 	    src = p->screen_base+sy*fontheight(p)*p->next_line+sx;
 	    dest = p->screen_base+dy*fontheight(p)*p->next_line+dx;
 	    for (i = p->var.bits_per_pixel*height*fontheight(p); i--;) {
-		mymemmove(dest, src, width);
+		fb_memmove(dest, src, width);
 		src += p->next_plane;
 		dest += p->next_plane;
 	    }
@@ -66,7 +66,7 @@
 	    for (i = p->var.bits_per_pixel*height*fontheight(p); i--;) {
 		src -= p->next_plane;
 		dest -= p->next_plane;
-		mymemmove(dest, src, width);
+		fb_memmove(dest, src, width);
 	    }
 	}
     }
@@ -86,9 +86,9 @@
 	bg = bg0;
 	for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
 	    if (bg & 1)
-		mymemset(dest, width);
+		fb_memset255(dest, width);
 	    else
-		mymemclear(dest, width);
+		fb_memclear(dest, width);
 	    bg >>= 1;
 	}
     }
diff -u --recursive --new-file v2.3.20/linux/drivers/video/fbcon-iplan2p2.c linux/drivers/video/fbcon-iplan2p2.c
--- v2.3.20/linux/drivers/video/fbcon-iplan2p2.c	Thu Feb 25 10:02:12 1999
+++ linux/drivers/video/fbcon-iplan2p2.c	Mon Oct 11 10:26:52 1999
@@ -169,7 +169,7 @@
 	/*  Special (but often used) case: Moving whole lines can be
 	 *  done with memmove()
 	 */
-	mymemmove(p->screen_base + dy * p->next_line * fontheight(p),
+	fb_memmove(p->screen_base + dy * p->next_line * fontheight(p),
 		  p->screen_base + sy * p->next_line * fontheight(p),
 		  p->next_line * height * fontheight(p));
     } else {
@@ -201,7 +201,7 @@
 		}
 		if (width > 1) {
 		    for (rows = colsize; rows > 0; --rows) {
-			mymemmove(dst, src, (width>>1)*4);
+			fb_memmove(dst, src, (width>>1)*4);
 			src += bytes;
 			dst += bytes;
 		    }
@@ -227,7 +227,7 @@
 		    for(rows = colsize; rows > 0; --rows) {
 			src -= bytes;
 			dst -= bytes;
-			mymemmove(dst, src, (width>>1)*4);
+			fb_memmove(dst, src, (width>>1)*4);
 		    }
 		}
 		if (width & 1)
@@ -295,7 +295,7 @@
 	/*  Clears are split if the region starts at an odd column or
 	 *  end at an even column. These extra columns are spread
 	 *  across the interleaved planes. All in between can be
-	 *  cleared by normal mymemclear_small(), because both bytes of
+	 *  cleared by normal fb_memclear_small(), because both bytes of
 	 *  the single plane words are affected.
 	 */
 
diff -u --recursive --new-file v2.3.20/linux/drivers/video/fbcon-iplan2p4.c linux/drivers/video/fbcon-iplan2p4.c
--- v2.3.20/linux/drivers/video/fbcon-iplan2p4.c	Thu Feb 25 10:02:12 1999
+++ linux/drivers/video/fbcon-iplan2p4.c	Mon Oct 11 10:26:52 1999
@@ -177,7 +177,7 @@
 	/*  Special (but often used) case: Moving whole lines can be
 	 *done with memmove()
 	 */
-	mymemmove(p->screen_base + dy * p->next_line * fontheight(p),
+	fb_memmove(p->screen_base + dy * p->next_line * fontheight(p),
 		  p->screen_base + sy * p->next_line * fontheight(p),
 		  p->next_line * height * fontheight(p));
     } else {
@@ -210,7 +210,7 @@
 		}
 		if (width > 1) {
 		    for(rows = colsize; rows > 0; --rows) {
-			mymemmove(dst, src, (width>>1)*8);
+			fb_memmove(dst, src, (width>>1)*8);
 			src += bytes;
 			dst += bytes;
 		    }
@@ -236,7 +236,7 @@
 		    for(rows = colsize; rows > 0; --rows) {
 			src -= bytes;
 			dst -= bytes;
-			mymemmove(dst, src, (width>>1)*8);
+			fb_memmove(dst, src, (width>>1)*8);
 		    }
 		}
 		if (width & 1) {
@@ -305,7 +305,7 @@
 	/*  Clears are split if the region starts at an odd column or
 	 *  end at an even column. These extra columns are spread
 	 *  across the interleaved planes. All in between can be
-	 *  cleared by normal mymemclear_small(), because both bytes of
+	 *  cleared by normal fb_memclear_small(), because both bytes of
 	 *  the single plane words are affected.
 	 */
 
diff -u --recursive --new-file v2.3.20/linux/drivers/video/fbcon-iplan2p8.c linux/drivers/video/fbcon-iplan2p8.c
--- v2.3.20/linux/drivers/video/fbcon-iplan2p8.c	Thu Feb 25 10:02:12 1999
+++ linux/drivers/video/fbcon-iplan2p8.c	Mon Oct 11 10:26:52 1999
@@ -337,7 +337,7 @@
 	/* Clears are split if the region starts at an odd column or
 	* end at an even column. These extra columns are spread
 	* across the interleaved planes. All in between can be
-	* cleared by normal mymemclear_small(), because both bytes of
+	* cleared by normal fb_memclear_small(), because both bytes of
 	* the single plane words are affected.
 	*/
 
diff -u --recursive --new-file v2.3.20/linux/drivers/video/fbcon-mac.c linux/drivers/video/fbcon-mac.c
--- v2.3.20/linux/drivers/video/fbcon-mac.c	Thu Feb 25 10:02:12 1999
+++ linux/drivers/video/fbcon-mac.c	Mon Oct 11 10:26:52 1999
@@ -62,7 +62,7 @@
 
    if( sx == 0 && width == p->conp->vc_cols) {
      s = height * fontheight(p) * p->next_line;
-     mymemmove(dest, src, s);
+     fb_memmove(dest, src, s);
      return;
    }
    
@@ -158,7 +158,7 @@
 	 plot_pixel_mac(p, get_pixel_mac(p, j+(dx-sx), i+(dy-sy)), j, i);
 
        if (j < r) {
-	 mymemmove(dest, src, s);
+	 fb_memmove(dest, src, s);
 	 if (move_up) {
 	   dest += p->next_line;
 	   src += p->next_line;
@@ -202,9 +202,9 @@
    if( sx == 0 && width == p->conp->vc_cols) {
      s = height * fontheight(p) * p->next_line;
      if (inverse)
-       mymemclear(dest, s);
+       fb_memclear(dest, s);
      else
-       mymemset(dest, s);
+       fb_memset255(dest, s);
    }
    
    l = sx * fontwidth(p);
@@ -251,9 +251,9 @@
 
      if (j < r) {
        if (PIXEL_WHITE_MAC == pixel)
-	 mymemclear(dest, s);
+	 fb_memclear(dest, s);
        else
-	 mymemset(dest, s);
+	 fb_memset255(dest, s);
        dest += p->next_line;
        j += w;
      }
diff -u --recursive --new-file v2.3.20/linux/drivers/video/fbcon-mfb.c linux/drivers/video/fbcon-mfb.c
--- v2.3.20/linux/drivers/video/fbcon-mfb.c	Thu Feb 25 10:02:12 1999
+++ linux/drivers/video/fbcon-mfb.c	Mon Oct 11 10:26:52 1999
@@ -41,12 +41,12 @@
     if (sx == 0 && dx == 0 && width == p->next_line) {
 	src = p->screen_base+sy*fontheight(p)*width;
 	dest = p->screen_base+dy*fontheight(p)*width;
-	mymemmove(dest, src, height*fontheight(p)*width);
+	fb_memmove(dest, src, height*fontheight(p)*width);
     } else if (dy <= sy) {
 	src = p->screen_base+sy*fontheight(p)*p->next_line+sx;
 	dest = p->screen_base+dy*fontheight(p)*p->next_line+dx;
 	for (rows = height*fontheight(p); rows--;) {
-	    mymemmove(dest, src, width);
+	    fb_memmove(dest, src, width);
 	    src += p->next_line;
 	    dest += p->next_line;
 	}
@@ -54,7 +54,7 @@
 	src = p->screen_base+((sy+height)*fontheight(p)-1)*p->next_line+sx;
 	dest = p->screen_base+((dy+height)*fontheight(p)-1)*p->next_line+dx;
 	for (rows = height*fontheight(p); rows--;) {
-	    mymemmove(dest, src, width);
+	    fb_memmove(dest, src, width);
 	    src -= p->next_line;
 	    dest -= p->next_line;
 	}
@@ -72,15 +72,15 @@
 
     if (sx == 0 && width == p->next_line) {
 	if (inverse)
-	    mymemset(dest, height*fontheight(p)*width);
+	    fb_memset255(dest, height*fontheight(p)*width);
 	else
-	    mymemclear(dest, height*fontheight(p)*width);
+	    fb_memclear(dest, height*fontheight(p)*width);
     } else
 	for (rows = height*fontheight(p); rows--; dest += p->next_line)
 	    if (inverse)
-		mymemset(dest, width);
+		fb_memset255(dest, width);
 	    else
-		mymemclear_small(dest, width);
+		fb_memclear_small(dest, width);
 }
 
 void fbcon_mfb_putc(struct vc_data *conp, struct display *p, int c, int yy,
@@ -104,7 +104,7 @@
 	    d |= d>>1;
 	if (revs)
 	    d = ~d;
-	*dest = d;
+    	fb_writeb (d, dest);
     }
 }
 
@@ -133,19 +133,21 @@
 		d |= d>>1;
 	    if (revs)
 		d = ~d;
-	    *dest = d;
+    	    fb_writeb (d, dest);
 	}
     }
 }
 
 void fbcon_mfb_revc(struct display *p, int xx, int yy)
 {
-    u8 *dest;
+    u8 *dest, d;
     u_int rows;
 
     dest = p->screen_base+yy*fontheight(p)*p->next_line+xx;
-    for (rows = fontheight(p); rows--; dest += p->next_line)
-	*dest = ~*dest;
+    for (rows = fontheight(p); rows--; dest += p->next_line) {
+    	d = fb_readb(dest);
+	fb_writeb (~d, dest);
+    }
 }
 
 void fbcon_mfb_clear_margins(struct vc_data *conp, struct display *p,
@@ -165,9 +167,9 @@
 	bottom -= p->vrows;
     dest = p->screen_base + bottom * fontheight(p) * p->next_line;
     if (inverse)
-	mymemset(dest, height * p->next_line);
+	fb_memset255(dest, height * p->next_line);
     else
-	mymemclear(dest, height * p->next_line);
+	fb_memclear(dest, height * p->next_line);
 }
 
 
diff -u --recursive --new-file v2.3.20/linux/drivers/video/fbcon.c linux/drivers/video/fbcon.c
--- v2.3.20/linux/drivers/video/fbcon.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/video/fbcon.c	Mon Oct 11 10:26:52 1999
@@ -526,7 +526,7 @@
     	q = (unsigned short *)(conp->vc_origin + conp->vc_size_row * old_rows);
     	step = logo_lines * old_cols;
     	for (r = q - logo_lines * old_cols; r < q; r++)
-    	    if (*r != conp->vc_video_erase_char)
+    	    if (scr_readw(r) != conp->vc_video_erase_char)
     	    	break;
 	if (r != q && nr_rows >= old_rows + logo_lines) {
     	    save = kmalloc(logo_lines * nr_cols * 2, GFP_KERNEL);
@@ -535,7 +535,7 @@
     	    	scr_memsetw(save, conp->vc_video_erase_char, logo_lines * nr_cols * 2);
     	    	r = q - step;
     	    	for (cnt = 0; cnt < logo_lines; cnt++, r += i)
-    	    		scr_memcpyw_to(save + cnt * nr_cols, r, 2 * i);
+    	    		scr_memcpyw_from(save + cnt * nr_cols, r, 2 * i);
     	    	r = q;
     	    }
     	}
@@ -551,7 +551,8 @@
     		conp->vc_pos += logo_lines * conp->vc_size_row;
     	    }
     	}
-    	scr_memsetw((unsigned short *)conp->vc_origin, conp->vc_video_erase_char, 
+    	scr_memsetw((unsigned short *)conp->vc_origin,
+		    conp->vc_video_erase_char, 
     		conp->vc_size_row * logo_lines);
     }
     
@@ -603,7 +604,7 @@
 	}
 	if (save) {
     	    q = (unsigned short *)(conp->vc_origin + conp->vc_size_row * old_rows);
-	    scr_memcpyw_from(q, save, logo_lines * nr_cols * 2);
+	    memcpy(q, save, logo_lines * nr_cols * 2);
 	    conp->vc_y += logo_lines;
     	    conp->vc_pos += logo_lines * conp->vc_size_row;
     	    kfree(save);
@@ -1386,19 +1387,11 @@
 
     if (!p->can_soft_blank) {
 	if (blank) {
-#ifdef CONFIG_MAC
-	    if (MACH_IS_MAC) {
-		if (p->screen_base)
-		    mymemset(p->screen_base,
-			     p->var.xres_virtual*p->var.yres_virtual*
-			     p->var.bits_per_pixel>>3);
-	    } else
-#endif
 	    if (p->visual == FB_VISUAL_MONO01) {
 		if (p->screen_base)
-		    mymemset(p->screen_base,
-			     p->var.xres_virtual*p->var.yres_virtual*
-			     p->var.bits_per_pixel>>3);
+		    fb_memset255(p->screen_base,
+				 p->var.xres_virtual*p->var.yres_virtual*
+				 p->var.bits_per_pixel>>3);
 	    } else {
 	    	unsigned short oldc;
 	    	u_int height;
@@ -2048,7 +2041,7 @@
 			      (*src << blueshift);
 			if (bdepth == 4 && !((long)dst & 3)) {
 			    /* Some cards require 32bit access */
-			    *(u32 *)dst = val;
+			    fb_writel (val, dst);
 			    dst += 4;
 			} else {
 #ifdef __LITTLE_ENDIAN
@@ -2056,7 +2049,7 @@
 #else
 			    for( i = bdepth-1; i >= 0; --i )
 #endif
-			        *dst++ = val >> (i*8);
+			        fb_writeb (val >> (i*8), dst++);
 			}
 		    }
 		}
@@ -2078,7 +2071,7 @@
 #else
 			for( i = bdepth-1; i >= 0; --i )
 #endif
-			    *dst++ = val >> (i*8);
+			    fb_writeb (val >> (i*8), dst++);
 			pix = (*src & 0x0f) | 0x10; /* lower nibble */
 			val = (pix << redshift) |
 			      (pix << greenshift) |
@@ -2088,7 +2081,7 @@
 #else
 			for( i = bdepth-1; i >= 0; --i )
 #endif
-			    *dst++ = val >> (i*8);
+			    fb_writeb (val >> (i*8), dst++);
 		    }
 		}
 	    }
@@ -2122,7 +2115,7 @@
 		          safe_shift((linux_logo_blue[*src-32]  & bluemask), blueshift);
 		    if (bdepth == 4 && !((long)dst & 3)) {
 			/* Some cards require 32bit access */
-			*(u32 *)dst = val;
+			fb_writel (val, dst);
 			dst += 4;
 		    } else {
 #ifdef __LITTLE_ENDIAN
@@ -2130,7 +2123,7 @@
 #else
 			for( i = bdepth-1; i >= 0; --i )
 #endif
-			    *dst++ = val >> (i*8);
+			    fb_writeb (val >> (i*8), dst++);
 		    }
 		}
 	    }
@@ -2145,7 +2138,7 @@
 			for( x1 = 0; x1 < LOGO_W/2; x1++) {
 				u8 q = *src++;
 				q = (q << 4) | (q >> 4);
-				*dst++ = q;
+				fb_writeb (q, dst++);
 			}
 		}
 		done = 1;
@@ -2159,7 +2152,7 @@
 	    for( y1 = 0; y1 < LOGO_H; y1++ ) {
 		dst = fb + y1*line + x;
 		for( x1 = 0; x1 < LOGO_W; x1++ )
-		    *dst++ = *src++;
+		    fb_writeb (*src++, dst++);
 	    }
 	    done = 1;
 	}
@@ -2228,14 +2221,15 @@
 			   p->type == FB_TYPE_INTERLEAVED_PLANES)) {
 
 	    /* monochrome */
-	    unsigned char inverse = p->inverse ? 0x00 : 0xff;
+	    unsigned char inverse = p->inverse || p->visual == FB_VISUAL_MONO01
+		? 0x00 : 0xff;
 
 	    /* can't use simply memcpy because need to apply inverse */
 	    for( y1 = 0; y1 < LOGO_H; y1++ ) {
-		src = logo + y1*LOGO_LINE + x/8;
-		dst = fb + y1*line;
+		src = logo + y1*LOGO_LINE;
+		dst = fb + y1*line + x/8;
 		for( x1 = 0; x1 < LOGO_LINE; ++x1 )
-		    *dst++ = *src++ ^ inverse;
+		    fb_writeb(fb_readb(src++) ^ inverse, dst++);
 	    }
 	    done = 1;
 	}
@@ -2255,13 +2249,15 @@
 				outb_p(*src >> 4,0x3cf);
 				outb_p(8,0x3ce);
 				outb_p(1 << (7 - x1 % 4 * 2),0x3cf);
-				*(volatile char *) dst |= 1;
+				fb_readb (dst);
+				fb_writeb (0, dst);
 
 				outb_p(0,0x3ce);
 				outb_p(*src & 0xf,0x3cf);
 				outb_p(8,0x3ce);
 				outb_p(1 << (7 - (1 + x1 % 4 * 2)),0x3cf);
-				*(volatile char *) dst |= 1;
+				fb_readb (dst);
+				fb_writeb (0, dst);
 
 				src++;
 			}
diff -u --recursive --new-file v2.3.20/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- v2.3.20/linux/drivers/video/fbmem.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/video/fbmem.c	Mon Oct 11 13:53:09 1999
@@ -100,12 +100,17 @@
 extern int q40fb_init(void);
 extern int sgivwfb_init(void);
 extern int sgivwfb_setup(char*);
+extern int tdfxfb_init(void);
+extern int tdfxfb_setup(char*);
 
 static struct {
 	const char *name;
 	int (*init)(void);
 	int (*setup)(char*);
 } fb_drivers[] __initdata = {
+#ifdef CONFIG_FB_3DFX
+	{ "tdfx", tdfxfb_init, tdfxfb_setup },
+#endif
 #ifdef CONFIG_FB_SGIVW
 	{ "sgivw", sgivwfb_init, sgivwfb_setup },
 #endif
@@ -453,6 +458,11 @@
 		    /* set them all */
 		    for (i = 0; i < MAX_NR_CONSOLES; i++)
 			set_con2fb_map(i, con2fb.framebuffer);
+		return 0;
+	case FBIOBLANK:
+		if (info->blank == 0)
+			return -EINVAL;
+		(*info->blank)(arg, info);
 		return 0;
 	default:
 		return fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE(info),
diff -u --recursive --new-file v2.3.20/linux/drivers/video/imsttfb.c linux/drivers/video/imsttfb.c
--- v2.3.20/linux/drivers/video/imsttfb.c	Thu Aug 26 13:05:40 1999
+++ linux/drivers/video/imsttfb.c	Mon Oct 11 10:26:52 1999
@@ -354,9 +354,12 @@
 	} palette[256];
 	struct imstt_regvals init;
 	struct imstt_cursor cursor;
-	__u8 *frame_buffer_phys, *frame_buffer;
-	__u32 *dc_regs_phys, *dc_regs;
-	__u8 *cmap_regs_phys, *cmap_regs;
+	unsigned long frame_buffer_phys;
+	__u8 *frame_buffer;
+	unsigned long dc_regs_phys;
+	__u32 *dc_regs;
+	unsigned long cmap_regs_phys;
+	__u8 *cmap_regs;
 	__u32 total_vram;
 	__u32 ramdac;
 };
@@ -1077,7 +1080,7 @@
 	out_le32(&p->dc_regs[BI], 0xffffffff);
 	out_le32(&p->dc_regs[MBC], 0xffffffff);
 	out_le32(&p->dc_regs[CLR], bgc);
-	out_le32(&p->dc_regs[BLTCTL], 0x200000);
+	out_le32(&p->dc_regs[BLTCTL], 0x840); /* 0x200000 */
 	while(in_le32(&p->dc_regs[SSTATUS]) & 0x80);
 	while(in_le32(&p->dc_regs[SSTATUS]) & 0x40);
 }
@@ -1854,10 +1857,10 @@
 	fb_info_imstt_p[i] = p;
 #ifdef CONFIG_FB_COMPAT_XPMAC
 	strncpy(display_info.name, "IMS,tt128mb", sizeof(display_info.name));
-	display_info.fb_address = (__u32)p->frame_buffer_phys;
-	display_info.cmap_adr_address = (__u32)&p->cmap_regs_phys[PADDRW];
-	display_info.cmap_data_address = (__u32)&p->cmap_regs_phys[PDATA];
-	display_info.disp_reg_address = (__u32)p->dc_regs_phys;
+	display_info.fb_address = p->frame_buffer_phys;
+	display_info.cmap_adr_address = p->cmap_regs_phys + PADDRW;
+	display_info.cmap_data_address = p->cmap_regs_phys + PDATA;
+	display_info.disp_reg_address = p->dc_regs_phys;
 	if (!console_fb_info)
 		console_fb_info = &p->info;
 #endif /* CONFIG_FB_COMPAT_XPMAC */
@@ -1897,11 +1900,11 @@
 	else
 		p->ramdac = IBM;
 
-	p->frame_buffer_phys = (__u8 *)addr;
+	p->frame_buffer_phys = addr;
 	p->frame_buffer = (__u8 *)ioremap(addr, p->ramdac == IBM ? 0x400000 : 0x800000);
-	p->dc_regs_phys = (__u32 *)(addr + 0x800000);
+	p->dc_regs_phys = addr + 0x800000;
 	p->dc_regs = (__u32 *)ioremap(addr + 0x800000, 0x1000);
-	p->cmap_regs_phys = (__u8 *)(addr + 0x840000);
+	p->cmap_regs_phys = addr + 0x840000;
 	p->cmap_regs = (__u8 *)ioremap(addr + 0x840000, 0x1000);
 
 	init_imstt(p);
@@ -1953,11 +1956,11 @@
 				break;
 		}
 
-		p->frame_buffer_phys = (__u8 *)addr;
+		p->frame_buffer_phys = addr;
 		p->frame_buffer = (__u8 *)ioremap(addr, p->ramdac == IBM ? 0x400000 : 0x800000);
-		p->dc_regs_phys = (__u32 *)(addr + 0x800000);
+		p->dc_regs_phys = addr + 0x800000;
 		p->dc_regs = (__u32 *)ioremap(addr + 0x800000, 0x1000);
-		p->cmap_regs_phys = (__u8 *)(addr + 0x840000);
+		p->cmap_regs_phys = addr + 0x840000;
 		p->cmap_regs = (__u8 *)ioremap(addr + 0x840000, 0x1000);
 
 		init_imstt(p);
diff -u --recursive --new-file v2.3.20/linux/drivers/video/modedb.c linux/drivers/video/modedb.c
--- v2.3.20/linux/drivers/video/modedb.c	Thu Aug 26 13:05:40 1999
+++ linux/drivers/video/modedb.c	Mon Oct 11 10:26:52 1999
@@ -14,7 +14,7 @@
 #include <linux/sched.h>
 
 
-#define DEBUG
+#undef DEBUG
 
 #define name_matches(v, s, l) \
     ((v).name && !strncmp((s), (v).name, (l)) && strlen((v).name) == (l))
diff -u --recursive --new-file v2.3.20/linux/drivers/video/platinumfb.c linux/drivers/video/platinumfb.c
--- v2.3.20/linux/drivers/video/platinumfb.c	Thu Aug 26 13:05:40 1999
+++ linux/drivers/video/platinumfb.c	Mon Oct 11 10:26:52 1999
@@ -10,7 +10,7 @@
  *
  *  Hardware information from:
  *    platinum.c: Console support for PowerMac "platinum" display adaptor.
- *    Copyright (C) 1996 Paul Mackerras
+ *    Copyright (C) 1996 Paul Mackerras and Mark Abene
  *
  *  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
@@ -39,7 +39,6 @@
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/pgtable.h>
-#include <asm/adb.h>
 
 #include <video/fbcon.h>
 #include <video/fbcon-cfb8.h>
@@ -66,6 +65,7 @@
 struct fb_info_platinum {
 	struct fb_info			fb_info;
 	struct display			disp;
+	struct display_switch		dispsw;
 	struct fb_par_platinum		default_par;
 	struct fb_par_platinum		current_par;
 
@@ -145,6 +145,8 @@
 static int platinum_encode_fix(struct fb_fix_screeninfo *fix,
 			       const struct fb_par_platinum *par,
 			       const struct fb_info_platinum *info);
+static void platinum_set_disp(struct display *disp, struct fb_info_platinum *info,
+			      int cmode, int accel);
 static int platinum_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
 			      u_int *transp, struct fb_info *fb);
 static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
@@ -175,10 +177,6 @@
 	platinum_ioctl
 };
 
-
-__openfirmware
-
-
 static int platinum_open(struct fb_info *info, int user)
 {
 	MOD_INC_USE_COUNT;
@@ -219,6 +217,36 @@
 	return 0;
 }
 
+static void platinum_set_disp(struct display *disp, struct fb_info_platinum *info,
+			      int cmode, int accel)
+{
+	switch(cmode) {
+#ifdef FBCON_HAS_CFB8
+	    case CMODE_8:
+		info->dispsw = fbcon_cfb8;
+		disp->dispsw = &info->dispsw;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	    case CMODE_16:
+		info->dispsw = fbcon_cfb16;
+		disp->dispsw = &info->dispsw;
+		disp->dispsw_data = info->fbcon_cmap.cfb16;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	    case CMODE_32:
+		info->dispsw = fbcon_cfb32;
+		disp->dispsw = &info->dispsw;
+		disp->dispsw_data = info->fbcon_cmap.cfb32;
+		break;
+#endif
+	    default:
+		disp->dispsw = &fbcon_dummy;
+		break;
+	}
+}
+
 static int platinum_set_var(struct fb_var_screeninfo *var, int con,
 			    struct fb_info *fb)
 {
@@ -227,6 +255,7 @@
 	struct display *display;
 	int oldxres, oldyres, oldvxres, oldvyres, oldbpp, err;
 	int activate = var->activate;
+	struct platinum_regvals *init;
 
 	display = (con >= 0) ? &fb_display[con] : fb->disp;
 
@@ -242,6 +271,8 @@
 		return 0;
 	}
 
+	init = platinum_reg_init[par.vmode-1];
+
 	oldxres = display->var.xres;
 	oldyres = display->var.yres;
 	oldvxres = display->var.xres_virtual;
@@ -255,7 +286,7 @@
 	    struct fb_fix_screeninfo fix;
 
 	    platinum_encode_fix(&fix, &par, info);
-	    display->screen_base = (char *) info->frame_buffer + 0x1000;
+	    display->screen_base = (char *) info->frame_buffer + init->fb_offset + 0x20;
 	    display->visual = fix.visual;
 	    display->type = fix.type;
 	    display->type_aux = fix.type_aux;
@@ -264,36 +295,14 @@
 	    display->line_length = fix.line_length;
 	    display->can_soft_blank = 1;
 	    display->inverse = 0;
-
-	    switch(par.cmode) {
-#ifdef FBCON_HAS_CFB8
-	     case CMODE_8:
-		display->dispsw = &fbcon_cfb8;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB16
-	     case CMODE_16:
-		display->dispsw = &fbcon_cfb16;
-		display->dispsw_data = info->fbcon_cmap.cfb16;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB32
-	     case CMODE_32:
-		display->dispsw = &fbcon_cfb32;
-		display->dispsw_data = info->fbcon_cmap.cfb32;
-		break;
-#endif
-	     default:
-		display->dispsw = &fbcon_dummy;
-		break;
-	    }
-	    
+	    platinum_set_disp(display, info, par.cmode, 0);
 	    display->scrollmode = SCROLL_YREDRAW;
 	    if (info->fb_info.changevar)
 	      (*info->fb_info.changevar)(con);
 	}
 
-	if (con == currcon)
+	if (!info->fb_info.display_fg ||
+	    info->fb_info.display_fg->vc_num == con)
 		platinum_set_par(&par, info);
 
 	if (oldbpp != var->bits_per_pixel) {
@@ -322,7 +331,8 @@
 static int platinum_get_cmap(struct fb_cmap *cmap, int kspc, int con,
 			     struct fb_info *info)
 {
-	if (con == currcon)		/* current console? */
+	if (!info->display_fg ||
+	    info->display_fg->vc_num == con)	/* current console? */
 		return fb_get_cmap(cmap, kspc, platinum_getcolreg, info);
 	if (fb_display[con].cmap.len)	/* non default colormap? */
 		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
@@ -337,17 +347,23 @@
 			     struct fb_info *info)
 {
 	int err;
+	struct display *disp;
 
-	if (!fb_display[con].cmap.len) {
-		int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
-		err = fb_alloc_cmap(&fb_display[con].cmap, size, 0);
-		if (err)
+	if (con >= 0)
+		disp = &fb_display[con];
+	else
+		disp = info->disp;
+	if (!disp->cmap.len) {     /* no colormap allocated? */
+		int size = disp->var.bits_per_pixel == 16 ? 32 : 256;
+		if ((err = fb_alloc_cmap(&disp->cmap, size, 0)))
 			return err;
 	}
 
-	if (con == currcon)
+	if (!info->display_fg ||
+	    info->display_fg->vc_num == con)	/* current console? */
 		return fb_set_cmap(cmap, kspc, platinum_setcolreg, info);
-	fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+	else
+		fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
 	return 0;
 }
 
@@ -368,8 +384,9 @@
 			    fb);
 	currcon = con;
 
-	platinum_var_to_par(&fb_display[currcon].var, &par, info);
+	platinum_var_to_par(&fb_display[con].var, &par, info);
 	platinum_set_par(&par, info);
+	platinum_set_disp(&fb_display[con], info, par.cmode, 0);
 	do_install_cmap(con, fb);
 
 	return 1;
@@ -431,7 +448,6 @@
 {
 	struct fb_info_platinum *info = (struct fb_info_platinum *) fb;
 	volatile struct cmap_regs *cmap_regs = info->cmap_regs;
-	int scale;
 
 	if (regno > 255)
 		return 1;
@@ -444,12 +460,10 @@
 	info->palette[regno].green = green;
 	info->palette[regno].blue = blue;
 
-	scale = (info->current_par.cmode == CMODE_16) ? 3 : 0;
-
 	out_8(&cmap_regs->addr, regno);		/* tell clut what addr to fill	*/
-	out_8(&cmap_regs->lut, red<<scale);	/* send one color channel at	*/
-	out_8(&cmap_regs->lut, green<<scale);	/* a time...			*/
-	out_8(&cmap_regs->lut, blue<<scale);
+	out_8(&cmap_regs->lut, red);		/* send one color channel at	*/
+	out_8(&cmap_regs->lut, green);		/* a time...			*/
+	out_8(&cmap_regs->lut, blue);
 
 	if(regno < 16) {
 #ifdef FBCON_HAS_CFB16
@@ -538,7 +552,7 @@
 	out_be32(&platinum_regs->reg[26+32].r, (info->total_vram == 0x100000 ?
 						init->offset[cmode] + 4 - cmode :
 						init->offset[cmode]));
-	out_be32(&platinum_regs->reg[16].r, (unsigned) info->frame_buffer_phys + 0x1000 - 0x10);
+	out_be32(&platinum_regs->reg[16].r, (unsigned) info->frame_buffer_phys+init->fb_offset+0x10);
 	out_be32(&platinum_regs->reg[18].r, init->pitch[cmode]);
 	out_be32(&platinum_regs->reg[19].r, (info->total_vram == 0x100000 ?
 					     init->mode[cmode+1] :
@@ -571,7 +585,7 @@
 		display_info.mode = vmode;
 		strncpy(display_info.name, "platinum",
 			sizeof(display_info.name));
-		display_info.fb_address = info->frame_buffer_phys + 0x1000;
+		display_info.fb_address = info->frame_buffer_phys + init->fb_offset + 0x20;
 		display_info.cmap_adr_address = info->cmap_regs_phys;
 		display_info.cmap_data_address = info->cmap_regs_phys + 0x30;
 		display_info.disp_reg_address = info->platinum_regs_phys;
@@ -665,7 +679,7 @@
 
 #ifdef __powerpc__
 #define invalidate_cache(addr) \
-	asm volatile("eieio; dcbi 0,%1" \
+	asm volatile("eieio; dcbf 0,%1" \
 	: "=m" (*(addr)) : "r" (addr) : "memory");
 #else
 #define invalidate_cache(addr)
@@ -675,6 +689,7 @@
 {
 	struct fb_info_platinum	*info;
 	unsigned long		addr, size;
+	volatile __u8		*fbuffer;
 	int			i, bank0, bank1, bank2, bank3;
 
 	if(dp->n_addrs != 2) {
@@ -711,19 +726,20 @@
 	out_be32(&info->platinum_regs->reg[20].r, 0x1011);	/* select max vram */
 	out_be32(&info->platinum_regs->reg[24].r, 0);	/* switch in vram */
 
-	info->base_frame_buffer[0x100000] = 0x34;
-	info->base_frame_buffer[0x100008] = 0x0;
-	invalidate_cache(&info->base_frame_buffer[0x100000]);
-	info->base_frame_buffer[0x200000] = 0x56;
-	info->base_frame_buffer[0x200008] = 0x0;
-	invalidate_cache(&info->base_frame_buffer[0x200000]);
-	info->base_frame_buffer[0x300000] = 0x78;
-	info->base_frame_buffer[0x300008] = 0x0;
-	invalidate_cache(&info->base_frame_buffer[0x300000]);
+	fbuffer = info->base_frame_buffer;
+	fbuffer[0x100000] = 0x34;
+	fbuffer[0x100008] = 0x0;
+	invalidate_cache(&fbuffer[0x100000]);
+	fbuffer[0x200000] = 0x56;
+	fbuffer[0x200008] = 0x0;
+	invalidate_cache(&fbuffer[0x200000]);
+	fbuffer[0x300000] = 0x78;
+	fbuffer[0x300008] = 0x0;
+	invalidate_cache(&fbuffer[0x300000]);
 	bank0 = 1; /* builtin 1MB vram, always there */
-	bank1 = info->base_frame_buffer[0x100000] == 0x34;
-	bank2 = info->base_frame_buffer[0x200000] == 0x56;
-	bank3 = info->base_frame_buffer[0x300000] == 0x78;
+	bank1 = fbuffer[0x100000] == 0x34;
+	bank2 = fbuffer[0x200000] == 0x56;
+	bank3 = fbuffer[0x300000] == 0x78;
 	info->total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000;
 	printk(KERN_INFO "Total VRAM = %dMB %d%d%d%d\n", (int) (info->total_vram / 1024 / 1024), bank3, bank2, bank1, bank0);
 
@@ -835,10 +851,14 @@
 			       const struct fb_par_platinum *par,
 			       const struct fb_info_platinum *info)
 {
+	struct platinum_regvals *init;
+
+	init = platinum_reg_init[par->vmode-1];
+
 	memset(fix, 0, sizeof(*fix));
 	strcpy(fix->id, "platinum");
-	fix->smem_start = (info->frame_buffer_phys + 0x1000);
-	fix->smem_len = (u32) info->total_vram - 0x1000;
+	fix->smem_start = (info->frame_buffer_phys) + init->fb_offset + 0x20;
+	fix->smem_len = (u32) info->total_vram;
 	fix->mmio_start = (info->platinum_regs_phys);
 	fix->mmio_len = 0x1000;
 	fix->type = FB_TYPE_PACKED_PIXELS;
@@ -884,6 +904,7 @@
 		} else if (!strncmp(this_opt, "cmode:", 6)) {
 			int depth = simple_strtoul(this_opt+6, NULL, 0);
 			switch (depth) {
+			 case 0:
 			 case 8:
 			    default_cmode = CMODE_8;
 			    break;
diff -u --recursive --new-file v2.3.20/linux/drivers/video/sbusfb.c linux/drivers/video/sbusfb.c
--- v2.3.20/linux/drivers/video/sbusfb.c	Fri Sep 10 23:57:36 1999
+++ linux/drivers/video/sbusfb.c	Mon Oct 11 10:26:52 1999
@@ -304,13 +304,13 @@
 			fb_base -= (skip_bytes + fb->x_margin) / 8;
 			skip_bytes /= 8;
 			scr_size /= 8;
-			mymemset (fb_base, skip_bytes - fb->x_margin / 8);
-			mymemset (fb_base + scr_size - skip_bytes + fb->x_margin / 8, skip_bytes - fb->x_margin / 8);
+			fb_memset255 (fb_base, skip_bytes - fb->x_margin / 8);
+			fb_memset255 (fb_base + scr_size - skip_bytes + fb->x_margin / 8, skip_bytes - fb->x_margin / 8);
 			incr = fb->var.xres_virtual / 8;
 			size = fb->x_margin / 8 * 2;
 			for (q = fb_base + skip_bytes - fb->x_margin / 8, h = 0;
 			     h <= he; q += incr, h++)
-				mymemset (q, size);
+				fb_memset255 (q, size);
 		} else {
 			fb_base -= (skip_bytes + fb->x_margin);
 			memset (fb_base, attr_bgcol(p,s), skip_bytes - fb->x_margin);
diff -u --recursive --new-file v2.3.20/linux/drivers/video/tdfxfb.c linux/drivers/video/tdfxfb.c
--- v2.3.20/linux/drivers/video/tdfxfb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/tdfxfb.c	Mon Oct 11 10:26:52 1999
@@ -0,0 +1,1891 @@
+/*
+ *
+ * tdfxfb.c
+ *
+ * Author: Hannu Mallat <hmallat@cc.hut.fi>
+ *
+ * Copyright © 1999 Hannu Mallat
+ * All rights reserved
+ *
+ * Created      : Thu Sep 23 18:17:43 1999, hmallat
+ * Last modified: Thu Oct  7 18:39:04 1999, hmallat
+ *
+ * Lots of the information here comes from the Daryll Strauss' Banshee 
+ * patches to the XF86 server, and the rest comes from the 3dfx
+ * Banshee specification. I'm very much indebted to Daryll for his
+ * work on the X server.
+ *
+ * Voodoo3 support was contributed Harold Oga. Thanks!
+ *
+ * While I _am_ grateful to 3Dfx for releasing the specs for Banshee,
+ * I do wish the next version is a bit more complete. Without the XF86
+ * patches I couldn't have gotten even this far... for instance, the
+ * extensions to the VGA register set go completely unmentioned in the
+ * spec! Also, lots of references are made to the 'SST core', but no
+ * spec is publicly available, AFAIK.
+ *
+ * The structure of this driver comes pretty much from the Permedia
+ * driver by Ilario Nardinocchi, which in turn is based on skeletonfb.
+ * 
+ * TODO:
+ * - support for 16/32 bpp needs fixing (funky bootup penguin)
+ * - multihead support (it's all hosed now with pokes to VGA standard
+ *   register locations, but shouldn't be that hard to change, some
+ *   other code needs to be changed too where the fb_info (which should
+ *   be an array of head-specific information) is referred to directly.
+ *   are referred to )
+ * - hw cursor
+ * - better acceleration support (e.g., font blitting from fb memory?)
+ * - banshee and voodoo3 now supported -- any others? afaik, the original
+ *   voodoo was a 3d-only card, so we won't consider that. what about
+ *   voodoo2?
+ * - 24bpp 
+ * - panning (doesn't seem to work properly yet)
+ *
+ * Version history:
+ *
+ * 0.1.1 (released 1999-10-07) added Voodoo3 support by Harold Oga.
+ * 0.1.0 (released 1999-10-06) initial version
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#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/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/selection.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/nvram.h>
+#include <linux/kd.h>
+#include <linux/vt_kern.h>
+#include <asm/io.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb32.h>
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+#define PCI_DEVICE_ID_3DFX_VOODOO3      0x0005
+#endif
+
+/* membase0 register offsets */
+#define STATUS		0x00
+#define PCIINIT0	0x04
+#define SIPMONITOR	0x08
+#define LFBMEMORYCONFIG	0x0c
+#define MISCINIT0	0x10
+#define MISCINIT1	0x14
+#define DRAMINIT0	0x18
+#define DRAMINIT1	0x1c
+#define AGPINIT		0x20
+#define TMUGBEINIT	0x24
+#define VGAINIT0	0x28
+#define VGAINIT1	0x2c
+#define DRAMCOMMAND	0x30
+#define DRAMDATA	0x34
+/* reserved             0x38 */
+/* reserved             0x3c */
+#define PLLCTRL0	0x40
+#define PLLCTRL1	0x44
+#define PLLCTRL2	0x48
+#define DACMODE		0x4c
+#define DACADDR		0x50
+#define DACDATA		0x54
+#define RGBMAXDELTA	0x58
+#define VIDPROCCFG	0x5c
+#define HWCURPATADDR	0x60
+#define HWCURLOC	0x64
+#define HWCURC0		0x68
+#define HWCURC1		0x6c
+#define VIDINFORMAT	0x70
+#define VIDINSTATUS	0x74
+#define VIDSERPARPORT	0x78
+#define VIDINXDELTA	0x7c
+#define VIDININITERR	0x80
+#define VIDINYDELTA	0x84
+#define VIDPIXBUFTHOLD	0x88
+#define VIDCHRMIN	0x8c
+#define VIDCHRMAX	0x90
+#define VIDCURLIN	0x94
+#define VIDSCREENSIZE	0x98
+#define VIDOVRSTARTCRD	0x9c
+#define VIDOVRENDCRD	0xa0
+#define VIDOVRDUDX	0xa4
+#define VIDOVRDUDXOFF	0xa8
+#define VIDOVRDVDY	0xac
+/*  ... */
+#define VIDOVRDVDYOFF	0xe0
+#define VIDDESKSTART	0xe4
+#define VIDDESKSTRIDE	0xe8
+#define VIDINADDR0	0xec
+#define VIDINADDR1	0xf0
+#define VIDINADDR2	0xf4
+#define VIDINSTRIDE	0xf8
+#define VIDCUROVRSTART	0xfc
+
+#define INTCTRL		(0x00100000 + 0x04)
+#define CLIP0MIN	(0x00100000 + 0x08)
+#define CLIP0MAX	(0x00100000 + 0x0c)
+#define DSTBASE		(0x00100000 + 0x10)
+#define DSTFORMAT	(0x00100000 + 0x14)
+#define SRCBASE		(0x00100000 + 0x34)
+#define COMMANDEXTRA_2D	(0x00100000 + 0x38)
+#define CLIP1MIN	(0x00100000 + 0x4c)
+#define CLIP1MAX	(0x00100000 + 0x50)
+#define SRCFORMAT	(0x00100000 + 0x54)
+#define SRCSIZE		(0x00100000 + 0x58)
+#define SRCXY		(0x00100000 + 0x5c)
+#define COLORBACK	(0x00100000 + 0x60)
+#define COLORFORE	(0x00100000 + 0x64)
+#define DSTSIZE		(0x00100000 + 0x68)
+#define DSTXY		(0x00100000 + 0x6c)
+#define COMMAND_2D	(0x00100000 + 0x70)
+#define LAUNCH_2D	(0x00100000 + 0x80)
+
+#define COMMAND_3D	(0x00200000 + 0x120)
+
+/* register bitfields (not all, only as needed) */
+
+#define BIT(x) (1UL << (x))
+
+#define ROP_COPY	0xcc
+
+#define COMMAND_2D_FILLRECT		0x05
+#define COMMAND_2D_BITBLT		0x01
+
+#define COMMAND_3D_NOP			0x00
+
+#define STATUS_RETRACE			BIT(6)
+#define STATUS_BUSY			BIT(9)
+
+#define MISCINIT1_CLUT_INV		BIT(0)
+#define MISCINIT1_2DBLOCK_DIS		BIT(15)
+
+#define DRAMINIT0_SGRAM_NUM		BIT(26)
+#define DRAMINIT0_SGRAM_TYPE		BIT(27)
+
+#define DRAMINIT1_MEM_SDRAM		BIT(30)
+
+#define VGAINIT0_VGA_DISABLE		BIT(0)
+#define VGAINIT0_EXT_TIMING		BIT(1)
+#define VGAINIT0_8BIT_DAC		BIT(2)
+#define VGAINIT0_EXT_ENABLE		BIT(6)
+#define VGAINIT0_WAKEUP_3C3		BIT(8)
+#define VGAINIT0_LEGACY_DISABLE		BIT(9)
+#define VGAINIT0_ALT_READBACK		BIT(10)
+#define VGAINIT0_FAST_BLINK		BIT(11)
+#define VGAINIT0_EXTSHIFTOUT		BIT(12)
+#define VGAINIT0_DECODE_3C6		BIT(13)
+#define VGAINIT0_SGRAM_HBLANK_DISABLE	BIT(22)
+
+#define VGAINIT1_MASK			0x1fffff
+
+#define VIDCFG_VIDPROC_ENABLE		BIT(0)
+#define VIDCFG_CURS_X11			BIT(1)
+#define VIDCFG_HALF_MODE		BIT(4)
+#define VIDCFG_DESK_ENABLE		BIT(7)
+#define VIDCFG_CLUT_BYPASS		BIT(10)
+#define VIDCFG_2X			BIT(26)
+#define VIDCFG_PIXFMT_SHIFT		18
+
+#define DACMODE_2X			BIT(0)
+
+/* VGA rubbish, need to change this for multihead support */
+#define MISC_W 	0x3c2
+#define MISC_R 	0x3cc
+#define SEQ_I 	0x3c4
+#define SEQ_D	0x3c5
+#define CRT_I	0x3d4
+#define CRT_D	0x3d5
+#define ATT_IW	0x3c0
+#define IS1_R	0x3da
+#define GRA_I	0x3ce
+#define GRA_D	0x3cf
+#define DAC_IR	0x3c7
+#define DAC_IW	0x3c8
+#define DAC_D	0x3c9
+
+#ifndef FB_ACCEL_3DFX_BANSHEE 
+#define FB_ACCEL_3DFX_BANSHEE 31
+#endif
+
+#define TDFXF_HSYNC_ACT_HIGH	0x01
+#define TDFXF_HSYNC_ACT_LOW	0x02
+#define TDFXF_VSYNC_ACT_HIGH	0x04
+#define TDFXF_VSYNC_ACT_LOW	0x08
+#define TDFXF_LINE_DOUBLE	0x10
+#define TDFXF_VIDEO_ENABLE	0x20
+
+#define TDFXF_HSYNC_MASK	0x03
+#define TDFXF_VSYNC_MASK	0x0c
+
+/* #define TDFXFB_DEBUG */
+#ifdef TDFXFB_DEBUG
+#define DPRINTK(a,b...) printk("fb: %s: " a, __FUNCTION__ , ## b)
+#else
+#define DPRINTK(a,b...)
+#endif 
+
+#define PICOS2KHZ(a) (1000000000UL/(a))
+#define KHZ2PICOS(a) (1000000000UL/(a))
+
+#define BANSHEE_MAX_PIXCLOCK 270000.0
+#define VOODOO3_MAX_PIXCLOCK 300000.0
+
+struct banshee_reg {
+  /* VGA rubbish */
+  unsigned char att[21];
+  unsigned char crt[25];
+  unsigned char gra[ 9];
+  unsigned char misc[1];
+  unsigned char seq[ 5];
+
+  /* Banshee extensions */
+  unsigned char ext[2];
+  unsigned long vidcfg;
+  unsigned long vidpll;
+  unsigned long mempll;
+  unsigned long gfxpll;
+  unsigned long dacmode;
+  unsigned long vgainit0;
+  unsigned long vgainit1;
+  unsigned long screensize;
+  unsigned long stride;
+  unsigned long cursloc;
+  unsigned long startaddr;
+  unsigned long clip0min;
+  unsigned long clip0max;
+  unsigned long clip1min;
+  unsigned long clip1max;
+  unsigned long srcbase;
+  unsigned long dstbase;
+};
+
+struct tdfxfb_par {
+  u32 pixclock;
+
+  u32 baseline;
+
+  u32 width;
+  u32 height;
+  u32 width_virt;
+  u32 height_virt;
+  u32 lpitch; /* line pitch, in bytes */
+  u32 ppitch; /* pixel pitch, in bits */
+  u32 bpp;    
+
+  u32 hdispend;
+  u32 hsyncsta;
+  u32 hsyncend;
+  u32 htotal;
+
+  u32 vdispend;
+  u32 vsyncsta;
+  u32 vsyncend;
+  u32 vtotal;
+
+  u32 video;
+  u32 accel_flags;
+};
+
+struct fb_info_tdfx {
+  struct fb_info fb_info;
+
+  u16 dev;
+  u32 max_pixclock;
+
+  unsigned long regbase_phys;
+  unsigned long regbase_virt;
+  unsigned long regbase_size;
+  unsigned long bufbase_phys;
+  unsigned long bufbase_virt;
+  unsigned long bufbase_size;
+
+  struct { u8 red, green, blue, pad; } palette[256];
+  struct tdfxfb_par default_par;
+  struct tdfxfb_par current_par;
+  struct display disp;
+  struct display_switch dispsw;
+  
+  union {
+#ifdef FBCON_HAS_CFB16
+    u16 cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+    u32 cfb32[16];
+#endif
+  } fbcon_cmap;
+};
+
+/*
+ *  Frame buffer device API
+ */
+static int tdfxfb_open(struct fb_info* info, 
+		       int user);
+static int tdfxfb_release(struct fb_info* info, 
+			  int user);
+static int tdfxfb_get_fix(struct fb_fix_screeninfo* fix, 
+			  int con,
+			  struct fb_info* fb);
+static int tdfxfb_get_var(struct fb_var_screeninfo* var, 
+			  int con,
+			  struct fb_info* fb);
+static int tdfxfb_set_var(struct fb_var_screeninfo* var,
+			  int con,
+			  struct fb_info* fb);
+static int tdfxfb_pan_display(struct fb_var_screeninfo* var, 
+			      int con,
+			      struct fb_info* fb);
+static int tdfxfb_get_cmap(struct fb_cmap *cmap, 
+			   int kspc, 
+			   int con,
+			   struct fb_info* info);
+static int tdfxfb_set_cmap(struct fb_cmap* cmap, 
+			   int kspc, 
+			   int con,
+			   struct fb_info* info);
+static int tdfxfb_ioctl(struct inode* inode, 
+			struct file* file, 
+			u_int cmd,
+			u_long arg, 
+			int con, 
+			struct fb_info* info);
+
+/*
+ *  Interface to the low level console driver
+ */
+static int  tdfxfb_switch_con(int con, 
+			      struct fb_info* fb);
+static int  tdfxfb_updatevar(int con, 
+			     struct fb_info* fb);
+static void tdfxfb_blank(int blank, 
+			 struct fb_info* fb);
+
+/*
+ *  Internal routines
+ */
+static void tdfxfb_set_par(const struct tdfxfb_par* par,
+			   struct fb_info_tdfx* 
+			   info);
+static int  tdfxfb_decode_var(const struct fb_var_screeninfo *var,
+			      struct tdfxfb_par *par,
+			      const struct fb_info_tdfx *info);
+static int  tdfxfb_encode_var(struct fb_var_screeninfo* var,
+			      const struct tdfxfb_par* par,
+			      const struct fb_info_tdfx* info);
+static int  tdfxfb_encode_fix(struct fb_fix_screeninfo* fix,
+			      const struct tdfxfb_par* par,
+			      const struct fb_info_tdfx* info);
+static void tdfxfb_set_disp(struct display* disp, 
+			    struct fb_info_tdfx* info,
+			    int bpp, 
+			    int accel);
+static int  tdfxfb_getcolreg(u_int regno,
+			     u_int* red, 
+			     u_int* green, 
+			     u_int* blue,
+			     u_int* transp, 
+			     struct fb_info* fb);
+static int  tdfxfb_setcolreg(u_int regno, 
+			     u_int red, 
+			     u_int green, 
+			     u_int blue,
+			     u_int transp, 
+			     struct fb_info* fb);
+static void  tdfxfb_install_cmap(int con, 
+				 struct fb_info *info);
+
+/*
+ *  Interface used by the world
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+void tdfxfb_init(void);
+#else
+int tdfxfb_init(void);
+#endif
+void tdfxfb_setup(char *options, 
+		  int *ints);
+
+static int currcon = 0;
+
+static struct fb_ops tdfxfb_ops = {
+  tdfxfb_open, 
+  tdfxfb_release, 
+  tdfxfb_get_fix, 
+  tdfxfb_get_var, 
+  tdfxfb_set_var,
+  tdfxfb_get_cmap, 
+  tdfxfb_set_cmap, 
+  tdfxfb_pan_display, 
+  tdfxfb_ioctl,
+  NULL
+};
+
+struct mode {
+  char* name;
+  struct fb_var_screeninfo var;
+} mode;
+
+/* 2.3.x kernels have a fb mode database, so supply only one backup default */
+struct mode default_mode[] = {
+  { "640x480-8@60", /* @ 60 Hz */
+    {
+      640, 480, 640, 480, 0, 0, 8, 0,
+      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+      0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT, 
+      39722, 40, 24, 32, 11, 96, 2,
+      0, FB_VMODE_NONINTERLACED
+    }
+  }
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+  ,
+  { "800x600-8@56", /* @ 56 Hz */
+    {
+      800, 600, 800, 600, 0, 0, 8, 0,
+      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+      0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT, 
+      27778, 128, 24, 22, 1, 72, 2,
+      0, FB_VMODE_NONINTERLACED
+    }
+  },
+  { "1024x768-8@60", /* @ 60 Hz */
+    {
+      1024, 768, 1024, 768, 0, 0, 8, 0,
+      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+      0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT, 
+      15385, 168, 8, 29, 3, 144, 6,
+      0, FB_VMODE_NONINTERLACED
+    }
+  },
+  { "1280x1024-8@61", /* @ 61 Hz */
+    {
+      1280, 1024, 1280, 1024, 0, 0, 8, 0,
+      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+      0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT, 
+      9091, 200, 48, 26, 1, 184, 3,
+      0, FB_VMODE_NONINTERLACED
+    }
+  },
+  { "1024x768-16@60", /* @ 60 Hz */ /* basically for testing */
+    {
+      1024, 768, 1024, 768, 0, 0, 16, 0,
+      {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
+      0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT, 
+      15385, 168, 8, 29, 3, 144, 6,
+      0, FB_VMODE_NONINTERLACED
+    }
+  }
+#endif
+};
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+static int modes = sizeof(default_mode)/sizeof(struct mode);
+static int default_mode_index = 0;
+#endif
+
+static struct fb_info_tdfx fb_info;
+
+static int  __initdata noaccel = 0;
+static int  __initdata nopan   = 0;
+static int  __initdata nowrap  = 0;
+static int  __initdata inverse = 0;
+static char __initdata fontname[40] = { 0 };
+static const char *mode_option __initdata = NULL;
+
+/* ------------------------------------------------------------------------- */
+
+static inline  __u8 vga_inb(__u32 reg) { return inb(reg); }
+static inline __u16 vga_inw(__u32 reg) { return inw(reg); }
+static inline __u16 vga_inl(__u32 reg) { return inl(reg); }
+
+static inline void vga_outb(__u32 reg,  __u8 val) { outb(val, reg); }
+static inline void vga_outw(__u32 reg, __u16 val) { outw(val, reg); }
+static inline void vga_outl(__u32 reg, __u32 val) { outl(val, reg); }
+
+static inline void gra_outb(__u32 idx, __u8 val) {
+  vga_outb(GRA_I, idx); vga_outb(GRA_D, val);
+}
+
+static inline __u8 gra_inb(__u32 idx) {
+  vga_outb(GRA_I, idx); return vga_inb(GRA_D);
+}
+
+static inline void seq_outb(__u32 idx, __u8 val) {
+  vga_outb(SEQ_I, idx); vga_outb(SEQ_D, val);
+}
+
+static inline __u8 seq_inb(__u32 idx) {
+  vga_outb(SEQ_I, idx); return vga_inb(SEQ_D);
+}
+
+static inline void crt_outb(__u32 idx, __u8 val) {
+  vga_outb(CRT_I, idx); vga_outb(CRT_D, val);
+}
+
+static inline __u8 crt_inb(__u32 idx) {
+  vga_outb(CRT_I, idx); return vga_inb(CRT_D);
+}
+
+static inline void att_outb(__u32 idx, __u8 val) {
+  unsigned char tmp;
+  tmp = vga_inb(IS1_R);
+  vga_outb(ATT_IW, idx);
+  vga_outb(ATT_IW, val);
+}
+
+static inline __u8 att_inb(__u32 idx) {
+  unsigned char tmp;
+  tmp = vga_inb(IS1_R);
+  vga_outb(ATT_IW, idx);
+  return vga_inb(ATT_IW);
+}
+
+static inline void vga_disable_video(void) {
+  unsigned char s;
+  s = seq_inb(0x01) | 0x20;
+  seq_outb(0x00, 0x01);
+  seq_outb(0x01, s);
+  seq_outb(0x00, 0x03);
+}
+
+static inline void vga_enable_video(void) {
+  unsigned char s;
+  s = seq_inb(0x01) & 0xdf;
+  seq_outb(0x00, 0x01);
+  seq_outb(0x01, s);
+  seq_outb(0x00, 0x03);
+}
+
+static inline void vga_disable_palette(void) {
+  vga_inb(IS1_R);
+  vga_outb(ATT_IW, 0x00);
+}
+
+static inline void vga_enable_palette(void) {
+  vga_inb(IS1_R);
+  vga_outb(ATT_IW, 0x20);
+}
+
+static inline __u32 tdfx_inl(unsigned int reg) {
+  return readl(fb_info.regbase_virt + reg);
+}
+
+static inline void tdfx_outl(unsigned int reg, __u32 val) {
+  writel(val, fb_info.regbase_virt + reg);
+}
+
+static inline void banshee_make_room(int size) {
+  while((tdfx_inl(STATUS) & 0x1f) < size);
+}
+ 
+static inline void banshee_wait_idle(void) {
+  int i = 0;
+
+  banshee_make_room(1);
+  tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
+
+  while(1) {
+    i = (tdfx_inl(STATUS) & STATUS_BUSY) ? 0 : i + 1;
+    if(i == 3) break;
+  }
+}
+
+static void banshee_fillrect(__u32 x, 
+			     __u32 y, 
+			     __u32 w,
+			     __u32 h, 
+			     __u32 color,
+			     __u32 stride,
+			     __u32 bpp) {
+  banshee_make_room(2);
+  tdfx_outl(DSTFORMAT, 
+	    (stride & 0x3fff) | 
+	    (bpp ==  8 ? 0x10000 : 
+	     bpp == 16 ? 0x30000 : 0x50000));
+  tdfx_outl(COLORFORE, color);
+  
+  banshee_make_room(3);
+  tdfx_outl(COMMAND_2D, COMMAND_2D_FILLRECT | (ROP_COPY << 24));
+  tdfx_outl(DSTSIZE,    (w & 0x1fff) | ((h & 0x1fff) << 16));
+  tdfx_outl(LAUNCH_2D,  (x & 0x1fff) | ((y & 0x1fff) << 16));
+}
+
+static void banshee_bitblt(__u32 curx, 
+			   __u32 cury, 
+			   __u32 dstx,
+			   __u32 dsty, 
+			   __u32 width, 
+			   __u32 height,
+			   __u32 stride,
+			   __u32 bpp) {
+  int xdir, ydir;
+
+  xdir = dstx < curx ? 1 : -1;
+  ydir = dsty < cury ? 1 : -1;
+
+  banshee_make_room(4);
+  tdfx_outl(SRCFORMAT, 
+	    (stride & 0x3fff) | 
+	    (bpp ==  8 ? 0x10000 : 
+	     bpp == 16 ? 0x30000 : 0x50000));
+  tdfx_outl(DSTFORMAT, 
+	    (stride & 0x3fff) | 
+	    (bpp ==  8 ? 0x10000 : 
+	     bpp == 16 ? 0x30000 : 0x50000));
+  tdfx_outl(COMMAND_2D, 
+	    COMMAND_2D_BITBLT | 
+	    (xdir == -1 ? BIT(14) : 0) |
+	    (ydir == -1 ? BIT(15) : 0));
+  tdfx_outl(COMMANDEXTRA_2D, 0); /* no color keying */
+
+  if(xdir == -1) {
+    curx += width - 1;
+    dstx += width - 1;
+  }
+  if(ydir == -1) {
+    cury += height - 1;
+    dsty += height - 1;
+  }
+  
+  /* Consecutive overlapping regions can hang the board -- 
+     since we allow mmap'ing of control registers, we cannot
+     __safely__ assume anything, like XF86 does... */
+  banshee_make_room(1);
+  tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
+
+  banshee_make_room(3);
+  tdfx_outl(DSTSIZE,   (width & 0x1fff) | ((height & 0x1fff) << 16));
+  tdfx_outl(DSTXY,     (dstx  & 0x1fff) | ((dsty  & 0x1fff) << 16));
+  tdfx_outl(LAUNCH_2D, (curx  & 0x1fff) | ((cury  & 0x1fff) << 16));
+}
+
+static __u32 banshee_calc_pll(int freq, int* freq_out) {
+  int m, n, k, best_m, best_n, best_k, f_cur, best_error;
+  int fref = 14318;
+  
+  /* this really could be done with more intelligence */
+  best_error = freq;
+  best_n = best_m = best_k = 0;
+  for(n = 1; n < 256; n++) {
+    for(m = 1; m < 64; m++) {
+      for(k = 0; k < 4; k++) {
+	f_cur = fref*(n + 2)/(m + 2)/(1 << k);
+	if(abs(f_cur - freq) < best_error) {
+	  best_error = abs(f_cur-freq);
+	  best_n = n;
+	  best_m = m;
+	  best_k = k;
+	}
+      }
+    }
+  }
+  n = best_n;
+  m = best_m;
+  k = best_k;
+  *freq_out = fref*(n + 2)/(m + 2)/(1 << k);
+
+  DPRINTK("freq = %d kHz, freq_out = %d kHz\n", freq, *freq_out);
+  DPRINTK("N = %d, M = %d, K = %d\n", n, m, k);
+
+  return (n << 8) | (m << 2) | k;
+}
+
+static void banshee_write_regs(struct banshee_reg* reg) {
+  int i;
+
+  banshee_wait_idle();
+
+  tdfx_outl(MISCINIT1, tdfx_inl(MISCINIT1) | 0x01);
+
+  crt_outb(0x11, crt_inb(0x11) & 0x7f); /* CRT unprotect */
+
+  banshee_make_room(3);
+  tdfx_outl(VGAINIT1,      reg->vgainit1 &  0x001FFFFF);
+  tdfx_outl(VIDPROCCFG,    reg->vidcfg   & ~0x00000001);
+#if 0
+  tdfx_outl(PLLCTRL1,      reg->mempll);
+  tdfx_outl(PLLCTRL2,      reg->gfxpll);
+#endif
+  tdfx_outl(PLLCTRL0,      reg->vidpll);
+
+  vga_outb(MISC_W, reg->misc[0x00] | 0x01);
+
+  for(i = 0; i < 5; i++)
+    seq_outb(i, reg->seq[i]);
+
+  for(i = 0; i < 25; i++)
+    crt_outb(i, reg->crt[i]);
+
+  for(i = 0; i < 9; i++)
+    gra_outb(i, reg->gra[i]);
+
+  for(i = 0; i < 21; i++)
+    att_outb(i, reg->att[i]);
+
+  crt_outb(0x1a, reg->ext[0]);
+  crt_outb(0x1b, reg->ext[1]);
+
+  vga_enable_palette();
+  vga_enable_video();
+
+  banshee_make_room(9);
+  tdfx_outl(VGAINIT0,      reg->vgainit0);
+  tdfx_outl(DACMODE,       reg->dacmode);
+  tdfx_outl(VIDDESKSTRIDE, reg->stride);
+  tdfx_outl(HWCURPATADDR,  reg->cursloc);
+  tdfx_outl(VIDSCREENSIZE, reg->screensize);
+  tdfx_outl(VIDDESKSTART,  reg->startaddr);
+  tdfx_outl(VIDPROCCFG,    reg->vidcfg);
+  tdfx_outl(VGAINIT1,      reg->vgainit1);  
+
+  banshee_make_room(7);
+  tdfx_outl(SRCBASE,         reg->srcbase);
+  tdfx_outl(DSTBASE,         reg->dstbase);
+  tdfx_outl(COMMANDEXTRA_2D, 0);
+  tdfx_outl(CLIP0MIN,        0);
+  tdfx_outl(CLIP0MAX,        0x0fff0fff);
+  tdfx_outl(CLIP1MIN,        0);
+  tdfx_outl(CLIP1MAX,        0x0fff0fff);
+
+  banshee_wait_idle();
+}
+
+static unsigned long tdfx_lfb_size(void) {
+  __u32 draminit0 = 0;
+  __u32 draminit1 = 0;
+  __u32 miscinit1 = 0;
+  __u32 lfbsize   = 0;
+  int sgram_p     = 0;
+
+  if(!((fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE) ||
+       (fb_info.dev == PCI_DEVICE_ID_3DFX_VOODOO3)))
+    return 0;
+
+  draminit0 = tdfx_inl(DRAMINIT0);  
+  draminit1 = tdfx_inl(DRAMINIT1);
+
+  sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1;
+  
+  lfbsize = sgram_p ?
+    (((draminit0 & DRAMINIT0_SGRAM_NUM)  ? 2 : 1) * 
+     ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * 1024) :
+    16 * 1024 * 1024;
+
+  /* disable block writes for SDRAM (why?) */
+  miscinit1 = tdfx_inl(MISCINIT1);
+  miscinit1 |= sgram_p ? 0 : MISCINIT1_2DBLOCK_DIS;
+  miscinit1 |= MISCINIT1_CLUT_INV;
+  tdfx_outl(MISCINIT1, miscinit1);
+
+  return lfbsize;
+}
+
+static void fbcon_banshee_bmove(struct display* p, 
+				int sy, 
+				int sx, 
+				int dy,
+				int dx, 
+				int height, 
+				int width) {
+  banshee_bitblt(fontwidth(p)*sx,
+		 fontheight(p)*sy, 
+		 fontwidth(p)*dx,
+		 fontheight(p)*dy, 
+		 fontwidth(p)*width, 
+		 fontheight(p)*height, 
+		 fb_info.current_par.lpitch, 
+		 fb_info.current_par.bpp);
+}
+
+static void fbcon_banshee_clear(struct vc_data* conp, 
+				struct display* p, 
+				int sy,
+				int sx, 
+				int height, 
+				int width) {
+  unsigned int bg;
+
+  bg = attr_bgcol_ec(p,conp);
+  banshee_fillrect(fontwidth(p)*sx,
+		   fontheight(p)*sy,
+		   fontwidth(p)*width, 
+		   fontheight(p)*height,
+		   bg, 
+		   fb_info.current_par.lpitch, 
+		   fb_info.current_par.bpp);
+}
+
+#ifdef FBCON_HAS_CFB8
+static struct display_switch fbcon_banshee8 = {
+   fbcon_cfb8_setup, 
+   fbcon_banshee_bmove, 
+   fbcon_banshee_clear, 
+   fbcon_cfb8_putc,
+   fbcon_cfb8_putcs, 
+   fbcon_cfb8_revc, 
+   NULL, 
+   NULL, 
+   fbcon_cfb8_clear_margins,
+   FONTWIDTH(8)
+};
+#endif
+#ifdef FBCON_HAS_CFB16
+static struct display_switch fbcon_banshee16 = {
+   fbcon_cfb16_setup, 
+   fbcon_banshee_bmove, 
+   fbcon_banshee_clear, 
+   fbcon_cfb16_putc,
+   fbcon_cfb16_putcs, 
+   fbcon_cfb16_revc, 
+   NULL, 
+   NULL, 
+   fbcon_cfb16_clear_margins,
+   FONTWIDTH(8)
+};
+#endif
+#ifdef FBCON_HAS_CFB32
+static struct display_switch fbcon_banshee32 = {
+   fbcon_cfb32_setup, 
+   fbcon_banshee_bmove, 
+   fbcon_banshee_clear, 
+   fbcon_cfb32_putc,
+   fbcon_cfb32_putcs, 
+   fbcon_cfb32_revc, 
+   NULL, 
+   NULL, 
+   fbcon_cfb32_clear_margins,
+   FONTWIDTH(8)
+};
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+static void tdfxfb_set_par(const struct tdfxfb_par* par,
+			   struct fb_info_tdfx*     info) {
+  struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
+  struct banshee_reg reg;
+  __u32 cpp;
+  __u32 hd, hs, he, ht, hbs, hbe;
+  __u32 vd, vs, ve, vt, vbs, vbe;
+  __u32 wd;
+  int fout;
+  int freq;
+
+  memset(&reg, 0, sizeof(reg));
+
+  cpp = (par->bpp + 7)/8;
+  
+  wd = (par->hdispend >> 3) - 1;
+
+  hd  = (par->hdispend >> 3) - 1;
+  hs  = (par->hsyncsta >> 3) - 1;
+  he  = (par->hsyncend >> 3) - 1;
+  ht  = (par->htotal   >> 3) - 1;
+  hbs = hd;
+  hbe = ht;
+
+  vd  = par->vdispend - 1;
+  vs  = par->vsyncsta - 1;
+  ve  = par->vsyncend - 1;
+  vt  = par->vtotal   - 2;
+  vbs = vd;
+  vbe = vt;
+  
+  /* this is all pretty standard VGA register stuffing */
+  reg.misc[0x00] = 
+    0x0f |
+    (par->hdispend < 400 ? 0xa0 :
+     par->hdispend < 480 ? 0x60 :
+     par->hdispend < 768 ? 0xe0 : 0x20);
+     
+  reg.gra[0x00] = 0x00;
+  reg.gra[0x01] = 0x00;
+  reg.gra[0x02] = 0x00;
+  reg.gra[0x03] = 0x00;
+  reg.gra[0x04] = 0x00;
+  reg.gra[0x05] = 0x40;
+  reg.gra[0x06] = 0x05;
+  reg.gra[0x07] = 0x0f;
+  reg.gra[0x08] = 0xff;
+
+  reg.att[0x00] = 0x00;
+  reg.att[0x01] = 0x01;
+  reg.att[0x02] = 0x02;
+  reg.att[0x03] = 0x03;
+  reg.att[0x04] = 0x04;
+  reg.att[0x05] = 0x05;
+  reg.att[0x06] = 0x06;
+  reg.att[0x07] = 0x07;
+  reg.att[0x08] = 0x08;
+  reg.att[0x09] = 0x09;
+  reg.att[0x0a] = 0x0a;
+  reg.att[0x0b] = 0x0b;
+  reg.att[0x0c] = 0x0c;
+  reg.att[0x0d] = 0x0d;
+  reg.att[0x0e] = 0x0e;
+  reg.att[0x0f] = 0x0f;
+  reg.att[0x10] = 0x41;
+  reg.att[0x11] = 0x00;
+  reg.att[0x12] = 0x0f;
+  reg.att[0x13] = 0x00;
+  reg.att[0x14] = 0x00;
+
+  reg.seq[0x00] = 0x03;
+  reg.seq[0x01] = 0x01; /* fixme: clkdiv2? */
+  reg.seq[0x02] = 0x0f;
+  reg.seq[0x03] = 0x00;
+  reg.seq[0x04] = 0x0e;
+
+  reg.crt[0x00] = ht - 4;
+  reg.crt[0x01] = hd;
+  reg.crt[0x02] = hbs;
+  reg.crt[0x03] = 0x80 | (hbe & 0x1f);
+  reg.crt[0x04] = hs;
+  reg.crt[0x05] = 
+    ((hbe & 0x20) << 2) | 
+    (he & 0x1f);
+  reg.crt[0x06] = vt;
+  reg.crt[0x07] = 
+    ((vs & 0x200) >> 2) |
+    ((vd & 0x200) >> 3) |
+    ((vt & 0x200) >> 4) |
+    0x10 |
+    ((vbs & 0x100) >> 5) |
+    ((vs  & 0x100) >> 6) |
+    ((vd  & 0x100) >> 7) |
+    ((vt  & 0x100) >> 8);
+  reg.crt[0x08] = 0x00;
+  reg.crt[0x09] = 
+    0x40 |
+    ((vbs & 0x200) >> 4);
+  reg.crt[0x0a] = 0x00;
+  reg.crt[0x0b] = 0x00;
+  reg.crt[0x0c] = 0x00;
+  reg.crt[0x0d] = 0x00;
+  reg.crt[0x0e] = 0x00;
+  reg.crt[0x0f] = 0x00;
+  reg.crt[0x10] = vs;
+  reg.crt[0x11] = 
+    (ve & 0x0f) |
+    0x20;
+  reg.crt[0x12] = vd;
+  reg.crt[0x13] = wd;
+  reg.crt[0x14] = 0x00;
+  reg.crt[0x15] = vbs;
+  reg.crt[0x16] = vbe + 1; 
+  reg.crt[0x17] = 0xc3;
+  reg.crt[0x18] = 0xff;
+  
+  /* Banshee's nonvga stuff */
+  reg.ext[0x00] = (((ht  & 0x100) >> 8) | 
+		   ((hd  & 0x100) >> 6) |
+		   ((hbs & 0x100) >> 4) |
+		   ((hbe &  0x40) >> 1) |
+		   ((hs  & 0x100) >> 2) |
+		   ((he  &  0x20) << 2)); 
+  reg.ext[0x01] = (((vt  & 0x400) >> 10) |
+		   ((vd  & 0x400) >>  8) | 
+		   ((vbs & 0x400) >>  6) |
+		   ((vbe & 0x400) >>  4));
+  
+  reg.vgainit0 = 
+    VGAINIT0_8BIT_DAC     |
+    VGAINIT0_EXT_ENABLE   |
+    VGAINIT0_WAKEUP_3C3   |
+    VGAINIT0_ALT_READBACK |
+    VGAINIT0_EXTSHIFTOUT;
+  reg.vgainit1 = tdfx_inl(VGAINIT1) & 0x1fffff;
+
+  reg.vidcfg = 
+    VIDCFG_VIDPROC_ENABLE |
+    VIDCFG_DESK_ENABLE    |
+    ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) |
+    (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0);
+  reg.stride    = par->width*cpp;
+  reg.cursloc   = 0;
+
+  reg.startaddr = par->baseline*reg.stride;
+  reg.srcbase   = reg.startaddr;
+  reg.dstbase   = reg.startaddr;
+
+  /* PLL settings */
+  freq = par->pixclock;
+
+  reg.dacmode &= ~DACMODE_2X;
+  reg.vidcfg  &= ~VIDCFG_2X;
+  if(freq > i->max_pixclock/2) {
+    freq = freq > i->max_pixclock ? i->max_pixclock : freq;
+    reg.dacmode |= DACMODE_2X;
+    reg.vidcfg  |= VIDCFG_2X;
+  }
+  reg.vidpll = banshee_calc_pll(freq, &fout);
+#if 0
+  reg.mempll = banshee_calc_pll(..., &fout);
+  reg.gfxpll = banshee_calc_pll(..., &fout);
+#endif
+
+  reg.screensize = par->width | (par->height << 12);
+  reg.vidcfg &= ~VIDCFG_HALF_MODE;
+
+  banshee_write_regs(&reg);
+
+  i->current_par = *par;
+}
+
+static int tdfxfb_decode_var(const struct fb_var_screeninfo* var,
+			     struct tdfxfb_par*              par,
+			     const struct fb_info_tdfx*      info) {
+  struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
+
+  if(var->bits_per_pixel != 8  &&
+     var->bits_per_pixel != 16 &&
+     var->bits_per_pixel != 32) {
+    DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
+    return -EINVAL;
+  }
+
+  if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+    DPRINTK("interlace not supported\n");
+    return -EINVAL;
+  }
+
+  if(var->xoffset) {
+    DPRINTK("xoffset not supported\n");
+    return -EINVAL;
+  }
+
+  if(var->xres != var->xres_virtual) {
+    DPRINTK("virtual x resolution != physical x resolution not supported\n");
+    return -EINVAL;
+  }
+
+  if(nopan && nowrap) {
+    if(var->yres != var->yres_virtual) {
+      DPRINTK("virtual y resolution != physical y resolution not supported\n");
+      return -EINVAL;
+    }
+  } else {
+    if(var->yres > var->yres_virtual) {
+      DPRINTK("virtual y resolution < physical y resolution not possible\n");
+      return -EINVAL;
+    }
+  }
+
+  if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+    DPRINTK("interlace not supported\n");
+    return -EINVAL;
+  }
+
+  memset(par, 0, sizeof(struct tdfxfb_par));
+
+  switch(i->dev) {
+  case PCI_DEVICE_ID_3DFX_BANSHEE:
+  case PCI_DEVICE_ID_3DFX_VOODOO3:
+    par->width       = (var->xres + 15) & ~15; /* could sometimes be 8 */
+    par->width_virt  = par->width;
+    par->height      = var->yres;
+    par->height_virt = var->yres_virtual;
+    par->bpp         = var->bits_per_pixel;
+    par->ppitch      = var->bits_per_pixel;
+    par->lpitch      = par->width*par->ppitch/8;
+
+    par->baseline = 0;
+
+    if(par->width < 320 || par->width > 2048) {
+      DPRINTK("width not supported: %u\n", par->width);
+      return -EINVAL;
+    }
+    if(par->height < 200 || par->height > 2048) {
+      DPRINTK("height not supported: %u\n", par->height);
+      return -EINVAL;
+    }
+    if(par->lpitch*par->height_virt > i->bufbase_size) {
+      DPRINTK("no memory for screen (%ux%ux%u)\n",
+	      par->width, par->height_virt, par->bpp);
+      return -EINVAL;
+    }
+    par->pixclock = PICOS2KHZ(var->pixclock);
+    if(par->pixclock > i->max_pixclock) {
+      DPRINTK("pixclock too high (%uKHz)\n", par->pixclock);
+      return -EINVAL;
+    }
+
+    par->hdispend = var->xres;
+    par->hsyncsta = par->hdispend + var->right_margin;
+    par->hsyncend = par->hsyncsta + var->hsync_len;
+    par->htotal   = par->hsyncend + var->left_margin;
+
+    par->vdispend = var->yres;
+    par->vsyncsta = par->vdispend + var->lower_margin;
+    par->vsyncend = par->vsyncsta + var->vsync_len;
+    par->vtotal   = par->vsyncend + var->upper_margin;
+
+    if(var->sync & FB_SYNC_HOR_HIGH_ACT)
+      par->video |= TDFXF_HSYNC_ACT_HIGH;
+    else
+      par->video |= TDFXF_HSYNC_ACT_LOW;
+    if(var->sync & FB_SYNC_VERT_HIGH_ACT)
+      par->video |= TDFXF_VSYNC_ACT_HIGH;
+    else
+      par->video |= TDFXF_VSYNC_ACT_LOW;
+    if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
+      par->video |= TDFXF_LINE_DOUBLE;
+    if(var->activate == FB_ACTIVATE_NOW)
+      par->video |= TDFXF_VIDEO_ENABLE;
+  }
+
+  if(var->accel_flags & FB_ACCELF_TEXT)
+    par->accel_flags = FB_ACCELF_TEXT;
+  else
+    par->accel_flags = 0;
+
+  return 0;
+}
+
+static int tdfxfb_encode_var(struct fb_var_screeninfo* var,
+			    const struct tdfxfb_par* par,
+			    const struct fb_info_tdfx* info) {
+  struct fb_var_screeninfo v;
+
+  memset(&v, 0, sizeof(struct fb_var_screeninfo));
+  v.xres_virtual   = par->width_virt;
+  v.yres_virtual   = par->height_virt;
+  v.xres           = par->width;
+  v.yres           = par->height;
+  v.right_margin   = par->hsyncsta - par->hdispend;
+  v.hsync_len      = par->hsyncend - par->hsyncsta;
+  v.left_margin    = par->htotal   - par->hsyncend;
+  v.lower_margin   = par->vsyncsta - par->vdispend;
+  v.vsync_len      = par->vsyncend - par->vsyncsta;
+  v.upper_margin   = par->vtotal   - par->vsyncend;
+  v.bits_per_pixel = par->bpp;
+  switch(par->bpp) {
+  case 8:
+    v.red.length = v.green.length = v.blue.length = 8;
+    break;
+  case 16:
+    v.red.offset   = 11;
+    v.red.length   = 5;
+    v.green.offset = 5;
+    v.green.length = 6;
+    v.blue.offset  = 0;
+    v.blue.length  = 5;
+    break;
+  case 32:
+    v.red.offset   = 16;
+    v.green.offset = 8;
+    v.blue.offset  = 0;
+    v.red.length = v.green.length = v.blue.length = 8;
+    break;
+  }
+  v.height = v.width = -1;
+  v.pixclock = KHZ2PICOS(par->pixclock);
+  if((par->video & TDFXF_HSYNC_MASK) == TDFXF_HSYNC_ACT_HIGH)
+    v.sync |= FB_SYNC_HOR_HIGH_ACT;
+  if((par->video & TDFXF_VSYNC_MASK) == TDFXF_VSYNC_ACT_HIGH)
+    v.sync |= FB_SYNC_VERT_HIGH_ACT;
+  if(par->video & TDFXF_LINE_DOUBLE)
+    v.vmode = FB_VMODE_DOUBLE;
+  *var = v;
+  return 0;
+}
+
+static int tdfxfb_open(struct fb_info* info, 
+		       int user) {
+  MOD_INC_USE_COUNT;
+  return(0);
+}
+
+static int tdfxfb_release(struct fb_info* info, 
+			  int user) {
+  MOD_DEC_USE_COUNT;
+  return(0);
+}
+
+
+static int tdfxfb_encode_fix(struct fb_fix_screeninfo*  fix,
+			     const struct tdfxfb_par*   par,
+			     const struct fb_info_tdfx* info) {
+  memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+
+  switch(info->dev) {
+  case PCI_DEVICE_ID_3DFX_BANSHEE:
+  case PCI_DEVICE_ID_3DFX_VOODOO3:
+	if (info->dev == PCI_DEVICE_ID_3DFX_BANSHEE)
+      strcpy(fix->id, "3Dfx Banshee");
+	else
+      strcpy(fix->id, "3Dfx Voodoo3");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+    fix->smem_start  = (char*)info->bufbase_phys;
+    fix->smem_len    = info->bufbase_size;
+    fix->mmio_start  = (char*)info->regbase_phys;
+    fix->mmio_len    = info->regbase_size;
+#else
+    fix->smem_start  = info->bufbase_phys;
+    fix->smem_len    = info->bufbase_size;
+    fix->mmio_start  = info->regbase_phys;
+    fix->mmio_len    = info->regbase_size;
+#endif
+    fix->accel       = FB_ACCEL_3DFX_BANSHEE;
+    fix->type        = FB_TYPE_PACKED_PIXELS;
+    fix->type_aux    = 0;
+    fix->line_length = par->lpitch;
+    fix->visual      = par->bpp == 8 
+      ? FB_VISUAL_PSEUDOCOLOR
+      : FB_VISUAL_DIRECTCOLOR;
+
+    fix->xpanstep    = 0; 
+    fix->ypanstep    = (nowrap && nopan) ? 0 : 1;
+    fix->ywrapstep   = nowrap ? 0 : 1;
+
+    break;
+  default:
+    return -EINVAL;
+  }
+
+  return 0;
+}
+
+static int tdfxfb_get_fix(struct fb_fix_screeninfo *fix, 
+			  int con,
+			  struct fb_info *fb) {
+  const struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
+  struct tdfxfb_par par;
+
+  if(con == -1)
+    par = info->default_par;
+  else
+    tdfxfb_decode_var(&fb_display[con].var, &par, info);
+  tdfxfb_encode_fix(fix, &par, info);
+  return 0;
+}
+
+static int tdfxfb_get_var(struct fb_var_screeninfo *var, 
+			  int con,
+			  struct fb_info *fb) {
+  const struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
+
+  if(con == -1)
+    tdfxfb_encode_var(var, &info->default_par, info);
+  else
+    *var = fb_display[con].var;
+  return 0;
+}
+
+static void tdfxfb_set_disp(struct display *disp, 
+			    struct fb_info_tdfx *info,
+			    int bpp, 
+			    int accel) {
+  DPRINTK("actually, %s using acceleration!\n", 
+	  noaccel ? "NOT" : "");
+
+  switch(bpp) {
+#ifdef FBCON_HAS_CFB8
+  case 8:
+    info->dispsw = noaccel ? fbcon_cfb8 : fbcon_banshee8;
+    disp->dispsw = &info->dispsw;
+    break;
+#endif
+#ifdef FBCON_HAS_CFB16
+  case 16:
+    info->dispsw = noaccel ? fbcon_cfb16 : fbcon_banshee16;
+    disp->dispsw = &info->dispsw;
+    disp->dispsw_data = info->fbcon_cmap.cfb16;
+    break;
+#endif
+#ifdef FBCON_HAS_CFB32
+  case 32:
+    info->dispsw = noaccel ? fbcon_cfb32 : fbcon_banshee32;
+    disp->dispsw = &info->dispsw;
+    disp->dispsw_data = info->fbcon_cmap.cfb32;
+    break;
+#endif
+  default:
+    info->dispsw = fbcon_dummy;
+    disp->dispsw = &info->dispsw;
+  }
+}
+
+static int tdfxfb_set_var(struct fb_var_screeninfo *var, 
+			  int con,
+			  struct fb_info *fb) {
+  struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
+  struct tdfxfb_par par;
+  struct display *display;
+  int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err;
+  int activate = var->activate;
+
+  if(con >= 0)
+    display = &fb_display[con];
+  else
+    display = fb->disp;	/* used during initialization */
+
+  if((err = tdfxfb_decode_var(var, &par, info)))
+    return err;
+
+  tdfxfb_encode_var(var, &par, info);
+
+  if((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+    oldxres  = display->var.xres;
+    oldyres  = display->var.yres;
+    oldvxres = display->var.xres_virtual;
+    oldvyres = display->var.yres_virtual;
+    oldbpp   = display->var.bits_per_pixel;
+    oldaccel = display->var.accel_flags;
+    display->var = *var;
+    if(con < 0                         ||
+       oldxres  != var->xres           || 
+       oldyres  != var->yres           ||
+       oldvxres != var->xres_virtual   || 
+       oldvyres != var->yres_virtual   ||
+       oldbpp   != var->bits_per_pixel || 
+       oldaccel != var->accel_flags) {
+      struct fb_fix_screeninfo fix;
+
+      tdfxfb_encode_fix(&fix, &par, info);
+      display->screen_base    = (char *)info->bufbase_virt;
+      display->visual         = fix.visual;
+      display->type           = fix.type;
+      display->type_aux       = fix.type_aux;
+      display->ypanstep       = fix.ypanstep;
+      display->ywrapstep      = fix.ywrapstep;
+      display->line_length    = fix.line_length;
+      display->next_line      = fix.line_length;
+      display->can_soft_blank = 1;
+      display->inverse        = inverse;
+      accel = var->accel_flags & FB_ACCELF_TEXT;
+      tdfxfb_set_disp(display, info, par.bpp, accel);
+
+      if(nopan && nowrap) {
+	display->scrollmode = SCROLL_YREDRAW;
+#ifdef FBCON_HAS_CFB8
+	fbcon_banshee8.bmove = fbcon_redraw_bmove;
+#endif
+#ifdef FBCON_HAS_CFB16
+	fbcon_banshee16.bmove = fbcon_redraw_bmove;
+#endif
+#ifdef FBCON_HAS_CFB32
+	fbcon_banshee32.bmove = fbcon_redraw_bmove;
+#endif
+      }
+      if (info->fb_info.changevar)
+	(*info->fb_info.changevar)(con);
+    }
+    if(!info->fb_info.display_fg ||
+       info->fb_info.display_fg->vc_num == con ||
+       con < 0)
+      tdfxfb_set_par(&par, info);
+    if(oldbpp != var->bits_per_pixel || con < 0) {
+      if((err = fb_alloc_cmap(&display->cmap, 0, 0)))
+	return err;
+      tdfxfb_install_cmap(con, &info->fb_info);
+    }
+  }
+  
+  return 0;
+}
+
+static int tdfxfb_pan_display(struct fb_var_screeninfo* var, 
+			      int con,
+			      struct fb_info* fb) {
+  struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
+  __u32 addr;
+
+  if(nowrap && nopan) {
+    return -EINVAL;
+  } else {
+    if(var->xoffset) 
+      return -EINVAL;
+    if(var->yoffset < 0) 
+      return -EINVAL;
+    if(nopan && var->yoffset > var->yres_virtual) 
+      return -EINVAL;
+    if(nowrap && var->yoffset + var->yres > var->yres_virtual) 
+      return -EINVAL;
+    
+    i->current_par.baseline = var->yoffset;
+    
+    addr = var->yoffset*i->current_par.lpitch;
+    tdfx_outl(VIDDESKSTART, addr);
+    tdfx_outl(SRCBASE,      addr);
+    tdfx_outl(DSTBASE,      addr);
+    return 0;
+  }
+}
+
+static int tdfxfb_get_cmap(struct fb_cmap *cmap, 
+			   int kspc, 
+			   int con,
+			   struct fb_info *fb) {
+  if(!fb->display_fg || con == fb->display_fg->vc_num) {
+    /* current console? */
+    return fb_get_cmap(cmap, kspc, tdfxfb_getcolreg, fb);
+  } else if(fb_display[con].cmap.len) {
+    /* non default colormap? */
+    fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+  } else {
+    int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+    fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
+  }
+  return 0;
+}
+
+static int tdfxfb_set_cmap(struct fb_cmap *cmap, 
+			   int kspc, 
+			   int con,
+			   struct fb_info *fb) {
+  int err;
+  struct display *disp;
+
+  if(con >= 0)
+    disp = &fb_display[con];
+  else
+    disp = fb->disp;
+  if(!disp->cmap.len) {	/* no colormap allocated? */
+    int size = disp->var.bits_per_pixel == 16 ? 32 : 256;
+    if((err = fb_alloc_cmap(&disp->cmap, size, 0)))
+      return err;
+  }
+  if(!fb->display_fg || con == fb->display_fg->vc_num) {
+    /* current console? */
+    return fb_set_cmap(cmap, kspc, tdfxfb_setcolreg, fb);
+  } else {
+    fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
+  }
+  return 0;
+}
+
+static int tdfxfb_ioctl(struct inode *inode, 
+			struct file *file, 
+			u_int cmd,
+			u_long arg, 
+			int con, 
+			struct fb_info *fb) {
+  return -EINVAL;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+__initfunc(void tdfxfb_init(void)) {
+#else
+int __init tdfxfb_init(void) {
+#endif
+  struct pci_dev *pdev = NULL;
+  struct fb_var_screeninfo var;
+  int j, k;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+  if(!pcibios_present()) return;
+#else
+  if(!pcibios_present()) return -ENXIO;
+#endif
+
+  for(pdev = pci_devices; pdev; pdev = pdev->next) {
+    if(((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
+       (pdev->vendor == PCI_VENDOR_ID_3DFX) &&
+       ((pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE) ||
+	(pdev->device == PCI_DEVICE_ID_3DFX_VOODOO3))) {
+      
+      fb_info.dev   = pdev->device;
+      fb_info.max_pixclock = 
+	pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE 
+	? BANSHEE_MAX_PIXCLOCK
+	: VOODOO3_MAX_PIXCLOCK;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+      fb_info.regbase_phys = pdev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
+      fb_info.regbase_size = 1 << 25;
+      fb_info.regbase_virt = 
+	(__u32)ioremap_nocache(fb_info.regbase_phys, 1 << 25);
+      if(!fb_info.regbase_virt) {
+	if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
+	  printk("fb: Can't remap Banshee register area.\n");
+	else
+	  printk("fb: Can't remap Voodoo3 register area.\n");
+	return;
+      }
+
+      fb_info.bufbase_phys = pdev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK;
+      if(!(fb_info.bufbase_size = tdfx_lfb_size())) {
+	if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
+	  printk("fb: Can't count Banshee memory.\n");
+	else
+	  printk("fb: Can't count Voodoo3 memory.\n");
+	iounmap((void*)fb_info.regbase_virt);
+	return;
+      }
+      fb_info.bufbase_virt    = 
+	(__u32)ioremap_nocache(fb_info.bufbase_phys, 1 << 25);
+      if(!fb_info.regbase_virt) {
+	if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
+      printk("fb: Can't remap Banshee framebuffer.\n");
+	else
+      printk("fb: Can't remap Voodoo3 framebuffer.\n");
+	iounmap((void*)fb_info.regbase_virt);
+	return;
+      }
+#else
+      fb_info.regbase_phys = pdev->resource[0].start;
+      fb_info.regbase_size = 1 << 25;
+      fb_info.regbase_virt = 
+	(__u32)ioremap_nocache(fb_info.regbase_phys, 1 << 25);
+      if(!fb_info.regbase_virt) {
+	if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
+	  printk("fb: Can't remap Banshee register area.\n");
+	else
+	  printk("fb: Can't remap Voodoo3 register area.\n");
+	return -ENXIO;
+      }
+      
+      fb_info.bufbase_phys = pdev->resource[1].start;
+      if(!(fb_info.bufbase_size = tdfx_lfb_size())) {
+	iounmap((void*)fb_info.regbase_virt);
+	if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
+	  printk("fb: Can't count Banshee memory.\n");
+	else
+	  printk("fb: Can't count Voodoo3 memory.\n");
+	return -ENXIO;
+      }
+      fb_info.bufbase_virt    = 
+	(__u32)ioremap_nocache(fb_info.bufbase_phys, 1 << 25);
+      if(!fb_info.regbase_virt) {
+	if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
+	  printk("fb: Can't remap Banshee framebuffer.\n");
+	else
+	  printk("fb: Can't remap Voodoo3 framebuffer.\n");
+	iounmap((void*)fb_info.regbase_virt);
+	return -ENXIO;
+      }
+#endif
+      
+	if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
+      printk("fb: Banshee memory = %ldK\n", fb_info.bufbase_size >> 10);
+	else
+      printk("fb: Voodoo3 memory = %ldK\n", fb_info.bufbase_size >> 10);
+      
+      /* clear framebuffer memory */
+      memset_io(fb_info.bufbase_virt, 0, fb_info.bufbase_size);
+      
+	  if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
+        strcpy(fb_info.fb_info.modename, "3Dfx Banshee");
+	  else
+        strcpy(fb_info.fb_info.modename, "3Dfx Voodoo3");
+      fb_info.fb_info.changevar  = NULL;
+      fb_info.fb_info.node       = -1;
+      fb_info.fb_info.fbops      = &tdfxfb_ops;
+      fb_info.fb_info.disp       = &fb_info.disp;
+      strcpy(fb_info.fb_info.fontname, fontname);
+      fb_info.fb_info.switch_con = &tdfxfb_switch_con;
+      fb_info.fb_info.updatevar  = &tdfxfb_updatevar;
+      fb_info.fb_info.blank      = &tdfxfb_blank;
+      fb_info.fb_info.flags      = FBINFO_FLAG_DEFAULT;
+      
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+      var = default_mode[default_mode_index < modes
+			? default_mode_index
+			: 0].var;
+#else
+      memset(&var, 0, sizeof(var));
+      if(!mode_option || 
+	 !fb_find_mode(&var, &fb_info.fb_info, mode_option, NULL, 0, NULL, 8))
+	var = default_mode[0].var;
+#endif
+      
+      if(noaccel) var.accel_flags &= ~FB_ACCELF_TEXT;
+      else var.accel_flags |= FB_ACCELF_TEXT;
+      
+      if(tdfxfb_decode_var(&var, &fb_info.default_par, &fb_info)) {
+	/* ugh -- can't use the mode from the mode db. (or command line),
+	   so try the default */
+
+	printk("tdfxfb: "
+	       "can't decode the supplied video mode, using default\n");
+
+	var = default_mode[0].var;
+	if(noaccel) var.accel_flags &= ~FB_ACCELF_TEXT;
+	else var.accel_flags |= FB_ACCELF_TEXT;
+      
+	if(tdfxfb_decode_var(&var, &fb_info.default_par, &fb_info)) {
+	  printk("tdfxfb: can't decode default video mode\n");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+	  return;
+#else
+	  return -ENXIO;
+#endif
+	}
+      }
+      
+      fb_info.disp.screen_base    = (void*)fb_info.bufbase_virt;
+      fb_info.disp.visual         = 
+	var.bits_per_pixel == 8 
+	? FB_VISUAL_PSEUDOCOLOR
+	: FB_VISUAL_DIRECTCOLOR;
+      fb_info.disp.type           = FB_TYPE_PACKED_PIXELS;
+      fb_info.disp.type_aux       = 0;
+      
+      fb_info.disp.ypanstep       = (nowrap && nopan) ? 0 : 1;
+      fb_info.disp.ywrapstep      = nowrap ? 0 : 1;
+      
+      fb_info.disp.line_length    = 
+	fb_info.disp.next_line    = 	  
+	var.xres*(var.bits_per_pixel + 7)/8;
+      fb_info.disp.can_soft_blank = 1;
+      fb_info.disp.inverse        = inverse;
+      fb_info.disp.scrollmode     = SCROLL_YREDRAW;
+      fb_info.disp.var            = var;
+      tdfxfb_set_disp(&fb_info.disp, &fb_info, 
+		      var.bits_per_pixel, 
+		      0);
+      
+      for(j = 0; j < 16; j++) {
+	k = color_table[j];
+	fb_info.palette[j].red   = default_red[k];
+	fb_info.palette[j].green = default_grn[k];
+	fb_info.palette[j].blue  = default_blu[k];
+      }
+      
+      if(tdfxfb_set_var(&var, -1, &fb_info.fb_info)) {
+	printk("tdfxfb: can't set default video mode\n");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+	return;
+#else
+	return -ENXIO;
+#endif
+      }
+      
+      if(register_framebuffer(&fb_info.fb_info) < 0) {
+	printk("tdfxfb: can't register framebuffer\n");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+	return;
+#else
+	return -ENXIO;
+#endif
+      }
+
+      printk("fb%d: %s frame buffer device\n", 
+	     GET_FB_IDX(fb_info.fb_info.node),
+	     fb_info.fb_info.modename);
+      
+      MOD_INC_USE_COUNT;
+      
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+      return;
+#else
+      return 0;
+#endif
+    }
+  }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+  return;
+#else
+  return -ENXIO;
+#endif
+}
+
+void tdfxfb_setup(char *options, 
+		  int *ints) {
+  char* this_opt;
+
+  if(!options || !*options)
+    return;
+
+  for(this_opt = strtok(options, ","); 
+      this_opt;
+      this_opt = strtok(NULL, ",")) {
+    if(!strcmp(this_opt, "inverse")) {
+      inverse = 1;
+      fb_invert_cmaps();
+    } else if(!strcmp(this_opt, "noaccel")) {
+      noaccel = 1;
+    } else if(!strcmp(this_opt, "nopan")) {
+      nopan = 1;
+    } else if(!strcmp(this_opt, "nowrap")) {
+      nowrap = 1;
+    } else if (!strncmp(this_opt, "font:", 5)) {
+      strncpy(fontname, this_opt + 5, 40);
+    } else {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+      int i;
+      for(i = 0; i < modes; i++) {
+	if(!strcmp(this_opt, default_mode[i].name)) {
+	  default_mode_index = i;
+	}
+      }
+#else
+      mode_option = this_opt;
+#endif
+    }
+  } 
+}
+
+static int tdfxfb_switch_con(int con, 
+			     struct fb_info *fb) {
+  struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
+  struct tdfxfb_par par;
+
+  /* Do we have to save the colormap? */
+  if(fb_display[currcon].cmap.len)
+    fb_get_cmap(&fb_display[currcon].cmap, 1, tdfxfb_getcolreg, fb);
+
+  currcon = con;
+
+  tdfxfb_decode_var(&fb_display[con].var, &par, info);
+  tdfxfb_set_par(&par, info);
+  tdfxfb_set_disp(&fb_display[con], 
+		  info, 
+		  par.bpp,
+		  par.accel_flags & FB_ACCELF_TEXT);
+
+  tdfxfb_install_cmap(con, fb);
+  tdfxfb_updatevar(con, fb);
+
+  return 1;
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+static void tdfxfb_blank(int blank, 
+			 struct fb_info *fb) {
+  u32 dacmode, state = 0, vgablank = 0;
+
+  dacmode = tdfx_inl(DACMODE);
+
+  switch(blank) {
+  case 0: /* Screen: On; HSync: On, VSync: On */    
+    state    = 0;
+    vgablank = 0;
+    break;
+  case 1: /* Screen: Off; HSync: On, VSync: On */
+    state    = 0;
+    vgablank = 1;
+    break;
+  case 2: /* Screen: Off; HSync: On, VSync: Off */
+    state    = BIT(3);
+    vgablank = 1;
+    break;
+  case 3: /* Screen: Off; HSync: Off, VSync: On */
+    state    = BIT(1);
+    vgablank = 1;
+    break;
+  case 4: /* Screen: Off; HSync: Off, VSync: Off */
+    state    = BIT(1) | BIT(3);
+    vgablank = 1;
+    break;
+  }
+
+  dacmode &= ~(BIT(1) | BIT(3));
+  dacmode |= state;
+  tdfx_outl(DACMODE, dacmode);
+  if(vgablank) 
+    vga_disable_video();
+  else
+    vga_enable_video();
+
+  return;
+}
+
+static int  tdfxfb_updatevar(int con, 
+			     struct fb_info* fb) {
+  if(con != currcon || (nowrap && nopan)) { 
+    return 0;
+  } else {
+    struct fb_var_screeninfo* var = &fb_display[currcon].var;
+    return tdfxfb_pan_display(var, con, fb);
+  }
+}
+
+static int tdfxfb_getcolreg(unsigned        regno, 
+			    unsigned*       red, 
+			    unsigned*       green,
+			    unsigned*       blue, 
+			    unsigned*       transp,
+			    struct fb_info* fb) {
+  struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
+
+  if(regno < 256) {
+    *red    = i->palette[regno].red   << 8 | i->palette[regno].red;
+    *green  = i->palette[regno].green << 8 | i->palette[regno].green;
+    *blue   = i->palette[regno].blue  << 8 | i->palette[regno].blue;
+    *transp = 0;
+  }
+  return regno > 255;
+}
+
+static int tdfxfb_setcolreg(unsigned        regno, 
+			    unsigned        red, 
+			    unsigned        green,
+			    unsigned        blue, 
+			    unsigned        transp,
+			    struct fb_info* info) {
+  struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
+
+  if(regno < 16) {
+    switch(i->current_par.bpp) {
+#ifdef FBCON_HAS_CFB8
+    case 8:
+      break;
+#endif
+#ifdef FBCON_HAS_CFB16
+    case 16:
+      i->fbcon_cmap.cfb16[regno] =
+	(((u32)red   & 0xf800) >> 0) |
+	(((u32)green & 0xfc00) >> 5) |
+	(((u32)blue  & 0xf800) >> 11);
+      break;
+#endif
+#ifdef FBCON_HAS_CFB32
+    case 32:
+      i->fbcon_cmap.cfb32[regno] =
+	(((u32)red   & 0xff00) << 8) |
+	(((u32)green & 0xff00) << 0) |
+	(((u32)blue  & 0xff00) >> 8);
+      break;
+#endif
+    default:
+      DPRINTK("bad depth %u\n", i->current_par.bpp);
+      break;
+    }
+  }
+  if(regno < 256) {
+    i->palette[regno].red    = red   >> 8;
+    i->palette[regno].green  = green >> 8;
+    i->palette[regno].blue   = blue  >> 8;
+    if(i->current_par.bpp == 8) {
+      vga_outb(DAC_IW, (unsigned char)regno);
+      vga_outb(DAC_D,  (unsigned char)(red   >> 8));
+      vga_outb(DAC_D,  (unsigned char)(green >> 8));
+      vga_outb(DAC_D,  (unsigned char)(blue  >> 8));
+    }
+  }
+  return regno > 255;
+}
+
+static void tdfxfb_install_cmap(int             con, 
+				struct fb_info* info) {
+  if(con != currcon) return;
+  if(fb_display[con].cmap.len) {
+    fb_set_cmap(&fb_display[con].cmap, 1, tdfxfb_setcolreg, info);
+  } else {
+    int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+    fb_set_cmap(fb_default_cmap(size), 1, tdfxfb_setcolreg, info);
+  }
+}
+
diff -u --recursive --new-file v2.3.20/linux/drivers/video/valkyriefb.c linux/drivers/video/valkyriefb.c
--- v2.3.20/linux/drivers/video/valkyriefb.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/video/valkyriefb.c	Mon Oct 11 10:26:52 1999
@@ -55,11 +55,11 @@
 #ifdef CONFIG_FB_COMPAT_XPMAC
 #include <asm/vc_ioctl.h>
 #endif
+#include <linux/adb.h>
+#include <linux/cuda.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/pgtable.h>
-#include <asm/adb.h>
-#include <asm/cuda.h>
 
 #include <video/fbcon.h>
 #include <video/fbcon-cfb8.h>
@@ -167,10 +167,6 @@
 static int valkyriefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 			     u_int transp, struct fb_info *info);
 static void do_install_cmap(int con, struct fb_info *info);
-
-
-__openfirmware
-
 
 static int valkyrie_open(struct fb_info *info, int user)
 {
diff -u --recursive --new-file v2.3.20/linux/drivers/video/vesafb.c linux/drivers/video/vesafb.c
--- v2.3.20/linux/drivers/video/vesafb.c	Thu Aug 26 13:05:40 1999
+++ linux/drivers/video/vesafb.c	Mon Oct 11 10:26:52 1999
@@ -532,6 +532,8 @@
 
 	video_base          = screen_info.lfb_base;
 	video_bpp           = screen_info.lfb_depth;
+	if (15 == video_bpp)
+		video_bpp = 16;
 	video_width         = screen_info.lfb_width;
 	video_height        = screen_info.lfb_height;
 	video_linelength    = screen_info.lfb_linelength;
diff -u --recursive --new-file v2.3.20/linux/drivers/video/virgefb.c linux/drivers/video/virgefb.c
--- v2.3.20/linux/drivers/video/virgefb.c	Thu Aug 26 13:05:40 1999
+++ linux/drivers/video/virgefb.c	Mon Oct 11 10:26:52 1999
@@ -1163,7 +1163,7 @@
  *    Initialization
  */
 
-void __init virgefb_init(void)
+int __init virgefb_init(void)
 {
 	struct virgefb_par par;
 	unsigned long board_addr;
diff -u --recursive --new-file v2.3.20/linux/fs/buffer.c linux/fs/buffer.c
--- v2.3.20/linux/fs/buffer.c	Sat Oct  9 11:47:50 1999
+++ linux/fs/buffer.c	Mon Oct 11 10:18:07 1999
@@ -1205,6 +1205,18 @@
 	return 0;
 }
 
+static void unmap_buffer(struct buffer_head * bh)
+{
+	if (buffer_mapped(bh))
+	{
+		mark_buffer_clean(bh);
+		wait_on_buffer(bh);
+		clear_bit(BH_Uptodate, &bh->b_state);
+		clear_bit(BH_Mapped, &bh->b_state);
+		clear_bit(BH_Req, &bh->b_state);
+	}
+}
+
 /*
  * We don't have to release all buffers here, but
  * we have to be sure that no dirty buffer is left
@@ -1231,16 +1243,8 @@
 		/*
 		 * is this block fully flushed?
 		 */
-		if (offset <= curr_off) {
-			if (buffer_mapped(bh)) {
-				mark_buffer_clean(bh);
-				wait_on_buffer(bh);
-				clear_bit(BH_Uptodate, &bh->b_state);
-				clear_bit(BH_Mapped, &bh->b_state);
-				clear_bit(BH_Req, &bh->b_state);
-				bh->b_blocknr = 0;
-			}
-		}
+		if (offset <= curr_off)
+			unmap_buffer(bh);
 		curr_off = next_off;
 		bh = next;
 	} while (bh != head);
@@ -1286,6 +1290,19 @@
 	get_page(page);
 }
 
+static void unmap_underlying_metadata(struct buffer_head * bh)
+{
+	bh = get_hash_table(bh->b_dev, bh->b_blocknr, bh->b_size);
+	if (bh)
+	{
+		unmap_buffer(bh);
+		/* Here we could run brelse or bforget. We use
+		   bforget because it will try to put the buffer
+		   in the freelist. */
+		__bforget(bh);
+	}
+}
+
 /*
  * block_write_full_page() is SMP-safe - currently it's still
  * being called with the kernel lock held, but the code is ready.
@@ -1331,6 +1348,7 @@
 			err = inode->i_op->get_block(inode, block, bh, 1);
 			if (err)
 				goto out;
+			unmap_underlying_metadata(bh);
 		}
 		set_bit(BH_Uptodate, &bh->b_state);
 		mark_buffer_dirty(bh,0);
@@ -1420,6 +1438,7 @@
 			err = inode->i_op->get_block(inode, block, bh, 1);
 			if (err)
 				goto out;
+			unmap_underlying_metadata(bh);
 		}
 
 		if (!buffer_uptodate(bh) && (start_offset || (end_bytes && (i == end_block)))) {
@@ -1582,6 +1601,7 @@
 			err = inode->i_op->get_block(inode, block, bh, 1);
 			if (err)
 				goto out;
+			unmap_underlying_metadata(bh);
 		}
 
 		if (!buffer_uptodate(bh) && (start_offset || (end_bytes && (i == end_block)))) {
diff -u --recursive --new-file v2.3.20/linux/fs/exec.c linux/fs/exec.c
--- v2.3.20/linux/fs/exec.c	Tue Sep  7 12:14:07 1999
+++ linux/fs/exec.c	Mon Oct 11 10:13:25 1999
@@ -169,7 +169,7 @@
 /*
  * count() counts the number of arguments/envelopes
  */
-static int count(char ** argv)
+static int count(char ** argv, int max)
 {
 	int i = 0;
 
@@ -184,7 +184,8 @@
 			if (!p)
 				break;
 			argv++;
-			i++;
+			if(++i > max)
+				return -E2BIG;
 		}
 	}
 	return i;
@@ -202,7 +203,7 @@
 		int len;
 		unsigned long pos;
 
-		if (get_user(str, argv+argc) || !str || !(len = strlen_user(str))) 
+		if (get_user(str, argv+argc) || !str || !(len = strnlen_user(str, bprm->p))) 
 			return -EFAULT;
 		if (bprm->p < len) 
 			return -E2BIG; 
@@ -211,7 +212,7 @@
 		/* XXX: add architecture specific overflow check here. */ 
 
 		pos = bprm->p;
-		while (len) {
+		while (len>0) {
 			char *pag;
 			int offset, bytes_to_copy;
 
@@ -274,7 +275,7 @@
 		mpnt->vm_ops = NULL;
 		mpnt->vm_offset = 0;
 		mpnt->vm_file = NULL;
-		mpnt->vm_private_data = NULL;
+		mpnt->vm_private_data = (void *) 0;
 		insert_vm_struct(current->mm, mpnt);
 		current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
 	} 
@@ -753,12 +754,12 @@
 	bprm.sh_bang = 0;
 	bprm.loader = 0;
 	bprm.exec = 0;
-	if ((bprm.argc = count(argv)) < 0) {
+	if ((bprm.argc = count(argv, bprm.p / sizeof(void *))) < 0) {
 		dput(dentry);
 		return bprm.argc;
 	}
 
-	if ((bprm.envc = count(envp)) < 0) {
+	if ((bprm.envc = count(envp, bprm.p / sizeof(void *))) < 0) {
 		dput(dentry);
 		return bprm.envc;
 	}
diff -u --recursive --new-file v2.3.20/linux/fs/fcntl.c linux/fs/fcntl.c
--- v2.3.20/linux/fs/fcntl.c	Tue Aug 31 17:29:14 1999
+++ linux/fs/fcntl.c	Mon Oct 11 10:13:25 1999
@@ -8,6 +8,8 @@
 #include <linux/file.h>
 #include <linux/smp_lock.h>
 
+#include <asm/poll.h>
+#include <asm/siginfo.h>
 #include <asm/uaccess.h>
 
 extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
@@ -255,8 +257,22 @@
 	return err;
 }
 
+/* Table to convert sigio signal codes into poll band bitmaps */
+
+static int band_table[NSIGPOLL+1] = {
+	~0,
+	POLLIN | POLLRDNORM,			/* POLL_IN */
+	POLLOUT | POLLWRNORM | POLLWRBAND,	/* POLL_OUT */
+	POLLIN | POLLRDNORM | POLLMSG,		/* POLL_MSG */
+	POLLERR,				/* POLL_ERR */
+	POLLPRI | POLLRDBAND,			/* POLL_PRI */
+	POLLHUP | POLLERR			/* POLL_HUP */
+};
+
 static void send_sigio_to_task(struct task_struct *p,
-			       struct fown_struct *fown, struct fasync_struct *fa)
+			       struct fown_struct *fown, 
+			       struct fasync_struct *fa,
+			       int reason)
 {
 	if ((fown->euid != 0) &&
 	    (fown->euid ^ p->suid) && (fown->euid ^ p->uid) &&
@@ -273,9 +289,11 @@
 			   back to SIGIO in that case. --sct */
 			si.si_signo = fown->signum;
 			si.si_errno = 0;
-		        si.si_code  = SI_SIGIO;
-			si.si_pid   = fown->pid;
-			si.si_uid   = fown->uid;
+		        si.si_code  = reason;
+			if (reason < 0 || reason > NSIGPOLL)
+				si.si_band  = ~0;
+			else
+				si.si_band = band_table[reason];
 			si.si_fd    = fa->fa_fd;
 			if (!send_sig_info(fown->signum, &si, p))
 				break;
@@ -285,14 +303,15 @@
 	}
 }
 
-static void send_sigio(struct fown_struct *fown, struct fasync_struct *fa)
+static void send_sigio(struct fown_struct *fown, struct fasync_struct *fa, 
+		       int band)
 {
 	struct task_struct * p;
 	int   pid	= fown->pid;
 	
 	read_lock(&tasklist_lock);
 	if ( (pid > 0) && (p = find_task_by_pid(pid)) ) {
-		send_sigio_to_task(p, fown, fa);
+		send_sigio_to_task(p, fown, fa, band);
 		goto out;
 	}
 	for_each_task(p) {
@@ -301,13 +320,13 @@
 			match = -p->pgrp;
 		if (pid != match)
 			continue;
-		send_sigio_to_task(p, fown, fa);
+		send_sigio_to_task(p, fown, fa, band);
 	}
 out:
 	read_unlock(&tasklist_lock);
 }
 
-void kill_fasync(struct fasync_struct *fa, int sig)
+void kill_fasync(struct fasync_struct *fa, int sig, int band)
 {
 	while (fa) {
 		struct fown_struct * fown;
@@ -317,8 +336,11 @@
 			return;
 		}
 		fown = &fa->fa_file->f_owner;
-		if (fown->pid)
-			send_sigio(fown, fa);
+		/* Don't send SIGURG to processes which have not set a
+		   queued signum: SIGURG has its own default signalling
+		   mechanism. */
+		if (fown->pid && !(sig == SIGURG && fown->signum == 0))
+			send_sigio(fown, fa, band);
 		fa = fa->fa_next;
 	}
 }
diff -u --recursive --new-file v2.3.20/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- v2.3.20/linux/fs/ncpfs/dir.c	Sat Oct  9 11:47:50 1999
+++ linux/fs/ncpfs/dir.c	Mon Oct 11 10:13:25 1999
@@ -433,7 +433,7 @@
 	ino = find_inode_number(dentry, &qname);
 
 	if (!ino)
-		ino = iunique(2);
+		ino = iunique(dentry->d_inode->i_sb, 2);
 
 	result = filldir(dirent, name, len, filp->f_pos, ino);
 	if (!result)
@@ -478,7 +478,7 @@
 
 		if (!newdent->d_inode) {
 			entry->opened = 0;
-			entry->ino = iunique(2);
+			entry->ino = iunique(inode->i_sb, 2);
 			newino = ncp_iget(inode->i_sb, entry);
 			if (newino) {
 				newdent->d_op = &ncp_dentry_operations;
@@ -501,7 +501,7 @@
 		ino = find_inode_number(dentry, &qname);
 
 	if (!ino)
-		ino = iunique(2);
+		ino = iunique(inode->i_sb, 2);
 
 	result = filldir(dirent, entry->i.entryName, entry->i.nameLen,
 				filp->f_pos, ino);
@@ -794,7 +794,7 @@
 	 * Create an inode for the entry.
 	 */
 	finfo.opened = 0;
-	finfo.ino = iunique(2);
+	finfo.ino = iunique(dir->i_sb, 2);
 	error = -EACCES;
 	inode = ncp_iget(dir->i_sb, &finfo);
 
@@ -822,7 +822,7 @@
 	struct inode *inode;
 	int error = -EINVAL;
 
-	finfo->ino = iunique(2);
+	finfo->ino = iunique(dir->i_sb, 2);
 	inode = ncp_iget(dir->i_sb, finfo);
 	if (!inode)
 		goto out_close;
diff -u --recursive --new-file v2.3.20/linux/fs/partitions/msdos.c linux/fs/partitions/msdos.c
--- v2.3.20/linux/fs/partitions/msdos.c	Mon Oct  4 15:49:30 1999
+++ linux/fs/partitions/msdos.c	Mon Oct 11 11:49:09 1999
@@ -26,6 +26,7 @@
 #include <linux/major.h>
 #include <linux/string.h>
 #include <linux/blk.h>
+#include <linux/ide.h>	/* IDE xlate */
 
 #include <asm/system.h>
 
@@ -356,7 +357,6 @@
 		/*
 		 * Look for various forms of IDE disk geometry translation
 		 */
-		extern int ide_xlate_1024(kdev_t, int, int, const char *);
 		unsigned int sig = le16_to_cpu(*(unsigned short *)(data + 2));
 		int heads = 0;
 		/*
diff -u --recursive --new-file v2.3.20/linux/fs/smbfs/cache.c linux/fs/smbfs/cache.c
--- v2.3.20/linux/fs/smbfs/cache.c	Sun Mar  7 15:25:23 1999
+++ linux/fs/smbfs/cache.c	Sun Oct 10 08:47:09 1999
@@ -14,12 +14,67 @@
 #include <linux/mm.h>
 #include <linux/dirent.h>
 #include <linux/smb_fs.h>
+#include <linux/pagemap.h>
 
 #include <asm/page.h>
 
 #define SMBFS_PARANOIA 1
 /* #define SMBFS_DEBUG_VERBOSE 1 */
 
+#ifdef SMBFS_DEBUG_VERBOSE
+/*
+ * Print a cache_dirent->name, max 80 chars
+ * You can't just printk non-null terminated strings ...
+ */
+printk_name(const char *name, int len)
+{
+	char buf[81];
+
+	if(len > 80)
+		len = 80;
+	strncpy(buf, name, len);
+	buf[len] = 0;
+	printk(buf);
+}
+#endif
+
+/*
+ * Get a page for this inode, if new is set then we want to allocate
+ * the page if it isn't in memory. As I understand it the rest of the
+ * smb-cache code assumes we return a locked page.
+ */
+unsigned long
+get_cached_page(struct inode * inode, unsigned long offset, int new)
+{
+	struct page * page;
+	struct page ** hash;
+	unsigned long new_page;
+
+ again:
+	hash = page_hash(inode, offset);
+	page = __find_lock_page(inode, offset, hash);
+	if(!page && new) {
+		/* not in cache, alloc a new page */
+		new_page = page_cache_alloc();
+		if (!new_page)
+			return 0;
+		clear_page(new_page);	/* smb code assumes pages are zeroed */
+		page = page_cache_entry(new_page);
+		if (add_to_page_cache_unique(page, inode, offset, hash)) {
+			/* Hmm, a page has materialized in the
+                           cache. Fine. Go back and get that page
+                           instead ... throwing away this one first. */
+			put_cached_page((unsigned long) page);
+			goto again;
+		}
+	}
+	if(!page)
+		return 0;
+	if(!PageLocked(page))
+		printk(KERN_ERR "smbfs/cache.c: page isn't locked! This could be fun ...\n");
+	return page_address(page);
+}
+
 static inline struct inode * 
 get_cache_inode(struct cache_head *cachep)
 {
@@ -38,8 +93,8 @@
 	struct cache_head * cachep;
 
 #ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_get_dircache: finding cache for %s/%s\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
+	printk("smb_get_dircache: finding cache for %s/%s\n",
+	       dentry->d_parent->d_name.name, dentry->d_name.name);
 #endif
 	cachep = (struct cache_head *) get_cached_page(inode, 0, 1);
 	if (!cachep)
@@ -140,8 +195,10 @@
 	unsigned int needed = len + sizeof(struct cache_entry);
 
 #ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_add_to_cache: cache inode %p, status %d, adding %s at %ld\n",
-inode, cachep->status, entry->name, fpos);
+printk("smb_add_to_cache: cache inode %p, status %d, adding ", 
+       inode, cachep->status);
+printk_name(entry->name, entry->len);
+printk(" at %ld\n", fpos);
 #endif
 	/*
 	 * Don't do anything if we've had an error ...
@@ -169,8 +226,10 @@
 		block->cb_data.table[nent].ino = entry->ino;
 		cachep->entries++;
 #ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_add_to_cache: added entry %s, len=%d, pos=%ld, entries=%d\n",
-entry->name, len, fpos, cachep->entries);
+printk("smb_add_to_cache: added entry ");
+printk_name(entry->name, entry->len);
+printk(", len=%d, pos=%ld, entries=%d\n",
+len, fpos, cachep->entries);
 #endif
 		return;
 	}
@@ -231,7 +290,7 @@
 		nent = pos - next_pos;
 		next_pos += index->num_entries;
 		if (pos >= next_pos)
-			continue; 
+			continue;
 		/*
 		 * The entry is in this block. Note: we return
 		 * then name as a reference with _no_ null byte.
@@ -242,8 +301,9 @@
 		offset = block->cb_data.table[nent].offset;
 		entry->name = &block->cb_data.names[offset];
 #ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_find_in_cache: found %s, len=%d, pos=%ld\n",
-entry->name, entry->len, pos);
+printk("smb_find_in_cache: found ");
+printk_name(entry->name, entry->len);
+printk(", len=%d, pos=%ld\n", entry->len, pos);
 #endif
 		break;
 	}
@@ -312,4 +372,3 @@
 	dir->u.smbfs_i.cache_valid &= ~SMB_F_CACHEVALID;
 	dir->u.smbfs_i.oldmtime = 0;
 }
-
diff -u --recursive --new-file v2.3.20/linux/fs/smbfs/file.c linux/fs/smbfs/file.c
--- v2.3.20/linux/fs/smbfs/file.c	Sun Jun 27 10:10:41 1999
+++ linux/fs/smbfs/file.c	Sun Oct 10 08:47:09 1999
@@ -32,13 +32,6 @@
 	return a < b ? a : b;
 }
 
-static inline void
-smb_unlock_page(struct page *page)
-{
-	clear_bit(PG_locked, &page->flags);
-	wake_up(&page->wait);
-}
-
 static int
 smb_fsync(struct file *file, struct dentry * dentry)
 {
@@ -61,7 +54,9 @@
 	int count = PAGE_SIZE;
 	int result;
 
-	clear_bit(PG_error, &page->flags);
+	/* We can't replace this with ClearPageError. why? is it a problem? 
+	   fs/buffer.c:brw_page does the same. */
+	/* clear_bit(PG_error, &page->flags); */
 
 #ifdef SMBFS_DEBUG_VERBOSE
 printk("smb_readpage_sync: file %s/%s, count=%d@%ld, rsize=%d\n",
@@ -94,11 +89,11 @@
 	} while (count);
 
 	memset(buffer, 0, count);
-	set_bit(PG_uptodate, &page->flags);
+	SetPageUptodate(page);
 	result = 0;
 
 io_error:
-	smb_unlock_page(page);
+	UnlockPage(page);
 	return result;
 }
 
@@ -110,13 +105,13 @@
 
 	pr_debug("SMB: smb_readpage %08lx\n", page_address(page));
 #ifdef SMBFS_PARANOIA
-	if (test_bit(PG_locked, &page->flags))
-		printk("smb_readpage: page already locked!\n");
+	if (!PageLocked(page))
+		printk("smb_readpage: page not already locked!\n");
 #endif
-	set_bit(PG_locked, &page->flags);
-	atomic_inc(&page->count);
+
+	get_page(page);
 	error = smb_readpage_sync(dentry, page);
-	free_page(page_address(page));
+	put_page(page);
 	return error;
 }
 
@@ -169,6 +164,8 @@
 /*
  * Write a page to the server. This will be used for NFS swapping only
  * (for now), and we currently do this synchronously only.
+ *
+ * We are called with the page locked and the caller unlocks.
  */
 static int
 smb_writepage(struct file *file, struct page *page)
@@ -177,14 +174,13 @@
 	int 	result;
 
 #ifdef SMBFS_PARANOIA
-	if (test_bit(PG_locked, &page->flags))
-		printk("smb_writepage: page already locked!\n");
+	if (!PageLocked(page))
+		printk("smb_writepage: page not already locked!\n");
 #endif
-	set_bit(PG_locked, &page->flags);
-	atomic_inc(&page->count);
+	get_page(page);
 	result = smb_writepage_sync(dentry, page, 0, PAGE_SIZE);
-	smb_unlock_page(page);
-	free_page(page_address(page));
+	SetPageUptodate(page);
+	put_page(page);
 	return result;
 }
 
@@ -266,9 +262,9 @@
  * If the writer ends up delaying the write, the writer needs to
  * increment the page use counts until he is done with the page.
  */
-static long smb_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+static int smb_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
 {
-	long status;
+	int status;
 
 	bytes -= copy_from_user((u8*)page_address(page) + offset, buf, bytes);
 	status = -EFAULT;
diff -u --recursive --new-file v2.3.20/linux/include/asm-alpha/keyboard.h linux/include/asm-alpha/keyboard.h
--- v2.3.20/linux/include/asm-alpha/keyboard.h	Mon Apr 26 10:54:25 1999
+++ linux/include/asm-alpha/keyboard.h	Mon Oct 11 14:40:01 1999
@@ -37,6 +37,31 @@
 
 #define SYSRQ_KEY 0x54
 
+/* resource allocation */
+#define kbd_request_region()
+#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
+                                             "keyboard", NULL)
+
+/* How to access the keyboard macros on this platform.  */
+#define kbd_read_input() inb(KBD_DATA_REG)
+#define kbd_read_status() inb(KBD_STATUS_REG)
+#define kbd_write_output(val) outb(val, KBD_DATA_REG)
+#define kbd_write_command(val) outb(val, KBD_CNTL_REG)
+
+/* Some stoneage hardware needs delays after some operations.  */
+#define kbd_pause() do { } while(0)
+
+/*
+ * Machine specific bits for the PS/2 driver
+ */
+
+#define AUX_IRQ 12
+
+#define aux_request_irq(hand, dev_id)                                  \
+       request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
+
+#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASMalpha_KEYBOARD_H */
diff -u --recursive --new-file v2.3.20/linux/include/asm-alpha/uaccess.h linux/include/asm-alpha/uaccess.h
--- v2.3.20/linux/include/asm-alpha/uaccess.h	Thu Jul 29 13:37:22 1999
+++ linux/include/asm-alpha/uaccess.h	Mon Oct 11 14:40:01 1999
@@ -487,6 +487,15 @@
 	return access_ok(VERIFY_READ,str,0) ? __strlen_user(str) : 0;
 }
 
+/* Returns: 0 if exception before NUL or reaching the supplied limit (N),
+ * a value greater than N if the limit would be exceeded, else strlen.  */
+extern long __strnlen_user(const char *, long);
+
+extern inline long strnlen_user(const char *str, long n)
+{
+	return access_ok(VERIFY_READ,str,0) ? __strnlen_user(str, n) : 0;
+}
+
 /*
  * About the exception table:
  *
diff -u --recursive --new-file v2.3.20/linux/include/asm-i386/keyboard.h linux/include/asm-i386/keyboard.h
--- v2.3.20/linux/include/asm-i386/keyboard.h	Mon Apr 26 10:54:03 1999
+++ linux/include/asm-i386/keyboard.h	Mon Oct 11 14:58:31 1999
@@ -13,6 +13,10 @@
 
 #ifdef __KERNEL__
 
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+
 #define KEYBOARD_IRQ			1
 #define DISABLE_KBD_DURING_INTERRUPTS	0
 
@@ -35,6 +39,30 @@
 
 #define SYSRQ_KEY 0x54
 
-#endif /* __KERNEL__ */
+/* resource allocation */
+#define kbd_request_region()
+#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
+                                             "keyboard", NULL)
+
+/* How to access the keyboard macros on this platform.  */
+#define kbd_read_input() inb(KBD_DATA_REG)
+#define kbd_read_status() inb(KBD_STATUS_REG)
+#define kbd_write_output(val) outb(val, KBD_DATA_REG)
+#define kbd_write_command(val) outb(val, KBD_CNTL_REG)
+
+/* Some stoneage hardware needs delays after some operations.  */
+#define kbd_pause() do { } while(0)
+
+/*
+ * Machine specific bits for the PS/2 driver
+ */
 
-#endif /* __ASMi386_KEYBOARD_H */
+#define AUX_IRQ 12
+
+#define aux_request_irq(hand, dev_id)					\
+	request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
+
+#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)
+
+#endif /* __KERNEL__ */
+#endif /* _I386_KEYBOARD_H */
diff -u --recursive --new-file v2.3.20/linux/include/asm-i386/mmx.h linux/include/asm-i386/mmx.h
--- v2.3.20/linux/include/asm-i386/mmx.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-i386/mmx.h	Mon Oct 11 10:06:34 1999
@@ -0,0 +1,14 @@
+#ifndef _ASM_MMX_H
+#define _ASM_MMX_H
+
+/*
+ *	MMX 3Dnow! helper operations
+ */
+
+#include <linux/types.h>
+ 
+extern void *_mmx_memcpy(void *to, const void *from, size_t size);
+extern void mmx_clear_page(long page);
+extern void mmx_copy_page(long to, long from);
+
+#endif
diff -u --recursive --new-file v2.3.20/linux/include/asm-i386/page.h linux/include/asm-i386/page.h
--- v2.3.20/linux/include/asm-i386/page.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-i386/page.h	Mon Oct 11 14:58:03 1999
@@ -11,8 +11,26 @@
 
 #define STRICT_MM_TYPECHECKS
 
+#include <linux/config.h>
+
+#ifdef CONFIG_X86_USE_3DNOW
+
+#include <asm/mmx.h>
+
+#define clear_page(page)	mmx_clear_page(page)
+#define copy_page(to,from)	mmx_copy_page(to,from)
+
+#else
+
+/*
+ *	On older X86 processors its not a win to use MMX here it seems.
+ *	Maybe the K6-III ?
+ */
+ 
 #define clear_page(page)	memset((void *)(page), 0, PAGE_SIZE)
 #define copy_page(to,from)	memcpy((void *)(to), (void *)(from), PAGE_SIZE)
+
+#endif
 
 #ifdef STRICT_MM_TYPECHECKS
 /*
diff -u --recursive --new-file v2.3.20/linux/include/asm-i386/string-486.h linux/include/asm-i386/string-486.h
--- v2.3.20/linux/include/asm-i386/string-486.h	Thu Feb 27 10:57:31 1997
+++ linux/include/asm-i386/string-486.h	Mon Oct 11 10:06:34 1999
@@ -14,6 +14,8 @@
  *		1994/03/15 by Alberto Vignani/Davide Parodi @crf.it
  *
  *	Split into 2 CPU specific files by Alan Cox to keep #ifdef noise down.
+ *
+ *	99/9/15  Proper reg args for newer gcc/egcs - Petkan (petkan@spct.net)
  */
 
 #define __HAVE_ARCH_STRCPY
@@ -180,6 +182,7 @@
 #define __HAVE_ARCH_STRRCHR
 extern inline char * strrchr(const char * s, int c)
 {
+int	d0, d1;
 register char * __res;
 __asm__ __volatile__(
 	"cld\n\t"
@@ -190,17 +193,19 @@
 	"leal -1(%%esi),%0\n"
 	"2:\ttestb %%al,%%al\n\t"
 	"jne 1b"
-	:"=d" (__res):"0" (0),"S" (s),"a" (c):"ax","si");
+	:"=d" (__res), "=&S" (d0), "=&a" (d1)
+	:"0" (0), "1" (s), "2" (c));
 return __res;
 }
 
 #define __HAVE_ARCH_STRSPN
 extern inline size_t strspn(const char * cs, const char * ct)
 {
+int	d0, d1;
 register char * __res;
 __asm__ __volatile__(
 	"cld\n\t"
-	"movl %4,%%edi\n\t"
+	"movl %6,%%edi\n\t"
 	"repne\n\t"
 	"scasb\n\t"
 	"notl %%ecx\n\t"
@@ -209,24 +214,26 @@
 	"1:\tlodsb\n\t"
 	"testb %%al,%%al\n\t"
 	"je 2f\n\t"
-	"movl %4,%%edi\n\t"
+	"movl %6,%%edi\n\t"
 	"movl %%edx,%%ecx\n\t"
 	"repne\n\t"
 	"scasb\n\t"
 	"je 1b\n"
 	"2:\tdecl %0"
-	:"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
-	:"ax","cx","dx","di");
+	:"=S" (__res), "=&a" (d0), "=&c" (d1)
+	:"0" (cs), "1" (0), "2" (0xffffffff), "g" (ct)
+	:"dx", "di");
 return __res-cs;
 }
 
 #define __HAVE_ARCH_STRCSPN
 extern inline size_t strcspn(const char * cs, const char * ct)
 {
+int	d0, d1;
 register char * __res;
 __asm__ __volatile__(
 	"cld\n\t"
-	"movl %4,%%edi\n\t"
+	"movl %6,%%edi\n\t"
 	"repne\n\t"
 	"scasb\n\t"
 	"notl %%ecx\n\t"
@@ -235,20 +242,22 @@
 	"1:\tlodsb\n\t"
 	"testb %%al,%%al\n\t"
 	"je 2f\n\t"
-	"movl %4,%%edi\n\t"
+	"movl %6,%%edi\n\t"
 	"movl %%edx,%%ecx\n\t"
 	"repne\n\t"
 	"scasb\n\t"
 	"jne 1b\n"
 	"2:\tdecl %0"
-	:"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
-	:"ax","cx","dx","di");
+	:"=S" (__res), "=&a" (d0), "=&c" (d1)
+	:"0" (cs), "1" (0), "2" (0xffffffff), "g" (ct)
+	:"dx", "di");
 return __res-cs;
 }
 
 #define __HAVE_ARCH_STRPBRK
 extern inline char * strpbrk(const char * cs,const char * ct)
 {
+int	d0, d1;
 register char * __res;
 __asm__ __volatile__(
 	"cld\n\t"
@@ -270,14 +279,16 @@
 	"jmp 3f\n"
 	"2:\txorl %0,%0\n"
 	"3:"
-	:"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
-	:"ax","cx","dx","di");
+	:"=S" (__res), "=&a" (d0), "=&c" (d1)
+	:"0" (cs), "1" (0), "2" (0xffffffff), "g" (ct)
+	:"dx", "di");
 return __res;
 }
 
 #define __HAVE_ARCH_STRSTR
 extern inline char * strstr(const char * cs,const char * ct)
 {
+int	d0, d1;
 register char * __res;
 __asm__ __volatile__(
 	"cld\n\t" \
@@ -299,8 +310,9 @@
 	"jne 1b\n\t"
 	"xorl %%eax,%%eax\n\t"
 	"2:"
-	:"=a" (__res):"0" (0),"c" (0xffffffff),"S" (cs),"g" (ct)
-	:"cx","dx","di","si");
+	:"=a" (__res), "=&c" (d0), "=&S" (d1)
+	:"0" (0), "1" (0xffffffff), "2" (cs), "g" (ct)
+	:"dx", "di");
 return __res;
 }
 
@@ -328,6 +340,7 @@
 #define __HAVE_ARCH_STRNLEN
 extern inline size_t strnlen(const char * s, size_t count)
 {
+int	d0;
 register int __res;
 __asm__ __volatile__(
 	"movl %1,%0\n\t"
@@ -339,9 +352,8 @@
 	"cmpl $-1,%2\n\t"
 	"jne 1b\n"
 	"3:\tsubl %1,%0"
-	:"=a" (__res)
-	:"c" (s),"d" (count)
-	:"dx");
+	:"=a" (__res), "=&d" (d0)
+	:"1" (count), "c" (s));
 return __res;
 }
 /* end of additional stuff */
@@ -464,6 +476,7 @@
 
 extern inline void * __memcpy_g(void * to, const void * from, size_t n)
 {
+int	d0, d1, d2;
 register void *tmp = (void *)to;
 __asm__ __volatile__ (
 	"cld\n\t"
@@ -475,9 +488,9 @@
 	"movsw\n"
 	"2:\trep\n\t"
 	"movsl"
-	: /* no output */
-	:"c" (n),"D" ((long) tmp),"S" ((long) from)
-	:"cx","di","si","memory");
+	:"=&c" (d0), "=&D" (d1), "=&S" (d2)
+	:"0" (n), "1" ((long) tmp), "2" ((long) from)
+	:"memory");
 return (to);
 }
 
@@ -485,29 +498,31 @@
 #define __HAVE_ARCH_MEMMOVE
 extern inline void * memmove(void * dest,const void * src, size_t n)
 {
+int	d0, d1, d2;
 register void *tmp = (void *)dest;
 if (dest<src)
 __asm__ __volatile__ (
 	"cld\n\t"
 	"rep\n\t"
 	"movsb"
-	: /* no output */
-	:"c" (n),"S" (src),"D" (tmp)
-	:"cx","si","di");
+	:"=&c" (d0), "=&S" (d1), "=&D" (d2)
+	:"0" (n), "1" (src), "2" (tmp)
+	:"memory");
 else
 __asm__ __volatile__ (
 	"std\n\t"
 	"rep\n\t"
 	"movsb\n\t"
 	"cld"
-	: /* no output */
-	:"c" (n), "S" (n-1+(const char *)src), "D" (n-1+(char *)tmp)
-	:"cx","si","di","memory");
+	:"=&c" (d0), "=&S" (d1), "=&D" (d2)
+	:"0" (n), "1" (n-1+(const char *)src), "2" (n-1+(char *)tmp)
+	:"memory");
 return dest;
 }
 
 extern inline int memcmp(const void * cs,const void * ct,size_t count)
 {
+int	d0, d1, d2;
 register int __res;
 __asm__ __volatile__(
 	"cld\n\t"
@@ -517,14 +532,15 @@
 	"sbbl %0,%0\n\t"
 	"orb $1,%b0\n"
 	"1:"
-	:"=abd" (__res):"0" (0),"S" (cs),"D" (ct),"c" (count)
-	:"si","di","cx");
+	:"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
+	:"0" (0), "1" (cs), "2" (ct), "3" (count));
 return __res;
 }
 
 #define __HAVE_ARCH_MEMCHR
 extern inline void * memchr(const void * cs,int c,size_t count)
 {
+int	d0;
 register void * __res;
 if (!count)
 	return NULL;
@@ -535,8 +551,8 @@
 	"je 1f\n\t"
 	"movl $1,%0\n"
 	"1:\tdecl %0"
-	:"=D" (__res):"a" (c),"D" (cs),"c" (count)
-	:"cx");
+	:"=D" (__res), "=&c" (d0)
+	:"a" (c), "0" (cs), "1" (count));
 return __res;
 }
 
@@ -643,6 +659,7 @@
 
 extern inline void * __memset_cg(void * s, char c, size_t count)
 {
+int	d0, d1;
 register void *tmp = (void *)s;
 __asm__ __volatile__ (
 	"shrl $1,%%ecx\n\t"
@@ -651,14 +668,15 @@
 	"jnc 1f\n\t"
 	"movb %%al,(%%edi)\n"
 	"1:"
-	: /* no output */
-	:"c" (count),"D" (tmp), "a" (0x0101U * (unsigned char) c)
-	:"cx","di","memory");
+	:"=&c" (d0), "=&D" (d1) 
+	:"a" (0x0101U * (unsigned char) c), "0" (count), "1" (tmp)
+	:"memory");
 return s;
 }
 
 extern inline void * __memset_gg(void * s,char c,size_t count)
 {
+int	d0, d1, d2;
 register void *tmp = (void *)s;
 __asm__ __volatile__ (
 	"movb %%al,%%ah\n\t"
@@ -668,9 +686,9 @@
 	"jnc 1f\n\t"
 	"movb %%al,(%%edi)\n"
 	"1:"
-	: /* no output */
-	:"c" (count),"D" (tmp), "a" (c)
-	:"cx","di","memory");
+	:"=&c" (d0), "=&D" (d1), "=&D" (d2)
+	:"0" (count), "1" (tmp), "2" (c)
+	:"memory");
 return s;
 }
 
diff -u --recursive --new-file v2.3.20/linux/include/asm-i386/string.h linux/include/asm-i386/string.h
--- v2.3.20/linux/include/asm-i386/string.h	Thu Apr 22 09:59:46 1999
+++ linux/include/asm-i386/string.h	Mon Oct 11 14:58:11 1999
@@ -293,10 +293,54 @@
 }
 
 #define __HAVE_ARCH_MEMCPY
+
+#include <linux/config.h>
+
+#ifdef CONFIG_X86_USE_3DNOW
+
+/* All this just for in_interrupt() ... */
+
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <asm/mmx.h>
+
+/*
+ *	This CPU favours 3DNow strongly (eg AMD Athlon)
+ */
+
+extern inline void * __constant_memcpy3d(void * to, const void * from, size_t len)
+{
+	if(len<512 || in_interrupt())
+		return __constant_memcpy(to, from, len);
+	return _mmx_memcpy(to, from, len);
+}
+
+extern __inline__ void *__memcpy3d(void *to, const void *from, size_t len)
+{
+	if(len<512 || in_interrupt())
+		return __memcpy(to, from, len);
+	return _mmx_memcpy(to, from, len);
+}
+
+#define memcpy(t, f, n) \
+(__builtin_constant_p(n) ? \
+ __constant_memcpy3d((t),(f),(n)) : \
+ __memcpy3d((t),(f),(n)))
+
+#else
+
+/*
+ *	No 3D Now!
+ */
+ 
 #define memcpy(t, f, n) \
 (__builtin_constant_p(n) ? \
  __constant_memcpy((t),(f),(n)) : \
  __memcpy((t),(f),(n)))
+
+#endif
 
 #define __HAVE_ARCH_MEMMOVE
 extern inline void * memmove(void * dest,const void * src, size_t n)
diff -u --recursive --new-file v2.3.20/linux/include/asm-i386/uaccess.h linux/include/asm-i386/uaccess.h
--- v2.3.20/linux/include/asm-i386/uaccess.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-i386/uaccess.h	Mon Oct 11 14:58:12 1999
@@ -597,7 +597,8 @@
 
 long strncpy_from_user(char *dst, const char *src, long count);
 long __strncpy_from_user(char *dst, const char *src, long count);
-long strlen_user(const char *str);
+#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
+long strnlen_user(const char *str, long n);
 unsigned long clear_user(void *mem, unsigned long len);
 unsigned long __clear_user(void *mem, unsigned long len);
 
diff -u --recursive --new-file v2.3.20/linux/include/asm-sparc/keyboard.h linux/include/asm-sparc/keyboard.h
--- v2.3.20/linux/include/asm-sparc/keyboard.h	Wed Apr 28 08:47:39 1999
+++ linux/include/asm-sparc/keyboard.h	Mon Oct 11 10:15:40 1999
@@ -13,6 +13,9 @@
 
 #ifdef __KERNEL__
 
+#include <linux/ioport.h>
+#include <asm/io.h>
+
 #define KEYBOARD_IRQ			13
 #define DISABLE_KBD_DURING_INTERRUPTS	0
 
@@ -44,6 +47,31 @@
 
 /* #define SYSRQ_KEY 0x54 */	/* sparc64 */
 #define SYSRQ_KEY 0x63		/* sparc */
+
+/* resource allocation */
+#define kbd_request_region() request_region(0x60, 16, "keyboard")
+#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
+                                             "keyboard", NULL)
+
+/* How to access the keyboard macros on this platform.  */
+#define kbd_read_input() inb(KBD_DATA_REG)
+#define kbd_read_status() inb(KBD_STATUS_REG)
+#define kbd_write_output(val) outb(val, KBD_DATA_REG)
+#define kbd_write_command(val) outb(val, KBD_CNTL_REG)
+
+/* Some stoneage hardware needs delays after some operations.  */
+#define kbd_pause() do { } while(0)
+
+/*
+ * Machine specific bits for the PS/2 driver
+ */
+
+#define AUX_IRQ 12
+
+#define aux_request_irq(hand, dev_id)					\
+	request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
+
+#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.3.20/linux/include/linux/fb.h linux/include/linux/fb.h
--- v2.3.20/linux/include/linux/fb.h	Thu Aug 26 13:05:41 1999
+++ linux/include/linux/fb.h	Mon Oct 11 13:53:09 1999
@@ -26,6 +26,7 @@
 /* #define FBIOSWITCH_MONIBIT	0x460E */
 #define FBIOGET_CON2FBMAP	0x460F
 #define FBIOPUT_CON2FBMAP	0x4610
+#define FBIOBLANK		0x4611		/* arg: 0 or vesa level + 1 */
 
 #define FB_TYPE_PACKED_PIXELS		0	/* Packed Pixels	*/
 #define FB_TYPE_PLANES			1	/* Non interleaved planes */
@@ -80,6 +81,8 @@
 #define FB_ACCEL_NV3		27	/* nVidia RIVA 128              */
 #define FB_ACCEL_NV4		28	/* nVidia RIVA TNT		*/
 #define FB_ACCEL_NV5		29	/* nVidia RIVA TNT2		*/
+#define FB_ACCEL_CT_6555x	30	/* C&T 6555x			*/
+#define FB_ACCEL_3DFX_BANSHEE	31	/* 3Dfx Banshee			*/
 
 struct fb_fix_screeninfo {
 	char id[16];			/* identification string eg "TT Builtin" */
diff -u --recursive --new-file v2.3.20/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.3.20/linux/include/linux/fs.h	Sat Oct  9 11:47:50 1999
+++ linux/include/linux/fs.h	Mon Oct 11 14:58:07 1999
@@ -727,7 +727,7 @@
 #define __getname()	((char *) __get_free_page(GFP_KERNEL))
 #define putname(name)	free_page((unsigned long)(name))
 
-extern void kill_fasync(struct fasync_struct *, int);
+extern void kill_fasync(struct fasync_struct *, int, int);
 extern int register_blkdev(unsigned int, const char *, struct file_operations *);
 extern int unregister_blkdev(unsigned int, const char *);
 extern int blkdev_open(struct inode *, struct file *);
diff -u --recursive --new-file v2.3.20/linux/include/linux/ide.h linux/include/linux/ide.h
--- v2.3.20/linux/include/linux/ide.h	Wed Aug 18 16:43:32 1999
+++ linux/include/linux/ide.h	Mon Oct 11 14:58:14 1999
@@ -46,9 +46,6 @@
 #ifndef OK_TO_RESET_CONTROLLER		/* 1 needed for good error recovery */
 #define OK_TO_RESET_CONTROLLER	1	/* 0 for use with AH2372A/B interface */
 #endif
-#ifndef FAKE_FDISK_FOR_EZDRIVE		/* 1 to help linux fdisk with EZDRIVE */
-#define FAKE_FDISK_FOR_EZDRIVE 	1	/* 0 to reduce kernel size */
-#endif
 #ifndef FANCY_STATUS_DUMPS		/* 1 for human-readable drive errors */
 #define FANCY_STATUS_DUMPS	1	/* 0 to reduce kernel size */
 #endif
@@ -262,9 +259,7 @@
 	unsigned nice2		: 1;	/* flag: give a share in our own bandwidth */
 	unsigned doorlocking	: 1;	/* flag: for removable only: door lock/unlock works */
 	unsigned autotune	: 2;	/* 1=autotune, 2=noautotune, 0=default */
-#if FAKE_FDISK_FOR_EZDRIVE
-	unsigned remap_0_to_1	: 1;	/* flag: partitioned with ezdrive */
-#endif /* FAKE_FDISK_FOR_EZDRIVE */
+	unsigned remap_0_to_1	: 2;	/* 0=remap if ezdrive, 1=remap, 2=noremap */
 	unsigned ata_flash	: 1;	/* 1=present, 0=default */
 	byte		media;		/* disk, cdrom, tape, floppy, ... */
 	select_t	select;		/* basic drive/head select reg value */
@@ -282,8 +277,9 @@
 	byte		sect;		/* "real" sectors per track */
 	byte		bios_head;	/* BIOS/fdisk/LILO number of heads */
 	byte		bios_sect;	/* BIOS/fdisk/LILO sectors per track */
-	unsigned short	bios_cyl;	/* BIOS/fdisk/LILO number of cyls */
-	unsigned short	cyl;		/* "real" number of cyls */
+	unsigned int	bios_cyl;	/* BIOS/fdisk/LILO number of cyls */
+	unsigned int	cyl;		/* "real" number of cyls */
+	unsigned long	capacity;	/* total number of sectors */
 	unsigned int	drive_data;	/* for use by tuneproc/selectproc as needed */
 	void		  *hwif;	/* actually (ide_hwif_t *) */
 	wait_queue_head_t wqueue;	/* used to wait for drive in open() */
@@ -624,20 +620,18 @@
 /*
  * This routine is called from the partition-table code in genhd.c
  * to "convert" a drive to a logical geometry with fewer than 1024 cyls.
- *
- * The second parameter, "xparm", determines exactly how the translation
- * will be handled:
- *		 0 = convert to CHS with fewer than 1024 cyls
- *			using the same method as Ontrack DiskManager.
- *		 1 = same as "0", plus offset everything by 63 sectors.
- *		-1 = similar to "0", plus redirect sector 0 to sector 1.
- *		>1 = convert to a CHS geometry with "xparm" heads.
- *
- * Returns 0 if the translation was not possible, if the device was not
- * an IDE disk drive, or if a geometry was "forced" on the commandline.
- * Returns 1 if the geometry translation was successful.
  */
-int ide_xlate_1024 (kdev_t, int, const char *);
+int ide_xlate_1024 (kdev_t, int, int, const char *);
+
+/*
+ * Convert kdev_t structure into ide_drive_t * one.
+ */
+ide_drive_t *get_info_ptr (kdev_t i_rdev);
+
+/*
+ * Return the current idea about the total capacity of this drive.
+ */
+unsigned long current_capacity (ide_drive_t *drive);
 
 /*
  * Start a reset operation for an IDE interface.
diff -u --recursive --new-file v2.3.20/linux/include/linux/net.h linux/include/linux/net.h
--- v2.3.20/linux/include/linux/net.h	Thu Aug 26 13:05:41 1999
+++ linux/include/linux/net.h	Mon Oct 11 14:58:05 1999
@@ -126,7 +126,7 @@
 	void (*init_func)(struct net_proto *);	/* Bootstrap */
 };
 
-extern int	sock_wake_async(struct socket *sk, int how);
+extern int	sock_wake_async(struct socket *sk, int how, int band);
 extern int	sock_register(struct net_proto_family *fam);
 extern int	sock_unregister(int family);
 extern struct socket *sock_alloc(void);
diff -u --recursive --new-file v2.3.20/linux/include/linux/pc_keyb.h linux/include/linux/pc_keyb.h
--- v2.3.20/linux/include/linux/pc_keyb.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/pc_keyb.h	Mon Oct 11 10:15:40 1999
@@ -0,0 +1,130 @@
+/*
+ *	include/linux/pc_keyb.h
+ *
+ *	PC Keyboard And Keyboard Controller
+ *
+ *	(c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+/*
+ *	Configuration Switches
+ */
+
+#undef KBD_REPORT_ERR			/* Report keyboard errors */
+#define KBD_REPORT_UNKN			/* Report unknown scan codes */
+#define KBD_REPORT_TIMEOUTS		/* Report keyboard timeouts */
+#undef KBD_IS_FOCUS_9000		/* We have the brain-damaged FOCUS-9000 keyboard */
+#undef INITIALIZE_MOUSE			/* Define if your PS/2 mouse needs initialization. */
+
+
+
+#define KBD_INIT_TIMEOUT 1000		/* Timeout in ms for initializing the keyboard */
+#define KBC_TIMEOUT 250			/* Timeout in ms for sending to keyboard controller */
+#define KBD_TIMEOUT 1000		/* Timeout in ms for keyboard command acknowledge */
+
+/*
+ *	Internal variables of the driver
+ */
+
+extern unsigned char pckbd_read_mask;
+extern unsigned char aux_device_present;
+
+/*
+ *	Keyboard Controller Registers on normal PCs.
+ */
+
+#define KBD_STATUS_REG		0x64	/* Status register (R) */
+#define KBD_CNTL_REG		0x64	/* Controller command register (W) */
+#define KBD_DATA_REG		0x60	/* Keyboard data register (R/W) */
+
+/*
+ *	Keyboard Controller Commands
+ */
+
+#define KBD_CCMD_READ_MODE	0x20	/* Read mode bits */
+#define KBD_CCMD_WRITE_MODE	0x60	/* Write mode bits */
+#define KBD_CCMD_GET_VERSION	0xA1	/* Get controller version */
+#define KBD_CCMD_MOUSE_DISABLE	0xA7	/* Disable mouse interface */
+#define KBD_CCMD_MOUSE_ENABLE	0xA8	/* Enable mouse interface */
+#define KBD_CCMD_TEST_MOUSE	0xA9	/* Mouse interface test */
+#define KBD_CCMD_SELF_TEST	0xAA	/* Controller self test */
+#define KBD_CCMD_KBD_TEST	0xAB	/* Keyboard interface test */
+#define KBD_CCMD_KBD_DISABLE	0xAD	/* Keyboard interface disable */
+#define KBD_CCMD_KBD_ENABLE	0xAE	/* Keyboard interface enable */
+#define KBD_CCMD_WRITE_AUX_OBUF	0xD3    /* Write to output buffer as if
+					   initiated by the auxiliary device */
+#define KBD_CCMD_WRITE_MOUSE	0xD4	/* Write the following byte to the mouse */
+
+/*
+ *	Keyboard Commands
+ */
+
+#define KBD_CMD_SET_LEDS	0xED	/* Set keyboard leds */
+#define KBD_CMD_SET_RATE	0xF3	/* Set typematic rate */
+#define KBD_CMD_ENABLE		0xF4	/* Enable scanning */
+#define KBD_CMD_DISABLE		0xF5	/* Disable scanning */
+#define KBD_CMD_RESET		0xFF	/* Reset */
+
+/*
+ *	Keyboard Replies
+ */
+
+#define KBD_REPLY_POR		0xAA	/* Power on reset */
+#define KBD_REPLY_ACK		0xFA	/* Command ACK */
+#define KBD_REPLY_RESEND	0xFE	/* Command NACK, send the cmd again */
+
+/*
+ *	Status Register Bits
+ */
+
+#define KBD_STAT_OBF 		0x01	/* Keyboard output buffer full */
+#define KBD_STAT_IBF 		0x02	/* Keyboard input buffer full */
+#define KBD_STAT_SELFTEST	0x04	/* Self test successful */
+#define KBD_STAT_CMD		0x08	/* Last write was a command write (0=data) */
+#define KBD_STAT_UNLOCKED	0x10	/* Zero if keyboard locked */
+#define KBD_STAT_MOUSE_OBF	0x20	/* Mouse output buffer full */
+#define KBD_STAT_GTO 		0x40	/* General receive/xmit timeout */
+#define KBD_STAT_PERR 		0x80	/* Parity error */
+
+#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF)
+
+/*
+ *	Controller Mode Register Bits
+ */
+
+#define KBD_MODE_KBD_INT	0x01	/* Keyboard data generate IRQ1 */
+#define KBD_MODE_MOUSE_INT	0x02	/* Mouse data generate IRQ12 */
+#define KBD_MODE_SYS 		0x04	/* The system flag (?) */
+#define KBD_MODE_NO_KEYLOCK	0x08	/* The keylock doesn't affect the keyboard if set */
+#define KBD_MODE_DISABLE_KBD	0x10	/* Disable keyboard interface */
+#define KBD_MODE_DISABLE_MOUSE	0x20	/* Disable mouse interface */
+#define KBD_MODE_KCC 		0x40	/* Scan code conversion to PC format */
+#define KBD_MODE_RFU		0x80
+
+/*
+ *	Mouse Commands
+ */
+
+#define AUX_SET_RES		0xE8	/* Set resolution */
+#define AUX_SET_SCALE11		0xE6	/* Set 1:1 scaling */
+#define AUX_SET_SCALE21		0xE7	/* Set 2:1 scaling */
+#define AUX_GET_SCALE		0xE9	/* Get scaling factor */
+#define AUX_SET_STREAM		0xEA	/* Set stream mode */
+#define AUX_SET_SAMPLE		0xF3	/* Set sample rate */
+#define AUX_ENABLE_DEV		0xF4	/* Enable aux device */
+#define AUX_DISABLE_DEV		0xF5	/* Disable aux device */
+#define AUX_RESET		0xFF	/* Reset aux device */
+#define AUX_ACK			0xFA	/* Command byte ACK. */
+
+#define AUX_BUF_SIZE		2048	/* This might be better divisible by
+					   three to make overruns stay in sync
+					   but then the read function would need
+					   a lock etc - ick */
+
+struct aux_queue {
+	unsigned long head;
+	unsigned long tail;
+	wait_queue_head_t proc_list;
+	struct fasync_struct *fasync;
+	unsigned char buf[AUX_BUF_SIZE];
+};
diff -u --recursive --new-file v2.3.20/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.3.20/linux/include/linux/sched.h	Sat Oct  9 11:47:50 1999
+++ linux/include/linux/sched.h	Mon Oct 11 14:58:12 1999
@@ -823,8 +823,8 @@
 extern inline void unhash_process(struct task_struct *p)
 {
 	if (task_on_runqueue(p)) BUG();
-	nr_threads--;
 	write_lock_irq(&tasklist_lock);
+	nr_threads--;
 	unhash_pid(p);
 	REMOVE_LINKS(p);
 	write_unlock_irq(&tasklist_lock);
diff -u --recursive --new-file v2.3.20/linux/include/linux/synclink.h linux/include/linux/synclink.h
--- v2.3.20/linux/include/linux/synclink.h	Wed Jun 16 19:26:27 1999
+++ linux/include/linux/synclink.h	Mon Oct 11 10:15:40 1999
@@ -1,7 +1,7 @@
 /*
  * SyncLink Multiprotocol Serial Adapter Driver
  *
- * ==FILEDATE 19990523==
+ * ==FILEDATE 19990810==
  *
  * Copyright (C) 1998 by Microgate Corporation
  * 
@@ -50,8 +50,9 @@
 #define BIT31	0x80000000
 
 
-#define HDLC_MAX_FRAME_SIZE	4096
+#define HDLC_MAX_FRAME_SIZE	65535
 #define MAX_ASYNC_TRANSMIT	4096
+#define MAX_ASYNC_BUFFER_SIZE	4096
 
 #define ASYNC_PARITY_NONE		0
 #define ASYNC_PARITY_EVEN		1
@@ -68,12 +69,12 @@
 #define HDLC_FLAG_AUTO_RTS		0x0080
 #define HDLC_FLAG_RXC_DPLL		0x0100
 #define HDLC_FLAG_RXC_BRG		0x0200
-#define HDLC_FLAG_RXC_TXCPIN	0x8000
-#define HDLC_FLAG_RXC_RXCPIN	0x0000
+#define HDLC_FLAG_RXC_TXCPIN		0x8000
+#define HDLC_FLAG_RXC_RXCPIN		0x0000
 #define HDLC_FLAG_TXC_DPLL		0x0400
 #define HDLC_FLAG_TXC_BRG		0x0800
-#define HDLC_FLAG_TXC_TXCPIN	0x0000
-#define HDLC_FLAG_TXC_RXCPIN	0x0008
+#define HDLC_FLAG_TXC_TXCPIN		0x0000
+#define HDLC_FLAG_TXC_RXCPIN		0x0008
 #define HDLC_FLAG_DPLL_DIV8		0x1000
 #define HDLC_FLAG_DPLL_DIV16		0x2000
 #define HDLC_FLAG_DPLL_DIV32		0x0000
@@ -81,6 +82,7 @@
 
 #define HDLC_CRC_NONE			0
 #define HDLC_CRC_16_CCITT		1
+#define HDLC_CRC_32_CCITT		2
 
 #define HDLC_TXIDLE_FLAGS		0
 #define HDLC_TXIDLE_ALT_ZEROS_ONES	1
@@ -132,7 +134,7 @@
 	unsigned char	encoding;	/* NRZ, NRZI, etc. */
 	unsigned long	clock_speed;	/* external clock speed in bits per second */
 	unsigned char	addr_filter;	/* receive HDLC address filter, 0xFF = disable */
-	unsigned short	crc_type;	/* None, CRC16 or CRC16-CCITT */
+	unsigned short	crc_type;	/* None, CRC16-CCITT, or CRC32-CCITT */
 	unsigned char	preamble_length;
 	unsigned char	preamble;
 
diff -u --recursive --new-file v2.3.20/linux/include/linux/tty.h linux/include/linux/tty.h
--- v2.3.20/linux/include/linux/tty.h	Tue Sep  7 12:14:07 1999
+++ linux/include/linux/tty.h	Mon Oct 11 14:58:09 1999
@@ -326,6 +326,7 @@
 #define TTY_HW_COOK_OUT 14
 #define TTY_HW_COOK_IN 15
 #define TTY_PTY_LOCK 16
+#define TTY_NO_WRITE_SPLIT 17
 
 #define TTY_WRITE_FLUSH(tty) tty_write_flush((tty))
 
diff -u --recursive --new-file v2.3.20/linux/include/video/fbcon.h linux/include/video/fbcon.h
--- v2.3.20/linux/include/video/fbcon.h	Tue Aug 31 17:29:15 1999
+++ linux/include/video/fbcon.h	Mon Oct 11 10:26:52 1999
@@ -16,6 +16,8 @@
 #include <linux/console_struct.h>
 #include <linux/vt_buffer.h>
 
+#include <asm/io.h>
+
 
     /*                                  
      *  `switch' for the Low Level Operations
@@ -179,7 +181,7 @@
    movep is rather expensive compared to ordinary move's
    some functions rewritten in C for clarity, no speed loss */
 
-static __inline__ void *mymemclear_small(void *s, size_t count)
+static __inline__ void *fb_memclear_small(void *s, size_t count)
 {
    if (!count)
       return(0);
@@ -202,7 +204,7 @@
 }
 
 
-static __inline__ void *mymemclear(void *s, size_t count)
+static __inline__ void *fb_memclear(void *s, size_t count)
 {
    if (!count)
       return(0);
@@ -244,7 +246,7 @@
 }
 
 
-static __inline__ void *mymemset(void *s, size_t count)
+static __inline__ void *fb_memset255(void *s, size_t count)
 {
    if (!count)
       return(0);
@@ -267,7 +269,7 @@
 }
 
 
-static __inline__ void *mymemmove(void *d, const void *s, size_t count)
+static __inline__ void *fb_memmove(void *d, const void *s, size_t count)
 {
    if (d < s) {
       if (count < 16) {
@@ -389,17 +391,17 @@
     return s;
 }
 
-static __inline__ void *mymemset(void *s, size_t count)
+static __inline__ void *fb_memset255(void *s, size_t count)
 {
     return sun4_memset(s, 255, count);
 }
 
-static __inline__ void *mymemclear(void *s, size_t count)
+static __inline__ void *fb_memclear(void *s, size_t count)
 {
     return sun4_memset(s, 0, count);
 }
 
-static __inline__ void *mymemclear_small(void *s, size_t count)
+static __inline__ void *fb_memclear_small(void *s, size_t count)
 {
     return sun4_memset(s, 0, count);
 }
@@ -416,7 +418,7 @@
 	    ((char *) d)[count-i-1] = ((char *) s)[count-i-1];
 }
 
-static __inline__ void *mymemmove(char *dst, const char *src, size_t size)
+static __inline__ void *fb_memmove(char *dst, const char *src, size_t size)
 {
     fast_memmove(dst, src, size);
     return dst;
@@ -424,17 +426,17 @@
 
 #else
 
-static __inline__ void *mymemclear_small(void *s, size_t count)
+static __inline__ void *fb_memclear_small(void *s, size_t count)
 {
     return(memset(s, 0, count));
 }
 
-static __inline__ void *mymemclear(void *s, size_t count)
+static __inline__ void *fb_memclear(void *s, size_t count)
 {
     return(memset(s, 0, count));
 }
 
-static __inline__ void *mymemset(void *s, size_t count)
+static __inline__ void *fb_memset255(void *s, size_t count)
 {
     return(memset(s, 255, count));
 }
@@ -484,7 +486,7 @@
     }
 }
 
-static __inline__ void *mymemmove(char *dst, const char *src, size_t size)
+static __inline__ void *fb_memmove(char *dst, const char *src, size_t size)
 {
     fast_memmove(dst, src, size);
     return dst;
@@ -497,7 +499,7 @@
      *   (Why are these functions better than those from include/asm/string.h?)
      */
 
-static __inline__ void *mymemmove(void *d, const void *s, size_t count)
+static __inline__ void *fb_memmove(void *d, const void *s, size_t count)
 {
     return(memmove(d, s, count));
 }
@@ -512,7 +514,21 @@
 #endif
 
 
-#if defined(__i386__) || defined(__alpha__)
+#if defined(__sparc__)
+
+/* We map all of our framebuffers such that big-endian accesses
+ * are what we want, so the following is sufficient.
+ */
+
+#define fb_readb sbus_readb
+#define fb_readw sbus_readw
+#define fb_readl sbus_readl
+#define fb_writeb sbus_writeb
+#define fb_writew sbus_writew
+#define fb_writel sbus_writel
+#define fb_memset sbus_memset_io
+
+#elif defined(__i386__) || defined(__alpha__)
 
 #define fb_readb __raw_readb
 #define fb_readw __raw_readw
@@ -520,6 +536,7 @@
 #define fb_writeb __raw_writeb
 #define fb_writew __raw_writew
 #define fb_writel __raw_writel
+#define fb_memset memset_io
 
 #else
 
@@ -529,6 +546,7 @@
 #define fb_writeb(b,addr) (*(volatile u8 *) (addr) = (b))
 #define fb_writew(b,addr) (*(volatile u16 *) (addr) = (b))
 #define fb_writel(b,addr) (*(volatile u32 *) (addr) = (b))
+#define fb_memset memset
 
 #endif
 
diff -u --recursive --new-file v2.3.20/linux/include/video/macmodes.h linux/include/video/macmodes.h
--- v2.3.20/linux/include/video/macmodes.h	Tue Sep 29 21:04:37 1998
+++ linux/include/video/macmodes.h	Mon Oct 11 10:26:52 1999
@@ -52,6 +52,9 @@
 extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
 			    int *cmode);
 extern int mac_map_monitor_sense(int sense);
+extern int __init mac_find_mode(struct fb_var_screeninfo *var,
+				struct fb_info *info, const char *mode_option,
+				unsigned int default_bpp);
 
 
     /*
diff -u --recursive --new-file v2.3.20/linux/kernel/fork.c linux/kernel/fork.c
--- v2.3.20/linux/kernel/fork.c	Mon Aug  2 22:07:16 1999
+++ linux/kernel/fork.c	Mon Oct 11 14:38:39 1999
@@ -592,6 +592,12 @@
 	struct task_struct *p;
 	DECLARE_MUTEX_LOCKED(sem);
 
+	if (clone_flags & CLONE_PID) {
+		/* This is only allowed from the boot up thread */
+		if (current->pid)
+			return -EPERM;
+	}
+	
 	current->vfork_sem = &sem;
 
 	p = alloc_task_struct();
@@ -610,8 +616,9 @@
 	}
 
 	/*
-	 * Counter atomicity is protected by
-	 * the kernel lock
+	 * Counter increases are protected by
+	 * the kernel lock so nr_threads can't
+	 * increase under us (but it may decrease).
 	 */
 	if (nr_threads >= max_threads)
 		goto bad_fork_cleanup_count;
@@ -711,9 +718,9 @@
 	write_lock_irq(&tasklist_lock);
 	SET_LINKS(p);
 	hash_pid(p);
+	nr_threads++;
 	write_unlock_irq(&tasklist_lock);
 
-	nr_threads++;
 	wake_up_process(p);		/* do this last */
 	++total_forks;
 
@@ -735,8 +742,6 @@
 		__MOD_DEC_USE_COUNT(p->exec_domain->module);
 	if (p->binfmt && p->binfmt->module)
 		__MOD_DEC_USE_COUNT(p->binfmt->module);
-
-	nr_threads--;
 bad_fork_cleanup_count:
 	if (p->user)
 		free_uid(p);
diff -u --recursive --new-file v2.3.20/linux/kernel/signal.c linux/kernel/signal.c
--- v2.3.20/linux/kernel/signal.c	Thu Aug 26 13:05:42 1999
+++ linux/kernel/signal.c	Mon Oct 11 10:15:40 1999
@@ -353,13 +353,9 @@
 				break;
 			}
 		} else {
-			/* If this was sent by a rt mechanism, try again.  */
-			if (info->si_code < 0) {
-				ret = -EAGAIN;
-				goto out;
-			}
-			/* Otherwise, mention that the signal is pending,
-			   but don't queue the info.  */
+			/* Queue overflow, we have to abort. */
+			ret = -EAGAIN;
+			goto out;
 		}
 	}
 
@@ -792,6 +788,8 @@
 {
 	struct siginfo info;
 
+	memset(&info, 0, sizeof(info));
+	
 	info.si_signo = sig;
 	info.si_errno = 0;
 	info.si_code = SI_USER;
diff -u --recursive --new-file v2.3.20/linux/mm/filemap.c linux/mm/filemap.c
--- v2.3.20/linux/mm/filemap.c	Sat Oct  9 11:47:50 1999
+++ linux/mm/filemap.c	Mon Oct 11 10:44:11 1999
@@ -912,6 +912,8 @@
 	ahead = 0;
 	while (ahead < max_ahead) {
 		ahead += PAGE_CACHE_SIZE;
+		if ((raend + ahead) >= inode->i_size)
+			break;
 		page_cache_read(filp, raend + ahead);
 	}
 /*
@@ -1779,6 +1781,7 @@
 	long		status;
 	int		err;
 
+	down(&inode->i_sem);
 	err = file->f_error;
 	if (err) {
 		file->f_error = 0;
@@ -1872,6 +1875,7 @@
 
 	err = written ? written : status;
 out:
+	up(&inode->i_sem);
 	return err;
 }
 
diff -u --recursive --new-file v2.3.20/linux/net/core/sock.c linux/net/core/sock.c
--- v2.3.20/linux/net/core/sock.c	Fri Sep 10 23:57:38 1999
+++ linux/net/core/sock.c	Mon Oct 11 10:15:40 1999
@@ -1013,7 +1013,7 @@
 	read_lock(&sk->callback_lock);
 	if (!sk->dead) {
 		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket,0); 
+		sock_wake_async(sk->socket,0,POLL_ERR); 
 	}
 	read_unlock(&sk->callback_lock);
 }
@@ -1023,7 +1023,7 @@
 	read_lock(&sk->callback_lock);
 	if(!sk->dead) {
 		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket,1);
+		sock_wake_async(sk->socket,1,POLL_IN);
 	}
 	read_unlock(&sk->callback_lock);
 }
@@ -1041,7 +1041,7 @@
 
 		/* Should agree with poll, otherwise some programs break */
 		if (sock_writeable(sk))
-			sock_wake_async(sk->socket, 2);
+			sock_wake_async(sk->socket, 2, POLL_OUT);
 	}
 	read_unlock(&sk->callback_lock);
 }
diff -u --recursive --new-file v2.3.20/linux/net/decnet/dn_nsp_in.c linux/net/decnet/dn_nsp_in.c
--- v2.3.20/linux/net/decnet/dn_nsp_in.c	Tue Aug 31 17:29:15 1999
+++ linux/net/decnet/dn_nsp_in.c	Mon Oct 11 10:15:40 1999
@@ -431,7 +431,8 @@
 		struct socket *sock = sk->socket;
 		wake_up_interruptible(sk->sleep);
 		if (!(sock->flags & SO_WAITDATA) && sock->fasync_list)
-			kill_fasync(sock->fasync_list, sig);
+			kill_fasync(sock->fasync_list, sig, 
+				    (sig == SIGURG) ? POLL_PRI : POLL_IN);
 	}
 	read_unlock_irqrestore(&sk->callback_lock, flags);
 
diff -u --recursive --new-file v2.3.20/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.3.20/linux/net/ipv4/tcp.c	Fri Sep 10 23:57:38 1999
+++ linux/net/ipv4/tcp.c	Mon Oct 11 10:15:40 1999
@@ -626,7 +626,7 @@
 		wake_up_interruptible(sk->sleep);
 
 		if (sock_wspace(sk) >= tcp_min_write_space(sk))
-			sock_wake_async(sk->socket, 2);
+			sock_wake_async(sk->socket, 2, POLL_OUT);
 	}
 	read_unlock(&sk->callback_lock);
 }
diff -u --recursive --new-file v2.3.20/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.3.20/linux/net/ipv4/tcp_input.c	Fri Sep 10 23:57:38 1999
+++ linux/net/ipv4/tcp_input.c	Mon Oct 11 10:15:40 1999
@@ -1403,7 +1403,7 @@
 
 	if (!sk->dead) {
 		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket, 1);
+		sock_wake_async(sk->socket, 1, POLL_HUP);
 	}
 
 	switch(sk->state) {
@@ -1806,7 +1806,7 @@
 	 */
 	if (!sk->dead) {
 		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket,1);
+		sock_wake_async(sk->socket,1, POLL_IN);
 	}
 	return(1);
 }
@@ -1965,6 +1965,7 @@
 			kill_proc(sk->proc, SIGURG, 1);
 		else
 			kill_pg(-sk->proc, SIGURG, 1);
+		sock_wake_async(sk->socket, 3, POLL_PRI);
 	}
 
 	/* We may be adding urgent data when the last byte read was
@@ -2201,7 +2202,7 @@
 			 * this frame, the pred_flags won't match up. -DaveM
 			 */
 			wake_up_interruptible(sk->sleep);
-			sock_wake_async(sk->socket,1);
+			sock_wake_async(sk->socket,1, POLL_IN);
 			tcp_delack_estimator(tp);
 
 			tcp_remember_ack(tp, th, skb); 
@@ -2760,7 +2761,7 @@
 
 		if(!sk->dead) {
 			wake_up_interruptible(sk->sleep);
-			sock_wake_async(sk->socket, 0);
+			sock_wake_async(sk->socket, 0, POLL_IN);
 		}
 		return -1;
 	}
@@ -3017,7 +3018,7 @@
 				 */
 				if (!sk->dead && sk->sleep) {
 					wake_up_interruptible(sk->sleep);
-					sock_wake_async(sk->socket, 1);
+					sock_wake_async(sk->socket,0,POLL_OUT);
 				}
 
 				tp->snd_una = TCP_SKB_CB(skb)->ack_seq;
diff -u --recursive --new-file v2.3.20/linux/net/socket.c linux/net/socket.c
--- v2.3.20/linux/net/socket.c	Tue Sep  7 12:14:07 1999
+++ linux/net/socket.c	Mon Oct 11 10:15:40 1999
@@ -670,7 +670,7 @@
 
 /* This function may be called only under socket lock or callback_lock */
 
-int sock_wake_async(struct socket *sock, int how)
+int sock_wake_async(struct socket *sock, int how, int band)
 {
 	if (!sock || !sock->fasync_list)
 		return -1;
@@ -689,9 +689,11 @@
 	call_kill:
 		/* read_lock(&sock->sk->callback_lock); */
 		if(sock->fasync_list != NULL)
-			kill_fasync(sock->fasync_list, SIGIO);
+			kill_fasync(sock->fasync_list, SIGIO, band);
 		/* read_unlock(&sock->sk->callback_lock); */
 		break;
+	case 3:
+		kill_fasync(sock->fasync_list, SIGURG, band);
 	}
 	return 0;
 }
diff -u --recursive --new-file v2.3.20/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.3.20/linux/net/unix/af_unix.c	Fri Sep 10 23:57:38 1999
+++ linux/net/unix/af_unix.c	Mon Oct 11 10:15:40 1999
@@ -299,7 +299,7 @@
 	read_lock(&sk->callback_lock);
 	if (!sk->dead && unix_writable(sk)) {
 		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket, 2);
+		sock_wake_async(sk->socket, 2, POLL_OUT);
 	}
 	read_unlock(&sk->callback_lock);
 }
diff -u --recursive --new-file v2.3.20/linux/net/x25/x25_in.c linux/net/x25/x25_in.c
--- v2.3.20/linux/net/x25/x25_in.c	Sun Jul 26 23:35:58 1998
+++ linux/net/x25/x25_in.c	Mon Oct 11 10:15:40 1999
@@ -278,6 +278,7 @@
 					kill_proc(sk->proc, SIGURG, 1);
 				else
 					kill_pg(-sk->proc, SIGURG, 1);
+				sock_wake_async(sk, 3, POLL_PRI);
 			}
 			x25_write_internal(sk, X25_INTERRUPT_CONFIRMATION);
 			break;
