]> git.neil.brown.name Git - history.git/commitdiff
Import 2.3.21pre1 2.3.21pre1
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:27:36 +0000 (15:27 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:27:36 +0000 (15:27 -0500)
187 files changed:
Documentation/Changes
Documentation/Configure.help
Documentation/fb/clgenfb.txt
Documentation/ioctl-number.txt
Makefile
arch/alpha/kernel/alpha_ksyms.c
arch/alpha/lib/strlen_user.S
arch/i386/config.in
arch/i386/defconfig
arch/i386/kernel/apm.c
arch/i386/kernel/i386_ksyms.c
arch/i386/lib/Makefile
arch/i386/lib/mmx.c [new file with mode: 0644]
arch/i386/lib/usercopy.c
arch/sh/config.in
arch/sparc64/solaris/timod.c
drivers/acorn/block/Config.in
drivers/acorn/scsi/Config.in
drivers/block/Config.in
drivers/block/Makefile
drivers/block/cmos-probe.c [deleted file]
drivers/block/cpqarray.c
drivers/block/ide-disk.c
drivers/block/ide-dma.c
drivers/block/ide-floppy.c
drivers/block/ide-geometry.c [new file with mode: 0644]
drivers/block/ide-pmac.c
drivers/block/ide.c
drivers/block/pdc202xx.c
drivers/char/adbmouse.c
drivers/char/busmouse.c
drivers/char/console.c
drivers/char/dn_keyb.c
drivers/char/drm/fops.c
drivers/char/ftape/Config.in
drivers/char/joystick/Config.in
drivers/char/keyboard.c
drivers/char/misc.c
drivers/char/n_hdlc.c
drivers/char/n_tty.c
drivers/char/pc110pad.c
drivers/char/pc_keyb.c
drivers/char/pc_keyb.h [deleted file]
drivers/char/ppdev.h
drivers/char/tty_io.c
drivers/fc4/Config.in
drivers/net/Config.in
drivers/net/Makefile
drivers/net/Space.c
drivers/net/arcnet.c
drivers/net/cosa.c [deleted file]
drivers/net/cosa.h [deleted file]
drivers/net/cycx_drv.c [deleted file]
drivers/net/cycx_main.c [deleted file]
drivers/net/cycx_x25.c [deleted file]
drivers/net/dlci.c [deleted file]
drivers/net/hostess_sv11.c [deleted file]
drivers/net/ibmtr.c [deleted file]
drivers/net/ibmtr.h [deleted file]
drivers/net/lapbether.c [deleted file]
drivers/net/ncr885_debug.h [new file with mode: 0644]
drivers/net/ncr885e.c [new file with mode: 0644]
drivers/net/ncr885e.h [new file with mode: 0644]
drivers/net/olympic.c [deleted file]
drivers/net/olympic.h [deleted file]
drivers/net/sdla.c [deleted file]
drivers/net/sdla_fr.c [deleted file]
drivers/net/sdla_ppp.c [deleted file]
drivers/net/sdla_x25.c [deleted file]
drivers/net/sdladrv.c [deleted file]
drivers/net/sdlamain.c [deleted file]
drivers/net/sealevel.c [deleted file]
drivers/net/sgiseeq.h
drivers/net/sk_mca.c
drivers/net/sktr.c [deleted file]
drivers/net/sktr.h [deleted file]
drivers/net/sktr_firmware.h [deleted file]
drivers/net/syncppp.c [deleted file]
drivers/net/syncppp.h [deleted file]
drivers/net/tokenring/Config.in [new file with mode: 0644]
drivers/net/tokenring/Makefile [new file with mode: 0644]
drivers/net/tokenring/ibmtr.c [new file with mode: 0644]
drivers/net/tokenring/ibmtr.h [new file with mode: 0644]
drivers/net/tokenring/olympic.c [new file with mode: 0644]
drivers/net/tokenring/olympic.h [new file with mode: 0644]
drivers/net/tokenring/sktr.c [new file with mode: 0644]
drivers/net/tokenring/sktr.h [new file with mode: 0644]
drivers/net/tokenring/sktr_firmware.h [new file with mode: 0644]
drivers/net/wan/Config.in [new file with mode: 0644]
drivers/net/wan/Makefile [new file with mode: 0644]
drivers/net/wan/cosa.c [new file with mode: 0644]
drivers/net/wan/cosa.h [new file with mode: 0644]
drivers/net/wan/cycx_drv.c [new file with mode: 0644]
drivers/net/wan/cycx_main.c [new file with mode: 0644]
drivers/net/wan/cycx_x25.c [new file with mode: 0644]
drivers/net/wan/dlci.c [new file with mode: 0644]
drivers/net/wan/hostess_sv11.c [new file with mode: 0644]
drivers/net/wan/lapbether.c [new file with mode: 0644]
drivers/net/wan/sbni.c [new file with mode: 0644]
drivers/net/wan/sbni.h [new file with mode: 0644]
drivers/net/wan/sdla.c [new file with mode: 0644]
drivers/net/wan/sdla_fr.c [new file with mode: 0644]
drivers/net/wan/sdla_ppp.c [new file with mode: 0644]
drivers/net/wan/sdla_x25.c [new file with mode: 0644]
drivers/net/wan/sdladrv.c [new file with mode: 0644]
drivers/net/wan/sdlamain.c [new file with mode: 0644]
drivers/net/wan/sealevel.c [new file with mode: 0644]
drivers/net/wan/syncppp.c [new file with mode: 0644]
drivers/net/wan/syncppp.h [new file with mode: 0644]
drivers/net/wan/x25_asy.c [new file with mode: 0644]
drivers/net/wan/x25_asy.h [new file with mode: 0644]
drivers/net/wan/z85230.c [new file with mode: 0644]
drivers/net/wan/z85230.h [new file with mode: 0644]
drivers/net/x25_asy.c [deleted file]
drivers/net/x25_asy.h [deleted file]
drivers/net/z85230.c [deleted file]
drivers/net/z85230.h [deleted file]
drivers/pnp/Config.in
drivers/sbus/char/pcikbd.c
drivers/sbus/char/sunkbd.c
drivers/sbus/char/sunmouse.c
drivers/sbus/char/uctrl.c
drivers/scsi/sg.c
drivers/sgi/char/shmiq.c
drivers/usb/audio.c
drivers/usb/mouse.c
drivers/video/Config.in
drivers/video/Makefile
drivers/video/amifb.c
drivers/video/aty.h
drivers/video/atyfb.c
drivers/video/chipsfb.c
drivers/video/controlfb.c
drivers/video/fbcon-afb.c
drivers/video/fbcon-cfb16.c
drivers/video/fbcon-cfb2.c
drivers/video/fbcon-cfb24.c
drivers/video/fbcon-cfb32.c
drivers/video/fbcon-cfb4.c
drivers/video/fbcon-cfb8.c
drivers/video/fbcon-ilbm.c
drivers/video/fbcon-iplan2p2.c
drivers/video/fbcon-iplan2p4.c
drivers/video/fbcon-iplan2p8.c
drivers/video/fbcon-mac.c
drivers/video/fbcon-mfb.c
drivers/video/fbcon.c
drivers/video/fbmem.c
drivers/video/imsttfb.c
drivers/video/modedb.c
drivers/video/platinumfb.c
drivers/video/sbusfb.c
drivers/video/tdfxfb.c [new file with mode: 0644]
drivers/video/valkyriefb.c
drivers/video/vesafb.c
drivers/video/virgefb.c
fs/buffer.c
fs/exec.c
fs/fcntl.c
fs/ncpfs/dir.c
fs/partitions/msdos.c
fs/smbfs/cache.c
fs/smbfs/file.c
include/asm-i386/keyboard.h
include/asm-i386/mmx.h [new file with mode: 0644]
include/asm-i386/page.h
include/asm-i386/string-486.h
include/asm-i386/string.h
include/asm-i386/uaccess.h
include/asm-sparc/keyboard.h
include/linux/fb.h
include/linux/fs.h
include/linux/ide.h
include/linux/net.h
include/linux/pc_keyb.h [new file with mode: 0644]
include/linux/synclink.h
include/video/fbcon.h
include/video/macmodes.h
kernel/signal.c
mm/filemap.c
net/core/sock.c
net/decnet/dn_nsp_in.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/socket.c
net/unix/af_unix.c
net/x25/x25_in.c

index d69f5130f8b32673abe5367ebe9c4058fc1d9527..c3c1cb7263a7a89ccd784db1556b5cd05614b126 100644 (file)
@@ -392,6 +392,8 @@ PPP
    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
 ====
 
index 8c00e9998b3fecf6fd4c75fed43cb02b584b4883..cb15ef5240d479fc70b6721779e9591e66c5960e 100644 (file)
@@ -1976,8 +1976,9 @@ CONFIG_M386
    - "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 @@ CONFIG_FB_CLGEN
   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 @@ CONFIG_NTFS_FS
   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 @@ CONFIG_AFFS_FS
   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 @@ CONFIG_AUTOFS_FS
   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 @@ CONFIG_EFS_FS
   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 @@ CONFIG_UFS_FS
 
   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 @@ CONFIG_PPDEV
 
   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
index aad85d9a920d9e113ec6e7fec638b1cdcb42e27c..4e3de5e83120a85016b01c65ac86799211a0a2a1 100644 (file)
@@ -45,9 +45,7 @@ Full support for startup video modes (modedb) will be integrated soon.
 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.
index cc9e3704bbf0f6ef9d5ad4c03ceaa2b4dc7eb5c1..aa075a45c854cac59a52ecda4423aca13766cfa3 100644 (file)
@@ -1,5 +1,5 @@
 Ioctl Numbers
-2 September 1999
+10 October 1999
 Michael Elizabeth Chastain
 <mec@shout.net>
 
@@ -114,6 +114,8 @@ Code        Seq#    Include File            Comments
 '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 @@ Code        Seq#    Include File            Comments
 '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
index 39e92a6a0cd4795949d21541a6b90b9cb4ec2892..9a3da9537c76cb2574522413a6d6c21286a45a02 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -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/)
@@ -126,6 +126,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
 endif
index d8e1082d8c33f7cc4013f09214c5c61afab959f5..f280e454165cc8203139255cec53b57cff91cf3e 100644 (file)
@@ -139,7 +139,7 @@ EXPORT_SYMBOL(alpha_fp_emul);
 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.
