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
====
- "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
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.
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
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.
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
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.
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.
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
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.
Ioctl Numbers
-2 September 1999
+10 October 1999
Michael Elizabeth Chastain
<mec@shout.net>
'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
'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
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/)
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
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.
*
* 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
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
$exception:
ret
+ .align 3 # currently redundant
+$limit:
+ subq a1, t2, v0
+ ret
+
.end __strlen_user
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
#
# 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
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
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
# 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
# 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
# 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
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;
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;
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",
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;
}
/*
if (apm_disabled) {
printk(KERN_NOTICE "apm: disabled on user request.\n");
- return;
+ return -1;
}
#ifdef CONFIG_SMP
misc_register(&apm_device);
kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
+ return 0;
}
module_init(apm_init)
#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 *);
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);
#ifdef CONFIG_VT
EXPORT_SYMBOL(screen_info);
#endif
+
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
--- /dev/null
+#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);
+}
* 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)
return n;
}
+#endif
/*
* Copy a null terminated string from userspace.
/*
* 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;
}
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
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
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
sock = ¤t->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");
}
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
#
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
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
# 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 \
"$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
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
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
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
+
+++ /dev/null
-/*
- * 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
-}
*/
static void ida_procinit(int i)
{
+#ifdef CONFIG_PROC_FS
struct proc_dir_entry *pd;
if (proc_array == NULL) {
if (!pd) return;
pd->read_proc = ida_proc_get_info;
pd->data = hba[i];
+#endif
}
/*
}
}
}
+#ifdef CONFIG_PROC_FS
remove_proc_entry("array", &proc_root);
+#endif
kfree(ida);
kfree(ida_sizes);
kfree(ida_hardsizes);
*
* 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 */
}
/*
}
/*
- * 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)
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);
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);
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 */
}
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
#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;
return 0;
}
-#else /* !IDEDMA_NEW_DRIVE_LISTINGS */
+#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
/*
* good_dma_drives() lists the model names (from "hdparm -i")
"WDC AC31600H",
NULL};
-#endif /* IDEDMA_NEW_DRIVE_LISTINGS */
+#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
/*
* Our Physical Region Descriptor (PRD) table should be large enough
{
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 {
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) {
}
}
}
-#endif /* IDEDMA_NEW_DRIVE_LISTINGS */
+#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
return 0;
}
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);
--- /dev/null
+/*
+ * 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;
+}
#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"
#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 */
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 */
}
#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 */
* 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;
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);
* 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;
}
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 */
}
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;
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;
* "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.
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;
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];
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
*/
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
*/
* 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.
*
(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));
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;
}
#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
wake_up(&mse->wait);
if (mse->fasyncptr)
- kill_fasync(mse->fasyncptr, SIGIO);
+ kill_fasync(mse->fasyncptr, SIGIO, POLL_IN);
}
}
#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
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;
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); */
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;
#
# 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 \
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
# 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
#include <linux/string.h>
#include <linux/random.h>
#include <linux/init.h>
+#include <linux/module.h>
#include <asm/keyboard.h>
#include <asm/bitops.h>
#ifdef CONFIG_MAGIC_SYSRQ
static int sysrq_pressed;
-int sysrq_enabled = 1;
#endif
/*
#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",
* 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
*/
#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)
/*
* 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;
#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 *,
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;
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) {
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)
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;
}
/* 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() */
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;
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 */
/* 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);
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);
}
/* 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 */
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 */
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;
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);
}
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);
#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"
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.
{
wake_up_interruptible(&queue);
if(asyncptr)
- kill_fasync(asyncptr, SIGIO);
+ kill_fasync(asyncptr, SIGIO, POLL_IN);
}
*/
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 */
synthesize_tap=0;
del_timer(&bounce_timer);
del_timer(&tap_timer);
- sti();
+ restore_flags(flags);
return 0;
}
{
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;
}
int init_module(void)
{
+ init_MUTEX(&read_lock);
return pc110pad_init();
}
#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 */
"\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;
#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 */
/*
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);
}
}
*/
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;
{
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);
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;
#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))
int maxread = 100; /* Random number */
do {
- if (kbd_read_input() == KBD_NO_DATA)
+ if (kbd_read_data() == KBD_NO_DATA)
break;
} while (--maxread);
}
long timeout = KBD_INIT_TIMEOUT;
do {
- int retval = kbd_read_input();
+ int retval = kbd_read_data();
if (retval >= 0)
return retval;
mdelay(1);
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);
}
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 */
* 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";
* 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
* 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;
* 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;
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";
void __init pckbd_init_hw(void)
{
+ kbd_request_region();
+
/* Flush any pending input. */
kbd_clear_input();
#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
* 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;
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);
}
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();
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;
}
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 */
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;
+++ /dev/null
-/*
- * 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];
-};
#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)
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;
{
int retval;
struct tty_driver *p;
- int found = 0;
+ int i, found = 0;
+ struct termios *tp;
const char *othername = NULL;
if (*driver->refcount)
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;
}
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
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
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
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
#
#
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
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
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
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
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
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
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
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
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
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
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
#
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
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
* 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.
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);
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);
/* 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);
#ifdef CONFIG_SIS900
{sis900_probe, 0},
#endif
+
+#ifdef CONFIG_DM9102
+ {dmfe_reg_board, 0},
+#endif
+
#ifdef CONFIG_YELLOWFIN
{yellowfin_probe, 0},
#endif
/*
* 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 */
#endif
#ifdef CONFIG_BMAC
{bmac_probe, 0},
+#endif
+#ifdef CONFIG_NCR885E
+ {ncr885e_probe, 0},
#endif
{NULL, 0},
};
/* 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)
# 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
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);
+++ /dev/null
-/* $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 */
+++ /dev/null
-/* $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__ */
+++ /dev/null
-/*
-* 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 */
+++ /dev/null
-/*
-* 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 */
+++ /dev/null
-/*
-* 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 */
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-#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
-
+++ /dev/null
-/* 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 */
+++ /dev/null
-/* 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;
-};
-
+++ /dev/null
-/*
- * "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
--- /dev/null
+#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
--- /dev/null
+/*
+ * 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 *) ®
+ 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:
+ */
--- /dev/null
+#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
+++ /dev/null
-/*
- * 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 */
-
+++ /dev/null
-/*
- * 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] ;
-};
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-/*****************************************************************************
-* 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 *****************************************************************/
+++ /dev/null
-/*****************************************************************************
-* 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 *****************************************************************/
+++ /dev/null
-/*****************************************************************************
-* 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 *****************************************************************/
+++ /dev/null
-/*****************************************************************************
-* 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 *****************************************************************/
+++ /dev/null
-/*****************************************************************************
-* 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 *****************************************************************/
+++ /dev/null
-#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
-
-/* $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)
#include <linux/version.h>
#include <linux/kernel.h>
+#include <linux/version.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-/* 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 */
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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_ */
--- /dev/null
+#
+# 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
--- /dev/null
+#
+# 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
+
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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];
+};
+
--- /dev/null
+/*
+ * 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 */
+
--- /dev/null
+/*
+ * 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] ;
+};
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/* 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+#
+# 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
+
--- /dev/null
+# 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)
+
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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__ */
--- /dev/null
+/*
+* 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 */
--- /dev/null
+/*
+* 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 */
--- /dev/null
+/*
+* 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+#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
+
--- /dev/null
+/*
+ * "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
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*****************************************************************************
+* 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 *****************************************************************/
--- /dev/null
+/*****************************************************************************
+* 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 *****************************************************************/
--- /dev/null
+/*****************************************************************************
+* 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 *****************************************************************/
--- /dev/null
+/*****************************************************************************
+* 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 *****************************************************************/
--- /dev/null
+/*****************************************************************************
+* 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 *****************************************************************/
--- /dev/null
+#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
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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 */
+
--- /dev/null
+#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 */
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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) */
+++ /dev/null
-/*
- * 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 */
-
+++ /dev/null
-#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 */
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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) */
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
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);
}
kbd_head = next;
}
if (kb_fasync)
- kill_fasync (kb_fasync, SIGIO);
+ kill_fasync (kb_fasync, SIGIO, POLL_IN);
wake_up_interruptible (&kbd_wait);
}
}
sunmouse.ready = 1;
if (sunmouse.fasync)
- kill_fasync (sunmouse.fasync, SIGIO);
+ kill_fasync (sunmouse.fasync, SIGIO, POLL_IN);
wake_up_interruptible (&sunmouse.proc_list);
}
*/
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;
#ifdef MODULE
int init_module(void)
#else
-__initfunc(int uctrl_init(void))
+int __init uctrl_init(void)
#endif
{
struct uctrl_driver *driver = &drv;
/* 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)
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);
}
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
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;
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;
}
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
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 &&
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;
}
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])
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]);
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
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;
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;
}
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
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 &&
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;
}
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])
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)
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);
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;
}
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)
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);
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;
}
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;
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;
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;
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;
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);
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));
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;
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;
/* 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;
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;
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;
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;
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;
}
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;
}
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;
}
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];
}
}
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];
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);
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:
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);
wake_up_interruptible(&mouse->wait);
if (mouse->fasync)
- kill_fasync(mouse->fasync, SIGIO);
+ kill_fasync(mouse->fasync, SIGIO, POLL_IN);
return 1;
}
# 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
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
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))
#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 */
-/* $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
#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>
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
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
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
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);
}
return res;
}
-#if defined(CONFIG_PPC)
+#ifdef CONFIG_PMAC
/*
* Apple monitor sense
return sense;
}
-#endif /* defined(CONFIG_PPC) */
+#endif /* CONFIG_PMAC */
/* ------------------------------------------------------------------------- */
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
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;
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 */
}
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))
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;
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:
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;
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)
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
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
};
#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)
{
#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>
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
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;
#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;
* 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,
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 */
#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>
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);
}
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);
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);
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;
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;
#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>
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;
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;
}
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;
}
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;
}
}
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;
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;
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;;
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;
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);
}
}
}
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);
}
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;
}
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;
}
if (sx == 0 && width * 2 == bytes) {
for (i = 0 ; i < lines * width ; i++) {
- ((u16 *)dest)[0]=bgx;
+ fb_writew (bgx, dest);
dest+=2;
}
} else {
dest=dest0;
for (i = 0 ; i < width ; i++) {
/* memset ?? */
- ((u16 *)dest)[0]=bgx;
+ fb_writew (bgx, dest);
dest+=2;
}
}
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);
}
}
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;
}
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);
}
}
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;
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;
}
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;
}
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,
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;
}
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));
}
}
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;
}
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);
}
}
}
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;
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;
}
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;
}
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;
}
}
{
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)
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++);
}
}
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))];
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;
}
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 */
}
}
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);
}
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;
}
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;
}
if (sx == 0 && width * 4 == bytes) {
for (i = 0 ; i < lines * width ; i++) {
- ((u32 *)dest)[0]=bgx;
+ fb_writel (bgx, dest);
dest+=4;
}
} else {
dest=dest0;
for (i = 0 ; i < width ; i++) {
/* memset ?? */
- ((u32 *)dest)[0]=bgx;
+ fb_writel (bgx, dest);
dest+=4;
}
}
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);
}
}
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;
}
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);
}
}
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;
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;
}
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;
}
int linesize)
{
while (height-- > 0) {
- memset(dest, data, width);
+ fb_memset(dest, data, width);
dest += linesize;
}
}
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;
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;
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;
}
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);
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;
}
}
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 {
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;
}
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);
}
}
}
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;
}
}
/* 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 {
}
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;
}
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)
/* 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.
*/
/* 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 {
}
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;
}
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) {
/* 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.
*/
/* 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.
*/
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;
}
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;
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);
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;
}
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;
}
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;
}
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,
d |= d>>1;
if (revs)
d = ~d;
- *dest = d;
+ fb_writeb (d, dest);
}
}
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,
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);
}
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);
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;
}
}
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);
}
}
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);
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;
(*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
#else
for( i = bdepth-1; i >= 0; --i )
#endif
- *dst++ = val >> (i*8);
+ fb_writeb (val >> (i*8), dst++);
}
}
}
#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) |
#else
for( i = bdepth-1; i >= 0; --i )
#endif
- *dst++ = val >> (i*8);
+ fb_writeb (val >> (i*8), dst++);
}
}
}
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
#else
for( i = bdepth-1; i >= 0; --i )
#endif
- *dst++ = val >> (i*8);
+ fb_writeb (val >> (i*8), dst++);
}
}
}
for( x1 = 0; x1 < LOGO_W/2; x1++) {
u8 q = *src++;
q = (q << 4) | (q >> 4);
- *dst++ = q;
+ fb_writeb (q, dst++);
}
}
done = 1;
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;
}
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;
}
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++;
}
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
} 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;
};
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);
}
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 */
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);
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);
#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))
*
* 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
#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>
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;
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,
platinum_ioctl
};
-
-__openfirmware
-
-
static int platinum_open(struct fb_info *info, int user)
{
MOD_INC_USE_COUNT;
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)
{
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;
return 0;
}
+ init = platinum_reg_init[par.vmode-1];
+
oldxres = display->var.xres;
oldyres = display->var.yres;
oldvxres = display->var.xres_virtual;
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;
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) {
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);
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;
}
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;
{
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;
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
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] :
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;
#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)
{
struct fb_info_platinum *info;
unsigned long addr, size;
+ volatile __u8 *fbuffer;
int i, bank0, bank1, bank2, bank3;
if(dp->n_addrs != 2) {
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);
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;
} 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;
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);
--- /dev/null
+/*
+ *
+ * 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(®, 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(®);
+
+ 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);
+ }
+}
+
#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>
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;
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;
* Initialization
*/
-void __init virgefb_init(void)
+int __init virgefb_init(void)
{
struct virgefb_par par;
unsigned long board_addr;
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
/*
* 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);
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.
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);
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)))) {
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)))) {
/*
* count() counts the number of arguments/envelopes
*/
-static int count(char ** argv)
+static int count(char ** argv, int max)
{
int i = 0;
if (!p)
break;
argv++;
- i++;
+ if(++i > max)
+ return -E2BIG;
}
}
return i;
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;
/* XXX: add architecture specific overflow check here. */
pos = bprm->p;
- while (len) {
+ while (len>0) {
char *pag;
int offset, bytes_to_copy;
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;
}
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;
}
#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);
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) &&
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;
}
}
-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) {
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;
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;
}
}
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)
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;
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);
* 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);
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;
/*
* 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;
/*
#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)
{
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)
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 ...
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;
}
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.
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;
}
dir->u.smbfs_i.cache_valid &= ~SMB_F_CACHEVALID;
dir->u.smbfs_i.oldmtime = 0;
}
-
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)
{
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",
} 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;
}
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;
}
/*
* 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)
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;
}
* 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;
#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+
#define KEYBOARD_IRQ 1
#define DISABLE_KBD_DURING_INTERRUPTS 0
#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 */
--- /dev/null
+#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
#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..
* 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
#define __HAVE_ARCH_STRRCHR
extern inline char * strrchr(const char * s, int c)
{
+int d0, d1;
register char * __res;
__asm__ __volatile__(
"cld\n\t"
"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"
"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"
"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"
"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" \
"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;
}
#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"
"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 */
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"
"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);
}
#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"
"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;
"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;
}
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"
"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"
"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;
}
}
#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)
{
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);
#ifdef __KERNEL__
+#include <linux/ioport.h>
+#include <asm/io.h>
+
#define KEYBOARD_IRQ 13
#define DISABLE_KBD_DURING_INTERRUPTS 0
/* #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) */
#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" */
#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 *);
* 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.
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);
--- /dev/null
+/*
+ * 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];
+};
/*
* SyncLink Multiprotocol Serial Adapter Driver
*
- * ==FILEDATE 19990523==
+ * ==FILEDATE 19990810==
*
* Copyright (C) 1998 by Microgate Corporation
*
#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
#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
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;
#include <linux/console_struct.h>
#include <linux/vt_buffer.h>
+#include <asm/io.h>
+
/*
* `switch' for the Low Level Operations
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);
}
-static __inline__ void *mymemclear(void *s, size_t count)
+static __inline__ void *fb_memclear(void *s, size_t count)
{
if (!count)
return(0);
}
-static __inline__ void *mymemset(void *s, size_t count)
+static __inline__ void *fb_memset255(void *s, size_t count)
{
if (!count)
return(0);
}
-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) {
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);
}
((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;
#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));
}
}
}
-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;
* (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));
}
#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
#define fb_writeb __raw_writeb
#define fb_writew __raw_writew
#define fb_writel __raw_writel
+#define fb_memset memset_io
#else
#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
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);
/*
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;
}
}
{
struct siginfo info;
+ memset(&info, 0, sizeof(info));
+
info.si_signo = sig;
info.si_errno = 0;
info.si_code = SI_USER;
ahead = 0;
while (ahead < max_ahead) {
ahead += PAGE_CACHE_SIZE;
+ if ((raend + ahead) >= inode->i_size)
+ break;
page_cache_read(filp, raend + ahead);
}
/*
long status;
int err;
+ down(&inode->i_sem);
err = file->f_error;
if (err) {
file->f_error = 0;
err = written ? written : status;
out:
+ up(&inode->i_sem);
return err;
}
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);
}
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);
}
/* 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);
}
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);
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);
}
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) {
*/
if (!sk->dead) {
wake_up_interruptible(sk->sleep);
- sock_wake_async(sk->socket,1);
+ sock_wake_async(sk->socket,1, POLL_IN);
}
return(1);
}
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
* 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);
if(!sk->dead) {
wake_up_interruptible(sk->sleep);
- sock_wake_async(sk->socket, 0);
+ sock_wake_async(sk->socket, 0, POLL_IN);
}
return -1;
}
*/
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;
/* 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;
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;
}
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);
}
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;