index 1f4fb07f589a4fd906d9da611b12f32168b97173..80094e18a26746c8a2a70b66f1f8ca9ebba480f7 100644 (file)
@@ -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>
 
        .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 @@ __strlen_user:
        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
@@ -61,4 +84,9 @@ $found:       negq    t1, t2          # clear all but least set bit
 $exception:
        ret
 
+       .align 3                # currently redundant
+$limit:
+       subq    a1, t2, v0
+       ret
+
        .end __strlen_user
index 8e9c288326e3383638acafbc5c41455d62446ca9..872822e6cadc03803e4c0dbbf9053a904072b8b1 100644 (file)
@@ -183,9 +183,8 @@ if [ "$CONFIG_VT" = "y" ]; then
   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
 
index bf0e611d8633800b87fa92e3525193f8da60bc58..15d916e3b5070490890a50aa721bd4f31b9592cf 100644 (file)
@@ -41,6 +41,9 @@ CONFIG_MODULES=y
 #
 # 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_GOANY=y
 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_IDE=y
 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_IDEPCI=y
 # 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
@@ -241,53 +242,6 @@ CONFIG_DUMMY=m
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
-# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_LANCE is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_NET_ISA is not set
-CONFIG_NET_EISA=y
-# CONFIG_PCNET32 is not set
-# CONFIG_APRICOT is not set
-# CONFIG_CS89x0 is not set
-# CONFIG_DE4X5 is not set
-# CONFIG_DEC_ELCP is not set
-# CONFIG_DGRS is not set
-CONFIG_EEXPRESS_PRO100=y
-# 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
-# CONFIG_NET_RADIO is not set
-
-#
-# Token ring devices
-#
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_HOSTESS_SV11 is not set
-# CONFIG_COSA is not set
-# CONFIG_SEALEVEL_4021 is not set
-# CONFIG_DLCI is not set
-# CONFIG_WAN_DRIVERS is not set
-# CONFIG_LAPBETHER is not set
-# CONFIG_X25_ASY is not set
-
-#
-# PCMCIA network devices
-#
-# CONFIG_PCMCIA_PCNET is not set
-# CONFIG_PCMCIA_3C589 is not set
-CONFIG_PCMCIA_RAYCS=y
-CONFIG_PCMCIA_NETCARD=y
 
 #
 # Amateur Radio support
@@ -327,7 +281,7 @@ CONFIG_UNIX98_PTY_COUNT=256
 # 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
index 3bafdfcfc50bba57a252f0e9387a1f7be230d8d7..a549946674eac1b8d3c30bfcd9ba2096ed1a6cd4 100644 (file)
@@ -643,33 +643,6 @@ static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
        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 @@ int apm_get_info(char *buf, char **start, off_t fpos, int length, int dummy)
        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 @@ static int __init apm_init(void)
 
        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 @@ static int __init apm_init(void)
                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 @@ static int __init apm_init(void)
 
        if (apm_disabled) {
                printk(KERN_NOTICE "apm: disabled on user request.\n");
-               return;
+               return -1;
        }
 
 #ifdef CONFIG_SMP
@@ -1571,6 +1543,7 @@ static int __init apm_init(void)
        misc_register(&apm_device);
 
        kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
+       return 0;
 }
 
 module_init(apm_init)
index 5f5a6d50b5734c07918310a54f4787f7316c7bf3..043132b8e9f55f5112064378fac269e0d8170216 100644 (file)
@@ -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(__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 @@ EXPORT_SYMBOL(mca_is_adapter_used);
 #ifdef CONFIG_VT
 EXPORT_SYMBOL(screen_info);
 #endif
+
index a6f8dff0993b2cfbe635de06a22e4514a84de1a2..3f7bef4aa5d6019a59a88b2e12a562b11fc27719 100644 (file)
@@ -9,4 +9,8 @@ L_TARGET = lib.a
 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 --git a/arch/i386/lib/mmx.c b/arch/i386/lib/mmx.c
new file mode 100644 (file)
index 0000000..5257aeb
--- /dev/null
@@ -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);
+}
index f43be511f34a67848ac4a9544d30e2d12def883b..21d8fdf62f982791f6eb4a59cfae81597527b5f3 100644 (file)
@@ -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 @@ __generic_copy_from_user(void *to, const void *from, unsigned long n)
        return n;
 }
 
+#endif
 
 /*
  * Copy a null terminated string from userspace.
@@ -117,26 +149,31 @@ __clear_user(void *to, unsigned long n)
 /*
  * 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;
 }
index 043af83045c0bc6c4b71a822a5c6e9d29fa90e92..48874a0f0f9cb4d22ffa7dd2916b9456c42d3db7 100644 (file)
@@ -22,8 +22,8 @@ mainmenu_option next_comment
 comment 'Loadable module support'
 bool 'Enable loadable module support' CONFIG_MODULES
 if [ "$CONFIG_MODULES" = "y" ]; then
-  bool 'Set version information on all 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 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
 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 @@ tristate 'Network block device support' CONFIG_BLK_DEV_NBD
 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
 
index 5ee6df467f2cd407dcbbea7723ba729731a96c33..050c6e0b38904eb0866fd09d0516518896cee5d9 100644 (file)
@@ -152,7 +152,7 @@ static void timod_wake_socket(unsigned int fd)
        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");
 }
 
index 6ed6cf6a33892c912edf8e26b4638e8ca3512fbf..be2d2432ff2054f4c19355156ba961c68452c20e 100644 (file)
@@ -5,11 +5,11 @@ mainmenu_option next_comment
 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
index 68d4f920bf51aa528a502657f07d2dd4ac55efca..28030bc32d1f65d142575c2bf42227f76d6e5537 100644 (file)
@@ -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
 
index 7c00c4dd233126b1f19d8d92533e8ba9d9b3b9bf..c23b8d094b4c0292d885b5a0d6d697bb60acbe4e 100644 (file)
@@ -6,198 +6,200 @@ comment 'Block devices'
 
 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
+   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_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
-          bool '   Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
+      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
-    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
+      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
-    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
+      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
-      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
+      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
-    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 '  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
-fi
-tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA
+   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
 
 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 @@ tristate 'XT hard disk support' CONFIG_BLK_DEV_XD
 # 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 @@ if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
      "$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
index abc2242dc1007ae5b24ddb71c278d58be9388614..8519318d93f01469188b70c06b1f9e23118fee9e 100644 (file)
@@ -20,7 +20,7 @@ ALL_SUB_DIRS := $(SUB_DIRS) paride
 
 
 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 @@ ifeq ($(CONFIG_BLK_DEV_IDE),y)
 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 @@ include $(TOPDIR)/Rules.make
 
 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 --git a/drivers/block/cmos-probe.c b/drivers/block/cmos-probe.c
deleted file mode 100644 (file)
index f0147d5..0000000
+++ /dev/null
@@ -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
-}
index 1b2be20dd6481768f8e0f07ac72d167186984e64..579fbc13ae178647c25d58b07bb575539323996b 100644 (file)
@@ -212,6 +212,7 @@ struct file_operations ida_fops  = {
  */
 static void ida_procinit(int i)
 {
+#ifdef CONFIG_PROC_FS
        struct proc_dir_entry *pd;
 
        if (proc_array == NULL) {
@@ -224,6 +225,7 @@ static void ida_procinit(int i)
        if (!pd) return;
        pd->read_proc = ida_proc_get_info;
        pd->data = hba[i];
+#endif 
 }
 
 /*
@@ -356,7 +358,9 @@ void cleanup_module(void)
                        }
                }
        }
+#ifdef CONFIG_PROC_FS
        remove_proc_entry("array", &proc_root);
+#endif
        kfree(ida);
        kfree(ida_sizes);
        kfree(ida_hardsizes);
index 2ea7d5b51d003e2d32773a83d9a769c173917e01..d2941a1ab7a8cea13ba21161eed934ec0897f03c 100644 (file)
@@ -94,42 +94,40 @@ static inline void idedisk_output_data (ide_drive_t *drive, void *buffer, unsign
  *
  * 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 @@ static int idedisk_media_change (ide_drive_t *drive)
 }
 
 /*
- * 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 @@ static void idedisk_add_settings(ide_drive_t *drive)
        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 int idedisk_cleanup (ide_drive_t *drive)
 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 @@ static void idedisk_setup (ide_drive_t *drive)
                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 */
@@ -791,19 +760,6 @@ static void idedisk_setup (ide_drive_t *drive)
        }
        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) {
 #ifdef CONFIG_IDEDISK_MULTI_MODE
index cd631c621728bebd7b0e152e0abaa57e8c6e4c33..d3c65751677080b2057a664c62cde8e0d8a39327 100644 (file)
@@ -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 @@ int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
        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 @@ const char *bad_dma_drives[] = {"WDC AC11000H",
                                "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 @@ int check_drive_lists (ide_drive_t *drive, int good_bad)
 {
        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 @@ int check_drive_lists (ide_drive_t *drive, int good_bad)
                        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 @@ int check_drive_lists (ide_drive_t *drive, int good_bad)
                        }
                }
        }
-#endif /* IDEDMA_NEW_DRIVE_LISTINGS */
+#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
        return 0;
 }
 
index 66b71b3a23d02f18c326c263004e3e09e21fa391..f1c8baef8bc4346988fb7226b73b68b8e8139cf0 100644 (file)
@@ -1498,7 +1498,7 @@ static void idefloppy_add_settings(ide_drive_t *drive)
        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 --git a/drivers/block/ide-geometry.c b/drivers/block/ide-geometry.c
new file mode 100644 (file)
index 0000000..974fb24
--- /dev/null
@@ -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;
+}
index 90fbf9cbc9cad6efbc3a0b024b1638f9b51cc868..1ad5b3b969ac95f27a910ed74bd01d6ffc86f967 100644 (file)
@@ -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 @@ static int pmac_ide_build_dmatable(ide_drive_t *drive, int wr);
 #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 @@ void __init pmac_ide_probe(void)
        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 @@ int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
 #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;
+
+       /* 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;
+       }
+}
 
-       switch (code) {
-       case PBOOK_SLEEP:
-               /* do anything here?? */
+/* 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 */
index 74b3f71c6173e8bea5df35a8b7806e6c2cf437ce..d2cb4b34b4e1da3fc58748a2cbcccdf567d31db6 100644 (file)
@@ -526,7 +526,7 @@ void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int t
  * 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 @@ static inline void start_request (ide_drive_t *drive)
                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 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
  * 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 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
        }
        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 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                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 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                                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 @@ static int __init match_parm (char *s, const char *keywords[], int vals[], int m
  * "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 @@ void __init ide_setup (char *s)
        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 @@ void __init ide_setup (char *s)
                        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];
@@ -3022,113 +3032,6 @@ done:
        printk("\n");
 }
 
-/*
- * 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
  */
@@ -3524,6 +3427,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
  */
index 5bbd0c3e77dc572b12e4a4b6044f38dd4d2e8ed3..aeffcc9ba93908588b1af8cec86203c31e1ddf1c 100644 (file)
@@ -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 @@ unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
                (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 @@ unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
                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;
 }
 
index eaf1a8357a94f58ab0f062f8dafe1b7278d03ef9..95c25b519047d4f15dbba77e7a8b83e83dacc049 100644 (file)
@@ -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
index 4620a3d60eac3cd9b330466bee16e9e579b31b80..42c2642f669800a1388f05fa4016cdaa96fd4eea 100644 (file)
@@ -144,7 +144,7 @@ busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons)
                wake_up(&mse->wait);
 
                if (mse->fasyncptr)
-                       kill_fasync(mse->fasyncptr, SIGIO);
+                       kill_fasync(mse->fasyncptr, SIGIO, POLL_IN);
        }
 }
 
@@ -450,13 +450,10 @@ bus_mouse_init(void)
 #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
index d0503cdcb9f2a87ae9a2dd1db1be01316eaff72e..f452237ab979b73a7c8564a986b396c023f10032 100644 (file)
@@ -681,7 +681,7 @@ int vc_resize(unsigned int lines, unsigned int cols,
                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;
index 97b237ca3628fcb37f7fca38d36658d0a04ba829..38010e29b63e9846b027b845a9bae0a4336a5853 100644 (file)
@@ -469,7 +469,7 @@ static void dn_keyb_process_mouse_event(unsigned char mouse_data) {
                        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); */
index 12ab4d6283d9221deb3093c4b53b21aeabefa0f4..55deade81c98ea7ebc171d1d5c1950f461aa0b01 100644 (file)
@@ -197,7 +197,7 @@ int drm_write_string(drm_device_t *dev, const char *s)
                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;
index 2f837be5b7b483de8d7a17e10a3bfced2cb64c3f..59004dcf294e91f1b2dbee57a9cafc013826d113 100644 (file)
@@ -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 @@ choice 'Floppy tape controllers'                            \
         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
index a41eaac33d98d20ddd2ca560426701e70e1560ed..810decada90f0ffe6ba4a528e32a71e30e9d0d2f 100644 (file)
@@ -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
index 85167d74a156404c215c6ae3a40c5db2c4e82742..5fa95dff2412a146b9483ec7a22d68a2681b08d0 100644 (file)
@@ -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 @@ struct pt_regs * kbd_pt_regs;
 
 #ifdef CONFIG_MAGIC_SYSRQ
 static int sysrq_pressed;
-int sysrq_enabled = 1;
 #endif
 
 /*
index 02f3873a0522163f59fa01d2f5479567267f4252..18ab3f269083e51a095c63fd60c208de1b455ea4 100644 (file)
@@ -258,6 +258,12 @@ int __init misc_init(void)
 #endif
 #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",
index 7251a4e05098bc6349ef45b4300ccfe65097ceb6..0717fa4182641a4e624a9975d43e0b91e967b6b4 100644 (file)
@@ -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)
  *
  * 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>
 #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>
 #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 @@ typedef size_t            rw_count_t;
 /*
  * 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 @@ static struct n_hdlc *n_hdlc_alloc (void);
 
 #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 @@ static void n_hdlc_tty_close(struct tty_struct *tty)
                        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 @@ static int n_hdlc_tty_open (struct tty_struct *tty)
        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 @@ static int n_hdlc_tty_open (struct tty_struct *tty)
                
        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 @@ static void n_hdlc_tty_receive(struct tty_struct *tty,
                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 @@ static void n_hdlc_tty_receive(struct tty_struct *tty,
        /* 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 @@ static rw_ret_t n_hdlc_tty_read (struct tty_struct *tty,
                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 @@ static rw_ret_t n_hdlc_tty_write (struct tty_struct *tty, struct file *file,
                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 @@ static rw_ret_t n_hdlc_tty_write (struct tty_struct *tty, struct file *file,
                /* 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 @@ static rw_ret_t n_hdlc_tty_write (struct tty_struct *tty, struct file *file,
                        
                        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 @@ static struct n_hdlc *n_hdlc_alloc (void)
        
        /* 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 @@ int init_module(void)
        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 */
        
index d95cda30edd4ed390a3b7ed392facb35cb0801d0..9027aa67ee010cda3d8c1889910b6c42b161a0c4 100644 (file)
@@ -604,7 +604,7 @@ send_signal:
                        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 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
 
        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 @@ static inline int copy_from_read_buf(struct tty_struct *tty,
        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);
index 0c00dcfa5be9e7d232dbdede8ced9e9385419e92..7e4518e158657e064a02e4918f04e98ad95a9a45 100644 (file)
@@ -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 struct pc110pad_params current_params;
 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 @@ static void wake_readers(void)
 {
        wake_up_interruptible(&queue);
        if(asyncptr)
-               kill_fasync(asyncptr, SIGIO);
+               kill_fasync(asyncptr, SIGIO, POLL_IN);
 }
 
 
@@ -503,10 +505,13 @@ static int close_pad(struct inode * inode, struct file * file)
  */
 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 @@ static int open_pad(struct inode * inode, struct file * file)
        synthesize_tap=0;
        del_timer(&bounce_timer);
        del_timer(&tap_timer);
-       sti();
+       restore_flags(flags);
 
        return 0;
 }
@@ -556,14 +561,19 @@ static ssize_t read_pad(struct file * file, char * buffer, size_t count, loff_t
 {
        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 @@ static void pc110pad_unload(void)
 
 int init_module(void)
 {
+       init_MUTEX(&read_lock);
        return pc110pad_init();
 }
 
index b4b6069744f70ef49af7e95d6aefc746bd5a910a..e17d44b1652a52c35291b4c3e7aa3bcc9648f615 100644 (file)
@@ -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>
 
 #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 @@ unsigned char pckbd_sysrq_xlate[128] =
        "\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 @@ static unsigned char mouse_reply_expected = 0;
 #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 @@ static inline void handle_mouse_event(unsigned char scancode)
                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 inline void handle_mouse_event(unsigned char scancode)
  */
 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 @@ static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        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 @@ static int send_data(unsigned char data)
                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 @@ __setup("kbd-reset", kbd_reset_setup);
 #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 @@ static void __init kbd_clear_input(void)
        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 @@ static int __init kbd_wait_for_input(void)
        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 @@ static int __init kbd_wait_for_input(void)
        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 @@ static void kbd_write_cmd(int cmd)
 
        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 @@ static char * __init initialize_kbd(void)
         * 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 @@ static char * __init initialize_kbd(void)
         * 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 @@ static char * __init initialize_kbd(void)
         * 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 @@ static char * __init initialize_kbd(void)
         * 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 @@ static char * __init initialize_kbd(void)
                        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 @@ static char * __init initialize_kbd(void)
 
 void __init pckbd_init_hw(void)
 {
+       kbd_request_region();
+
        /* Flush any pending input. */
        kbd_clear_input();
 
@@ -707,7 +725,7 @@ void __init pckbd_init_hw(void)
 #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 @@ static int __init detect_auxiliary_port(void)
         * 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 @@ static void aux_write_dev(int val)
 
        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 @@ static void aux_write_ack(int val)
 
        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 @@ static int release_aux(struct inode * inode, struct file * file)
        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 @@ static int open_aux(struct inode * inode, struct file * file)
                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 @@ static int __init psaux_init(void)
        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 --git a/drivers/char/pc_keyb.h b/drivers/char/pc_keyb.h
deleted file mode 100644 (file)
index 245df62..0000000
+++ /dev/null
@@ -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];
-};
index 40f013556c5f3e6eb9af0db854087f46fe386a1d..f466f11e690a824f7d04b6ff05f452b9ed159d39 100644 (file)
@@ -75,7 +75,7 @@ struct ppdev_frob_struct {
 #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)
 
 
index 7d99d5b6883158708f94111bb5cf2296b4f862f2..17711734f336bca6f586e4e38cf9bcfd5c63b69e 100644 (file)
@@ -661,25 +661,31 @@ static inline ssize_t do_tty_write(
        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 tty_unregister_driver(struct tty_driver *driver)
 {
        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 @@ int tty_unregister_driver(struct tty_driver *driver)
        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;
 }
index 8328f32bdef8a7d55f16891e5f6c175d7d96f988..a11ab5b3e447ae3c6cb18069dbba827c40b9199c 100644 (file)
@@ -6,22 +6,22 @@ comment 'Fibre Channel support'
 
 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
index 1902e507065be6bfe5b1073df2106b960859fff3..3e07e6caee5e2041904164239231ee21e1350503 100644 (file)
@@ -7,12 +7,12 @@ comment 'ARCnet devices'
 
 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 @@ endmenu
 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 @@ comment 'Ethernet (10 or 100Mbit)'
 
 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 @@ fi
 #
 
 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
+   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
 
-mainmenu_option next_comment
-comment 'Token ring devices'
-
-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
+   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
-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
index e1abc4c0e3ae54a21e642e5a880bd17e7f44c183..4589d0ee31bde1c8b02482b8d33ab16278c3b061 100644 (file)
@@ -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_BUILTIN :=
 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 @@ ifeq ($(CONFIG_SEEQ8005),y)
 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 @@ else
   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 @@ else
   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 @@ else
   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 @@ else
   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 @@ else
   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 @@ else
   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 @@ else
   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 @@ else
   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
@@ -1225,11 +1088,5 @@ 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)
-
 rcpci.o: rcpci45.o rclanmtl.o
        $(LD) -r -o rcpci.o rcpci45.o rclanmtl.o
index 27c431e14804327efd8ac7a536d94472ffd7f0d2..a10d519f58138e92575b17bd58a3ee0719f0f5bd 100644 (file)
@@ -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 pamsnet_probe(struct net_device *);
 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 bagetlance_probe(struct net_device *);
 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 @@ extern int rr_hippi_probe(struct net_device *);
 /* 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 @@ struct devprobe pci_probes[] __initdata = {
 #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 @@ struct devprobe mca_probes[] __initdata = {
 
 /*
  * 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 */
@@ -457,6 +469,9 @@ struct devprobe ppc_probes[] __initdata = {
 #endif
 #ifdef CONFIG_BMAC
        {bmac_probe, 0},
+#endif
+#ifdef CONFIG_NCR885E
+       {ncr885e_probe, 0},
 #endif
        {NULL, 0},
 };
@@ -781,6 +796,7 @@ struct net_device eql_dev = {
 /* 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 @@ static struct net_device tr0_dev = {
 #   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
index d8bddd665b3033c9e8f4ed471d99fb02ea96d959..353b44dc8ef619e66ebcc4f7d811ecbb46b30377 100644 (file)
@@ -474,10 +474,12 @@ arcnet_open(struct net_device *dev)
   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 --git a/drivers/net/cosa.c b/drivers/net/cosa.c
deleted file mode 100644 (file)
index 863cd4b..0000000
+++ /dev/null
@@ -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
- */
-\f
-/* ---------- 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
-
-\f
-/* ---------- 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++;
-}
-
-\f
-/*---------- 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;
-}
-
-\f
-/*---------- 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
-
-\f
-/* ---------- 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);
-}
-
-\f
-/*---------- 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;
-}
-
-\f
-/* ---------- 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;
-}
-
-\f
-/* ---------- 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;
-}
-
-\f
-/* ---------- 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
-}
-
-\f
-/* ---------- 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 --git a/drivers/net/cosa.h b/drivers/net/cosa.h
deleted file mode 100644 (file)
index 7b5a390..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/cycx_drv.c b/drivers/net/cycx_drv.c
deleted file mode 100644 (file)
index 1629bdc..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/cycx_main.c b/drivers/net/cycx_main.c
deleted file mode 100644 (file)
index 52a2abd..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/cycx_x25.c b/drivers/net/cycx_x25.c
deleted file mode 100644 (file)
index 7e79943..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/dlci.c b/drivers/net/dlci.c
deleted file mode 100644 (file)
index a8c52f0..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/hostess_sv11.c b/drivers/net/hostess_sv11.c
deleted file mode 100644 (file)
index 7b24901..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/ibmtr.c b/drivers/net/ibmtr.c
deleted file mode 100644 (file)
index cf2514f..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/ibmtr.h b/drivers/net/ibmtr.h
deleted file mode 100644 (file)
index f51174c..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/lapbether.c b/drivers/net/lapbether.c
deleted file mode 100644 (file)
index a4564af..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/ncr885_debug.h b/drivers/net/ncr885_debug.h
new file mode 100644 (file)
index 0000000..bd1fead
--- /dev/null
@@ -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 --git a/drivers/net/ncr885e.c b/drivers/net/ncr885e.c
new file mode 100644 (file)
index 0000000..277f925
--- /dev/null
@@ -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 --git a/drivers/net/ncr885e.h b/drivers/net/ncr885e.h
new file mode 100644 (file)
index 0000000..bbcc82e
--- /dev/null
@@ -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 --git a/drivers/net/olympic.c b/drivers/net/olympic.c
deleted file mode 100644 (file)
index 460480c..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/olympic.h b/drivers/net/olympic.h
deleted file mode 100644 (file)
index d5a0642..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/sdla.c b/drivers/net/sdla.c
deleted file mode 100644 (file)
index 9b51523..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/sdla_fr.c b/drivers/net/sdla_fr.c
deleted file mode 100644 (file)
index 6b2201a..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/sdla_ppp.c b/drivers/net/sdla_ppp.c
deleted file mode 100644 (file)
index d35ac7c..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/sdla_x25.c b/drivers/net/sdla_x25.c
deleted file mode 100644 (file)
index 270c5a5..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/sdladrv.c b/drivers/net/sdladrv.c
deleted file mode 100644 (file)
index 7182dff..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/sdlamain.c b/drivers/net/sdlamain.c
deleted file mode 100644 (file)
index ca98eef..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/sealevel.c b/drivers/net/sealevel.c
deleted file mode 100644 (file)
index 1dc1467..0000000
+++ /dev/null
@@ -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
-
index 4f684f5a152628e8c5480bb842c196bbdc58a7f4..72dcedf3fb1facb86863a636153bbdc2547b4ce2 100644 (file)
@@ -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)
index c112489584a067c88e58fda1f843b4a83d440f06..cdee2d6e68863216b17eb1c89718ce8021402887 100644 (file)
@@ -71,6 +71,7 @@ History:
 #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 --git a/drivers/net/sktr.c b/drivers/net/sktr.c
deleted file mode 100644 (file)
index f9b877f..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/sktr.h b/drivers/net/sktr.h
deleted file mode 100644 (file)
index 4c2a3bf..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/sktr_firmware.h b/drivers/net/sktr_firmware.h
deleted file mode 100644 (file)
index 25dd973..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/syncppp.c b/drivers/net/syncppp.c
deleted file mode 100644 (file)
index eee3fce..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/syncppp.h b/drivers/net/syncppp.h
deleted file mode 100644 (file)
index c03c720..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/tokenring/Config.in b/drivers/net/tokenring/Config.in
new file mode 100644 (file)
index 0000000..8b3065c
--- /dev/null
@@ -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 --git a/drivers/net/tokenring/Makefile b/drivers/net/tokenring/Makefile
new file mode 100644 (file)
index 0000000..038c58b
--- /dev/null
@@ -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 --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
new file mode 100644 (file)
index 0000000..85cdfb7
--- /dev/null
@@ -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 --git a/drivers/net/tokenring/ibmtr.h b/drivers/net/tokenring/ibmtr.h
new file mode 100644 (file)
index 0000000..3f3fa6a
--- /dev/null
@@ -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 --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
new file mode 100644 (file)
index 0000000..460480c
--- /dev/null
@@ -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 --git a/drivers/net/tokenring/olympic.h b/drivers/net/tokenring/olympic.h
new file mode 100644 (file)
index 0000000..d5a0642
--- /dev/null
@@ -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 --git a/drivers/net/tokenring/sktr.c b/drivers/net/tokenring/sktr.c
new file mode 100644 (file)
index 0000000..81b2df4
--- /dev/null
@@ -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 --git a/drivers/net/tokenring/sktr.h b/drivers/net/tokenring/sktr.h
new file mode 100644 (file)
index 0000000..90b5c38
--- /dev/null
@@ -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 --git a/drivers/net/tokenring/sktr_firmware.h b/drivers/net/tokenring/sktr_firmware.h
new file mode 100644 (file)
index 0000000..25dd973
--- /dev/null
@@ -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 --git a/drivers/net/wan/Config.in b/drivers/net/wan/Config.in
new file mode 100644 (file)
index 0000000..503854a
--- /dev/null
@@ -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 --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
new file mode 100644 (file)
index 0000000..73060f5
--- /dev/null
@@ -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 --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
new file mode 100644 (file)
index 0000000..863cd4b
--- /dev/null
@@ -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
+ */
+\f
+/* ---------- 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
+
+\f
+/* ---------- 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++;
+}
+
+\f
+/*---------- 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;
+}
+
+\f
+/*---------- 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
+
+\f
+/* ---------- 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);
+}
+
+\f
+/*---------- 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;
+}
+
+\f
+/* ---------- 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;
+}
+
+\f
+/* ---------- 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;
+}
+
+\f
+/* ---------- 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
+}
+
+\f
+/* ---------- 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 --git a/drivers/net/wan/cosa.h b/drivers/net/wan/cosa.h
new file mode 100644 (file)
index 0000000..7b5a390
--- /dev/null
@@ -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 --git a/drivers/net/wan/cycx_drv.c b/drivers/net/wan/cycx_drv.c
new file mode 100644 (file)
index 0000000..1629bdc
--- /dev/null
@@ -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 --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c
new file mode 100644 (file)
index 0000000..52a2abd
--- /dev/null
@@ -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 --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
new file mode 100644 (file)
index 0000000..7e79943
--- /dev/null
@@ -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 --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
new file mode 100644 (file)
index 0000000..a8c52f0
--- /dev/null
@@ -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 --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c
new file mode 100644 (file)
index 0000000..ba4e49c
--- /dev/null
@@ -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 --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
new file mode 100644 (file)
index 0000000..a4564af
--- /dev/null
@@ -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 --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
new file mode 100644 (file)
index 0000000..9d5fba0
--- /dev/null
@@ -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 --git a/drivers/net/wan/sbni.h b/drivers/net/wan/sbni.h
new file mode 100644 (file)
index 0000000..2e34d8d
--- /dev/null
@@ -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 --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
new file mode 100644 (file)
index 0000000..9b51523
--- /dev/null
@@ -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 --git a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c
new file mode 100644 (file)
index 0000000..6b2201a
--- /dev/null
@@ -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 --git a/drivers/net/wan/sdla_ppp.c b/drivers/net/wan/sdla_ppp.c
new file mode 100644 (file)
index 0000000..d35ac7c
--- /dev/null
@@ -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 --git a/drivers/net/wan/sdla_x25.c b/drivers/net/wan/sdla_x25.c
new file mode 100644 (file)
index 0000000..270c5a5
--- /dev/null
@@ -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 --git a/drivers/net/wan/sdladrv.c b/drivers/net/wan/sdladrv.c
new file mode 100644 (file)
index 0000000..5e1f6b9
--- /dev/null
@@ -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 --git a/drivers/net/wan/sdlamain.c b/drivers/net/wan/sdlamain.c
new file mode 100644 (file)
index 0000000..23b811f
--- /dev/null
@@ -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 --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c
new file mode 100644 (file)
index 0000000..5cbbff8
--- /dev/null
@@ -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 --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c
new file mode 100644 (file)
index 0000000..eee3fce
--- /dev/null
@@ -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 --git a/drivers/net/wan/syncppp.h b/drivers/net/wan/syncppp.h
new file mode 100644 (file)
index 0000000..c03c720
--- /dev/null
@@ -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 --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
new file mode 100644 (file)
index 0000000..49d041a
--- /dev/null
@@ -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 --git a/drivers/net/wan/x25_asy.h b/drivers/net/wan/x25_asy.h
new file mode 100644 (file)
index 0000000..5abeceb
--- /dev/null
@@ -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 --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
new file mode 100644 (file)
index 0000000..a802170
--- /dev/null
@@ -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 --git a/drivers/net/wan/z85230.h b/drivers/net/wan/z85230.h
new file mode 100644 (file)
index 0000000..0b4b487
--- /dev/null
@@ -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 --git a/drivers/net/x25_asy.c b/drivers/net/x25_asy.c
deleted file mode 100644 (file)
index 49d041a..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/x25_asy.h b/drivers/net/x25_asy.h
deleted file mode 100644 (file)
index 5abeceb..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/z85230.c b/drivers/net/z85230.c
deleted file mode 100644 (file)
index a802170..0000000
+++ /dev/null
@@ -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 --git a/drivers/net/z85230.h b/drivers/net/z85230.h
deleted file mode 100644 (file)
index 0b4b487..0000000
+++ /dev/null
@@ -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) */
index a350c45266f042c5c22fe0f641d5c0666fb63338..de0fa6cfa20127089413c714880bf695c514f9b8 100644 (file)
@@ -6,6 +6,6 @@ comment 'Plug and Play configuration'
 
 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
index dc34fe4cd24540b8d10c15c1d875df1cedb7dc30..3857c487d51e416538406f3d3ddc16e0697a18a8 100644 (file)
@@ -764,7 +764,7 @@ void pcimouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        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);
 }
 
index e8e6a168c5fed024f27e917b8e10d21f4f993d65..2b3a99604d5ed374f1c4eeacb673debd79011bdf 100644 (file)
@@ -1273,7 +1273,7 @@ push_kbd (int scan)
                kbd_head = next;
        }
        if (kb_fasync)
-               kill_fasync (kb_fasync, SIGIO);
+               kill_fasync (kb_fasync, SIGIO, POLL_IN);
        wake_up_interruptible (&kbd_wait);
 }
 
index 77fe2ee77ca90c57c12f4e12c8d340ee2196c934..c3d8462e68183219c9e9dafbe60b213ae7a5b260 100644 (file)
@@ -137,7 +137,7 @@ push_char (char c)
        }
        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 @@ sun_mouse_inbyte(unsigned char byte)
                 */
                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;
index b11de29ebd0a61d3471947467dca07dbc38c69db..ccf2268d8a070dc42f735f5273c4e4fe116d2405 100644 (file)
@@ -92,7 +92,7 @@ static struct miscdevice uctrl_dev = {
 #ifdef MODULE
 int init_module(void)
 #else
-__initfunc(int uctrl_init(void))
+int __init uctrl_init(void)
 #endif
 {
        struct uctrl_driver *driver = &drv;
index 74c3c9d222786bc693487b66db373f32a9125116..4a2258cb53b1ad5a730af5726d26d469de88f692 100644 (file)
@@ -815,7 +815,7 @@ static void sg_command_done(Scsi_Cmnd * SCpnt)
 /* 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)
index 5f4ece09f3eaec09c4f3f3614398bc96e0ea5ed4..59518b1536a8373eb14559d013f49fe20b4b2997 100644 (file)
@@ -118,7 +118,7 @@ shmiq_push_event (struct shmqevent *e)
        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);
 }
 
index 7d78404ee1573c729c6f47043375a9026435bd5e..291f424dcbaf3fd2bc0817621b49bb381eaf79a1 100644 (file)
@@ -769,7 +769,7 @@ static int usbin_retire_desc(struct usbin *u, struct usb_isoc_desc *id)
 
 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 @@ static int usbin_completed(int status, void *__buffer, int rval, void *dev_id)
         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 @@ static int usbin_completed(int status, void *__buffer, int rval, void *dev_id)
                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_retire_desc(struct usbin *u, struct usb_isoc_desc *id)
 
 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 @@ static int usbin_sync_completed(int status, void *__buffer, int rval, void *dev_
         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 @@ static int usbin_sync_completed(int status, void *__buffer, int rval, void *dev_
                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 @@ static void usbin_start(struct usb_audiodev *as)
        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 @@ static void usbout_stop(struct usb_audiodev *as)
         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_retire_desc(struct usbout *u, struct usb_isoc_desc *id)
 
 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 @@ static int usbout_completed(int status, void *__buffer, int rval, void *dev_id)
        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 @@ static int usbout_completed(int status, void *__buffer, int rval, void *dev_id)
                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_retire_desc(struct usbout *u, struct usb_isoc_desc *id)
 
 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 @@ static int usbout_sync_completed(int status, void *__buffer, int rval, void *dev
        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 @@ static int usbout_sync_completed(int status, void *__buffer, int rval, void *dev
                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 @@ static void usbout_start(struct usb_audiodev *as)
        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 @@ static int set_format_in(struct usb_audiodev *as)
        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 @@ static int set_format_in(struct usb_audiodev *as)
        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 @@ static int set_format_in(struct usb_audiodev *as)
        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 @@ static int set_format_out(struct usb_audiodev *as)
        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 @@ static int set_format_out(struct usb_audiodev *as)
        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 @@ static int set_format_out(struct usb_audiodev *as)
        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 @@ static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value)
                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 @@ static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value)
                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 @@ static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value)
                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 @@ static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value)
         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 @@ static int usb_audio_ioctl_mixdev(struct inode *inode, struct file *file, unsign
                         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 @@ static unsigned int getvolchannel(struct consmixstate *state)
        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 @@ static void prepmixch(struct consmixstate *state)
        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 @@ static void prepmixch(struct consmixstate *state)
                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 @@ static void prepmixch(struct consmixstate *state)
                /* 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 @@ static void prepmixch(struct consmixstate *state)
                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 @@ static void prepmixch(struct consmixstate *state)
        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 @@ static void prepmixch(struct consmixstate *state)
                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 @@ extern inline int checkmixbmap(unsigned char *bmap, unsigned char flg, unsigned
        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 @@ static void usb_audio_mixerunit(struct consmixstate *state, unsigned char *mixer
        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 @@ static void usb_audio_mixerunit(struct consmixstate *state, unsigned char *mixer
        }
        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 @@ static void usb_audio_mixerunit(struct consmixstate *state, unsigned char *mixer
                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 @@ static void usb_audio_mixerunit(struct consmixstate *state, unsigned char *mixer
                        }
                }
                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_featureunit(struct consmixstate *state, unsigned char *ftr
 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 @@ static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unit
                        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 @@ static int usb_audio_probe(struct usb_device *dev)
        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);
index 4384f07d3383dfd3ef7542006a04f2dc4953f995..da5ee515ef55380120b787ce7af099d5faa7581a 100644 (file)
@@ -120,7 +120,7 @@ static int mouse_irq(int state, void *__buffer, int len, void *dev_id)
 
        wake_up_interruptible(&mouse->wait);
        if (mouse->fasync)
-               kill_fasync(mouse->fasync, SIGIO);
+               kill_fasync(mouse->fasync, SIGIO, POLL_IN);
 
        return 1;
 }
index 9fb8d39050ac36b1123b784979cdb15c052277cc..a8e223f6bf048708ec648319a786679fb6d64664 100644 (file)
 # 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
+   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
-  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
+   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
-      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
+   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
-      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
+   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
-      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
+      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
-  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
+   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
-  fi
-  tristate 'Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL
-
-  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
+   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_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
+   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
-    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
+      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
-    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
+      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
-    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
+      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
-    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
+      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
-    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
+      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
-    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
+      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
-    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
+      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
-    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
+      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
-    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
+      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
-    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
+      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
-      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
+   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
-      if [ "$CONFIG_AMIGA" = "y" ]; then
-        define_bool CONFIG_FONT_PEARL_8x8 y
+   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_ARM" = "y" -a "$CONFIG_ARCH_ACORN" = "y" ]; then
-        define_bool CONFIG_FONT_ACORN_8x8 y
-      fi
-    fi
-  fi
+   fi
 fi
+
+endmenu
index 15050f347035d8d02276e87c4e7becdee54793bc..e4f8cefe1c8094c1e9d7844358163663cb6d16f2 100644 (file)
@@ -150,13 +150,17 @@ else
 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)
 L_OBJS += macfb.o
 endif
index 47531e1bb997210e7cd46b2039251aceb1f0100c..fb578ffdbc8fe4499928b3947180bb9a0f916b8b 100644 (file)
@@ -1736,6 +1736,7 @@ default_chipset:
        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))
index e7b6620adae79f9e87508963cce42d4ae41a67f9..2e5900f349054ac32b2ccd128a258cd8d8696a14 100644 (file)
 
 #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 */
 #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 */
index f12fec6e11d0428ed2dbb7c08e81c9be103d5e8d..edba704a3f7b1f33cc33624b9d5274afc674b0f5 100644 (file)
@@ -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>
 
 
 #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 @@ struct fb_info_aty {
     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_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
 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 int default_mclk __initdata = 0;
 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 const char *aty_ct_ram[8] __initdata = {
 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 @@ static u8 aty_ld_pll(int offset, const struct fb_info_aty *info)
     return res;
 }
 
-#if defined(CONFIG_PPC)
+#ifdef CONFIG_PMAC
 
     /*
      *  Apple monitor sense
@@ -831,7 +838,7 @@ static int read_aty_sense(const struct fb_info_aty *info)
     return sense;
 }
 
-#endif /* defined(CONFIG_PPC) */
+#endif /* CONFIG_PMAC */
 
 /* ------------------------------------------------------------------------- */
 
@@ -903,17 +910,19 @@ aty_set_cursor_shape(struct fb_info_aty *fb)
                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 @@ static int __init aty_init(struct fb_info_aty *info, const char *name)
     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 @@ static int __init aty_init(struct fb_info_aty *info, const char *name)
     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 @@ static int __init aty_init(struct fb_info_aty *info, const char *name)
        }
        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 @@ static int __init aty_init(struct fb_info_aty *info, const char *name)
     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 @@ void __init atyfb_of_init(struct device_node *dp)
     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 @@ void __init atyfb_of_init(struct device_node *dp)
        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 @@ int __init atyfb_setup(char *options)
                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 @@ static void atyfbcon_blank(int blank, struct fb_info *fb)
     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 @@ static void atyfbcon_blank(int blank, struct fb_info *fb)
        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
@@ -4736,6 +4768,98 @@ static struct display_switch fbcon_aty32 = {
 };
 #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)
 {
index 79df3aa98b5e53255acfc1a1031c26940e21c45c..dd20b767e203478b8ccbab404e9d63028801d08b 100644 (file)
@@ -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 @@ struct fb_info_chips {
 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 @@ static int chipsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
        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 @@ static void __init init_chips(struct fb_info_chips *p)
 
 #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 @@ void __init chips_of_init(struct device_node *dp)
  * 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;
-
-               switch (code) {
-               case PBOOK_SLEEP:
+               int i;
+
+               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 @@ chips_sleep_notify(struct notifier_block *this, unsigned long code, void *x)
                                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 */
index 6893afbefc122e77cc1b29ce51f184887b9217cd..cd269e86441c49ce3fd69c6cd018255884e4093c 100644 (file)
 #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 @@ void __init control_of_init(struct device_node *dp)
        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);
 }
 
index 3b9d4bb937cd9c582ca28937f9b71bacb238e146..5bc95651b11ff5efba5e9adfda3a25789d6222d4 100644 (file)
@@ -178,7 +178,7 @@ void fbcon_afb_bmove(struct display *p, int sy, int sx, int dy, int dx,
        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 @@ void fbcon_afb_bmove(struct display *p, int sy, int sx, int dy, int dx,
            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 @@ void fbcon_afb_bmove(struct display *p, int sy, int sx, int dy, int dx,
            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 @@ void fbcon_afb_clear(struct vc_data *conp, struct display *p, int sy, int sx,
        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;
index 9fef8171ee4aff0074b1fb568975443d4a9df6f5..0c3c79ab788ead0fee2bb1b907d136ad4ca4023b 100644 (file)
@@ -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 @@ void fbcon_cfb16_bmove(struct display *p, int sy, int sx, int dy, int dx,
     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 @@ void fbcon_cfb16_bmove(struct display *p, int sy, int sx, int dy, int dx,
        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 @@ void fbcon_cfb16_bmove(struct display *p, int sy, int sx, int dy, int dx,
        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 @@ static inline void rectfill(u8 *dest, int width, int height, u32 data,
     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 @@ void fbcon_cfb16_putc(struct vc_data *conp, struct display *p, int c, int yy,
        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 @@ void fbcon_cfb16_putc(struct vc_data *conp, struct display *p, int c, int yy,
        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 @@ void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p,
            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 @@ void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p,
            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 @@ void fbcon_cfb16_revc(struct display *p, int xx, int yy)
     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);
        }
     }
 }
index 5b339a4fa39d135ca8e1c89adcabcdde03afa386..4326b87f8e2f105faa746da07180c090eb13be3a 100644 (file)
@@ -61,7 +61,7 @@ void fbcon_cfb2_bmove(struct display *p, int sy, int sx, int dy, int dx,
        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 @@ void fbcon_cfb2_bmove(struct display *p, int sy, int sx, int dy, int dx,
                        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 @@ void fbcon_cfb2_bmove(struct display *p, int sy, int sx, int dy, int dx,
                        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 @@ void fbcon_cfb2_clear(struct vc_data *conp, struct display *p, int sy, int sx,
 
        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 @@ void fbcon_cfb2_clear(struct vc_data *conp, struct display *p, int sy, int sx,
                        dest=dest0;
                        for (i = 0 ; i < width ; i++) {
                                /* memset ?? */
-                               ((u16 *)dest)[0]=bgx;
+                               fb_writew (bgx, dest);
                                dest+=2;
                        }
                }
@@ -140,10 +140,8 @@ void fbcon_cfb2_putc(struct vc_data *conp, struct display *p, int c, int yy,
        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 @@ void fbcon_cfb2_putcs(struct vc_data *conp, struct display *p, const unsigned sh
                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 @@ void fbcon_cfb2_revc(struct display *p, int xx, int yy)
 
        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);
        }
 }
 
index 17e8ee08afa0765782e1372f4ff2d81b99b33ea1..74ace660f83fd4973c9038d4593d0e41752c974f 100644 (file)
@@ -36,7 +36,7 @@ void fbcon_cfb24_bmove(struct display *p, int sy, int sx, int dy, int dx,
     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 @@ void fbcon_cfb24_bmove(struct display *p, int sy, int sx, int dy, int dx,
        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 @@ void fbcon_cfb24_bmove(struct display *p, int sy, int sx, int dy, int dx,
        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 @@ void fbcon_cfb24_bmove(struct display *p, int sy, int sx, int dy, int dx,
 
 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 @@ static inline void rectfill(u8 *dest, int width, int height, u32 data,
     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 @@ void fbcon_cfb24_putc(struct vc_data *conp, struct display *p, int c, int yy,
        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 @@ void fbcon_cfb24_putcs(struct vc_data *conp, struct display *p,
            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 @@ void fbcon_cfb24_revc(struct display *p, int xx, int yy)
     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);
        }
     }
 }
index b66ec2badd4f056e4f91e8650f207b8e84ef5d61..bedd81c96497e1e3eb93e96396989c762ef5b2b1 100644 (file)
@@ -36,7 +36,7 @@ void fbcon_cfb32_bmove(struct display *p, int sy, int sx, int dy, int dx,
     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 @@ void fbcon_cfb32_bmove(struct display *p, int sy, int sx, int dy, int dx,
        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 @@ void fbcon_cfb32_bmove(struct display *p, int sy, int sx, int dy, int dx,
        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 @@ static inline void rectfill(u8 *dest, int width, int height, u32 data,
     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 @@ void fbcon_cfb32_putc(struct vc_data *conp, struct display *p, int c, int yy,
 {
     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 @@ void fbcon_cfb32_putc(struct vc_data *conp, struct display *p, int c, int yy,
 
     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 @@ void fbcon_cfb32_putcs(struct vc_data *conp, struct display *p,
     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 @@ void fbcon_cfb32_putcs(struct vc_data *conp, struct display *p,
            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 @@ void fbcon_cfb32_revc(struct display *p, int xx, int yy)
     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 */
        }
     }
index 6248c28eee894783e4793b3179963c3925aa9681..a885fddfa7944ae9d2b5c50a191c4c437f9df2e2 100644 (file)
@@ -61,7 +61,7 @@ void fbcon_cfb4_bmove(struct display *p, int sy, int sx, int dy, int dx,
        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 @@ void fbcon_cfb4_bmove(struct display *p, int sy, int sx, int dy, int dx,
                        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 @@ void fbcon_cfb4_bmove(struct display *p, int sy, int sx, int dy, int dx,
                        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 @@ void fbcon_cfb4_clear(struct vc_data *conp, struct display *p, int sy, int sx,
 
        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 @@ void fbcon_cfb4_clear(struct vc_data *conp, struct display *p, int sy, int sx,
                        dest=dest0;
                        for (i = 0 ; i < width ; i++) {
                                /* memset ?? */
-                               ((u32 *)dest)[0]=bgx;
+                               fb_writel (bgx, dest);
                                dest+=4;
                        }
                }
@@ -142,10 +142,8 @@ void fbcon_cfb4_putc(struct vc_data *conp, struct display *p, int c, int yy,
        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 @@ void fbcon_cfb4_putcs(struct vc_data *conp, struct display *p,
                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 @@ void fbcon_cfb4_revc(struct display *p, int xx, int yy)
 
        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);
        }
 }
 
index 0acf7c989a88eb18de00bb38f4e084cbc3627de4..78e3d462f9eb4c429b491fc6bb59427639569568 100644 (file)
@@ -52,7 +52,7 @@ void fbcon_cfb8_bmove(struct display *p, int sy, int sx, int dy, int dx,
     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 @@ void fbcon_cfb8_bmove(struct display *p, int sy, int sx, int dy, int dx,
        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 @@ void fbcon_cfb8_bmove(struct display *p, int sy, int sx, int dy, int dx,
        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 @@ static inline void rectfill(u8 *dest, int width, int height, u8 data,
                            int linesize)
 {
     while (height-- > 0) {
-       memset(dest, data, width);
+       fb_memset(dest, data, width);
        dest += linesize;
     }
 }
@@ -132,22 +132,22 @@ void fbcon_cfb8_putc(struct vc_data *conp, struct display *p, int c, int yy,
     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 @@ void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p,
            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 @@ void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p,
            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 @@ void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p,
            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 @@ void fbcon_cfb8_revc(struct display *p, int xx, int yy)
     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;
        }
     }
index fbba519d97349dd9f890458ee6910de043e3fb51..d23c7e4b186c50d168615d0faaef3a444fc82647 100644 (file)
@@ -45,7 +45,7 @@ void fbcon_ilbm_bmove(struct display *p, int sy, int sx, int dy, int dx,
                      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 @@ void fbcon_ilbm_bmove(struct display *p, int sy, int sx, int dy, int dx,
            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 @@ void fbcon_ilbm_bmove(struct display *p, int sy, int sx, int dy, int dx,
            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 @@ void fbcon_ilbm_clear(struct vc_data *conp, struct display *p, int sy, int sx,
        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;
        }
     }
index 0dfdc6107745936b012c2f5beb97be627037a04b..8be58150755d15b3c81b199eb8e07e743934a020 100644 (file)
@@ -169,7 +169,7 @@ void fbcon_iplan2p2_bmove(struct display *p, int sy, int sx, int dy, int dx,
        /*  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 @@ void fbcon_iplan2p2_bmove(struct display *p, int sy, int sx, int dy, int dx,
                }
                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 @@ void fbcon_iplan2p2_bmove(struct display *p, int sy, int sx, int dy, int dx,
                    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 @@ void fbcon_iplan2p2_clear(struct vc_data *conp, struct display *p, int sy,
        /*  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.
         */
 
index 805c9170b02a3b5534636286d1a7bc313ce2a882..8591783d9b57bef07377eab4230c563fb0d8d078 100644 (file)
@@ -177,7 +177,7 @@ void fbcon_iplan2p4_bmove(struct display *p, int sy, int sx, int dy, int dx,
        /*  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 @@ void fbcon_iplan2p4_bmove(struct display *p, int sy, int sx, int dy, int dx,
                }
                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 @@ void fbcon_iplan2p4_bmove(struct display *p, int sy, int sx, int dy, int dx,
                    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 @@ void fbcon_iplan2p4_clear(struct vc_data *conp, struct display *p, int sy,
        /*  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.
         */
 
index 411dc5ae94c907813df3d6731dc2c59ac4cbb83a..4ee366019de2dda74bcc70561612c5e061490b30 100644 (file)
@@ -337,7 +337,7 @@ void fbcon_iplan2p8_clear(struct vc_data *conp, struct display *p, int sy,
        /* 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.
        */
 
index 2c6486c41d38092cf6280c26d980d87d54b0763c..58deaff5458e2b2f711eea2e1b5b9d9ec64d0d5a 100644 (file)
@@ -62,7 +62,7 @@ void fbcon_mac_bmove(struct display *p, int sy, int sx, int dy, int dx,
 
    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 @@ void fbcon_mac_bmove(struct display *p, int sy, int sx, int dy, int dx,
         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 @@ void fbcon_mac_clear(struct vc_data *conp, struct display *p, int sy, int sx,
    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 @@ void fbcon_mac_clear(struct vc_data *conp, struct display *p, int sy, int sx,
 
      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;
      }
index 76caf5cc9ee0a948dd341d623a3a7368f4e12e85..9aa3528dd137a4f81f4e405788ab7280adf5f6a5 100644 (file)
@@ -41,12 +41,12 @@ void fbcon_mfb_bmove(struct display *p, int sy, int sx, int dy, int dx,
     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 @@ void fbcon_mfb_bmove(struct display *p, int sy, int sx, int dy, int dx,
        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 @@ void fbcon_mfb_clear(struct vc_data *conp, struct display *p, int sy, int sx,
 
     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 @@ void fbcon_mfb_putc(struct vc_data *conp, struct display *p, int c, int yy,
            d |= d>>1;
        if (revs)
            d = ~d;
-       *dest = d;
+       fb_writeb (d, dest);
     }
 }
 
@@ -133,19 +133,21 @@ void fbcon_mfb_putcs(struct vc_data *conp, struct display *p,
                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 @@ void fbcon_mfb_clear_margins(struct vc_data *conp, struct display *p,
        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);
 }
 
 
index b54d0b5a4b933c58cdd1f9805ae3e3ab7d35c8ac..77336e2231dc9edc39a33af768b644ec7364a074 100644 (file)
@@ -526,7 +526,7 @@ static void fbcon_setup(int con, int init, int logo)
        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 @@ static void fbcon_setup(int con, int init, int logo)
                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 @@ static void fbcon_setup(int con, int init, int logo)
                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 @@ static void fbcon_setup(int con, int init, int logo)
        }
        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 @@ static int fbcon_blank(struct vc_data *conp, int blank)
 
     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 @@ static int __init fbcon_show_logo( void )
                              (*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 @@ static int __init fbcon_show_logo( void )
 #else
                            for( i = bdepth-1; i >= 0; --i )
 #endif
-                               *dst++ = val >> (i*8);
+                               fb_writeb (val >> (i*8), dst++);
                        }
                    }
                }
@@ -2078,7 +2071,7 @@ static int __init fbcon_show_logo( void )
 #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 @@ static int __init fbcon_show_logo( void )
 #else
                        for( i = bdepth-1; i >= 0; --i )
 #endif
-                           *dst++ = val >> (i*8);
+                           fb_writeb (val >> (i*8), dst++);
                    }
                }
            }
@@ -2122,7 +2115,7 @@ static int __init fbcon_show_logo( void )
                          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 @@ static int __init fbcon_show_logo( void )
 #else
                        for( i = bdepth-1; i >= 0; --i )
 #endif
-                           *dst++ = val >> (i*8);
+                           fb_writeb (val >> (i*8), dst++);
                    }
                }
            }
@@ -2145,7 +2138,7 @@ static int __init fbcon_show_logo( void )
                        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 @@ static int __init fbcon_show_logo( void )
            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 @@ static int __init fbcon_show_logo( void )
                           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 @@ static int __init fbcon_show_logo( void )
                                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++;
                        }
index a0292039594f09673399399a3800a545c3fb6139..b65a40aa45881ef65464c2664d5745cef377e990 100644 (file)
@@ -100,12 +100,17 @@ extern int fm2fb_setup(char*);
 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
index 398e8e500a92c64728272429102104159901c763..d020ed75254470a54e852d601382de201932a37f 100644 (file)
@@ -354,9 +354,12 @@ struct fb_info_imstt {
        } 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 @@ imsttfbcon_clear (struct vc_data *conp, struct display *disp,
        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 @@ init_imstt(struct fb_info_imstt *p)
        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 @@ imsttfb_of_init(struct device_node *dp)
        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 @@ imsttfb_init(void)
                                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);
index af58b457ae9c7ca8e18cef1d2c222179434d3e2d..404c646f54b91b5924cc8e04c553d59a96c01446 100644 (file)
@@ -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))
index cf7fe3418e8016104a5d12fa4bd3553afa297b1d..12d067b79bb3dce8e8d05450b0f84f6be9aab8b5 100644 (file)
@@ -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_par_platinum {
 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_var_to_par(const struct fb_var_screeninfo *var,
 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 @@ static struct fb_ops platinumfb_ops = {
        platinum_ioctl
 };
 
-
-__openfirmware
-
-
 static int platinum_open(struct fb_info *info, int user)
 {
        MOD_INC_USE_COUNT;
@@ -219,6 +217,36 @@ static int platinum_get_var(struct fb_var_screeninfo *var, int con,
        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 @@ static int platinum_set_var(struct fb_var_screeninfo *var, int con,
        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 @@ static int platinum_set_var(struct fb_var_screeninfo *var, int con,
                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 @@ static int platinum_set_var(struct fb_var_screeninfo *var, int con,
            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 @@ static int platinum_set_var(struct fb_var_screeninfo *var, int con,
            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_pan_display(struct fb_var_screeninfo *var, int con,
 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 @@ static int platinum_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                             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 @@ static int platinum_switch(int con, struct fb_info *fb)
                            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 @@ static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 {
        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 @@ static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
        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 @@ static void platinum_set_par(const struct fb_par_platinum *par, struct fb_info_p
        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 @@ static void platinum_set_par(const struct fb_par_platinum *par, struct fb_info_p
                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 @@ int __init platinum_init(void)
 
 #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 @@ void __init platinum_of_init(struct device_node *dp)
 {
        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 @@ void __init platinum_of_init(struct device_node *dp)
        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 @@ static int platinum_encode_fix(struct fb_fix_screeninfo *fix,
                               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 @@ int __init platinum_setup(char *options)
                } 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;
index aafa045421540b803a89e006a1f4fc9bc09ba1a5..1a3b02e64e67309ed62f7540f0dec9bd8445d9d2 100644 (file)
@@ -304,13 +304,13 @@ static void sbusfb_clear_margin(struct display *p, int s)
                        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 --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
new file mode 100644 (file)
index 0000000..30f9111
--- /dev/null
@@ -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);
+  }
+}
+
index 2541d14a40ebfac41c462cbcb09f9548b5e66b53..a60774a61db8e05775e7911a353c1223fd575323 100644 (file)
 #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>
@@ -168,10 +168,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)
 {
        MOD_INC_USE_COUNT;
index bb98bd8c730b44b43c2337db1fe9ff801d4ee6b5..cf4f9baa9c987d9973e55630b56ab1d8eaace30b 100644 (file)
@@ -532,6 +532,8 @@ int __init vesafb_init(void)
 
        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;
index 1e9abfe3d6a021503c67d485f262115e1ecc7acd..050d34543493b4d826852c82a015f46a43bb88f1 100644 (file)
@@ -1163,7 +1163,7 @@ int __init virgefb_setup(char *options)
  *    Initialization
  */
 
-void __init virgefb_init(void)
+int __init virgefb_init(void)
 {
        struct virgefb_par par;
        unsigned long board_addr;
index 5fa99a017146f3f8da685c0a2d39cd22cccd4305..d77dc86bc8658d539f0a30a79c4f4aa4e1d4954f 100644 (file)
@@ -1205,6 +1205,18 @@ static int create_page_buffers(int rw, struct page *page, kdev_t dev, int b[], i
        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 @@ int block_flushpage(struct inode *inode, struct page *page, unsigned long offset
                /*
                 * 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 @@ static void create_empty_buffers(struct page *page, struct inode *inode, unsigne
        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 @@ int block_write_full_page(struct file *file, struct page *page)
                        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 @@ int block_write_partial_page(struct file *file, struct page *page, unsigned long
                        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 @@ int block_write_cont_page(struct file *file, struct page *page, unsigned long of
                        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)))) {
index 4d3295137bc9393f2bba38170ba844a342d50eb7..b3f31fd0ae85acdf27ea0f5003c1251959c5fccd 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -169,7 +169,7 @@ out:
 /*
  * 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 @@ static int count(char ** argv)
                        if (!p)
                                break;
                        argv++;
-                       i++;
+                       if(++i > max)
+                               return -E2BIG;
                }
        }
        return i;
@@ -202,7 +203,7 @@ int copy_strings(int argc,char ** argv, struct linux_binprm *bprm)
                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 @@ int copy_strings(int argc,char ** argv, struct linux_binprm *bprm)
                /* 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 @@ int setup_arg_pages(struct linux_binprm *bprm)
                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 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs
        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;
        }
index 26c9bf4a0bdfc344115e858b45ca9fd95b5f7459..255267da8f2f5e6946bcf8930bc7e153de01074d 100644 (file)
@@ -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 @@ out:
        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 @@ static void send_sigio_to_task(struct task_struct *p,
                           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_to_task(struct task_struct *p,
        }
 }
 
-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 @@ static void send_sigio(struct fown_struct *fown, struct fasync_struct *fa)
                        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 @@ void kill_fasync(struct fasync_struct *fa, int sig)
                        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;
        }
 }
index 594c996e3a83e6118bc62bea0f5026858c366095..ea541e7964f6e43090970ec9998fdbd633917674 100644 (file)
@@ -433,7 +433,7 @@ ncp_do_simple_filldir(struct file *filp, char* name, int len,
        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 @@ ncp_do_filldir(struct file *filp, struct ncp_entry_info *entry, void *dirent,
 
                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 @@ end_advance:
                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 @@ dentry->d_parent->d_name.name, __name, res);
         * 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 @@ static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
        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;
index a4ba9253be2ab5648dba335d2cb474499663e216..ab754e949b6cc4e16fbdc0a699400fc9a1a9135a 100644 (file)
@@ -356,7 +356,6 @@ check_table:
                /*
                 * 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;
                /*
index 36f1650ac32b683e75eb30f16eaaa0dc18693c15..14d61aba01d7b11f5a8118b98d5bf5022a3f9c71 100644 (file)
 #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 @@ smb_get_dircache(struct dentry * dentry)
        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 @@ smb_add_to_cache(struct cache_head * cachep, struct cache_dirent *entry,
        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 @@ inode, cachep->status, entry->name, fpos);
                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 @@ printk("smb_find_in_cache: cache %p, looking for pos=%ld\n", cachep, pos);
                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 @@ printk("smb_find_in_cache: cache %p, looking for pos=%ld\n", cachep, pos);
                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 @@ smb_invalid_dir_cache(struct inode * dir)
        dir->u.smbfs_i.cache_valid &= ~SMB_F_CACHEVALID;
        dir->u.smbfs_i.oldmtime = 0;
 }
-
index 682b511f66d4bdc690f108a2f1d4d3b4deceaa73..1aa6b711e62aa9152048b66da6c499a03b126c49 100644 (file)
@@ -32,13 +32,6 @@ min(int a, int b)
        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 @@ smb_readpage_sync(struct dentry *dentry, struct page *page)
        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 @@ dentry->d_parent->d_name.name, dentry->d_name.name, result);
        } 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 @@ smb_readpage(struct file *file, struct page *page)
 
        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 @@ printk("smb_writepage_sync: short write, wsize=%d, result=%d\n", wsize, result);
 /*
  * 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 @@ smb_writepage(struct file *file, struct page *page)
        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 @@ out:
  * 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;
index f5f7471424ec28f4f7891e622f1a3bb9f2943bf9..4b308f74638635afec930df1f0511337bc4f3795 100644 (file)
 
 #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 @@ extern unsigned char pckbd_sysrq_xlate[128];
 
 #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)
 
-#endif /* __ASMi386_KEYBOARD_H */
+/* 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 /* _I386_KEYBOARD_H */
diff --git a/include/asm-i386/mmx.h b/include/asm-i386/mmx.h
new file mode 100644 (file)
index 0000000..721a8e9
--- /dev/null
@@ -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
index 2e5006f4a6fd6eb6315173d58ea3611d7ff431c1..c3719d5d9cd19e1f0cae15253be83bda021fbf33 100644 (file)
 
 #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
 /*
  * These are used to make use of C type-checking..
index 34f5c16b1b00bd8551dfc26d88938b4245803a28..4b5c5fe25f92017424c26e55b3ad1a9f387828a5 100644 (file)
@@ -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 @@ return __res;
 #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 @@ __asm__ __volatile__(
        "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 @@ __asm__ __volatile__(
        "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 @@ __asm__ __volatile__(
        "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 @@ __asm__ __volatile__(
        "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 @@ __asm__ __volatile__(
        "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 @@ return (tmp-s-1);
 #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 @@ __asm__ __volatile__(
        "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 @@ return (to);
 
 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 @@ __asm__ __volatile__ (
        "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 @@ return (to);
 #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 @@ __asm__ __volatile__(
        "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 @@ __asm__ __volatile__(
        "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 @@ return s;
 
 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 @@ __asm__ __volatile__ (
        "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 @@ __asm__ __volatile__ (
        "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;
 }
 
index 8417d4abab404230dddcf1a1b42784ba853bd315..e03928ede324b1654db5e5a14c6ccbaf40ef6753 100644 (file)
@@ -293,11 +293,55 @@ __asm__ __volatile__( \
 }
 
 #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)
 {
index 2b1b3d7f461d26d33f406047a1d9af2ed4399614..7546159f647d4cd2397605563b7734466f4e9d0b 100644 (file)
@@ -597,7 +597,8 @@ __constant_copy_from_user_nocheck(void *to, const void *from, unsigned long n)
 
 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);
 
index 7b1cbb0be79ca37965a3476195ba8c1742170634..754537ed81ce281ece9d4f16b384437f288e8140 100644 (file)
@@ -13,6 +13,9 @@
 
 #ifdef __KERNEL__
 
+#include <linux/ioport.h>
+#include <asm/io.h>
+
 #define KEYBOARD_IRQ                   13
 #define DISABLE_KBD_DURING_INTERRUPTS  0
 
@@ -45,6 +48,31 @@ extern unsigned char pcikbd_sysrq_xlate[128];
 /* #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__ */
 
 #endif /* !(_SPARC_KEYBOARD_H) */
index f7a7e2b645c0959f15079a22798d4e4801433a29..ef4372cf40870e11c2acec1ec1a09e4361609a62 100644 (file)
@@ -80,6 +80,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" */
index cf9cad1101c022f2bb79ec5a19ebc48ee10c3c52..d1ee10406f3e1541b19185df28f13e5bcdb7b4cc 100644 (file)
@@ -727,7 +727,7 @@ extern char * getname(const char *);
 #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 *);
index 71bcdc98ec923c0aac9933e51414ffdaf5290def..f699f93ddeea77d4801e91a719f17d1b0c1018bc 100644 (file)
@@ -637,7 +637,7 @@ int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeou
  * 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 *);
 
 /*
  * Start a reset operation for an IDE interface.
index 8b4b3f35a3a05062e7529458b431e4016b5f045a..d91b6bcf600d04b98461ea9b7489469ab626eb0a 100644 (file)
@@ -126,7 +126,7 @@ struct net_proto
        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 --git a/include/linux/pc_keyb.h b/include/linux/pc_keyb.h
new file mode 100644 (file)
index 0000000..22e0098
--- /dev/null
@@ -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];
+};
index 70ce90e103a9d5d7f94eb7ecf27268d4d42ec203..450341b74628f1d1210029566e1453ba7f034810 100644 (file)
@@ -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
 #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 @@ typedef struct _MGSL_PARAMS
        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;
 
index 1d972dda31fda077699dbb1a90d84841af56a6b9..1cca4c90f73e5bc357fb0d958ed1e48c81f8fcad 100644 (file)
@@ -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 @@ extern void fbcon_redraw_bmove(struct display *, int, int, int, int, int, int);
    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_small(void *s, size_t count)
 }
 
 
-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 *mymemclear(void *s, size_t count)
 }
 
 
-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 *mymemset(void *s, size_t count)
 }
 
 
-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 @@ static __inline__ void *sun4_memset(void *s, char val, size_t count)
     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 @@ static __inline__ void fast_memmove(void *d, const void *s, size_t count)
            ((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 @@ static __inline__ void *mymemmove(char *dst, const char *src, size_t size)
 
 #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 @@ __asm__ __volatile__ (
     }
 }
 
-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 @@ static __inline__ void *mymemmove(char *dst, const char *src, size_t size)
      *   (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 @@ static __inline__ void fast_memmove(char *dst, const char *src, size_t size)
 #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 @@ static __inline__ void fast_memmove(char *dst, const char *src, size_t size)
 #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 @@ static __inline__ void fast_memmove(char *dst, const char *src, size_t size)
 #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
 
index c459987e331e4275fded60f1017d8c93f6632628..1bdfa815b851120033da906e741bcd3974ddcd7c 100644 (file)
@@ -52,6 +52,9 @@ extern int mac_vmode_to_var(int vmode, int cmode,
 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);
 
 
     /*
index 1d8cac7b7c12cb1edea35d05ec0bd6f562d4e2a9..ac0e62b47b2048c579a2ef783d92386e117d746a 100644 (file)
@@ -353,13 +353,9 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
                                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 @@ sys_kill(int pid, int sig)
 {
        struct siginfo info;
 
+       memset(&info, 0, sizeof(info));
+       
        info.si_signo = sig;
        info.si_errno = 0;
        info.si_code = SI_USER;
index e862c65bff5a188579594c73f2a7e029db624e53..51624abcfc51a573a9b96700adc12ed89b0c0faf 100644 (file)
@@ -912,6 +912,8 @@ static void generic_file_readahead(int reada_ok,
        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 @@ generic_file_write(struct file *file, const char *buf,
        long            status;
        int             err;
 
+       down(&inode->i_sem);
        err = file->f_error;
        if (err) {
                file->f_error = 0;
@@ -1872,6 +1875,7 @@ repeat_find:
 
        err = written ? written : status;
 out:
+       up(&inode->i_sem);
        return err;
 }
 
index 2b0018ec93bea6771da5124a357de05fe2bbefc4..15b0ec64fee312d31747ad427da56b8415b1543a 100644 (file)
@@ -1013,7 +1013,7 @@ void sock_def_error_report(struct sock *sk)
        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 @@ void sock_def_readable(struct sock *sk, int len)
        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 @@ void sock_def_write_space(struct sock *sk)
 
                /* 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);
 }
index 23119cd9f101943d0f6d048c3a44991a3a6bca40..a997d253ee81710c7ca653b047695c2a9b438f00 100644 (file)
@@ -431,7 +431,8 @@ static __inline__ int dn_queue_skb(struct sock *sk, struct sk_buff *skb, int sig
                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);
 
index b8e5d197c344a1c51880619cfdf13185d73f0dd9..4135d4c89efcd8e83ecbc536b54016e21d857ba8 100644 (file)
@@ -626,7 +626,7 @@ void tcp_write_space(struct sock *sk)
                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);
 }
index f0711fccc1b1a36deb7bdecba24437f547a0dc28..2f6bd37c9f9ab05802e46a9c63244d68573afb3e 100644 (file)
@@ -1403,7 +1403,7 @@ static void tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
 
        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 @@ static int tcp_data(struct sk_buff *skb, struct sock *sk, unsigned int len)
         */
        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 @@ static void tcp_check_urg(struct sock * sk, struct tcphdr * th)
                        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 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                         * 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 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
 
                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 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                                 */
                                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;
index 0064aaaa78170e9c75d4a70f9f0fe88c5f1d3473..b85ea2a86cf903c71a000d137006e25c00a61240 100644 (file)
@@ -670,7 +670,7 @@ out:
 
 /* 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 @@ int sock_wake_async(struct socket *sock, int how)
        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;
 }
index d4bec3a5d4e6526e8d9084d29593db0cfcb71b21..55d8eff1f3f6526a2f9a23daab5b24dd14bfba08 100644 (file)
@@ -299,7 +299,7 @@ static void unix_write_space(struct sock *sk)
        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);
 }
index ad7adb7ea558d1a8f8783a022661b0803bd06f90..f842aeeceb501f2482e03dcd971d111494e9e653 100644 (file)
@@ -278,6 +278,7 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
                                        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;