diff -u --recursive --new-file v2.3.20/linux/Documentation/Changes linux/Documentation/Changes --- v2.3.20/linux/Documentation/Changes Tue Aug 31 17:29:12 1999 +++ linux/Documentation/Changes Sun Oct 10 08:47:02 1999 @@ -392,6 +392,8 @@ Due to changes in the PPP driver and routing code, those of you using PPP networking will need to upgrade your pppd. +See ftp://cs.anu.edu.au/pub/software/ppp/ for newest versions. + iBCS ==== diff -u --recursive --new-file v2.3.20/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.3.20/linux/Documentation/Configure.help Sat Oct 9 11:47:49 1999 +++ linux/Documentation/Configure.help Sat Oct 9 18:51:41 1999 @@ -1976,8 +1976,9 @@ - "386" for the AMD/Cyrix/Intel 386DX/DXL/SL/SLC/SX, Cyrix/TI 486DLC/DLC2 and UMC 486SX-S. Only "386" kernels will run on a 386 class machine. - - "486" for the AMD/Cyrix/IBM/Intel DX4 or 486DX/DX2/SL/SX/SX2, - AMD/Cyrix 5x86, NexGen Nx586 and UMC U5D or U5S. + - "486" for the AMD/Cyrix/IBM/Intel 486DX/DX2/DX4 or + SL/SLC/SLC2/SLC3/SX/SX2, AMD/Cyrix 5x86, NexGen Nx586 and + UMC U5D or U5S. - "586" for generic Pentium CPUs, possibly lacking the TSC (time stamp counter) register. - "Pentium" for the Intel Pentium/Pentium MMX, AMD K5, K6 and @@ -2120,7 +2121,7 @@ Say N unless you have such a graphics board or plan to get one before you next recompile the kernel. -Permedia2 support (experimental) +Permedia2 support (EXPERIMENTAL) CONFIG_FB_PM2 Say Y here if this is your graphics board. @@ -8063,7 +8064,7 @@ The module will be called ntfs.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -NTFS read-write support (experimental) +NTFS read-write support (EXPERIMENTAL) CONFIG_NTFS_RW If you say Y here, you will (hopefully) be able to write to NTFS file systems as well as read from them. The read-write support @@ -8128,7 +8129,7 @@ The module is called affs.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say N. -Apple Macintosh filesystem support (experimental) +Apple Macintosh filesystem support (EXPERIMENTAL) CONFIG_HFS_FS If you say Y here, you will be able to mount Macintosh-formatted floppy disks and hard drive partitions with full read-write access. @@ -8192,7 +8193,7 @@ If you are not a part of a fairly large, distributed network, you probably do not need an automounter, and can say N here. -EFS filesystem support (experimental) +EFS filesystem support (EXPERIMENTAL) CONFIG_EFS_FS EFS is an older filesystem used for non-ISO9660 CDROMs and hard disk partitions by SGI's IRIX operating system (IRIX 6.0 and newer uses @@ -8202,7 +8203,7 @@ what all this is about, it's safe to say N. For more information about EFS see its home page at http://aeschi.ch.eu.org/efs/ . - If you want to compile the UFS filesystem support as a module ( = + If you want to compile the EFS filesystem support as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. The module will be called efs.o. @@ -8242,7 +8243,7 @@ If you haven't heard about all of this before, it's safe to say N. -UFS filesystem write support (experimental) +UFS filesystem write support (EXPERIMENTAL) CONFIG_UFS_FS_WRITE Say Y here if you want to try writing to UFS partitions. This is experimental, so you should back up your UFS partitions beforehand. @@ -12593,7 +12594,7 @@ If unsure, say N. -Kernel httpd acceleration (experimental) +Kernel httpd acceleration (EXPERIMENTAL) CONFIG_KHTTPD The kernel httpd acceleration daemon (kHTTPd) is a (limited) web server build into the kernel. It is limited since it can only diff -u --recursive --new-file v2.3.20/linux/Documentation/fb/clgenfb.txt linux/Documentation/fb/clgenfb.txt --- v2.3.20/linux/Documentation/fb/clgenfb.txt Fri Sep 10 23:57:27 1999 +++ linux/Documentation/fb/clgenfb.txt Mon Oct 11 10:06:33 1999 @@ -45,9 +45,7 @@ Version 1.9.4.4 --------------- * Preliminary Laguna support -* Overhaul color register routines. Shifts are now based on offset - values in var.cmap, so as long as those are correctly set for PReP - things should work (knock on wood). +* Overhaul color register routines. * Associated with the above, console colors are now obtained from a LUT called 'palette' instead of from the VGA registers. This code was modeled after that in atyfb and matroxfb. diff -u --recursive --new-file v2.3.20/linux/Documentation/fb/framebuffer.txt linux/Documentation/fb/framebuffer.txt --- v2.3.20/linux/Documentation/fb/framebuffer.txt Thu Aug 26 13:05:34 1999 +++ linux/Documentation/fb/framebuffer.txt Mon Oct 11 13:53:09 1999 @@ -2,7 +2,7 @@ ----------------------- Maintained by Geert Uytterhoeven -Last revised: November 7, 1998 +Last revised: October 7, 1999 0. Introduction @@ -304,7 +304,20 @@ o linux/include/video/ -8. Downloading + +8. Mailing list +--------------- + +There's a _development_ mailing list at linux-fbdev@vuser.vu.union.edu, +controlled by majordomo. Send an email with `help' in the message body to +majordomo@vuser.vu.union.edu for subscription information. + +The mailing list is archived at + + http://www.mail-archive.com/linux-fbdev@vuser.vu.union.edu/ + + +9. Downloading -------------- All necessary files can be found at @@ -313,8 +326,12 @@ and on its mirrors. +The latest version of fbset can be found at + + http://www.cs.kuleuven.ac.be/~geert/bin/ + -9. Credits +10. Credits ---------- This readme was written by Geert Uytterhoeven, partly based on the original diff -u --recursive --new-file v2.3.20/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt --- v2.3.20/linux/Documentation/ioctl-number.txt Fri Sep 10 23:57:27 1999 +++ linux/Documentation/ioctl-number.txt Mon Oct 11 10:18:07 1999 @@ -1,5 +1,5 @@ Ioctl Numbers -2 September 1999 +10 October 1999 Michael Elizabeth Chastain @@ -114,6 +114,8 @@ 'e' 00-1F linux/video_encoder.h conflict! 'e' 00-1F net/irda/irtty.h conflict! 'f' 00-1F linux/ext2_fs.h +'h' 00-7F Charon filesystem + 'i' 00-3F linux/i2o.h 'j' 00-3F linux/joystick.h 'k' all asm-sparc/kbio.h @@ -140,6 +142,8 @@ 'v' 00-1F linux/ext2_fs.h conflict! 'v' all linux/videodev.h conflict! 'w' all CERN SCI driver +'y' 00-1F packet based user level communications + 'z' 00-3F CAN bus card 'z' 40-7F CAN bus card diff -u --recursive --new-file v2.3.20/linux/Makefile linux/Makefile --- v2.3.20/linux/Makefile Sat Oct 9 11:47:50 1999 +++ linux/Makefile Mon Oct 11 10:13:24 1999 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 3 -SUBLEVEL = 20 +SUBLEVEL = 21 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -125,6 +125,18 @@ endif DRIVERS := $(DRIVERS) drivers/net/net.a + +ifdef CONFIG_NET_FC +DRIVERS := $(DRIVERS) drivers/net/fc/fc.a +endif + +ifdef CONFIG_TR +DRIVERS := $(DRIVERS) drivers/net/tokenring/tr.a +endif + +ifdef CONFIG_WAN +DRIVERS := $(DRIVERS) drivers/net/wan/wan.a +endif ifdef CONFIG_ATM DRIVERS := $(DRIVERS) drivers/atm/atm.a diff -u --recursive --new-file v2.3.20/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c --- v2.3.20/linux/arch/alpha/kernel/alpha_ksyms.c Tue Aug 31 17:29:12 1999 +++ linux/arch/alpha/kernel/alpha_ksyms.c Mon Oct 11 10:06:34 1999 @@ -139,7 +139,7 @@ EXPORT_SYMBOL_NOVERS(__copy_user); EXPORT_SYMBOL_NOVERS(__do_clear_user); EXPORT_SYMBOL(__strncpy_from_user); -EXPORT_SYMBOL(__strlen_user); +EXPORT_SYMBOL(__strnlen_user); /* * The following are specially called from the semaphore assembly stubs. diff -u --recursive --new-file v2.3.20/linux/arch/alpha/lib/strlen_user.S linux/arch/alpha/lib/strlen_user.S --- v2.3.20/linux/arch/alpha/lib/strlen_user.S Sat Apr 24 17:54:08 1999 +++ linux/arch/alpha/lib/strlen_user.S Mon Oct 11 10:06:34 1999 @@ -3,6 +3,13 @@ * * Return the length of the string including the NUL terminator * (strlen+1) or zero if an error occurred. + * + * In places where it is critical to limit the processing time, + * and the data is not trusted, strnlen_user() should be used. + * It will return a value greater than its second argument if + * that limit would be exceeded. This implementation is allowed + * to access memory beyond the limit, but will not cross a page + * boundary when doing so. */ #include @@ -27,6 +34,14 @@ .align 3 __strlen_user: + ldah a1, 32767(zero) # do not use plain strlen_user() for strings + # that might be almost 2 GB long; you should + # be using strnlen_user() instead + + .globl __strnlen_user + + .align 3 +__strnlen_user: ldgp $29,0($27) # we do exceptions -- we need the gp. .prologue 1 @@ -37,9 +52,17 @@ or t1, t0, t0 subq a0, 1, a0 # get our +1 for the return cmpbge zero, t0, t1 # t1 <- bitmask: bit i == 1 <==> i-th byte == 0 + subq a1, 7, t2 + subq a0, v0, t0 bne t1, $found -$loop: EX( ldq t0, 8(v0) ) + addq t2, t0, t2 + addq a1, 1, a1 + + .align 3 +$loop: ble t2, $limit + EX( ldq t0, 8(v0) ) + subq t2, 8, t2 addq v0, 8, v0 # addr += 8 cmpbge zero, t0, t1 beq t1, $loop @@ -59,6 +82,11 @@ nop # dual issue next two on ev4 and ev5 subq v0, a0, v0 $exception: + ret + + .align 3 # currently redundant +$limit: + subq a1, t2, v0 ret .end __strlen_user diff -u --recursive --new-file v2.3.20/linux/arch/i386/boot/Makefile linux/arch/i386/boot/Makefile --- v2.3.20/linux/arch/i386/boot/Makefile Tue Aug 31 17:29:12 1999 +++ linux/arch/i386/boot/Makefile Mon Oct 11 14:06:10 1999 @@ -8,9 +8,6 @@ # Copyright (C) 1994 by Linus Torvalds # -AS86 =$(CROSS_COMPILE)as86 -0 -a -LD86 =$(CROSS_COMPILE)ld86 -0 - BOOT_INCL = $(TOPDIR)/include/linux/config.h \ $(TOPDIR)/include/linux/autoconf.h \ $(TOPDIR)/include/asm/boot.h @@ -45,40 +42,40 @@ tools/build: tools/build.c $(HOSTCC) $(HOSTCFLAGS) -o $@ $< -I$(TOPDIR)/include -setup: setup.o - $(LD86) -s -o $@ $< +bootsect: bootsect.o + $(LD) -Ttext 0x0 -s -oformat binary -o $@ $< -setup.o: setup.s - $(AS86) -o $@ $< +bootsect.o: bootsect.s + $(AS) -o $@ $< -setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h +bootsect.s: bootsect.S Makefile $(BOOT_INCL) $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ -bsetup: bsetup.o - $(LD86) -s -o $@ $< +bbootsect: bbootsect.o bsetup + $(LD) -Ttext 0x0 -s -oformat binary $< -R bsetup.o -o $@ -bsetup.o: bsetup.s - $(AS86) -o $@ $< +bbootsect.o: bbootsect.s + $(AS) -o $@ $< -bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h +bbootsect.s: bootsect.S Makefile $(BOOT_INCL) $(CPP) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ -bootsect: bootsect.o - $(LD86) -s -o $@ $< +setup: setup.o + $(LD) -Ttext 0x0 -s -oformat binary -e begtext -o $@ $< -bootsect.o: bootsect.s - $(AS86) -o $@ $< +setup.o: setup.s + $(AS) -o $@ $< -bootsect.s: bootsect.S Makefile $(BOOT_INCL) +setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ -bbootsect: bbootsect.o - $(LD86) -s -o $@ $< +bsetup: bsetup.o + $(LD) -Ttext 0x0 -s -oformat binary -e begtext -o $@ $< -bbootsect.o: bbootsect.s - $(AS86) -o $@ $< +bsetup.o: bsetup.s + $(AS) -o $@ $< -bbootsect.s: bootsect.S Makefile $(BOOT_INCL) +bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h $(CPP) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ dep: diff -u --recursive --new-file v2.3.20/linux/arch/i386/boot/bootsect.S linux/arch/i386/boot/bootsect.S --- v2.3.20/linux/arch/i386/boot/bootsect.S Thu Aug 26 13:05:34 1999 +++ linux/arch/i386/boot/bootsect.S Mon Oct 11 14:06:10 1999 @@ -1,464 +1,423 @@ -! -! bootsect.s Copyright (C) 1991, 1992 Linus Torvalds -! modified by Drew Eckhardt -! modified by Bruce Evans (bde) -! -! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves -! itself out of the way to address 0x90000, and jumps there. -! -! bde - should not jump blindly, there may be systems with only 512K low -! memory. Use int 0x12 to get the top of memory, etc. -! -! It then loads 'setup' directly after itself (0x90200), and the system -! at 0x10000, using BIOS interrupts. -! -! NOTE! currently system is at most (8*65536-4096) bytes long. This should -! be no problem, even in the future. I want to keep it simple. This 508 kB -! kernel size should be enough, especially as this doesn't contain the -! buffer cache as in minix (and especially now that the kernel is -! compressed :-) -! -! The loader has been made as simple as possible, and continuous -! read errors will result in a unbreakable loop. Reboot by hand. It -! loads pretty fast by getting whole tracks at a time whenever possible. +/* + * bootsect.S Copyright (C) 1991, 1992 Linus Torvalds + * + * modified by Drew Eckhardt + * modified by Bruce Evans (bde) + * modified by Chris Noe (May 1999) (as86 -> gas) + * + * bootsect is loaded at 0x7c00 by the bios-startup routines, and moves + * itself out of the way to address 0x90000, and jumps there. + * + * bde - should not jump blindly, there may be systems with only 512K low + * memory. Use int 0x12 to get the top of memory, etc. + * + * It then loads 'setup' directly after itself (0x90200), and the system + * at 0x10000, using BIOS interrupts. + * + * NOTE! currently system is at most (8*65536-4096) bytes long. This should + * be no problem, even in the future. I want to keep it simple. This 508 kB + * kernel size should be enough, especially as this doesn't contain the + * buffer cache as in minix (and especially now that the kernel is + * compressed :-) + * + * The loader has been made as simple as possible, and continuous + * read errors will result in a unbreakable loop. Reboot by hand. It + * loads pretty fast by getting whole tracks at a time whenever possible. + */ -#include /* for CONFIG_ROOT_RDONLY */ +#include /* for CONFIG_ROOT_RDONLY */ #include -.text +SETUPSECS = 4 /* default nr of setup-sectors */ +BOOTSEG = 0x07C0 /* original address of boot-sector */ +INITSEG = DEF_INITSEG /* we move boot here - out of the way */ +SETUPSEG = DEF_SETUPSEG /* setup starts here */ +SYSSEG = DEF_SYSSEG /* system loaded at 0x10000 (65536) */ +SYSSIZE = DEF_SYSSIZE /* system size: # of 16-byte clicks */ + /* to be loaded */ +ROOT_DEV = 0 /* ROOT_DEV is now written by "build" */ +SWAP_DEV = 0 /* SWAP_DEV is now written by "build" */ -SETUPSECS = 4 ! default nr of setup-sectors -BOOTSEG = 0x07C0 ! original address of boot-sector -INITSEG = DEF_INITSEG ! we move boot here - out of the way -SETUPSEG = DEF_SETUPSEG ! setup starts here -SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536). -SYSSIZE = DEF_SYSSIZE ! system size: number of 16-byte clicks - ! to be loaded - -! ROOT_DEV & SWAP_DEV are now written by "build". -ROOT_DEV = 0 -SWAP_DEV = 0 #ifndef SVGA_MODE #define SVGA_MODE ASK_VGA #endif + #ifndef RAMDISK #define RAMDISK 0 #endif + #ifndef CONFIG_ROOT_RDONLY #define CONFIG_ROOT_RDONLY 1 #endif -! ld86 requires an entry symbol. This may as well be the usual one. -.globl _main -_main: +.code16 +.text + +.global _start +_start: + #if 0 /* hook for debugger, harmless unless BIOS is fussy (old HP) */ - int 3 + int $0x3 #endif - mov ax,#BOOTSEG - mov ds,ax - mov ax,#INITSEG - mov es,ax - mov cx,#128 - sub si,si - sub di,di + + movw $BOOTSEG, %ax + movw %ax, %ds + movw $INITSEG, %ax + movw %ax, %es + movw $128, %cx + subw %si, %si + subw %di, %di cld rep - movsd - jmpi go,INITSEG - -! ax and es already contain INITSEG - -go: mov di,#0x4000-12 ! 0x4000 is arbitrary value >= length of - ! bootsect + length of setup + room for stack - ! 12 is disk parm size - -! bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde). We -! wouldn't have to worry about this if we checked the top of memory. Also -! my BIOS can be configured to put the wini drive tables in high memory -! instead of in the vector table. The old stack might have clobbered the -! drive table. - - mov ds,ax - mov ss,ax ! put stack at INITSEG:0x4000-12. - mov sp,di -/* - * Many BIOS's default disk parameter tables will not - * recognize multi-sector reads beyond the maximum sector number - * specified in the default diskette parameter tables - this may - * mean 7 sectors in some cases. - * - * Since single sector reads are slow and out of the question, - * we must take care of this by creating new parameter tables - * (for the first disk) in RAM. We will set the maximum sector - * count to 36 - the most we will encounter on an ED 2.88. - * - * High doesn't hurt. Low does. - * - * Segments are as follows: ds=es=ss=cs - INITSEG, - * fs = 0, gs is unused. - */ - -! cx contains 0 from rep movsd above + movsl + ljmp $INITSEG, $go - mov fs,cx - mov bx,#0x78 ! fs:bx is parameter table address - push ds - seg fs - lds si,(bx) ! ds:si is source - - mov cl,#3 ! copy 12 bytes +# bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde). We +# wouldn't have to worry about this if we checked the top of memory. Also +# my BIOS can be configured to put the wini drive tables in high memory +# instead of in the vector table. The old stack might have clobbered the +# drive table. + +go: movw $0x4000-12, %di # 0x4000 is an arbitrary value >= + # length of bootsect + length of + # setup + room for stack; + # 12 is disk parm size. + movw %ax, %ds # ax and es already contain INITSEG + movw %ax, %ss + movw %di, %sp # put stack at INITSEG:0x4000-12. + +# Many BIOS's default disk parameter tables will not recognize +# multi-sector reads beyond the maximum sector number specified +# in the default diskette parameter tables - this may mean 7 +# sectors in some cases. +# +# Since single sector reads are slow and out of the question, +# we must take care of this by creating new parameter tables +# (for the first disk) in RAM. We will set the maximum sector +# count to 36 - the most we will encounter on an ED 2.88. +# +# High doesn't hurt. Low does. +# +# Segments are as follows: ds = es = ss = cs - INITSEG, fs = 0, +# and gs is unused. + + movw %cx, %fs # set fs to 0 + movw $0x78, %bx # fs:bx is parameter table address + pushw %ds + ldsw %fs:(%bx), %si # ds:si is source + movb $3, %cl # copy 12 bytes cld - push di - + pushw %di # di = 0x4000-12. rep - movsd - - pop di - pop ds - - movb 4(di),*36 ! patch sector count - - seg fs - mov (bx),di - seg fs - mov 2(bx),es - -! load the setup-sectors directly after the bootblock. -! Note that 'es' is already set up. -! Also cx is 0 from rep movsd above. + movsl + popw %di + popw %ds + movb $36, 0x4(%di) # patch sector count + movw %di, %fs:(%bx) + movw %es, %fs:2(%bx) + +# Load the setup-sectors directly after the bootblock. +# Note that 'es' is already set up. +# Also, cx = 0 from rep movsl above. load_setup: - xor ah,ah ! reset FDC - xor dl,dl - int 0x13 - - xor dx, dx ! drive 0, head 0 - mov cl,#0x02 ! sector 2, track 0 - mov bx,#0x0200 ! address = 512, in INITSEG - mov ah,#0x02 ! service 2, nr of sectors - mov al,setup_sects ! (assume all on head 0, track 0) - int 0x13 ! read it - jnc ok_load_setup ! ok - continue + xorb %ah, %ah # reset FDC + xorb %dl, %dl + int $0x13 + xorw %dx, %dx # drive 0, head 0 + movb $0x02, %cl # sector 2, track 0 + movw $0x0200, %bx # address = 512, in INITSEG + movb $0x02, %ah # service 2, "read sector(s)" + movb setup_sects, %al # (assume all on head 0, track 0) + int $0x13 # read it + jnc ok_load_setup # ok - continue - push ax ! dump error code + pushw %ax # dump error code call print_nl - mov bp, sp + movw %sp, %bp call print_hex - pop ax - + popw %ax jmp load_setup ok_load_setup: - -! Get disk drive parameters, specifically nr of sectors/track +# Get disk drive parameters, specifically nr of sectors/track. #if 0 -! bde - the Phoenix BIOS manual says function 0x08 only works for fixed -! disks. It doesn't work for one of my BIOS's (1987 Award). It was -! fatal not to check the error code. - - xor dl,dl - mov ah,#0x08 ! AH=8 is get drive parameters - int 0x13 - xor ch,ch -#else +# bde - the Phoenix BIOS manual says function 0x08 only works for fixed +# disks. It doesn't work for one of my BIOS's (1987 Award). It was +# fatal not to check the error code. + + xorb %dl, %dl + movb $0x08, %ah # AH=8 is get drive parameters + int $0x13 + xorb %ch, %ch -! It seems that there is no BIOS call to get the number of sectors. Guess -! 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read, -! 15 if sector 15 can be read. Otherwise guess 9. +#else - mov si,#disksizes ! table of sizes to try +# It seems that there is no BIOS call to get the number of sectors. +# Guess 36 sectors if sector 36 can be read, 18 sectors if sector 18 +# can be read, 15 if sector 15 can be read. Otherwise guess 9. + movw $disksizes, %si # table of sizes to try probe_loop: lodsb - cbw ! extend to word - mov sectors, ax - cmp si,#disksizes+4 - jae got_sectors ! if all else fails, try 9 - xchg ax, cx ! cx = track and sector - xor dx, dx ! drive 0, head 0 - xor bl, bl - mov bh,setup_sects - inc bh - shl bh,#1 ! address after setup (es = cs) - mov ax,#0x0201 ! service 2, 1 sector - int 0x13 - jc probe_loop ! try next value - + cbtw # extend to word + movw %ax, sectors + cmpw $disksizes+4, %si + jae got_sectors # if all else fails, try 9 + + xchgw %cx, %ax # cx = track and sector + xorw %dx, %dx # drive 0, head 0 + xorb %bl, %bl + movb setup_sects, %bh + incb %bh + shlb %bh # address after setup (es = cs) + movw $0x0201, %ax # service 2, 1 sector + int $0x13 + jc probe_loop # try next value #endif got_sectors: - -! Restore es - - mov ax,#INITSEG - mov es,ax - -! Print some inane message - - mov ah,#0x03 ! read cursor pos - xor bh,bh - int 0x10 - - mov cx,#9 - mov bx,#0x0007 ! page 0, attribute 7 (normal) - mov bp,#msg1 - mov ax,#0x1301 ! write string, move cursor - int 0x10 - -! ok, we've written the message, now -! we want to load the system (at 0x10000) - - mov ax,#SYSSEG - mov es,ax ! segment of 0x010000 + movw $INITSEG, %ax + movw %ax, %es # set up es + movb $0x03, %ah # read cursor pos + xorb %bh, %bh + int $0x10 + movw $9, %cx + movw $0x0007, %bx # page 0, attribute 7 (normal) + movw $msg1, %bp + movw $0x1301, %ax # write string, move cursor + int $0x10 # tell the user we're loading.. + movw $SYSSEG, %ax # ok, we've written the message, now + movw %ax, %es # we want to load system (at 0x10000) call read_it call kill_motor call print_nl -! After that we check which root-device to use. If the device is -! defined (!= 0), nothing is done and the given device is used. -! Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8), -! depending on the number of sectors we pretend to know we have. - - seg cs - mov ax,root_dev - or ax,ax +# After that we check which root-device to use. If the device is +# defined (!= 0), nothing is done and the given device is used. +# Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8) +# depending on the number of sectors we pretend to know we have. + + movw %cs:root_dev, %ax + orw %ax, %ax jne root_defined - seg cs - mov bx,sectors - mov ax,#0x0208 ! /dev/ps0 - 1.2Mb - cmp bx,#15 + + movw %cs:sectors, %bx + movw $0x0208, %ax # /dev/ps0 - 1.2Mb + cmpw $15, %bx je root_defined - mov al,#0x1c ! /dev/PS0 - 1.44Mb - cmp bx,#18 + + movb $0x1c, %al # /dev/PS0 - 1.44Mb + cmpw $18, %bx je root_defined - mov al,#0x20 ! /dev/fd0H2880 - 2.88Mb - cmp bx,#36 + + movb $0x20, %al # /dev/fd0H2880 - 2.88Mb + cmpw $36, %bx je root_defined - mov al,#0 ! /dev/fd0 - autodetect + + movb $0, %al # /dev/fd0 - autodetect root_defined: - seg cs - mov root_dev,ax + movw %ax, %cs:root_dev + +# After that (everything loaded), we jump to the setup-routine +# loaded directly after the bootblock: + + ljmp $SETUPSEG, $0 + +# This routine loads the system at address 0x10000, making sure +# no 64kB boundaries are crossed. We try to load it as fast as +# possible, loading whole tracks whenever we can. -! after that (everything loaded), we jump to -! the setup-routine loaded directly after -! the bootblock: - - jmpi 0,SETUPSEG - -! This routine loads the system at address 0x10000, making sure -! no 64kB boundaries are crossed. We try to load it as fast as -! possible, loading whole tracks whenever we can. -! -! in: es - starting address segment (normally 0x1000) -! -sread: .word 0 ! sectors read of current track -head: .word 0 ! current head -track: .word 0 ! current track +# es = starting address segment (normally 0x1000) + +sread: .word 0 # sectors read of current track +head: .word 0 # current head +track: .word 0 # current track read_it: - mov al,setup_sects - inc al - mov sread,al - mov ax,es - test ax,#0x0fff -die: jne die ! es must be at 64kB boundary - xor bx,bx ! bx is starting address within segment + movb setup_sects, %al + incb %al + movb %al, sread + movw %es, %ax + testw $0x0fff, %ax +die: jne die # es must be at 64kB boundary + + xorw %bx, %bx # bx is starting address within segment rp_read: #ifdef __BIG_KERNEL__ -#define CALL_HIGHLOAD_KLUDGE .word 0x1eff,0x220 ! call far * bootsect_kludge - ! NOTE: as86 can't assemble this - CALL_HIGHLOAD_KLUDGE ! this is within setup.S + lcall bootsect_kludge # in setup.S #else - mov ax,es - sub ax,#SYSSEG + movw %es, %ax + subw $SYSSEG, %ax #endif - cmp ax,syssize ! have we loaded all yet? - jbe ok1_read + cmpw syssize, %ax # have we loaded all yet? + jbe ok1_read + ret + ok1_read: - mov ax,sectors - sub ax,sread - mov cx,ax - shl cx,#9 - add cx,bx - jnc ok2_read - je ok2_read - xor ax,ax - sub ax,bx - shr ax,#9 + movw sectors, %ax + subw sread, %ax + movw %ax, %cx + shlw $9, %cx + addw %bx, %cx + jnc ok2_read + + je ok2_read + + xorw %ax, %ax + subw %bx, %ax + shrw $9, %ax ok2_read: - call read_track - mov cx,ax - add ax,sread - cmp ax,sectors - jne ok3_read - mov ax,#1 - sub ax,head - jne ok4_read - inc track + call read_track + movw %ax, %cx + addw sread, %ax + cmpw sectors, %ax + jne ok3_read + + movw $1, %ax + subw head, %ax + jne ok4_read + + incw track ok4_read: - mov head,ax - xor ax,ax + movw %ax, head + xorw %ax, %ax ok3_read: - mov sread,ax - shl cx,#9 - add bx,cx - jnc rp_read - mov ax,es - add ah,#0x10 - mov es,ax - xor bx,bx - jmp rp_read + movw %ax, sread + shlw $9, %cx + addw %cx, %bx + jnc rp_read + + movw %es, %ax + addb $0x10, %ah + movw %ax, %es + xorw %bx, %bx + jmp rp_read read_track: pusha pusha - mov ax, #0xe2e ! loading... message 2e = . - mov bx, #7 - int 0x10 + movw $0xe2e, %ax # loading... message 2e = . + movw $7, %bx + int $0x10 popa - - mov dx,track - mov cx,sread - inc cx - mov ch,dl - mov dx,head - mov dh,dl - and dx,#0x0100 - mov ah,#2 - - push dx ! save for error dump - push cx - push bx - push ax - - int 0x13 + movw track, %dx + movw sread, %cx + incw %cx + movb %dl, %ch + movw head, %dx + movb %dl, %dh + andw $0x0100, %dx + movb $2, %ah + pushw %dx # save for error dump + pushw %cx + pushw %bx + pushw %ax + int $0x13 jc bad_rt - add sp, #8 + + addw $8, %sp popa ret -bad_rt: push ax ! save error code - call print_all ! ah = error, al = read - - - xor ah,ah - xor dl,dl - int 0x13 - - - add sp, #10 - popa +bad_rt: + pushw %ax # save error code + call print_all # ah = error, al = read + xorb %ah, %ah + xorb %dl, %dl + int $0x13 + addw $10, %sp + popa jmp read_track -/* - * print_all is for debugging purposes. - * It will print out all of the registers. The assumption is that this is - * called from a routine, with a stack frame like - * dx - * cx - * bx - * ax - * error - * ret <- sp - * -*/ +# print_all is for debugging purposes. +# +# it will print out all of the registers. The assumption is that this is +# called from a routine, with a stack frame like +# +# %dx +# %cx +# %bx +# %ax +# (error) +# ret <- %sp print_all: - mov cx, #5 ! error code + 4 registers - mov bp, sp - + movw $5, %cx # error code + 4 registers + movw %sp, %bp print_loop: - push cx ! save count left - call print_nl ! nl for readability - - cmp cl, #5 - jae no_reg ! see if register name is needed + pushw %cx # save count left + call print_nl # nl for readability + cmpb $5, %cl + jae no_reg # see if register name is needed - mov ax, #0xe05 + 'A - 1 - sub al, cl - int 0x10 - - mov al, #'X - int 0x10 - - mov al, #': - int 0x10 - + movw $0xe05 + 'A' - 1, %ax + subb %cl, %al + int $0x10 + movb $'X', %al + int $0x10 + movb $':', %al + int $0x10 no_reg: - add bp, #2 ! next register - call print_hex ! print it - pop cx + addw $2, %bp # next register + call print_hex # print it + popw %cx loop print_loop ret print_nl: - mov ax, #0xe0d ! CR - int 0x10 - mov al, #0xa ! LF - int 0x10 + movw $0xe0d, %ax # CR + int $0x10 + movb $0xa, %al # LF + int $0x10 ret -/* - * print_hex is for debugging purposes, and prints the word - * pointed to by ss:bp in hexadecimal. -*/ +# print_hex is for debugging purposes, and prints the word +# pointed to by ss:bp in hexadecimal. print_hex: - mov cx, #4 ! 4 hex digits - mov dx, (bp) ! load word into dx + movw $4, %cx # 4 hex digits + movw (%bp), %dx # load word into dx print_digit: - rol dx, #4 ! rotate so that lowest 4 bits are used - mov ax, #0xe0f ! ah = request, al = mask for nybble - and al, dl - add al, #0x90 ! convert al to ASCII hex (four instructions) + rolw $4, %dx # rotate to use low 4 bits + movw $0xe0f, %ax # ah = request + andb %dl, %al # al = mask for nybble + addb $0x90, %al # convert al to ascii hex + daa # in only four instructions! + adc $0x40, %al daa - adc al, #0x40 - daa - int 0x10 + int $0x10 loop print_digit ret +# This procedure turns off the floppy drive motor, so +# that we enter the kernel in a known state, and +# don't have to worry about it later. -/* - * This procedure turns off the floppy drive motor, so - * that we enter the kernel in a known state, and - * don't have to worry about it later. - */ kill_motor: - push dx - mov dx,#0x3f2 - xor al, al - outb - pop dx + pushw %dx + movw $0x3f2, %dx + xorb %al, %al + outw %al, %dx + popw %dx ret -sectors: - .word 0 - -disksizes: - .byte 36,18,15,9 +sectors: .word 0 +disksizes: .byte 36, 18, 15, 9 +msg1: .byte 13, 10 + .ascii "Loading" -msg1: - .byte 13,10 - .ascii "Loading" +# XXX: This is a *very* snug fit. .org 497 -setup_sects: - .byte SETUPSECS -root_flags: - .word CONFIG_ROOT_RDONLY -syssize: - .word SYSSIZE -swap_dev: - .word SWAP_DEV -ram_size: - .word RAMDISK -vid_mode: - .word SVGA_MODE -root_dev: - .word ROOT_DEV -boot_flag: - .word 0xAA55 +setup_sects: .byte SETUPSECS +root_flags: .word CONFIG_ROOT_RDONLY +syssize: .word SYSSIZE +swap_dev: .word SWAP_DEV +ram_size: .word RAMDISK +vid_mode: .word SVGA_MODE +root_dev: .word ROOT_DEV +boot_flag: .word 0xAA55 diff -u --recursive --new-file v2.3.20/linux/arch/i386/boot/compressed/Makefile linux/arch/i386/boot/compressed/Makefile --- v2.3.20/linux/arch/i386/boot/compressed/Makefile Sun Jul 11 09:48:05 1999 +++ linux/arch/i386/boot/compressed/Makefile Mon Oct 11 14:06:10 1999 @@ -39,7 +39,7 @@ $(OBJCOPY) $(SYSTEM) $$tmppiggy; \ gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \ echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \ - $(LD) -m elf_i386 -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \ + $(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \ rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk clean: diff -u --recursive --new-file v2.3.20/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S --- v2.3.20/linux/arch/i386/boot/setup.S Sat Oct 9 11:47:50 1999 +++ linux/arch/i386/boot/setup.S Mon Oct 11 14:06:10 1999 @@ -1,35 +1,38 @@ -! -! setup.S Copyright (C) 1991, 1992 Linus Torvalds -! -! setup.s is responsible for getting the system data from the BIOS, -! and putting them into the appropriate places in system memory. -! both setup.s and system has been loaded by the bootblock. -! -! This code asks the bios for memory/disk/other parameters, and -! puts them in a "safe" place: 0x90000-0x901FF, ie where the -! boot-block used to be. It is then up to the protected mode -! system to read them from there before the area is overwritten -! for buffer-blocks. -! -! Move PS/2 aux init code to psaux.c -! (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92 -! -! some changes and additional features by Christoph Niemann, -! March 1993/June 1994 (Christoph.Niemann@linux.org) -! -! add APM BIOS checking by Stephen Rothwell, May 1994 -! (Stephen.Rothwell@canb.auug.org.au) -! -! High load stuff, initrd support and position independency -! by Hans Lermen & Werner Almesberger, February 1996 -! , -! -! Video handling moved to video.S by Martin Mares, March 1996 -! -! -! Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david -! parsons) to avoid loadlin confusion, July 1997 -! +/* + * setup.S Copyright (C) 1991, 1992 Linus Torvalds + * + * setup.s is responsible for getting the system data from the BIOS, + * and putting them into the appropriate places in system memory. + * both setup.s and system has been loaded by the bootblock. + * + * This code asks the bios for memory/disk/other parameters, and + * puts them in a "safe" place: 0x90000-0x901FF, ie where the + * boot-block used to be. It is then up to the protected mode + * system to read them from there before the area is overwritten + * for buffer-blocks. + * + * Move PS/2 aux init code to psaux.c + * (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92 + * + * some changes and additional features by Christoph Niemann, + * March 1993/June 1994 (Christoph.Niemann@linux.org) + * + * add APM BIOS checking by Stephen Rothwell, May 1994 + * (Stephen.Rothwell@canb.auug.org.au) + * + * High load stuff, initrd support and position independency + * by Hans Lermen & Werner Almesberger, February 1996 + * , + * + * Video handling moved to video.S by Martin Mares, March 1996 + * + * + * Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david + * parsons) to avoid loadlin confusion, July 1997 + * + * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999. + * + */ #define __ASSEMBLY__ #include @@ -39,17 +42,20 @@ #include #include -! Signature words to ensure LILO loaded us right +/* Signature words to ensure LILO loaded us right */ #define SIG1 0xAA55 #define SIG2 0x5A5A -INITSEG = DEF_INITSEG ! 0x9000, we move boot here - out of the way -SYSSEG = DEF_SYSSEG ! 0x1000, system loaded at 0x10000 (65536). -SETUPSEG = DEF_SETUPSEG ! 0x9020, this is the current segment - ! ... and the former contents of CS -DELTA_INITSEG = SETUPSEG - INITSEG ! 0x0020 +INITSEG = DEF_INITSEG # 0x9000, we move boot here, out of the way +SYSSEG = DEF_SYSSEG # 0x1000, system loaded at 0x10000 (65536). +SETUPSEG = DEF_SETUPSEG # 0x9020, this is the current segment + # ... and the former contents of CS +DELTA_INITSEG = SETUPSEG - INITSEG # 0x0020 + +.code16 .globl begtext, begdata, begbss, endtext, enddata, endbss + .text begtext: .data @@ -58,631 +64,617 @@ begbss: .text -entry start start: jmp trampoline -! ------------------------ start of header -------------------------------- -! -! SETUP-header, must start at CS:2 (old 0x9020:2) -! - .ascii "HdrS" ! Signature for SETUP-header - .word 0x0201 ! Version number of header format - ! (must be >= 0x0105 - ! else old loadlin-1.5 will fail) -realmode_swtch: .word 0,0 ! default_switch,SETUPSEG + +# This is the setup header, and it must start at %cs:2 (old 0x9020:2) + + .ascii "HdrS" # header signature + .word 0x0201 # header version number (>= 0x0105) + # or else old loadlin-1.5 will fail) +realmode_swtch: .word 0, 0 # default_switch, SETUPSEG start_sys_seg: .word SYSSEG - .word kernel_version ! pointing to kernel version string - ! note: above part of header is compatible with loadlin-1.5 (header v1.5), - ! must not change it - -type_of_loader: .byte 0 ! = 0, old one (LILO, Loadlin, - ! Bootlin, SYSLX, bootsect...) - ! else it is set by the loader: - ! 0xTV: T=0 for LILO - ! T=1 for Loadlin - ! T=2 for bootsect-loader - ! T=3 for SYSLX - ! T=4 for ETHERBOOT - ! V = version -loadflags: ! flags, unused bits must be zero (RFU) -LOADED_HIGH = 1 ! bit within loadflags, - ! if set, then the kernel is loaded high -CAN_USE_HEAP = 0x80 ! if set, the loader also has set heap_end_ptr - ! to tell how much space behind setup.S - | can be used for heap purposes. - ! Only the loader knows what is free! + .word kernel_version # pointing to kernel version string + # above section of header is compatible + # with loadlin-1.5 (header v1.5). Don't + # change it. + +type_of_loader: .byte 0 # = 0, old one (LILO, Loadlin, + # Bootlin, SYSLX, bootsect...) + # else it is set by the loader: + # 0xTV: T=0 for LILO + # T=1 for Loadlin + # T=2 for bootsect-loader + # T=3 for SYSLX + # T=4 for ETHERBOOT + # V = version + +# flags, unused bits must be zero (RFU) bit within loadflags +loadflags: +LOADED_HIGH = 1 # if set, the kernel is loaded high +CAN_USE_HEAP = 0x80 # if set, the loader also has set + # heap_end_ptr to tell how much + # space behind setup.S can be used for + # heap purposes. + # Only the loader knows what is free #ifndef __BIG_KERNEL__ - .byte 0x00 + .byte 0 #else .byte LOADED_HIGH #endif -setup_move_size: .word 0x8000 ! size to move, when we (setup) are not - ! loaded at 0x90000. We will move ourselves - ! to 0x90000 then just before jumping into - ! the kernel. However, only the loader - ! know how much of data behind us also needs - ! to be loaded. -code32_start: ! here loaders can put a different - ! start address for 32-bit code. +setup_move_size: .word 0x8000 # size to move, when setup is not + # loaded at 0x90000. We will move setup + # to 0x90000 then just before jumping + # into the kernel. However, only the + # loader knows how much data behind + # us also needs to be loaded. + +code32_start: # here loaders can put a different + # start address for 32-bit code. #ifndef __BIG_KERNEL__ - .long 0x1000 ! 0x1000 = default for zImage + .long 0x1000 # 0x1000 = default for zImage #else - .long 0x100000 ! 0x100000 = default for big kernel + .long 0x100000 # 0x100000 = default for big kernel #endif -ramdisk_image: .long 0 ! address of loaded ramdisk image - ! Here the loader (or kernel generator) puts - ! the 32-bit address were it loaded the image. - ! This only will be interpreted by the kernel. -ramdisk_size: .long 0 ! its size in bytes + +ramdisk_image: .long 0 # address of loaded ramdisk image + # Here the loader puts the 32-bit + # address where it loaded the image. + # This only will be read by the kernel. + +ramdisk_size: .long 0 # its size in bytes + +.global bootsect_kludge # so that we can see it in bootsect.S bootsect_kludge: - .word bootsect_helper,SETUPSEG -heap_end_ptr: .word modelist+1024 ! space from here (exclusive) down to - ! end of setup code can be used by setup - ! for local heap purposes. + .word bootsect_helper, SETUPSEG + +heap_end_ptr: .word modelist+1024 # space from here (exclusive) down to + # end of setup code can be used by setup + # for local heap purposes. trampoline: call start_of_setup .space 1024 -! ------------------------ end of header ---------------------------------- +# End of setup header ##################################################### start_of_setup: -! Bootlin depends on this being done early - mov ax,#0x01500 - mov dl,#0x81 - int 0x13 +# Bootlin depends on this being done early + movw $0x01500, %ax + movb $0x81, %dl + int $0x13 #ifdef SAFE_RESET_DISK_CONTROLLER -! Reset the disk controller. - mov ax,#0x0000 - mov dl,#0x80 - int 0x13 +# Reset the disk controller. + movw $0x0000, %ax + movb $0x80, $dl + int $0x13 #endif -! set DS=CS, we know that SETUPSEG == CS at this point - mov ax,cs ! aka #SETUPSEG - mov ds,ax - -! Check signature at end of setup - cmp setup_sig1,#SIG1 +# Set %ds = %cs, we know that SETUPSEG = %cs at this point + movw %cs, %ax # aka SETUPSEG + movw %ax, %ds +# Check signature at end of setup + cmpw $SIG1, setup_sig1 jne bad_sig - cmp setup_sig2,#SIG2 + + cmpw $SIG2, setup_sig2 jne bad_sig - jmp good_sig1 -! Routine to print ASCIIz string at DS:SI + jmp good_sig1 -prtstr: lodsb - and al,al +# Routine to print asciiz string at ds:si +prtstr: + lodsb + andb %al, %al jz fin + call prtchr jmp prtstr -fin: ret -! Space printing - -prtsp2: call prtspc ! Print double space -prtspc: mov al,#0x20 ! Print single space (fall-thru!) - -! Part of above routine, this one just prints ASCII al +fin: ret -prtchr: push ax - push cx - xor bh,bh - mov cx,#0x01 - mov ah,#0x0e - int 0x10 - pop cx - pop ax +# Space printing +prtsp2: call prtspc # Print double space +prtspc: movb $0x20, %al # Print single space (note: fall-thru) + +# Part of above routine, this one just prints ascii al +prtchr: pushw %ax + pushw %cx + xorb %bh, %bh + movw $0x01, %cx + movb $0x0e, %ah + int $0x10 + popw %cx + popw %ax ret -beep: mov al,#0x07 +beep: movb $0x07, %al jmp prtchr -no_sig_mess: .ascii "No setup signature found ..." - db 0x00 +no_sig_mess: .string "No setup signature found ..." good_sig1: jmp good_sig -! We now have to find the rest of the setup code/data +# We now have to find the rest of the setup code/data bad_sig: - mov ax,cs ! aka #SETUPSEG - sub ax,#DELTA_INITSEG ! aka #INITSEG - mov ds,ax - xor bh,bh - mov bl,[497] ! get setup sects from boot sector - sub bx,#4 ! LILO loads 4 sectors of setup - shl bx,#7 ! convert to dwords (1sect=2^7 dwords) - mov cx,bx - shr bx,#2 ! convert to segment - add bx,#SYSSEG - seg cs - mov start_sys_seg,bx - -! Move rest of setup code/data to here - mov di,#2048 ! four sectors loaded by LILO - sub si,si - mov ax,cs ! aka #SETUPSEG - mov es,ax - mov ax,#SYSSEG - mov ds,ax + movw %cs, %ax # SETUPSEG + subw $DELTA_INITSEG, %ax # INITSEG + movw %ax, %ds + xorb %bh, %bh + movb (497), %bl # get setup sect from bootsect + subw $4, %bx # LILO loads 4 sectors of setup + shlw $7, %bx # convert to dwords (1sect=2^7 dwords) + movw %bx, %cx + shrw $2, %bx # convert to segment + addw $SYSSEG, %bx + movw %bx, %cs:start_sys_seg +# Move rest of setup code/data to here + movw $2048, %di # four sectors loaded by LILO + subw %si, %si + movw %cs, %ax # aka SETUPSEG + movw %ax, %es + movw $SYSSEG, %ax + movw %ax, %ds rep - movsd - - mov ax,cs ! aka #SETUPSEG - mov ds,ax - cmp setup_sig1,#SIG1 + movsl + movw %cs, %ax # aka SETUPSEG + movw %ax, %ds + cmpw $SIG1, setup_sig1 jne no_sig - cmp setup_sig2,#SIG2 + + cmpw $SIG2, setup_sig2 jne no_sig + jmp good_sig no_sig: - lea si,no_sig_mess + lea no_sig_mess, %si call prtstr + no_sig_loop: jmp no_sig_loop good_sig: - mov ax,cs ! aka #SETUPSEG - sub ax,#DELTA_INITSEG ! aka #INITSEG - mov ds,ax - -! check if an old loader tries to load a big-kernel - seg cs - test byte ptr loadflags,#LOADED_HIGH ! Have we a big kernel? - jz loader_ok ! NO, no danger even for old loaders - ! YES, we have a big-kernel - seg cs - cmp byte ptr type_of_loader,#0 ! Have we one of the new loaders? - jnz loader_ok ! YES, OK - ! NO, we have an old loader, must give up - push cs - pop ds - lea si,loader_panic_mess + movw %cs, %ax # aka SETUPSEG + subw $DELTA_INITSEG, %ax # aka INITSEG + movw %ax, %ds +# Check if an old loader tries to load a big-kernel + testb $LOADED_HIGH, %cs:loadflags # Do we have a big kernel? + jz loader_ok # No, no danger for old loaders. + + cmpb $0, %cs:type_of_loader # Do we have a loader that + # can deal with us? + jnz loader_ok # Yes, continue. + + pushw %cs # No, we have an old loader, + popw %ds # die. + lea loader_panic_mess, %si call prtstr + jmp no_sig_loop -loader_panic_mess: - .ascii "Wrong loader: giving up." - db 0 + +loader_panic_mess: .string "Wrong loader, giving up..." loader_ok: -! Get memory size (extended mem, kB) +# Get memory size (extended mem, kB) - xor eax, eax - mov dword ptr [0x1e0], eax + xorl %eax, %eax + movl %eax, (0x1e0) #ifndef STANDARD_MEMORY_BIOS_CALL - - mov byte ptr [E820NR], al - -! Try three different memory detection schemes. First, try -! e820h, which lets us assemble a memory map, then try e801h, -! which returns a 32-bit memory size, and finally 88h, which -! returns 0-64m - -! method E820H: -! the memory map from hell. e820h returns memory classified into -! a whole bunch of different types, and allows memory holes and -! everything. We scan through this memory map and build a list -! of the first 32 memory areas, which we return at [E820MAP]. -! + movb %al, (E820NR) +# Try three different memory detection schemes. First, try +# e820h, which lets us assemble a memory map, then try e801h, +# which returns a 32-bit memory size, and finally 88h, which +# returns 0-64m + +# method E820H: +# the memory map from hell. e820h returns memory classified into +# a whole bunch of different types, and allows memory holes and +# everything. We scan through this memory map and build a list +# of the first 32 memory areas, which we return at [E820MAP]. +# meme820: - mov edx, #0x534d4150 ! ascii `SMAP' - xor ebx, ebx ! continuation counter - - mov di, #E820MAP ! point into the whitelist - ! so we can have the bios - ! directly write into it. + movl $0x534d4150, %edx # ascii `SMAP' + xorl %ebx, %ebx # continuation counter + movw $E820MAP, %di # point into the whitelist + # so we can have the bios + # directly write into it. jmpe820: - mov eax, #0x0000e820 ! e820, upper word zeroed - mov ecx, #20 ! size of the e820rec - - push ds ! data record. - pop es - int 0x15 ! make the call - jc bail820 ! fall to e801 if it fails - - cmp eax, #0x534d4150 ! check the return is `SMAP' - jne bail820 ! fall to e801 if it fails - -! cmp dword ptr [16+di], #1 ! is this usable memory? -! jne again820 - - ! If this is usable memory, we save it by simply advancing di by - ! sizeof(e820rec). - ! + movl $0x0000e820, %eax # e820, upper word zeroed + movl $20, %ecx # size of the e820rec + pushw %ds # data record. + popw %es + int $0x15 # make the call + jc bail820 # fall to e801 if it fails + + cmpl $0x534d4150, %eax # check the return is `SMAP' + jne bail820 # fall to e801 if it fails + +# cmpl $1, 16(%di) # is this usable memory? +# jne again820 + + # If this is usable memory, we save it by simply advancing %di by + # sizeof(e820rec). + # good820: - mov al, byte ptr [E820NR] ! up to 32 good entries, that is - cmp al, #E820MAX + movb (E820NR), %al # up to 32 entries + cmpb $E820MAX, %al jnl bail820 - inc byte ptr [E820NR] - mov ax, di - add ax, #20 - mov di, ax + incb (E820NR) + movw %di, %ax + addw $20, %ax + movw %ax, %di again820: - cmp ebx, #0 ! check to see if ebx is - jne jmpe820 ! set to EOF - + cmpl $0, %ebx # check to see if + jne jmpe820 # %ebx is set to EOF bail820: -! method E801H: -! memory size is in 1k chunksizes, to avoid confusing loadlin. -! we store the 0xe801 memory size in a completely different place, -! because it will most likely be longer than 16 bits. -! (use 1e0 because that's what Larry Augustine uses in his -! alternative new memory detection scheme, and it's sensible -! to write everything into the same place.) +# method E801H: +# memory size is in 1k chunksizes, to avoid confusing loadlin. +# we store the 0xe801 memory size in a completely different place, +# because it will most likely be longer than 16 bits. +# (use 1e0 because that's what Larry Augustine uses in his +# alternative new memory detection scheme, and it's sensible +# to write everything into the same place.) meme801: - - mov ax,#0xe801 - int 0x15 + movw $0xe801, %ax + int $0x15 jc mem88 - and edx, #0xffff ! clear sign extend - shl edx, 6 ! and go from 64k to 1k chunks - mov [0x1e0],edx ! store extended memory size + andl $0xffff, %edx # clear sign extend + shll $6, %edx # and go from 64k to 1k chunks + movl %edx, (0x1e0) # store extended memory size + andl $0xffff, %ecx # clear sign extend + addl %ecx, (0x1e0) # and add lower memory into + # total size. - and ecx, #0xffff ! clear sign extend - add [0x1e0],ecx ! and add lower memory into total size. - -! Ye Olde Traditional Methode. Returns the memory size (up to 16mb or -! 64mb, depending on the bios) in ax. +# Ye Olde Traditional Methode. Returns the memory size (up to 16mb or +# 64mb, depending on the bios) in ax. mem88: #endif - mov ah,#0x88 - int 0x15 - mov [2],ax - -! Set the keyboard repeat rate to the max - - mov ax,#0x0305 - xor bx,bx ! clear bx - int 0x16 - -! Check for video adapter and its parameters and allow the -! user to browse video modes. - - call video ! NOTE: we need DS pointing to boot sector - -! Get hd0 data - - xor ax,ax ! clear ax - mov ds,ax - lds si,[4*0x41] - mov ax,cs ! aka #SETUPSEG - sub ax,#DELTA_INITSEG ! aka #INITSEG - push ax - mov es,ax - mov di,#0x0080 - mov cx,#0x10 - push cx + movb $0x88, %ah + int $0x15 + movw %ax, (2) + +# Set the keyboard repeat rate to the max + movw $0x0305, %ax + xorw %bx, %bx + int $0x16 + +# Check for video adapter and its parameters and allow the +# user to browse video modes. + call video # NOTE: we need %ds pointing + # to bootsector + +# Get hd0 data... + xorw %ax, %ax + movw %ax, %ds + ldsw (4 * 0x41), %si + movw %cs, %ax # aka SETUPSEG + subw $DELTA_INITSEG, %ax # aka INITSEG + pushw %ax + movw %ax, %es + movw $0x0080, %di + movw $0x10, %cx + pushw %cx cld rep - movsb - -! Get hd1 data - - xor ax,ax ! clear ax - mov ds,ax - lds si,[4*0x46] - pop cx - pop es - mov di,#0x0090 + movsb +# Get hd1 data... + xorw %ax, %ax + movw %ax, %ds + ldsw (4 * 0x46), %si + popw %cx + popw %es + movw $0x0090, %di rep movsb - -! Check that there IS a hd1 :-) - - mov ax,#0x01500 - mov dl,#0x81 - int 0x13 +# Check that there IS a hd1 :-) + movw $0x01500, %ax + movb $0x81, %dl + int $0x13 jc no_disk1 - cmp ah,#3 + + cmpb $3, %ah je is_disk1 + no_disk1: - mov ax,cs ! aka #SETUPSEG - sub ax,#DELTA_INITSEG ! aka #INITSEG - mov es,ax - mov di,#0x0090 - mov cx,#0x10 - xor ax,ax ! clear ax + movw %cs, %ax # aka SETUPSEG + subw $DELTA_INITSEG, %ax # aka INITSEG + movw %ax, %es + movw $0x0090, %di + movw $0x10, %cx + xorw %ax, %ax cld rep stosb is_disk1: - -! check for Micro Channel (MCA) bus - mov ax,cs ! aka #SETUPSEG - sub ax,#DELTA_INITSEG ! aka #INITSEG - mov ds,ax - mov ds,ax - xor ax,ax - mov [0xa0], ax ! set table length to 0 - mov ah, #0xc0 +# check for Micro Channel (MCA) bus + movw %cs, %ax # aka SETUPSEG + subw $DELTA_INITSEG, %ax # aka INITSEG + movw %ax, %ds + xorw %ax, %ax + movw %ax, 0xa0 # set table length to 0 + movb $0xc0, %ah stc - int 0x15 ! puts feature table at es:bx - jc no_mca - push ds - mov ax,es - mov ds,ax - mov ax,cs ! aka #SETUPSEG - sub ax, #DELTA_INITSEG ! aka #INITSEG - mov es,ax - mov si,bx - mov di,#0xa0 - mov cx,(si) - add cx,#2 ! table length is a short - cmp cx,#0x10 - jc sysdesc_ok - mov cx,#0x10 ! we keep only first 16 bytes + int $0x15 # moves feature table to es:bx + jc no_mca + + pushw %ds + movw %es, %ax + movw %ax, %ds + movw %cs, %ax # aka SETUPSEG + subw $DELTA_INITSEG, %ax # aka INITSEG + movw %ax, %es + movw %bx, %si + movw $0xa0, %di + movw (%si), %cx + addw $2, %cx # table length is a short + cmpw $0x10, %cx + jc sysdesc_ok + + movw $0x10, %cx # we keep only first 16 bytes sysdesc_ok: rep movsb - pop ds - + popw %ds no_mca: - -! Check for PS/2 pointing device - - mov ax,cs ! aka #SETUPSEG - sub ax,#DELTA_INITSEG ! aka #INITSEG - mov ds,ax - mov [0x1ff],#0 ! default is no pointing device - int 0x11 ! int 0x11: equipment determination - test al,#0x04 ! check if pointing device installed +# Check for PS/2 pointing device + movw %cs, %ax # aka SETUPSEG + subw $DELTA_INITSEG, %ax # aka INITSEG + movw %ax, %ds + movw $0, (0x1ff) # default is no pointing device + int $0x11 # int 0x11: equipment list + testb $0x04, %al # check if mouse installed jz no_psmouse - mov [0x1ff],#0xaa ! device present + + movw $0xAA, (0x1ff) # device present no_psmouse: #ifdef CONFIG_APM -! check for APM BIOS - ! NOTE: DS is pointing to the boot sector - ! - mov [64],#0 ! version == 0 means no APM BIOS - - mov ax,#0x05300 ! APM BIOS installation check - xor bx,bx - int 0x15 - jc done_apm_bios ! error -> no APM BIOS - - cmp bx,#0x0504d ! check for "PM" signature - jne done_apm_bios ! no signature -> no APM BIOS - - and cx,#0x02 ! Is 32 bit supported? - je done_apm_bios ! no ... - - mov ax,#0x05304 ! Disconnect first just in case - xor bx,bx - int 0x15 ! ignore return code - - mov ax,#0x05303 ! 32 bit connect - xor ebx,ebx - int 0x15 - jc no_32_apm_bios ! error - - mov [66],ax ! BIOS code segment - mov [68],ebx ! BIOS entry point offset - mov [72],cx ! BIOS 16 bit code segment - mov [74],dx ! BIOS data segment - mov [78],esi ! BIOS code segment length - mov [82],di ! BIOS data segment length -! -! Redo the installation check as the 32 bit connect -! modifies the flags returned on some BIOSs -! - mov ax,#0x05300 ! APM BIOS installation check - xor bx,bx - int 0x15 - jc apm_disconnect ! error -> should not happen, tidy up +# Then check for an APM BIOS... + # %ds points to the bootsector + movw $0, 0x40 # version = 0 means no APM BIOS + movw $0x05300, %ax # APM BIOS installation check + xorw %bx, %bx + int $0x15 + jc done_apm_bios # Nope, no APM BIOS + + cmpw $0x0504d, %bx # Check for "PM" signature + jne done_apm_bios # No signature, no APM BIOS + + andw $0x02, %cx # Is 32 bit supported? + je done_apm_bios # No 32-bit, no (good) APM BIOS + + movw $0x05304, %ax # Disconnect first just in case + xorw %bx, %bx + int $0x15 # ignore return code + movw $0x05303, %ax # 32 bit connect + xorw %ebx, %ebx + int $0x15 + jc no_32_apm_bios # Ack, error. + + movw %ax, (66) # BIOS code segment + movl %ebx, (68) # BIOS entry point offset + movw %cx, (72) # BIOS 16 bit code segment + movw %dx, (74) # BIOS data segment + movl %esi, (78) # BIOS code segment length + movw %di, (82) # BIOS data segment length +# Redo the installation check as the 32 bit connect +# modifies the flags returned on some BIOSs + movw $0x05300, %ax # APM BIOS installation check + xorw %bx, %bx + int $0x15 + jc apm_disconnect # error -> shouldn't happen - cmp bx,#0x0504d ! check for "PM" signature - jne apm_disconnect ! no signature -> should not happen, tidy up + cmpw $0x0504d, %bx # check for "PM" signature + jne apm_disconnect # no sig -> shouldn't happen - mov [64],ax ! record the APM BIOS version - mov [76],cx ! and flags + movw %ax, (64) # record the APM BIOS version + movw %cx, (76) # and flags jmp done_apm_bios -apm_disconnect: - mov ax,#0x05304 ! Disconnect - xor bx,bx - int 0x15 ! ignore return code +apm_disconnect: # Tidy up + movw $0x05304, %ax # Disconnect + xorw %bx, %bx + int $0x15 # ignore return code + jmp done_apm_bios no_32_apm_bios: - and [76], #0xfffd ! remove 32 bit support bit - + andw $0xfffd, (76) # remove 32 bit support bit done_apm_bios: #endif -! Now we want to move to protected mode ... - - seg cs - cmp realmode_swtch,#0 +# Now we want to move to protected mode ... + cmpw $0, %cs:realmode_swtch jz rmodeswtch_normal - seg cs - callf far * realmode_swtch + + call *%cs:realmode_swtch + jmp rmodeswtch_end + rmodeswtch_normal: - push cs + pushw %cs call default_switch -rmodeswtch_end: -! we get the code32 start address and modify the below 'jmpi' -! (loader may have changed it) - seg cs - mov eax,code32_start - seg cs - mov code32,eax - -! Now we move the system to its rightful place -! ...but we check, if we have a big-kernel. -! in this case we *must* not move it ... - seg cs - test byte ptr loadflags,#LOADED_HIGH - jz do_move0 ! we have a normal low loaded zImage - ! we have a high loaded big kernel - jmp end_move ! ... and we skip moving +rmodeswtch_end: +# we get the code32 start address and modify the below 'jmpi' +# (loader may have changed it) + movl %cs:code32_start, %eax + movl %eax, %cs:code32 + +# Now we move the system to its rightful place ... but we check if we have a +# big-kernel. In that case we *must* not move it ... + testb $LOADED_HIGH, %cs:loadflags + jz do_move0 # .. then we have a normal low + # loaded zImage + # .. or else we have a high + # loaded bzImage + jmp end_move # ... and we skip moving do_move0: - mov ax,#0x100 ! start of destination segment - mov bp,cs ! aka #SETUPSEG - sub bp,#DELTA_INITSEG ! aka #INITSEG - seg cs - mov bx,start_sys_seg ! start of source segment - cld ! 'direction'=0, movs moves forward + movw $0x100, %ax # start of destination segment + movw %cs, %bp # aka SETUPSEG + subw $DELTA_INITSEG, %bp # aka INITSEG + movw %cs:start_sys_seg, %bx # start of source segment + cld do_move: - mov es,ax ! destination segment - inc ah ! instead of add ax,#0x100 - mov ds,bx ! source segment - add bx,#0x100 - sub di,di - sub si,si - mov cx,#0x400 + movw %ax, %es # destination segment + incb %ah # instead of add ax,#0x100 + movw %bx, %ds # source segment + addw $0x100, %bx + subw %di, %di + subw %si, %si + movw $0x400, %cx rep - movsd - cmp bx,bp ! we assume start_sys_seg > 0x200, - ! so we will perhaps read one page more then - ! needed, but never overwrite INITSEG because - ! destination is minimum one page below source + movsl + cmpw %bp, %bx # assume start_sys_seg > 0x200, + # so we will perhaps read one + # page more than needed, but + # never overwrite INITSEG + # because destination is a + # minimum one page below source jb do_move -! then we load the segment descriptors - end_move: - mov ax,cs ! aka #SETUPSEG ! right, forgot this at first. didn't work :-) - mov ds,ax - -! If we have our code not at 0x90000, we need to move it there now. -! We also then need to move the parameters behind it (command line) -! Because we would overwrite the code on the current IP, we move -! it in two steps, jumping high after the first one. - mov ax,cs - cmp ax,#SETUPSEG +# then we load the segment descriptors + movw %cs, %ax # aka SETUPSEG + movw %ax, %ds + +# If we have our code not at 0x90000, we need to move it there now. +# We also then need to move the params behind it (commandline) +# Because we would overwrite the code on the current IP, we move +# it in two steps, jumping high after the first one. + movw %cs, %ax + cmpw $SETUPSEG, %ax je end_move_self - cli ! make sure we really have interrupts disabled ! - ! because after this the stack should not be used - sub ax,#DELTA_INITSEG ! aka #INITSEG - mov dx,ss - cmp dx,ax + + cli # make sure we really have + # interrupts disabled ! + # because after this the stack + # should not be used + subw $DELTA_INITSEG, %ax # aka INITSEG + movw %ss, %dx + cmpw %ax, %dx jb move_self_1 - add dx,#INITSEG - sub dx,ax ! this will be SS after the move + + addw $INITSEG, %dx + subw %ax, %dx # this will go into %ss after + # the move move_self_1: - mov ds,ax - mov ax,#INITSEG ! real INITSEG - mov es,ax - seg cs - mov cx,setup_move_size - std ! we have to move up, so we use direction down - ! because the areas may overlap - mov di,cx - dec di - mov si,di - sub cx,#move_self_here+0x200 + movw %ax, %ds + movw $INITSEG, %ax # real INITSEG + movw %ax, %es + movw %cs:setup_move_size, %cx + std # we have to move up, so we use + # direction down because the + # areas may overlap + movw %cx, %di + decw %di + movw %di, %si + subw $move_self_here+0x200, %cx rep movsb - jmpi move_self_here,SETUPSEG ! jump to our final place + ljmp $SETUPSEG, $move_self_here + move_self_here: - mov cx,#move_self_here+0x200 + movw $move_self_here+0x200, %cx rep movsb - mov ax,#SETUPSEG - mov ds,ax - mov ss,dx - ! now we are at the right place -end_move_self: - - lidt idt_48 ! load idt with 0,0 - lgdt gdt_48 ! load gdt with whatever appropriate - -! that was painless, now we enable A20 + movw $SETUPSEG, %ax + movw %ax, %ds + movw %dx, %ss +end_move_self: # now we are at the right place + lidt idt_48 # load idt with 0,0 + lgdt gdt_48 # load gdt with whatever is + # appropriate +# that was painless, now we enable a20 call empty_8042 - mov al,#0xD1 ! command write - out #0x64,al + + movb $0xD1, %al # command write + outb %al, $0x64 call empty_8042 - mov al,#0xDF ! A20 on - out #0x60,al + + movb $0xDF, %al # A20 on + outb %al, $0x60 call empty_8042 -! wait until a20 really *is* enabled; it can take a fair amount of -! time on certain systems; Toshiba Tecras are known to have this -! problem. The memory location used here is the int 0x1f vector, -! which should be safe to use; any *unused* memory location < 0xfff0 -! should work here. - -#define TEST_ADDR 0x7c - - push ds - xor ax,ax ! segment 0x0000 - mov ds,ax - dec ax ! segment 0xffff (HMA) - mov gs,ax - mov bx,[TEST_ADDR] ! we want to restore the value later +# wait until a20 really *is* enabled; it can take a fair amount of +# time on certain systems; Toshiba Tecras are known to have this +# problem. The memory location used here (0x200) is the int 0x80 +# vector, which should be safe to use. + push %ds + push %es + xorw %ax, %ax # segment 0x0000 + movw %ax, %fs + decw %ax # segment 0xffff (HMA) + movw %ax, %gs a20_wait: - inc ax - mov [TEST_ADDR],ax - seg gs - cmp ax,[TEST_ADDR+0x10] - je a20_wait ! loop until no longer aliased - mov [TEST_ADDR],bx ! restore original value - pop ds - -! make sure any possible coprocessor is properly reset.. - - xor ax,ax - out #0xf0,al - call delay - out #0xf1,al + incw %ax # unused memory location <0xfff0 + movw %ax, %fs:(0x200) # we use the "int 0x80" vector + cmpw %gs:(0x210), %ax # and its corresponding HMA addr + je a20_wait # loop until no longer aliased + +# make sure any possible coprocessor is properly reset.. + xorw %ax, %ax + outb %al, $0xf0 call delay -! well, that went ok, I hope. Now we mask all interrupts - the rest -! is done in init_IRQ(). + outb %al, $0xf1 + call delay - mov al,#0xFF ! mask off all interrupts for now - out #0xA1,al +# well, that went ok, I hope. Now we mask all interrupts - the rest +# is done in init_IRQ(). + movb $0xFF, %al # mask all interrupts for now + outb %al, $0xA1 call delay - mov al,#0xFB ! mask all irq's but irq2 which - out #0x21,al ! is cascaded + + movb $0xFB, %al # mask all irq's but irq2 which + outb %al, $0x21 # is cascaded -! Well, that certainly wasn't fun :-(. Hopefully it works, and we don't -! need no steenking BIOS anyway (except for the initial loading :-). -! The BIOS routine wants lots of unnecessary data, and it's less -! "interesting" anyway. This is how REAL programmers do it. -! -! Well, now's the time to actually move into protected mode. To make -! things as simple as possible, we do no register set-up or anything, -! we let the GNU-compiled 32-bit programs do that. We just jump to -! absolute address 0x1000 (or the loader supplied one), -! in 32-bit protected mode. -! -! Note that the short jump isn't strictly needed, although there are -! reasons why it might be a good idea. It won't hurt in any case. -! - mov ax,#1 ! protected mode (PE) bit - lmsw ax ! This is it! +# Well, that certainly wasn't fun :-(. Hopefully it works, and we don't +# need no steenking BIOS anyway (except for the initial loading :-). +# The BIOS-routine wants lots of unnecessary data, and it's less +# "interesting" anyway. This is how REAL programmers do it. +# +# Well, now's the time to actually move into protected mode. To make +# things as simple as possible, we do no register set-up or anything, +# we let the gnu-compiled 32-bit programs do that. We just jump to +# absolute address 0x1000 (or the loader supplied one), +# in 32-bit protected mode. +# +# Note that the short jump isn't strictly needed, although there are +# reasons why it might be a good idea. It won't hurt in any case. + movw $1, %ax # protected mode (PE) bit + lmsw %ax # This is it! jmp flush_instr -flush_instr: - xor bx,bx ! Flag to indicate a boot -! NOTE: For high loaded big kernels we need a -! jmpi 0x100000,__KERNEL_CS -! -! but we yet haven't reloaded the CS register, so the default size -! of the target offset still is 16 bit. -! However, using an operant prefix (0x66), the CPU will properly -! take our 48 bit far pointer. (INTeL 80386 Programmer's Reference -! Manual, Mixing 16-bit and 32-bit code, page 16-6) - db 0x66,0xea ! prefix + jmpi-opcode -code32: dd 0x1000 ! will be set to 0x100000 for big kernels - dw __KERNEL_CS +flush_instr: + xorw %bx, %bx # Flag to indicate a boot +# NOTE: For high loaded big kernels we need a +# jmpi 0x100000,__KERNEL_CS +# +# but we yet haven't reloaded the CS register, so the default size +# of the target offset still is 16 bit. +# However, using an operant prefix (0x66), the CPU will properly +# take our 48 bit far pointer. (INTeL 80386 Programmer's Reference +# Manual, Mixing 16-bit and 32-bit code, page 16-6) + + .byte 0x66, 0xea # prefix + jmpi-opcode +code32: .long 0x1000 # will be set to 0x100000 + # for big kernels + .word __KERNEL_CS +# Here's a bunch of information about your current kernel.. kernel_version: .ascii UTS_RELEASE .ascii " (" .ascii LINUX_COMPILE_BY @@ -690,191 +682,184 @@ .ascii LINUX_COMPILE_HOST .ascii ") " .ascii UTS_VERSION - db 0 - -! This is the default real mode switch routine. -! to be called just before protected mode transition + .byte 0 +# This is the default real mode switch routine. +# to be called just before protected mode transition default_switch: - cli ! no interrupts allowed ! - mov al,#0x80 ! disable NMI for the bootup sequence - out #0x70,al - retf - -! This routine only gets called, if we get loaded by the simple -! bootsect loader _and_ have a bzImage to load. -! Because there is no place left in the 512 bytes of the boot sector, -! we must emigrate to code space here. -! + cli # no interrupts allowed ! + movb $0x80, %al # disable NMI for bootup + # sequence + outb %al, $0x70 + lret + +# This routine only gets called, if we get loaded by the simple +# bootsect loader _and_ have a bzImage to load. +# Because there is no place left in the 512 bytes of the boot sector, +# we must emigrate to code space here. bootsect_helper: - seg cs - cmp word ptr bootsect_es,#0 + cmpw $0, %cs:bootsect_es jnz bootsect_second - seg cs - mov byte ptr type_of_loader,#0x20 - mov ax,es - shr ax,#4 - seg cs - mov byte ptr bootsect_src_base+2,ah - mov ax,es - seg cs - mov bootsect_es,ax - sub ax,#SYSSEG - retf ! nothing else to do for now + + movb $0x20, %cs:type_of_loader + movw %es, %ax + shrw $4, %ax + movb %ah, %cs:bootsect_src_base+2 + movw %es, %ax + movw %ax, %cs:bootsect_es + subw $SYSSEG, %ax + lret # nothing else to do for now + bootsect_second: - push cx - push si - push bx - test bx,bx ! 64K full ? + pushw %cx + pushw %si + pushw %bx + testw %bx, %bx # 64K full? jne bootsect_ex - mov cx,#0x8000 ! full 64K move, INT15 moves words - push cs - pop es - mov si,#bootsect_gdt - mov ax,#0x8700 - int 0x15 - jc bootsect_panic ! this, if INT15 fails - seg cs - mov es,bootsect_es ! we reset es to always point to 0x10000 - seg cs - inc byte ptr bootsect_dst_base+2 + + movw $0x8000, %cx # full 64K, INT15 moves words + pushw %cs + popw %es + movw $bootsect_gdt, %si + movw $0x8700, %ax + int $0x15 + jc bootsect_panic # this, if INT15 fails + + movw %cs:bootsect_es, %es # we reset %es to always point + incb %cs:bootsect_dst_base+2 # to 0x10000 bootsect_ex: - seg cs - mov ah, byte ptr bootsect_dst_base+2 - shl ah,4 ! we now have the number of moved frames in ax - xor al,al - pop bx - pop si - pop cx - retf + movb %cs:bootsect_dst_base+2, %ah + shlb $4, %ah # we now have the number of + # moved frames in %ax + xorb %al, %al + popw %bx + popw %si + popw %cx + lret bootsect_gdt: - .word 0,0,0,0 - .word 0,0,0,0 + .word 0, 0, 0, 0 + .word 0, 0, 0, 0 + bootsect_src: .word 0xffff + bootsect_src_base: - .byte 0,0,1 ! base = 0x010000 - .byte 0x93 ! typbyte - .word 0 ! limit16,base24 =0 + .byte 0x00, 0x00, 0x01 # base = 0x010000 + .byte 0x93 # typbyte + .word 0 # limit16,base24 =0 + bootsect_dst: .word 0xffff + bootsect_dst_base: - .byte 0,0,0x10 ! base = 0x100000 - .byte 0x93 ! typbyte - .word 0 ! limit16,base24 =0 - .word 0,0,0,0 ! BIOS CS - .word 0,0,0,0 ! BIOS DS + .byte 0x00, 0x00, 0x10 # base = 0x100000 + .byte 0x93 # typbyte + .word 0 # limit16,base24 =0 + .word 0, 0, 0, 0 # BIOS CS + .word 0, 0, 0, 0 # BIOS DS + bootsect_es: .word 0 bootsect_panic: - push cs - pop ds + pushw %cs + popw %ds cld - lea si,bootsect_panic_mess + leaw bootsect_panic_mess, %si call prtstr + bootsect_panic_loop: jmp bootsect_panic_loop + bootsect_panic_mess: - .ascii "INT15 refuses to access high memory. Giving up." - db 0 + .string "INT15 refuses to access high mem, giving up." -! This routine checks that the keyboard command queue is empty -! (after emptying the output buffers) -! -! Some machines have delusions that the keyboard buffer is always full -! with no keyboard attached... +# This routine checks that the keyboard command queue is empty +# (after emptying the output buffers) +# +# Some machines have delusions that the keyboard buffer is always full +# with no keyboard attached... empty_8042: - push ecx - mov ecx,#0xFFFFFF + pushl %ecx + movl $0xFFFFFF, %ecx empty_8042_loop: - dec ecx - jz empty_8042_end_loop + decl %ecx + jz empty_8042_end_loop call delay - in al,#0x64 ! 8042 status port - test al,#1 ! output buffer? + + inb $0x64, %al # 8042 status port + testb $1, %al # output buffer? jz no_output + call delay - in al,#0x60 ! read it + inb $0x60, %al # read it jmp empty_8042_loop + no_output: - test al,#2 ! is input buffer full? - jnz empty_8042_loop ! yes - loop + testb $2, %al # is input buffer full? + jnz empty_8042_loop # yes - loop empty_8042_end_loop: - pop ecx + popl %ecx ret -! -! Read the CMOS clock. Return the seconds in al -! +# Read the cmos clock. Return the seconds in al gettime: - push cx - mov ah,#0x02 - int 0x1a - mov al,dh ! dh contains the seconds - and al,#0x0f - mov ah,dh - mov cl,#0x04 - shr ah,cl + pushw %cx + movb $0x02, %ah + int $0x1a + movb %dh, %al # %dh contains the seconds + andb $0x0f, %al + movb %dh, %ah + movb $0x04, %cl + shrb %cl, %ah aad - pop cx + popw %cx ret -! -! Delay is needed after doing I/O -! +# Delay is needed after doing I/O delay: - .word 0x00eb ! jmp $+2 + jmp .+2 # jmp $+2 ret -! -! Descriptor tables -! - +# Descriptor tables gdt: - .word 0,0,0,0 ! dummy - - .word 0,0,0,0 ! unused - - .word 0xFFFF ! 4Gb - (0x100000*0x1000 = 4Gb) - .word 0x0000 ! base address=0 - .word 0x9A00 ! code read/exec - .word 0x00CF ! granularity=4096, 386 (+5th nibble of limit) - - .word 0xFFFF ! 4Gb - (0x100000*0x1000 = 4Gb) - .word 0x0000 ! base address=0 - .word 0x9200 ! data read/write - .word 0x00CF ! granularity=4096, 386 (+5th nibble of limit) + .word 0, 0, 0, 0 # dummy + .word 0, 0, 0, 0 # unused + .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) + .word 0 # base address = 0 + .word 0x9A00 # code read/exec + .word 0x00CF # granularity = 4096, 386 + # (+5th nibble of limit) + + .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) + .word 0 # base address = 0 + .word 0x9200 # data read/write + .word 0x00CF # granularity = 4096, 386 + # (+5th nibble of limit) idt_48: - .word 0 ! idt limit=0 - .word 0,0 ! idt base=0L - + .word 0 # idt limit = 0 + .word 0, 0 # idt base = 0L gdt_48: - .word 0x800 ! gdt limit=2048, 256 GDT entries - .word 512+gdt,0x9 ! gdt base = 0X9xxxx + .word 0x8000 # gdt limit=2048, + # 256 GDT entries -! -! Include video setup & detection code -! + .word 512+gdt, 0x9 # gdt base = 0X9xxxx -#include "video.S" +# Include video setup & detection code -! -! Setup signature -- must be last -! +#include "video.S" +# Setup signature -- must be last setup_sig1: .word SIG1 setup_sig2: .word SIG2 -! -! After this point, there is some free space which is used by the video mode -! handling code to store the temporary mode table (not used by the kernel). -! +# After this point, there is some free space which is used by the video mode +# handling code to store the temporary mode table (not used by the kernel). modelist: diff -u --recursive --new-file v2.3.20/linux/arch/i386/boot/tools/build.c linux/arch/i386/boot/tools/build.c --- v2.3.20/linux/arch/i386/boot/tools/build.c Sun Oct 25 14:16:21 1998 +++ linux/arch/i386/boot/tools/build.c Mon Oct 11 14:06:10 1999 @@ -58,27 +58,10 @@ exit(1); } -/* Reading of ld86 output (Minix format) */ - -#define MINIX_HEADER_LEN 32 - -void minix_open(const char *name) +void file_open(const char *name) { - static byte hdr[] = { 0x01, 0x03, 0x10, 0x04, 0x20, 0x00, 0x00, 0x00 }; - static u32 *lb = (u32 *) buf; - if ((fd = open(name, O_RDONLY, 0)) < 0) die("Unable to open `%s': %m", name); - if (read(fd, buf, MINIX_HEADER_LEN) != MINIX_HEADER_LEN) - die("%s: Unable to read header", name); - if (memcmp(buf, hdr, sizeof(hdr)) || lb[5]) - die("%s: Non-Minix header", name); - if (lb[3]) - die("%s: Illegal data segment"); - if (lb[4]) - die("%s: Illegal bss segment"); - if (lb[7]) - die("%s: Illegal symbol table"); } void usage(void) @@ -125,7 +108,7 @@ } fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root); - minix_open(argv[1]); /* Copy the boot sector */ + file_open(argv[1]); i = read(fd, buf, sizeof(buf)); fprintf(stderr,"Boot sector %d bytes.\n",i); if (i != 512) @@ -138,7 +121,7 @@ die("Write call failed"); close (fd); - minix_open(argv[2]); /* Copy the setup code */ + file_open(argv[2]); /* Copy the setup code */ for (i=0 ; (c=read(fd, buf, sizeof(buf)))>0 ; i+=c ) if (write(1, buf, c) != c) die("Write call failed"); @@ -146,8 +129,8 @@ die("read-error on `setup'"); close (fd); - setup_sectors = (i + 511) / 512; /* Pad unused space with zeros */ - /* for compatibility with ancient versions of LILO */ + setup_sectors = (i + 511) / 512; /* Pad unused space with zeros */ + /* for compatibility with ancient versions of LILO. */ if (setup_sectors < SETUP_SECTS) setup_sectors = SETUP_SECTS; fprintf(stderr, "Setup is %d bytes.\n", i); @@ -161,8 +144,7 @@ i += c; } - if ((fd = open(argv[3], O_RDONLY, 0)) < 0) /* Copy the image itself */ - die("Unable to open `%s': %m", argv[3]); + file_open(argv[3]); if (fstat (fd, &sb)) die("Unable to stat `%s': %m", argv[3]); sz = sb.st_size; @@ -187,7 +169,7 @@ } close(fd); - if (lseek(1, 497, SEEK_SET) != 497) /* Write sizes to the boot sector */ + if (lseek(1, 497, SEEK_SET) != 497) /* Write sizes to the bootsector */ die("Output: seek failed"); buf[0] = setup_sectors; if (write(1, buf, 1) != 1) diff -u --recursive --new-file v2.3.20/linux/arch/i386/boot/video.S linux/arch/i386/boot/video.S --- v2.3.20/linux/arch/i386/boot/video.S Fri May 14 12:47:01 1999 +++ linux/arch/i386/boot/video.S Mon Oct 11 14:06:10 1999 @@ -1,60 +1,62 @@ -! -! Display adapter & video mode setup, version 2.13 (14-May-99) -! -! Copyright (C) 1995 -- 1999 Martin Mares -! Based on the original setup.S code (C) Linus Torvalds and Mats Anderson -! -! For further information, look at Documentation/svga.txt. -! +/* video.S + * + * Display adapter & video mode setup, version 2.13 (14-May-99) + * + * Copyright (C) 1995 -- 1998 Martin Mares + * Based on the original setup.S code (C) Linus Torvalds and Mats Anderson + * + * Rewritten to use GNU 'as' by Chris Noe May 1999 + * + * For further information, look at Documentation/svga.txt. + * + */ #include /* for CONFIG_VIDEO_* */ -! Enable autodetection of SVGA adapters and modes. If you really need this -! feature, drop me a mail as I think of removing it some day. You can -! always enter `scan' to get the video mode table and then use the real -! video mode numbers (those 4-digit hexadecimal numbers, NOT the menu -! item numbers) which don't rely on any autodetection. +/* Enable autodetection of SVGA adapters and modes. */ #undef CONFIG_VIDEO_SVGA -! Enable autodetection of VESA modes +/* Enable autodetection of VESA modes */ #define CONFIG_VIDEO_VESA -! Enable compacting of mode table +/* Enable compacting of mode table */ #define CONFIG_VIDEO_COMPACT -! Retain screen contents when switching modes +/* Retain screen contents when switching modes */ #define CONFIG_VIDEO_RETAIN -! Enable local mode list +/* Enable local mode list */ #undef CONFIG_VIDEO_LOCAL -! Force 400 scan lines for standard modes (hack to fix bad behaviour -! of certain broken BIOSes -- don't use unless needed) +/* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */ #undef CONFIG_VIDEO_400_HACK -! A special hack allowing to force specific BIOS mode ID along with specific -! dimensions. Especially useful for certain X-Window graphics mode hacks -! (e.g., 800x600 modes on IBM ThinkPad). +/* Hack that lets you force specific BIOS mode ID and specific dimensions */ #undef CONFIG_VIDEO_GFX_HACK #define VIDEO_GFX_BIOS_AX 0x4f02 /* 800x600 on ThinkPad */ #define VIDEO_GFX_BIOS_BX 0x0102 #define VIDEO_GFX_DUMMY_RESOLUTION 0x6425 /* 100x37 */ -! This code uses an extended set of video mode numbers. These include: -! Aliases for standard modes -! NORMAL_VGA (-1) -! EXTENDED_VGA (-2) -! ASK_VGA (-3) -! Video modes numbered by menu position -- NOT RECOMMENDED because of lack -! of compatibility when extending the table. These are between 0x00 and 0xff. +/* This code uses an extended set of video mode numbers. These include: + * Aliases for standard modes + * NORMAL_VGA (-1) + * EXTENDED_VGA (-2) + * ASK_VGA (-3) + * Video modes numbered by menu position -- NOT RECOMMENDED because of lack + * of compatibility when extending the table. These are between 0x00 and 0xff. + */ #define VIDEO_FIRST_MENU 0x0000 -! Standard BIOS video modes (BIOS number + 0x0100) + +/* Standard BIOS video modes (BIOS number + 0x0100) */ #define VIDEO_FIRST_BIOS 0x0100 -! VESA BIOS video modes (VESA number + 0x0200) + +/* VESA BIOS video modes (VESA number + 0x0200) */ #define VIDEO_FIRST_VESA 0x0200 -! Video7 special modes (BIOS number + 0x0900) + +/* Video7 special modes (BIOS number + 0x0900) */ #define VIDEO_FIRST_V7 0x0900 -! Special video modes + +/* Special video modes */ #define VIDEO_FIRST_SPECIAL 0x0f00 #define VIDEO_80x25 0x0f00 #define VIDEO_8POINT 0x0f01 @@ -66,14 +68,15 @@ #define VIDEO_80x60 0x0f07 #define VIDEO_GFX_HACK 0x0f08 #define VIDEO_LAST_SPECIAL 0x0f09 -! Video modes given by resolution + +/* Video modes given by resolution */ #define VIDEO_FIRST_RESOLUTION 0x1000 -! The "recalculate timings" flag +/* The "recalculate timings" flag */ #define VIDEO_RECALC 0x8000 -! Positions of various video parameters passed to the kernel -! (see also include/linux/tty.h) +/* Positions of various video parameters passed to the kernel */ +/* (see also include/linux/tty.h) */ #define PARAM_CURSOR_POS 0x00 #define PARAM_VIDEO_PAGE 0x04 #define PARAM_VIDEO_MODE 0x06 @@ -94,530 +97,505 @@ #define PARAM_VESAPM_OFF 0x30 #define PARAM_LFB_PAGES 0x32 -! Define DO_STORE according to CONFIG_VIDEO_RETAIN + +/* Define DO_STORE according to CONFIG_VIDEO_RETAIN */ #ifdef CONFIG_VIDEO_RETAIN #define DO_STORE call store_screen #else #define DO_STORE #endif /* CONFIG_VIDEO_RETAIN */ -! -! This is the main entry point called by setup.S -! -! Input: -! DS pointing to the boot sector - -video: push ds ! We use different segments - push ds ! FS contains original DS - pop fs - push cs ! DS is equal to CS - pop ds - push cs ! ES is equal to CS - pop es - xor ax,ax - mov gs,ax ! GS is zero +# This is the main entry point called by setup.S +# %ds *must* be pointing to the bootsector +video: pushw %ds # We use different segments + pushw %ds # FS contains original DS + popw %fs + pushw %cs # DS is equal to CS + popw %ds + pushw %cs # ES is equal to CS + popw %es + xorw %ax, %ax + movw %ax, %gs # GS is zero cld - call basic_detect ! Basic adapter type testing (EGA/VGA/MDA/CGA) + call basic_detect # Basic adapter type testing (EGA/VGA/MDA/CGA) #ifdef CONFIG_VIDEO_SELECT - seg fs ! User-selected video mode - mov ax,[0x01fa] - cmp ax,#ASK_VGA ! Bring up the menu + movw %fs:(0x01fa), %ax # User selected video mode + cmpw $ASK_VGA, %ax # Bring up the menu jz vid2 - call mode_set ! Set the mode + + call mode_set # Set the mode jc vid1 - lea si,badmdt ! Invalid mode ID + + leaw badmdt, %si # Invalid mode ID call prtstr vid2: call mode_menu vid1: #ifdef CONFIG_VIDEO_RETAIN - call restore_screen ! Restore screen contents + call restore_screen # Restore screen contents #endif /* CONFIG_VIDEO_RETAIN */ #endif /* CONFIG_VIDEO_SELECT */ - call mode_params ! Store mode parameters - pop ds ! Restore original DS + call mode_params # Store mode parameters + popw %ds # Restore original DS ret -! -! Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel. -! - +# Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel. basic_detect: - seg fs ! Default is no VGA - movb [PARAM_HAVE_VGA],#0 - - mov ah,#0x12 ! Check EGA/VGA - mov bl,#0x10 - int 0x10 - seg fs - mov [PARAM_VIDEO_EGA_BX],bx ! Used for identification of EGA in the kernel - cmp bl,#0x10 ! No, this is a CGA/MDA/HGA card. + movb $0, %fs:(PARAM_HAVE_VGA) + movb $0x12, %ah # Check EGA/VGA + movb $0x10, %bl + int $0x10 + movw %bx, %fs:(PARAM_VIDEO_EGA_BX) # Identifies EGA to the kernel + cmpb $0x10, %bl # No, it's a CGA/MDA/HGA card. je basret - incb [adapter] - - mov ax,#0x1a00 ! Check for EGA/VGA discrimination - int 0x10 - cmp al,#0x1a ! 1a means VGA, anything else EGA - jne basret - seg fs - incb [PARAM_HAVE_VGA] ! We've detected a VGA - incb [adapter] + incb adapter + movw $0x1a00, %ax # Check EGA or VGA? + int $0x10 + cmpb $0x1a, %al # 1a means VGA... + jne basret # anything else is EGA. + + incb %fs:(PARAM_HAVE_VGA) # We've detected a VGA + incb adapter basret: ret -! -! Store the video mode parameters for later usage by the kernel. -! This is done by asking the BIOS except for the rows/columns -! parameters in the default 80x25 mode -- these are set directly, -! because some very obscure BIOSes supply insane values. -! - +# Store the video mode parameters for later usage by the kernel. +# This is done by asking the BIOS except for the rows/columns +# parameters in the default 80x25 mode -- these are set directly, +# because some very obscure BIOSes supply insane values. mode_params: #ifdef CONFIG_VIDEO_SELECT - cmpb [graphic_mode],#0 + cmpb $0, graphic_mode jnz mopar_gr #endif - - mov ah,#0x03 ! Read cursor position - xor bh,bh - int 0x10 - seg fs - mov [PARAM_CURSOR_POS],dx - - mov ah,#0x0f ! Read page/mode/width - int 0x10 - seg fs - mov [PARAM_VIDEO_PAGE],bx - seg fs - mov [PARAM_VIDEO_MODE],ax ! Video mode and screen width - cmp al,#7 ! MDA/HGA => segment differs + movb $0x03, %ah # Read cursor position + xorb %bh, %bh + int $0x10 + movw %dx, %fs:(PARAM_CURSOR_POS) + movb $0x0f, %ah # Read page/mode/width + int $0x10 + movw %bx, %fs:(PARAM_VIDEO_PAGE) + movw %ax, %fs:(PARAM_VIDEO_MODE) # Video mode and screen width + cmpb $0x7, %al # MDA/HGA => segment differs jnz mopar0 - mov [video_segment],#0xb000 -mopar0: seg gs ! Font size - mov ax,[0x485] - seg fs - mov [PARAM_FONT_POINTS],ax ! (valid only on EGA/VGA) - mov ax,[force_size] ! Forced size? - or ax,ax + movw $0xb000, video_segment +mopar0: movw %gs:(0x485), %ax # Font size + movw %ax, %fs:(PARAM_FONT_POINTS) # (valid only on EGA/VGA) + movw force_size, %ax # Forced size? + orw %ax, %ax jz mopar1 - seg fs - mov [PARAM_VIDEO_COLS],ah - seg fs - mov [PARAM_VIDEO_LINES],al - ret -mopar1: mov al,#25 - cmpb [adapter],#0 ! If we are on CGA/MDA/HGA, the screen must - jz mopar2 ! have 25 lines. - seg gs ! On EGA/VGA, use the EGA+ BIOS variable - mov al,[0x484] ! containing maximal line number. - inc al -mopar2: seg fs - movb [PARAM_VIDEO_LINES],al + movb %ah, %fs:(PARAM_VIDEO_COLS) + movb %al, %fs:(PARAM_VIDEO_LINES) ret -#ifdef CONFIG_VIDEO_SELECT +mopar1: movb $25, %al + cmpb $0, adapter # If we are on CGA/MDA/HGA, the + jz mopar2 # screen must have 25 lines. -! -! Fetching of VESA frame buffer parameters -! + movb %gs:(0x484), %al # On EGA/VGA, use the EGA+ BIOS + incb %al # location of max lines. +mopar2: movb %al, %fs:(PARAM_VIDEO_LINES) + ret +#ifdef CONFIG_VIDEO_SELECT +# Fetching of VESA frame buffer parameters mopar_gr: - lea di,modelist+1024 - seg fs - movb [PARAM_HAVE_VGA],#0x23 - - mov ax,(di+16) - seg fs - mov [PARAM_LFB_LINELENGTH],ax - - mov ax,(di+18) - seg fs - mov [PARAM_LFB_WIDTH],ax - - mov ax,(di+20) - seg fs - mov [PARAM_LFB_HEIGHT],ax - - mov al,(di+25) - mov ah,#0 - seg fs - mov [PARAM_LFB_DEPTH],ax - - mov al,(di+29) - mov ah,#0 - seg fs - mov [PARAM_LFB_PAGES],ax - - mov eax,(di+40) - seg fs - mov [PARAM_LFB_BASE],eax - - mov eax,(di+31) - seg fs - mov [PARAM_LFB_COLORS],eax - - mov eax,(di+35) - seg fs - mov [PARAM_LFB_COLORS+4],eax - - ! get video mem size - lea di,modelist+1024 - mov ax,#0x4f00 - int 0x10 - - xor eax,eax - mov ax,(di+18) - seg fs - mov [PARAM_LFB_SIZE],eax - - ! get protected mode interface informations - mov ax,#0x4f0a - xor bx,bx - xor di,di - int 0x10 - cmp ax,#0x004f + leaw modelist+1024, %di + movb $0x23, %fs:(PARAM_HAVE_VGA) + movw 16(%di), %ax + movw %ax, %fs:(PARAM_LFB_LINELENGTH) + movw 18(%di), %ax + movw %ax, %fs:(PARAM_LFB_WIDTH) + movw 20(%di), %ax + movw %ax, %fs:(PARAM_LFB_HEIGHT) + movb 25(%di), %al + movb $0, %ah + movw %ax, %fs:(PARAM_LFB_DEPTH) + movb 29(%di), %al + movb $0, %ah + movw %ax, %fs:(PARAM_LFB_PAGES) + movl 40(%di), %eax + movl %eax, %fs:(PARAM_LFB_BASE) + movl 31(%di), %eax + movl %eax, %fs:(PARAM_LFB_COLORS) + movl 35(%di), %eax + movl %eax, %fs:(PARAM_LFB_COLORS+4) + +# get video mem size + leaw modelist+1024, %di + movw $0x4f00, %ax + int $0x10 + xorl %eax, %eax + movw 18(%di), %ax + movl %eax, %fs:(PARAM_LFB_SIZE) +# get protected mode interface informations + movw $0x4f0a, %ax + xorw %bx, %bx + xorw %di, %di + int $0x10 + cmp $0x004f, %ax jnz no_pm - seg fs - mov [PARAM_VESAPM_SEG],es - seg fs - mov [PARAM_VESAPM_OFF],di -no_pm: - ret - -! -! The video mode menu -! + movw %es, %fs:(PARAM_VESAPM_SEG) + movw %di, %fs:(PARAM_VESAPM_OFF) +no_pm: ret +# The video mode menu mode_menu: - lea si,keymsg ! "Return/Space/Timeout" message + leaw keymsg, %si # "Return/Space/Timeout" message call prtstr call flush nokey: call getkt - cmp al,#0x0d ! ENTER ? - je listm ! yes - manual mode selection - cmp al,#0x20 ! SPACE ? - je defmd1 ! no - repeat + + cmpb $0x0d, %al # ENTER ? + je listm # yes - manual mode selection + + cmpb $0x20, %al # SPACE ? + je defmd1 # no - repeat + call beep jmp nokey -defmd1: ret ! No mode selected => use the 80x25 default -listm: call mode_table ! We need a mode table to be listed -listm0: lea si,name_bann ! Print adapter name +defmd1: ret # No mode chosen? Default 80x25 + +listm: call mode_table # List mode table +listm0: leaw name_bann, %si # Print adapter name call prtstr - mov si,[card_name] - or si,si + movw card_name, %si + orw %si, %si jnz an2 - mov al,[adapter] - lea si,old_name - or al,al + + movb adapter, %al + leaw old_name, %si + orb %al, %al jz an1 - lea si,ega_name - dec al + + leaw ega_name, %si + decb %al jz an1 - lea si,vga_name + + leaw vga_name, %si jmp an1 + an2: call prtstr - lea si,svga_name + leaw svga_name, %si an1: call prtstr - lea si,listhdr ! Table header + leaw listhdr, %si # Table header call prtstr - mov dl,#0x30 ! DL holds mode number - lea si,modelist -lm1: cmp (si),#ASK_VGA ! End? + movb $0x30, %dl # DL holds mode number + leaw modelist, %si +lm1: cmpw $ASK_VGA, (%si) # End? jz lm2 - mov al,dl ! Menu selection number + + movb %dl, %al # Menu selection number call prtchr call prtsp2 lodsw - call prthw ! Mode ID + call prthw # Mode ID call prtsp2 - mov al,(si+1) - call prtdec ! Rows - mov al,#0x78 ! 'x' + movb 0x1(%si), %al + call prtdec # Rows + movb $0x78, %al # the letter 'x' call prtchr lodsw - call prtdec ! Columns - mov al,#0x0d ! New line + call prtdec # Columns + movb $0x0d, %al # New line call prtchr - mov al,#0x0a + movb $0x0a, %al call prtchr - inc dl ! Next character - cmp dl,#0x3a + incb %dl # Next character + cmpb $0x3a, %dl jnz lm1 - mov dl,#0x61 + + movb $0x61, %dl jmp lm1 -lm2: lea si,prompt ! Mode prompt +lm2: leaw prompt, %si # Mode prompt call prtstr - lea di,edit_buf ! Editor buffer + leaw edit_buf, %di # Editor buffer lm3: call getkey - cmp al,#0x0d ! Enter? + cmpb $0x0d, %al # Enter? jz lment - cmp al,#0x08 ! Backspace? + + cmpb $0x08, %al # Backspace? jz lmbs - cmp al,#0x20 ! Printable? + + cmpb $0x20, %al # Printable? jc lm3 - cmp di,#edit_buf+4 ! Enough space? + + cmpw $edit_buf+4, %di # Enough space? jz lm3 + stosb call prtchr jmp lm3 -lmbs: cmp di,#edit_buf ! Backspace +lmbs: cmpw $edit_buf, %di # Backspace jz lm3 - dec di - mov al,#0x08 + + decw %di + movb $0x08, %al call prtchr call prtspc - mov al,#0x08 + movb $0x08, %al call prtchr jmp lm3 - -lment: movb (di),#0 - lea si,crlft + +lment: movb $0, (%di) + leaw crlft, %si call prtstr - lea si,edit_buf - cmpb (si),#0 ! Empty string => use default mode + leaw edit_buf, %si + cmpb $0, (%si) # Empty string = default mode jz lmdef - cmpb (si+1),#0 ! One character => menu selection + + cmpb $0, 1(%si) # One character = menu selection jz mnusel - cmp (si),#0x6373 ! "scan" => mode scanning + + cmpw $0x6373, (%si) # "scan" => mode scanning jnz lmhx - cmp (si+2),#0x6e61 + + cmpw $0x6e61, 2(%si) jz lmscan -lmhx: xor bx,bx ! Else => mode ID in hex + +lmhx: xorw %bx, %bx # Else => mode ID in hex lmhex: lodsb - or al,al + orb %al, %al jz lmuse1 - sub al,#0x30 + + subb $0x30, %al jc lmbad - cmp al,#10 + + cmpb $10, %al jc lmhx1 - sub al,#7 - and al,#0xdf - cmp al,#10 + + subb $7, %al + andb $0xdf, %al + cmpb $10, %al jc lmbad - cmp al,#16 + + cmpb $16, %al jnc lmbad -lmhx1: shl bx,#4 - or bl,al + +lmhx1: shlw $4, %bx + orb %al, %bl jmp lmhex -lmuse1: mov ax,bx + +lmuse1: movw %bx, %ax jmp lmuse -mnusel: lodsb ! Menu selection - xor ah,ah - sub al,#0x30 +mnusel: lodsb # Menu selection + xorb %ah, %ah + subb $0x30, %al jc lmbad - cmp al,#10 + + cmpb $10, %al jc lmuse - cmp al,#0x61-0x30 + + cmpb $0x61-0x30, %al jc lmbad - sub al,#0x61-0x30-10 - cmp al,#36 + + subb $0x61-0x30-10, %al + cmpb $36, %al jnc lmbad + lmuse: call mode_set jc lmdef -lmbad: lea si,unknt - call prtstr - br lm2 -lmscan: cmpb [adapter],#0 ! Scanning supported only on EGA/VGA +lmbad: leaw unknt, %si + call prtstr + jmp lm2 +lmscan: cmpb $0, adapter # Scanning only on EGA/VGA jz lmbad - mov [mt_end],#0 ! Scanning of modes: done as new autodetection - movb [scanning],#1 - call mode_table - br listm0 + movw $0, mt_end # Scanning of modes is + movb $1, scanning # done as new autodetection. + call mode_table + jmp listm0 lmdef: ret -! -! Additional parts of mode_set... (relative jumps, you know) -! - -setv7: ! Video7 extended modes +# Additional parts of mode_set... (relative jumps, you know) +setv7: # Video7 extended modes DO_STORE - sub bh,#VIDEO_FIRST_V7>>8 - mov ax,#0x6f05 - int 0x10 + subb $VIDEO_FIRST_V7>>8, %bh + movw $0x6f05, %ax + int $0x10 stc ret -_setrec: br setrec ! Ugly... -_set_80x25: br set_80x25 - -! -! Aliases for backward compatibility. -! +_setrec: jmp setrec # Ugly... +_set_80x25: jmp set_80x25 +# Aliases for backward compatibility. setalias: - mov ax,#VIDEO_80x25 - inc bx + movw $VIDEO_80x25, %ax + incw %bx jz mode_set - mov al,#VIDEO_8POINT-VIDEO_FIRST_SPECIAL - inc bx - jnz setbad - ! Fall-through! - -! -! Setting of user mode (AX=mode ID) => CF=success -! + movb $VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al + incw %bx + jnz setbad # Fall-through! +# Setting of user mode (AX=mode ID) => CF=success mode_set: - mov bx,ax - cmp ah,#0xff + movw %ax, %bx + cmpb $0xff, %ah jz setalias - test ah,#VIDEO_RECALC>>8 + + testb $VIDEO_RECALC>>8, %ah jnz _setrec - cmp ah,#VIDEO_FIRST_RESOLUTION>>8 + + cmpb $VIDEO_FIRST_RESOLUTION>>8, %ah jnc setres - cmp ah,#VIDEO_FIRST_SPECIAL>>8 + + cmpb $VIDEO_FIRST_SPECIAL>>8, %ah jz setspc - cmp ah,#VIDEO_FIRST_V7>>8 + + cmpb $VIDEO_FIRST_V7>>8, %ah jz setv7 - cmp ah,#VIDEO_FIRST_VESA>>8 + + cmpb $VIDEO_FIRST_VESA>>8, %ah jnc check_vesa - or ah,ah + + orb %ah, %ah jz setmenu - dec ah + + decb %ah jz setbios + setbad: clc - movb [do_restore],#0 ! The screen needn't be restored + movb $0, do_restore # The screen needn't be restored ret setvesa: DO_STORE - sub bh,#VIDEO_FIRST_VESA>>8 - mov ax,#0x4f02 ! VESA BIOS mode set call - int 0x10 - cmp ax,#0x004f ! AL=4f if implemented, AH=0 if OK - jnz setbad + subb $VIDEO_FIRST_VESA>>8, %bh + movw $0x4f02, %ax # VESA BIOS mode set call + int $0x10 + cmpw $0x004f, %ax # AL=4f if implemented + jnz setbad # AH=0 if OK + stc ret setbios: DO_STORE - int 0x10 ! Standard BIOS mode set call - push bx - mov ah,#0x0f ! Check if really set - int 0x10 - pop bx - cmp al,bl + int $0x10 # Standard BIOS mode set call + pushw %bx + movb $0x0f, %ah # Check if really set + int $0x10 + popw %bx + cmpb %bl, %al jnz setbad + stc ret -setspc: xor bh,bh ! Set special mode - cmp bl,#VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL +setspc: xorb %bh, %bh # Set special mode + cmpb $VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl jnc setbad - add bx,bx - .word 0xa7ff, spec_inits ! JMP [BX+spec_inits] + + addw %bx, %bx + .word 0xa7ff, spec_inits # JMP [BX+spec_inits] setmenu: - or al,al ! 80x25 is an exception + orb %al, %al # 80x25 is an exception jz _set_80x25 - push bx ! Set mode chosen from menu - call mode_table ! Build the mode table - pop ax - shl ax,#2 - add si,ax - cmp si,di + + pushw %bx # Set mode chosen from menu + call mode_table # Build the mode table + popw %ax + shlw $2, %ax + addw %ax, %si + cmpw %di, %si jnc setbad - mov ax,(si) ! Fetch mode ID + + movw (%si), %ax # Fetch mode ID _m_s: jmp mode_set -setres: - push bx ! Set mode chosen by its resolution +setres: pushw %bx # Set mode chosen by resolution call mode_table - pop bx - xchg bh,bl + popw %bx + xchgb %bl, %bh setr1: lodsw - cmp ax,#ASK_VGA ! End of the list? + cmpw $ASK_VGA, %ax # End of the list? jz setbad + lodsw - cmp ax,bx + cmpw %bx, %ax jnz setr1 - mov ax,(si-4) ! Fetch mode ID + + movw -4(%si), %ax # Fetch mode ID jmp _m_s - check_vesa: - lea di,modelist+1024 - sub bh,#VIDEO_FIRST_VESA>>8 - mov cx,bx ! Get mode information structure - mov ax,#0x4f01 - int 0x10 - add bh,#VIDEO_FIRST_VESA>>8 - cmp ax,#0x004f + leaw modelist+1024, %di + subb $VIDEO_FIRST_VESA>>8, %bh + movw %bx, %cx # Get mode information structure + movw $0x4f01, %ax + int $0x10 + addb $VIDEO_FIRST_VESA>>8, %bh + cmpw $0x004f, %ax jnz setbad - mov al,(di) ! Check capabilities. - and al,#0x19 - cmp al,#0x09 - jz setvesa ! this is a text mode - - mov al,(di) ! Check capabilities. - and al,#0x99 - cmp al,#0x99 - jnz _setbad ! to bad, no linear frame buffer - - sub bh,#VIDEO_FIRST_VESA>>8 - or bx,#0x4000 ! want use linear frame buffer - mov ax,#0x4f02 ! VESA BIOS mode set call - int 0x10 - cmp ax,#0x004f ! AL=4f if implemented, AH=0 if OK - jnz _setbad + movb (%di), %al # Check capabilities. + andb $0x19, %al + cmpb $0x09, %al + jz setvesa # This is a text mode + + movb (%di), %al # Check capabilities. + andb $0x99, %al + cmpb $0x99, %al + jnz _setbad # Doh! No linear frame buffer. + + subb $VIDEO_FIRST_VESA>>8, %bh + orw $0x4000, %bx # Use linear frame buffer + movw $0x4f02, %ax # VESA BIOS mode set call + int $0x10 + cmpw $0x004f, %ax # AL=4f if implemented + jnz _setbad # AH=0 if OK - movb [graphic_mode],#1 ! flag graphic mode - movb [do_restore],#0 ! no screen restore + movb $1, graphic_mode # flag graphic mode + movb $0, do_restore # no screen restore stc ret - -_setbad: br setbad ! Ugly... - -! -! Recalculate vertical display end registers -- this fixes various -! inconsistencies of extended modes on many adapters. Called when -! the VIDEO_RECALC flag is set in the mode ID. -! -setrec: sub ah,#VIDEO_RECALC>>8 ! Set the base mode +_setbad: jmp setbad # Ugly... + +# Recalculate vertical display end registers -- this fixes various +# inconsistencies of extended modes on many adapters. Called when +# the VIDEO_RECALC flag is set in the mode ID. + +setrec: subb $VIDEO_RECALC>>8, %ah # Set the base mode call mode_set jnc rct3 - seg gs ! Font size in pixels - mov ax,[0x485] - seg gs ! Number of rows - mov bl,[0x484] - inc bl - mul bl ! Number of visible - dec ax ! scan lines - 1 - mov dx,#0x3d4 - mov bx,ax - mov al,#0x12 ! Lower 8 bits - mov ah,bl - out dx,ax - mov al,#0x07 ! Bits 8 and 9 in the overflow register + + movw %gs:(0x485), %ax # Font size in pixels + movb %gs:(0x484), %bl # Number of rows + incb %bl + mulb %bl # Number of visible + decw %ax # scan lines - 1 + movw $0x3d4, %dx + movw %ax, %bx + movb $0x12, %al # Lower 8 bits + movb %bl, %ah + outw %ax, %dx + movb $0x07, %al # Bits 8 and 9 in the overflow register call inidx - xchg ah,al - and ah,#0xbd - shr bh,#1 + xchgb %al, %ah + andb $0xbd, %ah + shrb %bh jnc rct1 - or ah,#0x02 -rct1: shr bh,#1 + orb $0x02, %ah +rct1: shrb %bh jnc rct2 - or ah,#0x40 -rct2: mov al,#0x07 - out dx,ax + orb $0x40, %ah +rct2: movb $0x07, %al + outw %ax, %dx stc rct3: ret -! -! Table of routines for setting of the special modes. -! - +# Table of routines for setting of the special modes. spec_inits: .word set_80x25 .word set_8pixel @@ -629,589 +607,575 @@ .word set_80x60 .word set_gfx -! -! Set the 80x25 mode. If already set, do nothing. -! - +# Set the 80x25 mode. If already set, do nothing. set_80x25: - mov [force_size],#0x5019 ! Override possibly broken BIOS vars + movw $0x5019, force_size # Override possibly broken BIOS use_80x25: #ifdef CONFIG_VIDEO_400_HACK - mov ax,#0x1202 ! Force 400 scan lines - mov bl,#0x30 - int 0x10 + movw $0x1202, %ax # Force 400 scan lines + movb $0x30, %bl + int $0x10 #else - mov ah,#0x0f ! Get current mode ID - int 0x10 - cmp ax,#0x5007 ! Mode 7 (80x25 mono) is the only one available - jz st80 ! on CGA/MDA/HGA and is also available on EGAM - cmp ax,#0x5003 ! Unknown mode => force 80x25 color + movb $0x0f, %ah # Get current mode ID + int $0x10 + cmpw $0x5007, %ax # Mode 7 (80x25 mono) is the only one available + jz st80 # on CGA/MDA/HGA and is also available on EGAM + + cmpw $0x5003, %ax # Unknown mode, force 80x25 color jnz force3 -st80: cmpb [adapter],#0 ! CGA/MDA/HGA => mode 3/7 is always 80x25 + +st80: cmpb $0, adapter # CGA/MDA/HGA => mode 3/7 is always 80x25 jz set80 - seg gs ! This is EGA+ -- beware of 80x50 etc. - mov al,[0x0484] - or al,al ! Some buggy BIOSes set 0 rows + + movb %gs:(0x0484), %al # This is EGA+ -- beware of 80x50 etc. + orb %al, %al # Some buggy BIOS'es set 0 rows jz set80 - cmp al,#24 ! Let's hope this is correct + + cmpb $24, %al # It's hopefully correct jz set80 #endif /* CONFIG_VIDEO_400_HACK */ force3: DO_STORE - mov ax,#0x0003 ! Forced set - int 0x10 + movw $0x0003, %ax # Forced set + int $0x10 set80: stc ret -! -! Set the 80x50/80x43 8-pixel mode. Simple BIOS calls. -! - +# Set the 80x50/80x43 8-pixel mode. Simple BIOS calls. set_8pixel: DO_STORE - call use_80x25 ! The base is 80x25 + call use_80x25 # The base is 80x25 set_8pt: - mov ax,#0x1112 ! Use 8x8 font - xor bl,bl - int 0x10 - mov ax,#0x1200 ! Use alternate print screen - mov bl,#0x20 - int 0x10 - mov ax,#0x1201 ! Turn off cursor emulation - mov bl,#0x34 - int 0x10 - mov ah,#0x01 ! Define cursor (scan lines 6 to 7) - mov cx,#0x0607 - int 0x10 + movw $0x1112, %ax # Use 8x8 font + xorb %bl, %bl + int $0x10 + movw $0x1200, %ax # Use alternate print screen + movb $0x20, %bl + int $0x10 + movw $0x1201, %ax # Turn off cursor emulation + movb $0x34, %bl + int $0x10 + movb $0x01, %ah # Define cursor scan lines 6-7 + movw $0x0607, %cx + int $0x10 set_current: stc ret -! -! Set the 80x28 mode. This mode works on all VGA's, because it's a standard -! 80x25 mode with 14-point fonts instead of 16-point. -! - +# Set the 80x28 mode. This mode works on all VGA's, because it's a standard +# 80x25 mode with 14-point fonts instead of 16-point. set_80x28: DO_STORE - call use_80x25 ! The base is 80x25 -set14: mov ax,#0x1111 ! Use 9x14 font - xor bl,bl - int 0x10 - mov ah,#0x01 ! Define cursor (scan lines 11 to 12) - mov cx,#0x0b0c - int 0x10 + call use_80x25 # The base is 80x25 +set14: movw $0x1111, %ax # Use 9x14 font + xorb %bl, %bl + int $0x10 + movb $0x01, %ah # Define cursor scan lines 11-12 + movw $0x0b0c, %cx + int $0x10 stc ret -! -! Set the 80x43 mode. This mode is works on all VGA's. -! It's a 350-scanline mode with 8-pixel font. -! - +# Set the 80x43 mode. This mode is works on all VGA's. +# It's a 350-scanline mode with 8-pixel font. set_80x43: DO_STORE - mov ax,#0x1201 ! Set 350 scans - mov bl,#0x30 - int 0x10 - mov ax,#0x0003 ! Reset video mode - int 0x10 - jmp set_8pt ! Use 8-pixel font - -! -! Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font. -! + movw $0x1201, %ax # Set 350 scans + movb $0x30, %bl + int $0x10 + movw $0x0003, %ax # Reset video mode + int $0x10 + jmp set_8pt # Use 8-pixel font +# Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font. set_80x30: - call use_80x25 ! Start with real 80x25 + call use_80x25 # Start with real 80x25 DO_STORE - mov dx,#0x3cc ! Get CRTC port - in al,dx - mov dl,#0xd4 - ror al,#1 ! Mono or color? + movw $0x3cc, %dx # Get CRTC port + inb %dx, %al + movb $0xd4, %dl + rorb %al # Mono or color? jc set48a - mov dl,#0xb4 -set48a: mov ax,#0x0c11 ! Vertical sync end (also unlocks CR0-7) + + movb $0xb4, %dl +set48a: movw $0x0c11, %ax # Vertical sync end (also unlocks CR0-7) call outidx - mov ax,#0x0b06 ! Vertical total + movw $0x0b06, %ax # Vertical total call outidx - mov ax,#0x3e07 ! (Vertical) overflow + movw $0x3e07, %ax # (Vertical) overflow call outidx - mov ax,#0xea10 ! Vertical sync start + movw $0xea10, %ax # Vertical sync start call outidx - mov ax,#0xdf12 ! Vertical display end + movw $0xdf12, %ax # Vertical display end call outidx - mov ax,#0xe715 ! Vertical blank start + movw $0xe715, %ax # Vertical blank start call outidx - mov ax,#0x0416 ! Vertical blank end + movw $0x0416, %ax # Vertical blank end call outidx - push dx - mov dl,#0xcc ! Misc output register (read) - in al,dx - mov dl,#0xc2 ! (write) - and al,#0x0d ! Preserve clock select bits and color bit - or al,#0xe2 ! Set correct sync polarity - out dx,al - pop dx - mov [force_size],#0x501e - stc ! That's all. + pushw %dx + movb $0xcc, %dl # Misc output register (read) + inb %dx, %al + movb $0xc2, %dl # (write) + andb $0x0d, %al # Preserve clock select bits and color bit + orb $0xe2, %al # Set correct sync polarity + outb %al, %dx + popw %dx + movw $0x501e, force_size + stc # That's all. ret -! -! Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font. -! - +# Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font. set_80x34: - call set_80x30 ! Set 480 scans - call set14 ! And 14-pt font - mov ax,#0xdb12 ! VGA vertical display end - mov [force_size],#0x5022 + call set_80x30 # Set 480 scans + call set14 # And 14-pt font + movw $0xdb12, %ax # VGA vertical display end + movw $0x5022, force_size setvde: call outidx stc ret -! -! Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font. -! - +# Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font. set_80x60: - call set_80x30 ! Set 480 scans - call set_8pt ! And 8-pt font - mov ax,#0xdf12 ! VGA vertical display end - mov [force_size],#0x503c + call set_80x30 # Set 480 scans + call set_8pt # And 8-pt font + movw $0xdf12, %ax # VGA vertical display end + movw $0x503c, force_size jmp setvde -! -! Special hack for ThinkPad graphics -! - +# Special hack for ThinkPad graphics set_gfx: #ifdef CONFIG_VIDEO_GFX_HACK - mov ax,# VIDEO_GFX_BIOS_AX - mov bx,# VIDEO_GFX_BIOS_BX - int 0x10 - mov [force_size],# VIDEO_GFX_DUMMY_RESOLUTION + movw $VIDEO_GFX_BIOS_AX, %ax + movw $VIDEO_GFX_BIOS_BX, %bx + int $0x10 + movw $VIDEO_GFX_DUMMY_RESOLUTION, force_size stc #endif ret #ifdef CONFIG_VIDEO_RETAIN -! -! Store screen contents to temporary buffer. -! - +# Store screen contents to temporary buffer. store_screen: - cmpb [do_restore],#0 ! Already stored? + cmpb $0, do_restore # Already stored? jnz stsr - testb [loadflags],#CAN_USE_HEAP ! Have we space for storing? + + testb $CAN_USE_HEAP, loadflags # Have we space for storing? jz stsr - push ax - push bx - push [force_size] ! Don't force specific size - mov [force_size],#0 - call mode_params ! Obtain params of current mode - pop [force_size] - - seg fs - mov ah,[PARAM_VIDEO_LINES] - seg fs - mov al,[PARAM_VIDEO_COLS] - mov bx,ax ! BX=dimensions - mul ah - mov cx,ax ! CX=number of characters to store - add ax,ax ! Calculate image size - add ax,#modelist+1024+4 - cmp ax,[heap_end_ptr] - jnc sts1 ! Unfortunately, out of memory - - seg fs ! Store mode params - mov ax,[PARAM_CURSOR_POS] - lea di,modelist+1024 + + pushw %ax + pushw %bx + pushw force_size # Don't force specific size + movw $0, force_size + call mode_params # Obtain params of current mode + popw force_size + movb %fs:(PARAM_VIDEO_LINES), %ah + movb %fs:(PARAM_VIDEO_COLS), %al + movw %ax, %bx # BX=dimensions + mulb %ah + movw %ax, %cx # CX=number of characters + addw %ax, %ax # Calculate image size + addw $modelist+1024+4, %ax + cmpw heap_end_ptr, %ax + jnc sts1 # Unfortunately, out of memory + + movw %fs:(PARAM_CURSOR_POS), %ax # Store mode params + leaw modelist+1024, %di stosw - mov ax,bx + movw %bx, %ax stosw - - push ds ! Store the screen - mov ds,[video_segment] - xor si,si + pushw %ds # Store the screen + movw video_segment, %ds + xorw %si, %si rep movsw - pop ds - incb [do_restore] ! Screen will be restored later -sts1: pop bx - pop ax + popw %ds + incb do_restore # Screen will be restored later +sts1: popw %bx + popw %ax stsr: ret -! -! Restore screen contents from temporary buffer. -! - +# Restore screen contents from temporary buffer. restore_screen: - cmpb [do_restore],#0 ! Has the screen been stored? + cmpb $0, do_restore # Has the screen been stored? jz res1 - call mode_params ! Get parameters of current mode - seg fs - mov cl,[PARAM_VIDEO_LINES] - seg fs - mov ch,[PARAM_VIDEO_COLS] - lea si,modelist+1024 ! Screen buffer - lodsw ! Set cursor position - mov dx,ax - cmp dh,cl + + call mode_params # Get parameters of current mode + movb %fs:(PARAM_VIDEO_LINES), %cl + movb %fs:(PARAM_VIDEO_COLS), %ch + leaw modelist+1024, %si # Screen buffer + lodsw # Set cursor position + movw %ax, %dx + cmpb %cl, %dh jc res2 - mov dh,cl - dec dh -res2: cmp dl,ch + + movb %cl, %dh + decb %dh +res2: cmpb %ch, %dl jc res3 - mov dl,ch - dec dl -res3: mov ah,#0x02 - mov bh,#0x00 - int 0x10 - lodsw ! Display size - mov dl,ah ! DL=number of lines - mov ah,#0 ! BX=physical length of orig. line - mov bx,ax - cmp dl,cl ! Too many? + + movb %ch, %dl + decb %dl +res3: movb $0x02, %ah + movb $0x00, %bh + int $0x10 + lodsw # Display size + movb %ah, %dl # DL=number of lines + movb $0, %ah # BX=phys. length of orig. line + movw %ax, %bx + cmpb %cl, %dl # Too many? jc res4 - push ax - mov al,dl - sub al,cl - mul bl - add si,ax - add si,ax - pop ax - mov dl,cl -res4: cmp al,ch ! Too wide? + + pushw %ax + movb %dl, %al + subb %cl, %al + mulb %bl + addw %ax, %si + addw %ax, %si + popw %ax + movb %cl, %dl +res4: cmpb %ch, %al # Too wide? jc res5 - mov al,ch ! AX=width of src. line -res5: mov cl,#0 - xchg cl,ch - mov bp,cx ! BP=width of dest. line - push es - mov es,[video_segment] - xor di,di ! Move the data - add bx,bx ! Convert BX and BP to _bytes_ - add bp,bp -res6: push si - push di - mov cx,ax + + movb %ch, %al # AX=width of src. line +res5: movb $0, %cl + xchgb %ch, %cl + movw %cx, %bp # BP=width of dest. line + pushw %es + movw video_segment, %es + xorw %di, %di # Move the data + addw %bx, %bx # Convert BX and BP to _bytes_ + addw %bp, %bp +res6: pushw %si + pushw %di + movw %ax, %cx rep movsw - pop di - pop si - add di,bp - add si,bx - dec dl + popw %di + popw %si + addw %bp, %di + addw %bx, %si + decb %dl jnz res6 - pop es ! Done + + popw %es # Done res1: ret - #endif /* CONFIG_VIDEO_RETAIN */ -! -! Write to indexed VGA register (AL=index, AH=data, DX=index reg. port) -! - -outidx: out dx,al - push ax - mov al,ah - inc dx - out dx,al - dec dx - pop ax - ret - -! -! Build the table of video modes (stored after the setup.S code at the -! `modelist' label. Each video mode record looks like: -! .word MODE-ID (our special mode ID (see above)) -! .byte rows (number of rows) -! .byte columns (number of columns) -! Returns address of the end of the table in DI, the end is marked -! with a ASK_VGA ID. -! - +# Write to indexed VGA register (AL=index, AH=data, DX=index reg. port) +outidx: outb %al, %dx + pushw %ax + movb %ah, %al + incw %dx + outb %al, %dx + decw %dx + popw %ax + ret + +# Build the table of video modes (stored after the setup.S code at the +# `modelist' label. Each video mode record looks like: +# .word MODE-ID (our special mode ID (see above)) +# .byte rows (number of rows) +# .byte columns (number of columns) +# Returns address of the end of the table in DI, the end is marked +# with a ASK_VGA ID. mode_table: - mov di,[mt_end] ! Already filled? - or di,di + movw mt_end, %di # Already filled? + orw %di, %di jnz mtab1x - lea di,modelist ! Store standard modes: - - mov eax,#VIDEO_80x25 + 0x50190000 ! The 80x25 mode (ALL) - stosd - mov al,[adapter] ! CGA/MDA/HGA -- no more modes - or al,al + + leaw modelist, %di # Store standard modes: + movl $VIDEO_80x25 + 0x50190000, %eax # The 80x25 mode (ALL) + stosl + movb adapter, %al # CGA/MDA/HGA -- no more modes + orb %al, %al jz mtabe - dec al + + decb %al jnz mtabv - mov eax,#VIDEO_8POINT + 0x502b0000 ! The 80x43 EGA mode - stosd + + movl $VIDEO_8POINT + 0x502b0000, %eax # The 80x43 EGA mode + stosl jmp mtabe + mtab1x: jmp mtab1 -mtabv: lea si,vga_modes ! All modes for std VGA - mov cx,#vga_modes_end-vga_modes - rep ! I'm unable to use movsw as I don't know how to store a half - movsb ! of the expression above to cx without using explicit shr. +mtabv: leaw vga_modes, %si # All modes for std VGA + movw $vga_modes_end-vga_modes, %cx + rep # I'm unable to use movsw as I don't know how to store a half + movsb # of the expression above to cx without using explicit shr. - cmpb [scanning],#0 ! Mode scan requested? + cmpb $0, scanning # Mode scan requested? jz mscan1 + call mode_scan mscan1: #ifdef CONFIG_VIDEO_LOCAL call local_modes #endif /* CONFIG_VIDEO_LOCAL */ + #ifdef CONFIG_VIDEO_VESA - call vesa_modes ! Detect VESA VGA modes + call vesa_modes # Detect VESA VGA modes #endif /* CONFIG_VIDEO_VESA */ + #ifdef CONFIG_VIDEO_SVGA - cmpb [scanning],#0 ! Bypass when scanning + cmpb $0, scanning # Bypass when scanning jnz mscan2 - call svga_modes ! Detect SVGA cards & modes + + call svga_modes # Detect SVGA cards & modes mscan2: #endif /* CONFIG_VIDEO_SVGA */ mtabe: #ifdef CONFIG_VIDEO_COMPACT - lea si,modelist ! Compact video mode list if requested. - mov dx,di - mov di,si -cmt1: cmp si,dx ! Scan all modes + leaw modelist, %si + movw %di, %dx + movw %si, %di +cmt1: cmpw %dx, %si # Scan all modes jz cmt2 - lea bx,modelist ! Find in previous entries - mov cx,(si+2) -cmt3: cmp si,bx + + leaw modelist, %bx # Find in previous entries + movw 2(%si), %cx +cmt3: cmpw %bx, %si jz cmt4 - cmp cx,(bx+2) ! Found => don't copy this entry + + cmpw 2(%bx), %cx # Found => don't copy this entry jz cmt5 - add bx,#4 + + addw $4, %bx jmp cmt3 -cmt4: movsd ! Copy entry +cmt4: movsl # Copy entry jmp cmt1 -cmt5: add si,#4 ! Skip entry +cmt5: addw $4, %si # Skip entry jmp cmt1 cmt2: #endif /* CONFIG_VIDEO_COMPACT */ - mov (di),#ASK_VGA ! End marker - mov [mt_end],di -mtab1: lea si,modelist ! Returning: SI=mode list, DI=list end + movw $ASK_VGA, (%di) # End marker + movw %di, mt_end +mtab1: leaw modelist, %si # SI=mode list, DI=list end ret0: ret -! Modes usable on all standard VGAs - +# Modes usable on all standard VGAs vga_modes: .word VIDEO_8POINT - .word 0x5032 ! 80x50 + .word 0x5032 # 80x50 .word VIDEO_80x43 - .word 0x502b ! 80x43 + .word 0x502b # 80x43 .word VIDEO_80x28 - .word 0x501c ! 80x28 + .word 0x501c # 80x28 .word VIDEO_80x30 - .word 0x501e ! 80x30 + .word 0x501e # 80x30 .word VIDEO_80x34 - .word 0x5022 ! 80x34 + .word 0x5022 # 80x34 .word VIDEO_80x60 - .word 0x503c ! 80x60 + .word 0x503c # 80x60 #ifdef CONFIG_VIDEO_GFX_HACK .word VIDEO_GFX_HACK .word VIDEO_GFX_DUMMY_RESOLUTION #endif -vga_modes_end: -! -! Detect VESA modes. -! +vga_modes_end: +# Detect VESA modes. #ifdef CONFIG_VIDEO_VESA - vesa_modes: - cmpb [adapter],#2 ! VGA only + cmpb $2, adapter # VGA only jnz ret0 - mov bp,di ! BP=original mode table end - add di,#0x200 ! Buffer space - mov ax,#0x4f00 ! VESA Get card info call - int #0x10 - mov di,bp - cmp ax,#0x004f ! Successful? + + movw %di, %bp # BP=original mode table end + addw $0x200, %di # Buffer space + movw $0x4f00, %ax # VESA Get card info call + int $0x10 + movw %bp, %di + cmpw $0x004f, %ax # Successful? jnz ret0 - cmp (di+0x200),#0x4556 + + cmpw $0x4556, 0x200(%di) jnz ret0 - cmp (di+0x202),#0x4153 + + cmpw $0x4153, 0x202(%di) jnz ret0 - mov [card_name],#vesa_name ! Set name to "VESA VGA" - push gs - lgs si,(di+0x20e) ! GS:SI=mode list - mov cx,#128 ! Iteration limit -vesa1: seg gs ! Get next mode in the list - lodsw - cmp ax,#0xffff ! End of the table? + + movw $vesa_name, card_name # Set name to "VESA VGA" + pushw %gs + lgsw 0x20e(%di), %si # GS:SI=mode list + movw $128, %cx # Iteration limit +vesa1: +# gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst. +# XXX: lodsw %gs:(%si), %ax # Get next mode in the list + .byte 0x66, 0x65, 0xAD + cmpw $0xffff, %ax # End of the table? jz vesar - cmp ax,#0x0080 ! Check validity of mode ID + + cmpw $0x0080, %ax # Check validity of mode ID jc vesa2 - or ah,ah ! Valid IDs are 0x0000-0x007f and 0x0100-0x07ff - jz vesan ! [Certain BIOSes erroneously report 0x80-0xff] - cmp ax,#0x0800 + + orb %ah, %ah # Valid IDs: 0x0000-0x007f/0x0100-0x07ff + jz vesan # Certain BIOSes report 0x80-0xff! + + cmpw $0x0800, %ax jnc vesae -vesa2: push cx - mov cx,ax ! Get mode information structure - mov ax,#0x4f01 - int 0x10 - mov bx,cx ! BX=mode number - add bh,#VIDEO_FIRST_VESA>>8 - pop cx - cmp ax,#0x004f - jnz vesan ! Don't report errors (buggy BIOSES :-[ ) - mov al,(di) ! Check capabilities. We require - and al,#0x19 ! a color text mode. - cmp al,#0x09 + +vesa2: pushw %cx + movw %ax, %cx # Get mode information structure + movw $0x4f01, %ax + int $0x10 + movw %cx, %bx # BX=mode number + addb $VIDEO_FIRST_VESA>>8, %bh + popw %cx + cmpw $0x004f, %ax + jnz vesan # Don't report errors (buggy BIOSES) + + movb (%di), %al # Check capabilities. We require + andb $0x19, %al # a color text mode. + cmpb $0x09, %al jnz vesan - cmp (di+8),#0xb800 ! Standard video memory address required + + cmpw $0xb800, 8(%di) # Standard video memory address required jnz vesan - testb (di),#2 ! Mode characteristics supplied? - mov (di),bx ! Store mode number + + testb $2, (%di) # Mode characteristics supplied? + movw %bx, (%di) # Store mode number jz vesa3 - xor dx,dx - mov bx,(di+0x12) ! Width - or bh,bh + + xorw %dx, %dx + movw 0x12(%di), %bx # Width + orb %bh, %bh jnz vesan - mov (di+3),bl - mov ax,(di+0x14) ! Height - or ah,ah + + movb %bl, 0x3(%di) + movw 0x14(%di), %ax # Height + orb %ah, %ah jnz vesan - mov (di+2),al - mul bl - cmp ax,#8193 ! Small enough for Linux console driver? + + movb %al, 2(%di) + mulb %bl + cmpw $8193, %ax # Small enough for Linux console driver? jnc vesan + jmp vesaok -vesa3: sub bx,#0x8108 ! This mode has no detailed info specified, - jc vesan ! so it must be a standard VESA mode. - cmp bx,#5 +vesa3: subw $0x8108, %bx # This mode has no detailed info specified, + jc vesan # so it must be a standard VESA mode. + + cmpw $5, %bx jnc vesan - mov ax,(bx+vesa_text_mode_table) - mov (di+2),ax -vesaok: add di,#4 ! The mode is valid. Store it. -vesan: loop vesa1 ! Next mode. Limit exceeded => error -vesae: lea si,vesaer + + movw vesa_text_mode_table(%bx), %ax + movw %ax, 2(%di) +vesaok: addw $4, %di # The mode is valid. Store it. +vesan: loop vesa1 # Next mode. Limit exceeded => error +vesae: leaw vesaer, %si call prtstr - mov di,bp ! Discard already found modes. -vesar: pop gs + movw %bp, %di # Discard already found modes. +vesar: popw %gs ret -! -! Dimensions of standard VESA text modes -! - +# Dimensions of standard VESA text modes vesa_text_mode_table: - db 60, 80 ! 0108 - db 25, 132 ! 0109 - db 43, 132 ! 010A - db 50, 132 ! 010B - db 60, 132 ! 010C - + .byte 60, 80 # 0108 + .byte 25, 132 # 0109 + .byte 43, 132 # 010A + .byte 50, 132 # 010B + .byte 60, 132 # 010C #endif /* CONFIG_VIDEO_VESA */ -! -! Scan for video modes. A bit dirty, but should work. -! - +# Scan for video modes. A bit dirty, but should work. mode_scan: - mov cx,#0x0100 ! Start with mode 0 -scm1: mov ah,#0 ! Test the mode - mov al,cl - int 0x10 - mov ah,#0x0f - int 0x10 - cmp al,cl - jnz scm2 ! Mode not set - mov dx,#0x3c0 ! Test if it's a text mode - mov al,#0x10 ! Mode bits + movw $0x0100, %cx # Start with mode 0 +scm1: movb $0, %ah # Test the mode + movb %cl, %al + int $0x10 + movb $0x0f, %ah + int $0x10 + cmpb %cl, %al + jnz scm2 # Mode not set + + movw $0x3c0, %dx # Test if it's a text mode + movb $0x10, %al # Mode bits call inidx - and al,#0x03 + andb $0x03, %al jnz scm2 - mov dl,#0xce ! Another set of mode bits - mov al,#0x06 + + movb $0xce, %dl # Another set of mode bits + movb $0x06, %al call inidx - shr al,#1 + shrb %al jc scm2 - mov dl,#0xd4 ! Cursor location - mov al,#0x0f + + movb $0xd4, %dl # Cursor location + movb $0x0f, %al call inidx - or al,al + orb %al, %al jnz scm2 - mov ax,cx ! OK, store the mode + + movw %cx, %ax # Ok, store the mode stosw - seg gs ! Number of rows - mov al,[0x484] - inc al + movb %gs:(0x484), %al # Number of rows + incb %al stosb - seg gs ! Number of columns - mov ax,[0x44a] + movw %gs:(0x44a), %ax # Number of columns stosb -scm2: inc cl +scm2: incb %cl jns scm1 - mov ax,#0x0003 ! Return back to mode 3 - int 0x10 + + movw $0x0003, %ax # Return back to mode 3 + int $0x10 ret -tstidx: out dx,ax ! OUT DX,AX and inidx -inidx: out dx,al ! Read from indexed VGA register - inc dx ! AL=index, DX=index reg port -> AL=data - in al,dx - dec dx +tstidx: outw %ax, %dx # OUT DX,AX and inidx +inidx: outb %al, %dx # Read from indexed VGA register + incw %dx # AL=index, DX=index reg port -> AL=data + inb %dx, %al + decw %dx ret -! -! Try to detect type of SVGA card and supply (usually approximate) video -! mode table for it. -! +# Try to detect type of SVGA card and supply (usually approximate) video +# mode table for it. #ifdef CONFIG_VIDEO_SVGA - svga_modes: - lea si,svga_table ! Test all known SVGA adapters + leaw svga_table, %si # Test all known SVGA adapters dosvga: lodsw - mov bp,ax ! Default mode table - or ax,ax + movw %ax, %bp # Default mode table + orw %ax, %ax jz didsv1 - lodsw ! Pointer to test routine - push si - push di - push es - mov bx,#0xc000 - mov es,bx - call ax ! Call test routine - pop es - pop di - pop si - or bp,bp + + lodsw # Pointer to test routine + pushw %si + pushw %di + pushw %es + movw $0xc000, %bx + movw %bx, %es + call ax # Call test routine + popw %es + popw %di + popw %si + orw %bp, %bp jz dosvga - mov si,bp ! Found, copy the modes - mov ah,[svga_prefix] + + movw %bp, %si # Found, copy the modes + movb svga_prefix, %ah cpsvga: lodsb - or al,al + orb %al, %al jz didsv + stosw movsw jmp cpsvga -didsv: mov [card_name],si ! Store pointer to card name +didsv: movw %si, card_name # Store pointer to card name didsv1: ret -! -! Table of all known SVGA cards. For each card, we store a pointer to -! a table of video modes supported by the card and a pointer to a routine -! used for testing of presence of the card. The video mode table is always -! followed by the name of the card or the chipset. -! - +# Table of all known SVGA cards. For each card, we store a pointer to +# a table of video modes supported by the card and a pointer to a routine +# used for testing of presence of the card. The video mode table is always +# followed by the name of the card or the chipset. svga_table: .word ati_md, ati_test .word oak_md, oak_test @@ -1230,88 +1194,91 @@ .word tseng_md, tseng_test .word 0 -! -! Test routines and mode tables: -! - -! S3 - The test algorithm was taken from the SuperProbe package -! for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org +# Test routines and mode tables: +# S3 - The test algorithm was taken from the SuperProbe package +# for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org s3_test: - mov cx,#0x0f35 ! we store some constants in cl/ch - mov dx,#0x03d4 - movb al,#0x38 + movw $0x0f35, %cx # we store some constants in cl/ch + movw $0x03d4, %dx + movb $0x38, %al call inidx - mov bh,al ! store current value of CRT-register 0x38 - mov ax,#0x0038 - call outidx ! disable writing to special regs - movb al,cl ! check whether we can write special reg 0x35 + movb %al, %bh # store current CRT-register 0x38 + movw $0x0038, %ax + call outidx # disable writing to special regs + movb %cl, %al # check whether we can write special reg 0x35 call inidx - movb bl,al ! save the current value of CRT reg 0x35 - andb al,#0xf0 ! clear bits 0-3 - movb ah,al - movb al,cl ! and write it to CRT reg 0x35 + movb %al, %bl # save the current value of CRT reg 0x35 + andb $0xf0, %al # clear bits 0-3 + movb %al, %ah + movb %cl, %al # and write it to CRT reg 0x35 call outidx - call inidx ! now read it back - andb al,ch ! clear the upper 4 bits - jz s3_2 ! the first test failed. But we have a - movb ah,bl ! second chance - mov al,cl + call inidx # now read it back + andb %ch, %al # clear the upper 4 bits + jz s3_2 # the first test failed. But we have a + + movb %bl, %ah # second chance + movb %cl, %al call outidx - jmp s3_1 ! do the other tests -s3_2: mov ax,cx ! load ah with 0xf and al with 0x35 - orb ah,bl ! set the upper 4 bits of ah with the orig value - call outidx ! write ... - call inidx ! ... and reread - andb al,cl ! turn off the upper 4 bits - push ax - movb ah,bl ! restore old value in register 0x35 - movb al,cl + jmp s3_1 # do the other tests + +s3_2: movw %cx, %ax # load ah with 0xf and al with 0x35 + orb %bl, %ah # set the upper 4 bits of ah with the orig value + call outidx # write ... + call inidx # ... and reread + andb %cl, %al # turn off the upper 4 bits + pushw %ax + movb %bl, %ah # restore old value in register 0x35 + movb %cl, %al call outidx - pop ax - cmp al,ch ! setting lower 4 bits was successful => bad - je no_s3 ! writing is allowed => this is not an S3 -s3_1: mov ax,#0x4838 ! allow writing to special regs by putting - call outidx ! magic number into CRT-register 0x38 - movb al,cl ! check whether we can write special reg 0x35 + popw %ax + cmpb %ch, %al # setting lower 4 bits was successful => bad + je no_s3 # writing is allowed => this is not an S3 + +s3_1: movw $0x4838, %ax # allow writing to special regs by putting + call outidx # magic number into CRT-register 0x38 + movb %cl, %al # check whether we can write special reg 0x35 call inidx - movb bl,al - andb al,#0xf0 - movb ah,al - movb al,cl + movb %al, %bl + andb $0xf0, %al + movb %al, %ah + movb %cl, %al call outidx call inidx - andb al,ch - jnz no_s3 ! no, we can't write => no S3 - mov ax,cx - orb ah,bl + andb %ch, %al + jnz no_s3 # no, we can't write => no S3 + + movw %cx, %ax + orb %bl, %ah call outidx call inidx - andb al,ch - push ax - movb ah,bl ! restore old value in register 0x35 - movb al,cl + andb %ch, %al + pushw %ax + movb %bl, %ah # restore old value in register 0x35 + movb %cl, %al call outidx - pop ax - cmp al,ch - jne no_s31 ! writing not possible => no S3 - movb al,#0x30 - call inidx ! now get the S3 id ... - lea di,idS3 - mov cx,#0x10 + popw %ax + cmpb %ch, %al + jne no_s31 # writing not possible => no S3 + movb $0x30, %al + call inidx # now get the S3 id ... + leaw idS3, %di + movw $0x10, %cx repne scasb je no_s31 - movb ah,bh - movb al,#0x38 + + movb %bh, %ah + movb $0x38, %al jmp s3rest -no_s3: movb al,#0x35 ! restore CRT register 0x35 - movb ah,bl + +no_s3: movb $0x35, %al # restore CRT register 0x35 + movb %bl, %ah + call outidx +no_s31: xorw %bp, %bp # Detection failed +s3rest: movb %bh, %ah + movb $0x38, %al # restore old value of CRT register 0x38 call outidx -no_s31: xor bp,bp ! Detection failed -s3rest: movb ah,bh - movb al,#0x38 ! restore old value of CRT register 0x38 - br outidx idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95 .byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0 @@ -1322,16 +1289,16 @@ .ascii "S3" .byte 0 -! ATI cards. - +# ATI cards. ati_test: - lea si,idati - mov di,#0x31 - mov cx,#0x09 + leaw idati, %si + movw $0x31, %di + movw $0x09, %cx repe cmpsb je atiok - xor bp,bp + + xorw %bp, %bp atiok: ret idati: .ascii "761295520" @@ -1346,19 +1313,20 @@ .ascii "ATI" .byte 0 -! AHEAD - +# AHEAD ahead_test: - mov ax,#0x200f - mov dx,#0x3ce - out dx,ax - inc dx - in al,dx - cmp al,#0x20 + movw $0x200f, %ax + movw $0x3ce, %dx + outw %ax, %dx + incw %dx + inb %dx, %al + cmpb $0x20, %al je isahed - cmp al,#0x21 + + cmpb $0x21, %al je isahed - xor bp,bp + + xorw %bp, %bp isahed: ret ahead_md: @@ -1372,23 +1340,23 @@ .ascii "Ahead" .byte 0 -! Chips & Tech. - +# Chips & Tech. chips_test: - mov dx,#0x3c3 - in al,dx - or al,#0x10 - out dx,al - mov dx,#0x104 - in al,dx - mov bl,al - mov dx,#0x3c3 - in al,dx - and al,#0xef - out dx,al - cmp bl,#0xa5 + movw $0x3c3, %dx + inb %dx, %al + orb $0x10, %al + outb %al, %dx + movw $0x104, %dx + inb %dx, %al + movb %al, %bl + movw $0x3c3, %dx + inb %dx, %al + andb $0xef, %al + outb %al, %dx + cmpb $0xa5, %bl je cantok - xor bp,bp + + xorw %bp, %bp cantok: ret chips_md: @@ -1398,50 +1366,51 @@ .ascii "Chips & Technologies" .byte 0 -! Cirrus Logic 5X0 - +# Cirrus Logic 5X0 cirrus1_test: - mov dx,#0x3d4 - mov al,#0x0c - out dx,al - inc dx - in al,dx - mov bl,al - xor al,al - out dx,al - dec dx - mov al,#0x1f - out dx,al - inc dx - in al,dx - mov bh,al - xor ah,ah - shl al,#4 - mov cx,ax - mov al,bh - shr al,#4 - add cx,ax - shl cx,#8 - add cx,#6 - mov ax,cx - mov dx,#0x3c4 - out dx,ax - inc dx - in al,dx - and al,al + movw $0x3d4, %dx + movb $0x0c, %al + outb %al, %dx + incw %dx + inb %dx, %al + movb %al, %bl + xorb %al, %al + outb %al, %dx + decw %dx + movb $0x1f, %al + outb %al, %dx + incw %dx + inb %dx, %al + movb %al, %bh + xorb %ah, %ah + shlb $4, %al + movw %ax, %cx + movb %bh, %al + shrb $4, %al + addw %ax, %cx + shlw $8, %cx + addw $6, %cx + movw %cx, %ax + movw $0x3c4, %dx + outw %ax, %dx + incw %dx + inb %dx, %al + andb %al, %al jnz nocirr - mov al,bh - out dx,al - in al,dx - cmp al,#0x01 + + movb %bh, %al + outb %al, %dx + inb %dx, %al + cmpb $0x01, %al je iscirr -nocirr: xor bp,bp -iscirr: mov dx,#0x3d4 - mov al,bl - xor ah,ah - shl ax,#8 - add ax,#0x0c - out dx,ax + +nocirr: xorw %bp, %bp +iscirr: movw $0x3d4, %dx + movb %bl, %al + xorb %ah, %ah + shlw $8, %ax + addw $0x0c, %ax + outw %ax, %dx ret cirrus1_md: @@ -1453,46 +1422,49 @@ .ascii "Cirrus Logic 5X0" .byte 0 -! Cirrus Logic 54XX - +# Cirrus Logic 54XX cirrus5_test: - mov dx,#0x3c4 - mov al,#6 + movw $0x3c4, %dx + movb $6, %al call inidx - mov bl,al ! BL=backup - mov ax,#6 + movb %al, %bl # BL=backup + movw $6, %ax call tstidx - cmp al,#0x0f + cmpb $0x0f, %al jne c5fail - mov ax,#0x1206 + + movw $0x1206, %ax call tstidx - cmp al,#0x12 + cmpb $0x12, %al jne c5fail - mov al,#0x1e + + movb $0x1e, %al call inidx - mov bh,al - mov ah,bh - and ah,#0xc0 - mov al,#0x1e + movb %al, %bh + movb %bh, %ah + andb $0xc0, %ah + movb $0x1e, %al call tstidx - and al,#0x3f + andb $0x3f, %al jne c5xx - mov al,#0x1e - mov ah,bh - or ah,#0x3f + + movb $0x1e, %al + movb %bh, %ah + orb $0x3f, %ah call tstidx - xor al,#0x3f - and al,#0x3f + xorb $0x3f, %al + andb $0x3f, %al c5xx: pushf - mov al,#0x1e - mov ah,bh - out dx,ax + movb $0x1e, %al + movb %bh, %ah + outw %ax, %dx popf je c5done -c5fail: xor bp,bp -c5done: mov al,#6 - mov ah,bl - out dx,ax + +c5fail: xorw %bp, %bp +c5done: movb $6, %al + movb %bl, %ah + outw %ax, %dx ret cirrus5_md: @@ -1502,37 +1474,42 @@ .ascii "Cirrus Logic 54XX" .byte 0 -! Cirrus Logic 64XX -- no known extra modes, but must be identified, because -! it's misidentified by the Ahead test. - +# Cirrus Logic 64XX -- no known extra modes, but must be identified, because +# it's misidentified by the Ahead test. cirrus6_test: - mov dx,#0x3ce - mov al,#0x0a + movw $0x3ce, %dx + movb $0x0a, %al call inidx - mov bl,al ! BL=backup - mov ax,#0xce0a + movb %al, %bl # BL=backup + movw $0xce0a, %ax call tstidx - or al,al + orb %al, %al jne c2fail - mov ax,#0xec0a + + movw $0xec0a, %ax call tstidx - cmp al,#0x01 + cmpb $0x01, %al jne c2fail - mov al,#0xaa - call inidx ! 4X, 5X, 7X and 8X are valid 64XX chip IDs - shr al,#4 - sub al,#4 + + movb $0xaa, %al + call inidx # 4X, 5X, 7X and 8X are valid 64XX chip ID's. + shrb $4, %al + subb $4, %al jz c6done - dec al + + decb %al jz c6done - sub al,#2 + + subb $2, %al jz c6done - dec al + + decb %al jz c6done -c2fail: xor bp,bp -c6done: mov al,#0x0a - mov ah,bl - out dx,ax + +c2fail: xorw %bp, %bp +c6done: movb $0x0a, %al + movb %bl, %ah + outw %ax, %dx ret cirrus6_md: @@ -1540,23 +1517,25 @@ .ascii "Cirrus Logic 64XX" .byte 0 -! Everex / Trident - +# Everex / Trident everex_test: - mov ax,#0x7000 - xor bx,bx - int 0x10 - cmp al,#0x70 + movw $0x7000, %ax + xorw %bx, %bx + int $0x10 + cmpb $0x70, %al jne noevrx - shr dx,#4 - cmp dx,#0x678 + + shrw $4, %dx + cmpw $0x678, %dx je evtrid - cmp dx,#0x236 + + cmpw $0x236, %dx jne evrxok -evtrid: lea bp,trident_md + +evtrid: leaw trident_md, %bp evrxok: ret -noevrx: xor bp,bp +noevrx: xorw %bp, %bp ret everex_md: @@ -1574,28 +1553,27 @@ .ascii "Everex/Trident" .byte 0 -! Genoa. - +# Genoa. genoa_test: - lea si,idgenoa ! Check Genoa 'clues' - xor ax,ax - seg es - mov al,[0x37] - mov di,ax - mov cx,#0x04 - dec si - dec di -l1: inc si - inc di - mov al,(si) - test al,al + leaw idgenoa, %si # Check Genoa 'clues' + xorw %ax, %ax + movb %es:(0x37), %al + movw %ax, %di + movw $0x04, %cx + decw %si + decw %di +l1: incw %si + incw %di + movb (%si), %al + testb %al, %al jz l2 - seg es - cmp al,(di) + + cmpb %es:(%di), %al l2: loope l1 - or cx,cx + orw %cx, %cx je isgen - xor bp,bp + + xorw %bp, %bp isgen: ret idgenoa: .byte 0x77, 0x00, 0x99, 0x66 @@ -1616,16 +1594,16 @@ .ascii "Genoa" .byte 0 -! OAK - +# OAK oak_test: - lea si,idoakvga - mov di,#0x08 - mov cx,#0x08 + leaw idoakvga, %si + movw $0x08, %di + movw $0x08, %cx repe cmpsb je isoak - xor bp,bp + + xorw %bp, %bp isoak: ret idoakvga: .ascii "OAK VGA " @@ -1638,16 +1616,16 @@ .ascii "OAK" .byte 0 -! WD Paradise. - +# WD Paradise. paradise_test: - lea si,idparadise - mov di,#0x7d - mov cx,#0x04 + leaw idparadise, %si + movw $0x7d, %di + movw $0x04, %cx repe cmpsb je ispara - xor bp,bp + + xorw %bp, %bp ispara: ret idparadise: .ascii "VGA=" @@ -1661,30 +1639,32 @@ .ascii "Paradise" .byte 0 -! Trident. - +# Trident. trident_test: - mov dx,#0x3c4 - mov al,#0x0e - out dx,al - inc dx - in al,dx - xchg ah,al - xor al,al - out dx,al - in al,dx - xchg al,ah - mov bl,al ! Strange thing ... in the book this wasn't - and bl,#0x02 ! necessary but it worked on my card which - jz setb2 ! is a trident. Without it the screen goes - and al,#0xfd ! blurred ... - jmp clrb2 ! -setb2: or al,#0x02 ! -clrb2: out dx,al - and ah,#0x0f - cmp ah,#0x02 + movw $0x3c4, %dx + movb $0x0e, %al + outb %al, %dx + incw %dx + inb %dx, %al + xchgb %al, %ah + xorb %al, %al + outb %al, %dx + inb %dx, %al + xchgb %ah, %al + movb %al, %bl # Strange thing ... in the book this wasn't + andb $0x02, %bl # necessary but it worked on my card which + jz setb2 # is a trident. Without it the screen goes + # blurred ... + andb $0xfd, %al + jmp clrb2 + +setb2: orb $0x02, %al +clrb2: outb %al, %dx + andb $0x0f, %ah + cmpb $0x02, %ah je istrid - xor bp,bp + + xorw %bp, %bp istrid: ret trident_md: @@ -1699,21 +1679,21 @@ .ascii "Trident" .byte 0 -! Tseng. - +# Tseng. tseng_test: - mov dx,#0x3cd - in al,dx ! Could things be this simple? :-) - mov bl,al - mov al,#0x55 - out dx,al - in al,dx - mov ah,al - mov al,bl - out dx,al - cmp ah,#0x55 + movw $0x3cd, %dx + inb %dx, %al # Could things be this simple ! :-) + movb %al, %bl + movb $0x55, %al + outb %al, %dx + inb %dx, %al + movb %al, %ah + movb %bl, %al + outb %al, %dx + cmpb $0x55, %ah je istsen -isnot: xor bp,bp + +isnot: xorw %bp, %bp istsen: ret tseng_md: @@ -1727,40 +1707,41 @@ .ascii "Tseng" .byte 0 -! Video7. - +# Video7. video7_test: - mov dx,#0x3cc - in al,dx - mov dx,#0x3b4 - and al,#0x01 + movw $0x3cc, %dx + inb %dx, %al + movw $0x3b4, %dx + andb $0x01, %al jz even7 - mov dx,#0x3d4 -even7: mov al,#0x0c - out dx,al - inc dx - in al,dx - mov bl,al - mov al,#0x55 - out dx,al - in al,dx - dec dx - mov al,#0x1f - out dx,al - inc dx - in al,dx - mov bh,al - dec dx - mov al,#0x0c - out dx,al - inc dx - mov al,bl - out dx,al - mov al,#0x55 - xor al,#0xea - cmp al,bh + + movw $0x3d4, %dx +even7: movb $0x0c, %al + outb %al, %dx + incw %dx + inb %dx, %al + movb %al, %bl + movb $0x55, %al + outb %al, %dx + inb %dx, %al + decw %dx + movb $0x1f, %al + outb %al, %dx + incw %dx + inb %dx, %al + movb %al, %bh + decw %dx + movb $0x0c, %al + outb %al, %dx + incw %dx + movb %bl, %al + outb %al, %dx + movb $0x55, %al + xorb $0xea, %al + cmpb %bh, %al jne isnot - movb [svga_prefix],#VIDEO_FIRST_V7>>8 ! Use special mode switching + + movb $VIDEO_FIRST_V7>>8, $svga_prefix # Use special mode switching ret video7_md: @@ -1774,16 +1755,16 @@ .ascii "Video 7" .byte 0 -! Realtek VGA - +# Realtek VGA realtek_test: - lea si,idrtvga - mov di,#0x45 - mov cx,#0x0b + leaw idrtvga, %si + movw $0x45, %di + movw $0x0b, %cx repe cmpsb je isrt - xor bp,bp + + xorw %bp, %bp isrt: ret idrtvga: .ascii "REALTEK VGA" @@ -1800,170 +1781,154 @@ #endif /* CONFIG_VIDEO_SVGA */ -! -! User-defined local mode table (VGA only) -! - +# User-defined local mode table (VGA only) #ifdef CONFIG_VIDEO_LOCAL - local_modes: - lea si,local_mode_table + leaw local_mode_table, %si locm1: lodsw - or ax,ax + orw %ax, %ax jz locm2 + stosw movsw jmp locm1 -locm2: ret -! This is the table of local video modes which can be supplied manually -! by the user. Each entry consists of mode ID (word) and dimensions -! (byte for column count and another byte for row count). These modes -! are placed before all SVGA and VESA modes and override them if table -! compacting is enabled. The table must end with a zero word followed -! by NUL-terminated video adapter name. +locm2: ret +# This is the table of local video modes which can be supplied manually +# by the user. Each entry consists of mode ID (word) and dimensions +# (byte for column count and another byte for row count). These modes +# are placed before all SVGA and VESA modes and override them if table +# compacting is enabled. The table must end with a zero word followed +# by NUL-terminated video adapter name. local_mode_table: - .word 0x0100 ! Example: 40x25 + .word 0x0100 # Example: 40x25 .byte 25,40 .word 0 .ascii "Local" .byte 0 - #endif /* CONFIG_VIDEO_LOCAL */ -! -! Read a key and return the ASCII code in al, scan code in ah -! - -getkey: xor ah,ah - int 0x16 +# Read a key and return the ASCII code in al, scan code in ah +getkey: xorb %ah, %ah + int $0x16 ret -! -! Read a key with a timeout of 30 seconds. The hardware clock is used to get -! the time. -! - +# Read a key with a timeout of 30 seconds. +# The hardware clock is used to get the time. getkt: call gettime - add al,#30 ! Wait 30 seconds - cmp al,#60 + addb $30, %al # Wait 30 seconds + cmpb $60, %al jl lminute - sub al,#60 + + subb $60, %al lminute: - mov cl,al -again: mov ah,#0x01 - int 0x16 - jnz getkey ! key pressed, so get it + movb %al, %cl +again: movb $0x01, %ah + int $0x16 + jnz getkey # key pressed, so get it + call gettime - cmp al,cl + cmpb %cl, %al jne again - mov al,#0x20 ! timeout, return default char `space' - ret -! -! Flush the keyboard buffer -! + movb $0x20, %al # timeout, return `space' + ret -flush: mov ah,#0x01 - int 0x16 +# Flush the keyboard buffer +flush: movb $0x01, %ah + int $0x16 jz empty - xor ah,ah - int 0x16 + + xorb %ah, %ah + int $0x16 jmp flush -empty: ret -! -! Print hexadecimal number. -! +empty: ret -prthw: push ax - mov al,ah +# Print hexadecimal number. +prthw: pushw %ax + movb %ah, %al call prthb - pop ax -prthb: push ax - shr al,#4 + popw %ax +prthb: pushw %ax + shrb $4, %al call prthn - pop ax - and al,#0x0f -prthn: cmp al,#0x0a + popw %ax + andb $0x0f, %al +prthn: cmpb $0x0a, %al jc prth1 - add al,#0x07 -prth1: add al,#0x30 - br prtchr - -! -! Print decimal number (AL). -! - -prtdec: push ax - push cx - xor ah,ah ! Clear ah - mov cl,#0x0a - idiv cl - cmp al,#0x09 + + addb $0x07, %al +prth1: addb $0x30, %al + jmp prtchr + +# Print decimal number in al +prtdec: pushw %ax + pushw %cx + xorb %ah, %ah + movb $0x0a, %cl + idivb %cl + cmpb $0x09, %al jbe lt100 + call prtdec jmp skip10 -lt100: add al,#0x30 + +lt100: addb $0x30, %al call prtchr -skip10: mov al,ah - add al,#0x30 +skip10: movb %ah, %al + addb $0x30, %al call prtchr - pop cx - pop ax + popw %cx + popw %ax ret -! -! VIDEO_SELECT-only variables -! - -mt_end: .word 0 ! End of video mode table if built -edit_buf: .space 6 ! Line editor buffer -card_name: .word 0 ! Pointer to adapter name -scanning: .byte 0 ! Performing mode scan -do_restore: .byte 0 ! Screen contents altered during mode change -svga_prefix: .byte VIDEO_FIRST_BIOS>>8 ! Default prefix for BIOS modes -graphic_mode: .byte 0 ! Graphic mode with a linear frame buffer - -! -! Messages: -! +# VIDEO_SELECT-only variables +mt_end: .word 0 # End of video mode table if built +edit_buf: .space 6 # Line editor buffer +card_name: .word 0 # Pointer to adapter name +scanning: .byte 0 # Performing mode scan +do_restore: .byte 0 # Screen contents altered during mode change +svga_prefix: .byte VIDEO_FIRST_BIOS>>8 # Default prefix for BIOS modes +graphic_mode: .byte 0 # Graphic mode with a linear frame buffer +# Status messages keymsg: .ascii "Press to see video modes available, " .ascii " to continue or wait 30 secs" - db 0x0d, 0x0a, 0 -listhdr: db 0x0d, 0x0a + .byte 0x0d, 0x0a, 0 + +listhdr: .byte 0x0d, 0x0a .ascii "Mode: COLSxROWS:" -crlft: db 0x0d, 0x0a, 0 -prompt: db 0x0d, 0x0a - .ascii "Enter mode number or `scan': " - db 0 -unknt: .ascii "Unknown mode ID. Try again." - db 0 + +crlft: .byte 0x0d, 0x0a, 0 + +prompt: .byte 0x0d, 0x0a + .asciz "Enter mode number or `scan': " + +unknt: .asciz "Unknown mode ID. Try again." + badmdt: .ascii "You passed an undefined mode number." - db 0x0d, 0x0a, 0 + .byte 0x0d, 0x0a, 0 + vesaer: .ascii "Error: Scanning of VESA modes failed. Please " .ascii "report to ." - db 0x0d, 0x0a, 0 -old_name: .ascii "CGA/MDA/HGA" - db 0 -ega_name: .ascii "EGA" - db 0 + .byte 0x0d, 0x0a, 0 + +old_name: .asciz "CGA/MDA/HGA" + +ega_name: .asciz "EGA" + svga_name: .ascii " " -vga_name: .ascii "VGA" - db 0 -vesa_name: .ascii "VESA" - db 0 -name_bann: .ascii "Video adapter: " - db 0 +vga_name: .asciz "VGA" + +vesa_name: .asciz "VESA" + +name_bann: .asciz "Video adapter: " #endif /* CONFIG_VIDEO_SELECT */ -! -! Other variables: -! - -adapter: .byte 0 ! Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA -video_segment: .word 0xb800 ! Video memory segment -force_size: .word 0 ! Use this size instead of the one in BIOS vars +# Other variables: +adapter: .byte 0 # Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA +video_segment: .word 0xb800 # Video memory segment +force_size: .word 0 # Use this size instead of the one in BIOS vars diff -u --recursive --new-file v2.3.20/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.3.20/linux/arch/i386/config.in Sat Oct 9 11:47:50 1999 +++ linux/arch/i386/config.in Mon Oct 11 10:37:44 1999 @@ -183,9 +183,8 @@ bool 'Video mode selection support' CONFIG_VIDEO_SELECT if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'MDA text console (dual-headed) (EXPERIMENTAL)' CONFIG_MDA_CONSOLE - bool 'Support for frame buffer devices (EXPERIMENTAL)' CONFIG_FB + source drivers/video/Config.in fi - source drivers/video/Config.in endmenu fi diff -u --recursive --new-file v2.3.20/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.3.20/linux/arch/i386/defconfig Sat Oct 9 11:47:50 1999 +++ linux/arch/i386/defconfig Mon Oct 11 14:57:23 1999 @@ -41,6 +41,9 @@ # # CONFIG_BIGMEM is not set CONFIG_NET=y +# CONFIG_VISWS is not set +CONFIG_X86_IO_APIC=y +CONFIG_X86_LOCAL_APIC=y CONFIG_PCI=y # CONFIG_PCI_GOBIOS is not set # CONFIG_PCI_GODIRECT is not set @@ -48,9 +51,6 @@ CONFIG_PCI_BIOS=y CONFIG_PCI_DIRECT=y # CONFIG_MCA is not set -# CONFIG_VISWS is not set -CONFIG_X86_IO_APIC=y -CONFIG_X86_LOCAL_APIC=y # # PCMCIA/Cardbus support @@ -95,10 +95,13 @@ CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set CONFIG_BLK_DEV_IDECD=y -# CONFIG_IDECD_SLOTS is not set # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set # CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# CONFIG_BLK_DEV_CMD640=y # CONFIG_BLK_DEV_CMD640_ENHANCED is not set CONFIG_BLK_DEV_RZ1000=y @@ -106,8 +109,6 @@ # CONFIG_BLK_DEV_IDEDMA_PCI is not set # CONFIG_BLK_DEV_OFFBOARD is not set # CONFIG_BLK_DEV_AEC6210 is not set -# CONFIG_BLK_DEV_HPT34X is not set -# CONFIG_BLK_DEV_HPT366 is not set CONFIG_BLK_DEV_PIIX=y # CONFIG_BLK_DEV_SIS5513 is not set # CONFIG_IDE_CHIPSETS is not set @@ -245,9 +246,11 @@ # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set CONFIG_NET_EISA=y # CONFIG_PCNET32 is not set +# CONFIG_ACENIC is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set # CONFIG_DE4X5 is not set @@ -257,15 +260,18 @@ # CONFIG_NE2K_PCI is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set -# CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# # CONFIG_NET_RADIO is not set # -# Token ring devices +# Token Ring driver support # # CONFIG_TR is not set # CONFIG_NET_FC is not set @@ -273,18 +279,12 @@ # # Wan interfaces # -# CONFIG_HOSTESS_SV11 is not set -# CONFIG_COSA is not set -# CONFIG_SEALEVEL_4021 is not set -# CONFIG_DLCI is not set -# CONFIG_WAN_DRIVERS is not set -# CONFIG_LAPBETHER is not set -# CONFIG_X25_ASY is not set +# CONFIG_WAN is not set # # PCMCIA network devices # -# CONFIG_PCMCIA_PCNET is not set +CONFIG_PCMCIA_PCNET=y # CONFIG_PCMCIA_3C589 is not set CONFIG_PCMCIA_RAYCS=y CONFIG_PCMCIA_NETCARD=y @@ -327,7 +327,7 @@ # CONFIG_BUSMOUSE is not set CONFIG_MOUSE=y CONFIG_PSMOUSE=y -CONFIG_82C710_MOUSE=y +# CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set # CONFIG_QIC02_TAPE is not set # CONFIG_WATCHDOG is not set diff -u --recursive --new-file v2.3.20/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c --- v2.3.20/linux/arch/i386/kernel/apm.c Fri Sep 10 23:57:27 1999 +++ linux/arch/i386/kernel/apm.c Mon Oct 11 10:06:34 1999 @@ -643,33 +643,6 @@ return APM_SUCCESS; } -static int apm_get_battery_status(u_short which, u_short *status, - u_short *bat, u_short *life, u_short *nbat) -{ - u32 eax; - u32 ebx; - u32 ecx; - u32 edx; - u32 esi; - - if (apm_bios_info.version < 0x0102) { - /* pretend we only have one battery. */ - if (which != 1) - return APM_BAD_DEVICE; - *nbat = 1; - return apm_get_power_status(status, bat, life); - } - - if (apm_bios_call(0x530a, (0x8000 | (which)), 0, &eax, - &ebx, &ecx, &edx, &esi)) - return (eax >> 8) & 0xff; - *status = ebx; - *bat = ecx; - *life = edx; - *nbat = esi; - return APM_SUCCESS; -} - static int __init apm_engage_power_management(u_short device) { u32 eax; @@ -1263,7 +1236,6 @@ unsigned short bx; unsigned short cx; unsigned short dx; - unsigned short nbat; unsigned short error; unsigned short ac_line_status = 0xff; unsigned short battery_status = 0xff; @@ -1473,7 +1445,7 @@ if (apm_bios_info.version == 0) { printk(KERN_INFO "apm: BIOS not found.\n"); - return; + return -1; } printk(KERN_INFO "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n", @@ -1483,7 +1455,7 @@ driver_version); if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) { printk(KERN_INFO "apm: no 32 bit BIOS support\n"); - return; + return -1; } /* @@ -1512,7 +1484,7 @@ if (apm_disabled) { printk(KERN_NOTICE "apm: disabled on user request.\n"); - return; + return -1; } #ifdef CONFIG_SMP @@ -1571,6 +1543,7 @@ misc_register(&apm_device); kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); + return 0; } module_init(apm_init) diff -u --recursive --new-file v2.3.20/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.3.20/linux/arch/i386/kernel/i386_ksyms.c Sat Oct 9 11:47:50 1999 +++ linux/arch/i386/kernel/i386_ksyms.c Mon Oct 11 10:06:34 1999 @@ -18,6 +18,7 @@ #include #include #include +#include extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(elf_fpregset_t *); @@ -73,7 +74,13 @@ EXPORT_SYMBOL(__clear_user); EXPORT_SYMBOL(__generic_copy_from_user); EXPORT_SYMBOL(__generic_copy_to_user); -EXPORT_SYMBOL(strlen_user); +EXPORT_SYMBOL(strnlen_user); + +#ifdef CONFIG_X86_USE_3DNOW +EXPORT_SYMBOL(_mmx_memcpy); +EXPORT_SYMBOL(mmx_clear_page); +EXPORT_SYMBOL(mmx_copy_page); +#endif #ifdef __SMP__ EXPORT_SYMBOL(cpu_data); @@ -119,3 +126,4 @@ #ifdef CONFIG_VT EXPORT_SYMBOL(screen_info); #endif + diff -u --recursive --new-file v2.3.20/linux/arch/i386/lib/Makefile linux/arch/i386/lib/Makefile --- v2.3.20/linux/arch/i386/lib/Makefile Thu Aug 26 13:05:34 1999 +++ linux/arch/i386/lib/Makefile Mon Oct 11 10:06:34 1999 @@ -9,4 +9,8 @@ L_OBJS = checksum.o old-checksum.o delay.o \ usercopy.o getuser.o putuser.o +ifdef CONFIG_X86_USE_3DNOW +L_OBJS += mmx.o +endif + include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.20/linux/arch/i386/lib/mmx.c linux/arch/i386/lib/mmx.c --- v2.3.20/linux/arch/i386/lib/mmx.c Wed Dec 31 16:00:00 1969 +++ linux/arch/i386/lib/mmx.c Mon Oct 11 10:06:34 1999 @@ -0,0 +1,236 @@ +#include +#include +#include + +/* + * MMX 3DNow! library helper functions + * + * To do: + * We can use MMX just for prefetch in IRQ's. This may be a win. + * (reported so on K6-III) + * We should use a better code neutral filler for the short jump + * leal ebx. [ebx] is apparently best for K6-2, but Cyrix ?? + * We also want to clobber the filler register so we dont get any + * register forwarding stalls on the filler. + * + * Add *user handling. Checksums are not a win with MMX on any CPU + * tested so far for any MMX solution figured. + * + */ + +void *_mmx_memcpy(void *to, const void *from, size_t len) +{ + void *p=to; + int i= len >> 6; /* len/64 */ + + if (!(current->flags & PF_USEDFPU)) + clts(); + else + { + __asm__ __volatile__ ( " fnsave %0; fwait\n"::"m"(current->thread.i387)); + current->flags &= ~PF_USEDFPU; + } + + __asm__ __volatile__ ( + "1: prefetch (%0)\n" /* This set is 28 bytes */ + " prefetch 64(%0)\n" + " prefetch 128(%0)\n" + " prefetch 192(%0)\n" + " prefetch 256(%0)\n" + "2: \n" + ".section .fixup, \"ax\"\n" + "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b, 3b\n" + ".previous" + : : "r" (from) ); + + + for(; i>0; i--) + { + __asm__ __volatile__ ( + "1: prefetch 320(%0)\n" + "2: movq (%0), %%mm0\n" + " movq 8(%0), %%mm1\n" + " movq 16(%0), %%mm2\n" + " movq 24(%0), %%mm3\n" + " movq %%mm0, (%1)\n" + " movq %%mm1, 8(%1)\n" + " movq %%mm2, 16(%1)\n" + " movq %%mm3, 24(%1)\n" + " movq 32(%0), %%mm0\n" + " movq 40(%0), %%mm1\n" + " movq 48(%0), %%mm2\n" + " movq 56(%0), %%mm3\n" + " movq %%mm0, 32(%1)\n" + " movq %%mm1, 40(%1)\n" + " movq %%mm2, 48(%1)\n" + " movq %%mm3, 56(%1)\n" + ".section .fixup, \"ax\"\n" + "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b, 3b\n" + ".previous" + : : "r" (from), "r" (to) : "memory"); + from+=64; + to+=64; + } + /* + * Now do the tail of the block + */ + __memcpy(to, from, len&63); + stts(); + return p; +} + +static void fast_clear_page(long page) +{ + int i; + if (!(current->flags & PF_USEDFPU)) + clts(); + else + { + __asm__ __volatile__ ( " fnsave %0; fwait\n"::"m"(current->thread.i387)); + current->flags &= ~PF_USEDFPU; + } + + __asm__ __volatile__ ( + " pxor %%mm0, %%mm0\n" : : + ); + + for(i=0;i<4096/128;i++) + { + __asm__ __volatile__ ( + " movq %%mm0, (%0)\n" + " movq %%mm0, 8(%0)\n" + " movq %%mm0, 16(%0)\n" + " movq %%mm0, 24(%0)\n" + " movq %%mm0, 32(%0)\n" + " movq %%mm0, 40(%0)\n" + " movq %%mm0, 48(%0)\n" + " movq %%mm0, 56(%0)\n" + " movq %%mm0, 64(%0)\n" + " movq %%mm0, 72(%0)\n" + " movq %%mm0, 80(%0)\n" + " movq %%mm0, 88(%0)\n" + " movq %%mm0, 96(%0)\n" + " movq %%mm0, 104(%0)\n" + " movq %%mm0, 112(%0)\n" + " movq %%mm0, 120(%0)\n" + : : "r" (page) : "memory"); + page+=128; + } + stts(); +} + +static void fast_copy_page(long to, long from) +{ + int i; + if (!(current->flags & PF_USEDFPU)) + clts(); + else + { + __asm__ __volatile__ ( " fnsave %0; fwait\n"::"m"(current->thread.i387)); + current->flags &= ~PF_USEDFPU; + } + + __asm__ __volatile__ ( + "1: prefetch (%0)\n" + " prefetch 64(%0)\n" + " prefetch 128(%0)\n" + " prefetch 192(%0)\n" + " prefetch 256(%0)\n" + "2: \n" + ".section .fixup, \"ax\"\n" + "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b, 3b\n" + ".previous" + : : "r" (from) ); + + for(i=0; i<4096/64; i++) + { + __asm__ __volatile__ ( + "1: prefetch 320(%0)\n" + "2: movq (%0), %%mm0\n" + " movq 8(%0), %%mm1\n" + " movq 16(%0), %%mm2\n" + " movq 24(%0), %%mm3\n" + " movq %%mm0, (%1)\n" + " movq %%mm1, 8(%1)\n" + " movq %%mm2, 16(%1)\n" + " movq %%mm3, 24(%1)\n" + " movq 32(%0), %%mm0\n" + " movq 40(%0), %%mm1\n" + " movq 48(%0), %%mm2\n" + " movq 56(%0), %%mm3\n" + " movq %%mm0, 32(%1)\n" + " movq %%mm1, 40(%1)\n" + " movq %%mm2, 48(%1)\n" + " movq %%mm3, 56(%1)\n" + ".section .fixup, \"ax\"\n" + "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b, 3b\n" + ".previous" + : : "r" (from), "r" (to) : "memory"); + from+=64; + to+=64; + } + stts(); +} + +/* + * Favour MMX for page clear and copy. + */ + +static void slow_zero_page(long page) +{ + int d0, d1; + __asm__ __volatile__( \ + "cld\n\t" \ + "rep ; stosl" \ + : "=&c" (d0), "=&D" (d1) + :"a" (0),"1" (page),"0" (1024) + :"memory"); +} + +void mmx_clear_page(long page) +{ + if(in_interrupt()) + slow_zero_page(page); + else + fast_clear_page(page); +} + +static void slow_copy_page(long to, long from) +{ + int d0, d1, d2; + __asm__ __volatile__( \ + "cld\n\t" \ + "rep ; movsl" \ + : "=&c" (d0), "=&D" (d1), "=&S" (d2) \ + : "0" (1024),"1" ((long) to),"2" ((long) from) \ + : "memory"); +} + + +void mmx_copy_page(long to, long from) +{ + if(in_interrupt()) + slow_copy_page(to, from); + else + fast_copy_page(to, from); +} diff -u --recursive --new-file v2.3.20/linux/arch/i386/lib/usercopy.c linux/arch/i386/lib/usercopy.c --- v2.3.20/linux/arch/i386/lib/usercopy.c Sun Dec 27 10:36:38 1998 +++ linux/arch/i386/lib/usercopy.c Mon Oct 11 10:06:34 1999 @@ -6,6 +6,37 @@ * Copyright 1997 Linus Torvalds */ #include +#include + +#ifdef CONFIG_X86_USE_3DNOW_AND_WORKS + +unsigned long +__generic_copy_to_user(void *to, const void *from, unsigned long n) +{ + if (access_ok(VERIFY_WRITE, to, n)) + { + if(n<512) + __copy_user(to,from,n); + else + mmx_copy_user(to,from,n); + } + return n; +} + +unsigned long +__generic_copy_from_user(void *to, const void *from, unsigned long n) +{ + if (access_ok(VERIFY_READ, from, n)) + { + if(n<512) + __copy_user_zeroing(to,from,n); + else + mmx_copy_user_zeroing(to, from, n); + } + return n; +} + +#else unsigned long __generic_copy_to_user(void *to, const void *from, unsigned long n) @@ -23,6 +54,7 @@ return n; } +#endif /* * Copy a null terminated string from userspace. @@ -117,26 +149,31 @@ /* * Return the size of a string (including the ending 0) * - * Return 0 for error + * Return 0 on exception, a value greater than N if too long */ -long strlen_user(const char *s) +long strnlen_user(const char *s, long n) { - unsigned long res; + unsigned long mask = -__addr_ok(s); + unsigned long res, tmp; __asm__ __volatile__( + " andl %0,%%ecx\n" "0: repne; scasb\n" - " notl %0\n" + " setne %%al\n" + " subl %%ecx,%0\n" + " addl %0,%%eax\n" "1:\n" ".section .fixup,\"ax\"\n" - "2: xorl %0,%0\n" + "2: xorl %%eax,%%eax\n" " jmp 1b\n" ".previous\n" ".section __ex_table,\"a\"\n" " .align 4\n" " .long 0b,2b\n" ".previous" - :"=c" (res), "=D" (s) - :"1" (s), "a" (0), "0" (-__addr_ok(s))); - return res & -__addr_ok(s); + :"=r" (n), "=D" (s), "=a" (res), "=c" (tmp) + :"0" (n), "1" (s), "2" (0), "3" (mask) + :"cc"); + return res & mask; } diff -u --recursive --new-file v2.3.20/linux/arch/sh/config.in linux/arch/sh/config.in --- v2.3.20/linux/arch/sh/config.in Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/config.in Mon Oct 11 10:06:34 1999 @@ -22,8 +22,8 @@ comment 'Loadable module support' bool 'Enable loadable module support' CONFIG_MODULES if [ "$CONFIG_MODULES" = "y" ]; then - bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS - bool 'Kernel module loader' CONFIG_KMOD + bool ' Set version information on all symbols for modules' CONFIG_MODVERSIONS + bool ' Kernel module loader' CONFIG_KMOD fi endmenu @@ -44,7 +44,7 @@ tristate 'RAM disk support' CONFIG_BLK_DEV_RAM if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then - bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD + bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD fi tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP @@ -52,14 +52,14 @@ endmenu if [ "$CONFIG_NET" = "y" ]; then - source net/Config.in + source net/Config.in fi mainmenu_option next_comment comment 'Unix 98 PTY support' bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then - int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 + int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 fi endmenu diff -u --recursive --new-file v2.3.20/linux/arch/sparc64/solaris/timod.c linux/arch/sparc64/solaris/timod.c --- v2.3.20/linux/arch/sparc64/solaris/timod.c Fri Sep 10 23:57:28 1999 +++ linux/arch/sparc64/solaris/timod.c Mon Oct 11 10:15:40 1999 @@ -152,7 +152,7 @@ sock = ¤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"); } diff -u --recursive --new-file v2.3.20/linux/drivers/acorn/block/Config.in linux/drivers/acorn/block/Config.in --- v2.3.20/linux/drivers/acorn/block/Config.in Thu Jun 17 01:11:35 1999 +++ linux/drivers/acorn/block/Config.in Mon Oct 11 10:06:34 1999 @@ -5,11 +5,11 @@ comment 'Acorn-specific block devices' if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then - tristate 'Old Archimedes floppy (1772) support' CONFIG_BLK_DEV_FD1772 - tristate 'MFM harddisk support' CONFIG_BLK_DEV_MFM - if [ "$CONFIG_BLK_DEV_MFM" != "n" ]; then - bool ' Autodetect hard drive geometry' CONFIG_BLK_DEV_MFM_AUTODETECT - fi + tristate 'Old Archimedes floppy (1772) support' CONFIG_BLK_DEV_FD1772 + tristate 'MFM harddisk support' CONFIG_BLK_DEV_MFM + if [ "$CONFIG_BLK_DEV_MFM" != "n" ]; then + bool ' Autodetect hard drive geometry' CONFIG_BLK_DEV_MFM_AUTODETECT + fi fi endmenu diff -u --recursive --new-file v2.3.20/linux/drivers/acorn/scsi/Config.in linux/drivers/acorn/scsi/Config.in --- v2.3.20/linux/drivers/acorn/scsi/Config.in Thu Jun 17 01:11:35 1999 +++ linux/drivers/acorn/scsi/Config.in Mon Oct 11 10:06:34 1999 @@ -3,21 +3,21 @@ # dep_tristate 'Acorn SCSI card (aka30) support' CONFIG_SCSI_ACORNSCSI_3 $CONFIG_SCSI if [ "$CONFIG_SCSI_ACORNSCSI_3" != "n" ]; then - bool ' Support SCSI 2 Tagged queueing' CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE - bool ' Support SCSI 2 Synchronous Transfers' CONFIG_SCSI_ACORNSCSI_SYNC + bool ' Support SCSI 2 Tagged queueing' CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE + bool ' Support SCSI 2 Synchronous Transfers' CONFIG_SCSI_ACORNSCSI_SYNC fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate 'ARXE SCSI support (Experimental)' CONFIG_SCSI_ARXESCSI $CONFIG_SCSI - dep_tristate 'CumanaSCSI II support (Experimental)' CONFIG_SCSI_CUMANA_2 $CONFIG_SCSI - dep_tristate 'EESOX support (Experimental)' CONFIG_SCSI_EESOXSCSI $CONFIG_SCSI - dep_tristate 'PowerTec support (Experimental)' CONFIG_SCSI_POWERTECSCSI $CONFIG_SCSI + dep_tristate 'ARXE SCSI support (EXPERIMENTAL)' CONFIG_SCSI_ARXESCSI $CONFIG_SCSI + dep_tristate 'CumanaSCSI II support (EXPERIMENTAL)' CONFIG_SCSI_CUMANA_2 $CONFIG_SCSI + dep_tristate 'EESOX support (EXPERIMENTAL)' CONFIG_SCSI_EESOXSCSI $CONFIG_SCSI + dep_tristate 'PowerTec support (EXPERIMENTAL)' CONFIG_SCSI_POWERTECSCSI $CONFIG_SCSI - comment 'The following drivers are not fully supported' + comment 'The following drivers are not fully supported' - dep_tristate 'CumanaSCSI I support' CONFIG_SCSI_CUMANA_1 $CONFIG_SCSI - if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then - dep_tristate 'EcoScsi support' CONFIG_SCSI_ECOSCSI $CONFIG_SCSI - fi - dep_tristate 'Oak SCSI support' CONFIG_SCSI_OAK1 $CONFIG_SCSI + dep_tristate 'CumanaSCSI I support' CONFIG_SCSI_CUMANA_1 $CONFIG_SCSI + if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then + dep_tristate 'EcoScsi support' CONFIG_SCSI_ECOSCSI $CONFIG_SCSI + fi + dep_tristate 'Oak SCSI support' CONFIG_SCSI_OAK1 $CONFIG_SCSI fi diff -u --recursive --new-file v2.3.20/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v2.3.20/linux/drivers/block/Config.in Tue Sep 7 12:14:06 1999 +++ linux/drivers/block/Config.in Mon Oct 11 10:10:19 1999 @@ -6,198 +6,200 @@ tristate 'Normal PC floppy disk support' CONFIG_BLK_DEV_FD if [ "$CONFIG_AMIGA" = "y" ]; then - tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY + tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY fi if [ "$CONFIG_ATARI" = "y" ]; then - tristate 'Atari floppy support' CONFIG_ATARI_FLOPPY + tristate 'Atari floppy support' CONFIG_ATARI_FLOPPY fi if [ "$CONFIG_MAC" = "y" ]; then - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'Macintosh IIfx/Quadra 900/Quadra 950 floppy support (EXPERIMENTAL)' CONFIG_BLK_DEV_SWIM_IOP - fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'Macintosh IIfx/Quadra 900/Quadra 950 floppy support (EXPERIMENTAL)' CONFIG_BLK_DEV_SWIM_IOP + fi fi tristate 'Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE comment 'Please see Documentation/ide.txt for help/info on IDE drives' if [ "$CONFIG_BLK_DEV_IDE" = "n" ]; then - bool 'Old hard disk (MFM/RLL/IDE) driver' CONFIG_BLK_DEV_HD_ONLY + bool 'Old hard disk (MFM/RLL/IDE) driver' CONFIG_BLK_DEV_HD_ONLY else - bool ' Use old disk-only driver on primary interface' CONFIG_BLK_DEV_HD_IDE - dep_tristate ' Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE - if [ "$CONFIG_BLK_DEV_IDEDISK" != "n" ]; then - bool ' Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE - fi - dep_tristate ' Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE - if [ "$CONFIG_BLK_DEV_IDECD" = "y" ]; then - bool ' Include CD-Changer Reporting' CONFIG_IDECD_SLOTS - fi - dep_tristate ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE - dep_tristate ' Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE - dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE - if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then - bool ' CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640 - if [ "$CONFIG_BLK_DEV_CMD640" = "y" ]; then - bool ' CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED - fi - if [ "$CONFIG_PCI" = "y" ]; then - bool ' RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 - bool ' Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI - if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then - bool ' Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI - if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then - bool ' Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' Good-Bad DMA Model-Firmware (EXPERIMENTAL)' IDEDMA_NEW_DRIVE_LISTINGS - define_bool IDEDMA_PCI_EXPERIMENTAL y - else - define_bool IDEDMA_PCI_EXPERIMENTAL n - fi - fi - bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD - bool ' AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210 - if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_X86" = "y" ]; then - bool ' ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3 - fi - bool ' CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646 - bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693 - fi - bool ' HPT34X chipset support' CONFIG_BLK_DEV_HPT34X - if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" -a \ - "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then - bool ' HPT34X DMA support (DANGEROUS)' CONFIG_BLK_DEV_HPT34X_DMA - fi - bool ' HPT366 chipset support' CONFIG_BLK_DEV_HPT366 - if [ "$CONFIG_X86" = "y" ]; then - bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX - if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" -a \ - "$CONFIG_BLK_DEV_PIIX" = "y" ]; then - bool ' PIIXn Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TUNING - fi - fi - if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then - bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 - fi - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 - fi - if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then - bool ' PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX - if [ "$CONFIG_EXPERIMENTAL" = "y" -a \ - "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then - bool ' Special UDMA Feature (EXPERIMENTAL)' PDC202XX_FORCE_BURST_BIT - bool ' Special Mode Feature (DANGEROUS)' PDC202XX_FORCE_MASTER_MODE - fi - fi - if [ "$CONFIG_X86" = "y" ]; then - bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 - fi - if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then - bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 - if [ "$CONFIG_X86" = "y" ]; then - bool ' VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586 - fi - fi - fi - if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then - bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 - fi - fi - if [ "$CONFIG_PMAC" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then - bool ' Builtin PowerMac IDE support' CONFIG_BLK_DEV_IDE_PMAC - if [ "$CONFIG_BLK_DEV_IDE_PMAC" != "n" ]; then - bool ' PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC - if [ "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" ]; then - bool ' Use DMA by default' CONFIG_IDEDMA_PMAC_AUTO - fi - fi - fi - if [ "$CONFIG_ARCH_ACORN" = "y" ]; then - bool ' ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE - if [ "$CONFIG_BLK_DEV_IDE_ICSIDE" = "y" ]; then - bool ' ICS DMA support' CONFIG_BLK_DEV_IDEDMA_ICS - if [ "$CONFIG_BLK_DEV_IDEDMA_ICS" = "y" ]; then - bool ' Use ICS DMA by default' CONFIG_IDEDMA_ICS_AUTO - fi - fi - bool ' RapIDE interface support' CONFIG_BLK_DEV_IDE_RAPIDE - fi - if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" -o \ - "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" -o \ - "$CONFIG_BLK_DEV_IDEDMA_ICS" = "y" ]; then - define_bool CONFIG_BLK_DEV_IDEDMA y - if [ "$CONFIG_IDEDMA_PCI_AUTO" = "y" -o \ - "$CONFIG_IDEDMA_PMAC_AUTO" = "y" -o \ - "$CONFIG_IDEDMA_ICS_AUTO" = "y" ]; then - define_bool CONFIG_IDEDMA_AUTO y - fi - fi - bool ' Other IDE chipset support' CONFIG_IDE_CHIPSETS - if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then - comment 'Note: most of these also require special kernel boot parameters' - bool ' Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES - bool ' ALI M14xx support' CONFIG_BLK_DEV_ALI14XX - bool ' DTC-2278 support' CONFIG_BLK_DEV_DTC2278 - bool ' Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B - if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a \ - "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030 - fi - bool ' QDI QD6580 support' CONFIG_BLK_DEV_QD6580 - bool ' UMC-8672 support' CONFIG_BLK_DEV_UMC8672 - fi - if [ "$CONFIG_AMIGA" = "y" ]; then - bool ' Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' Amiga IDE Doubler support' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE - fi - fi - if [ "$CONFIG_ZORRO" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' Buddha/Catweasel IDE interface support' CONFIG_BLK_DEV_BUDDHA - fi - if [ "$CONFIG_ATARI" = "y" ]; then - bool ' Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE - fi - if [ "$CONFIG_MAC" = "y" ]; then - bool ' Macintosh Quadra/Powerbook IDE interface support' CONFIG_BLK_DEV_MAC_IDE - fi - fi + bool ' Use old disk-only driver on primary interface' CONFIG_BLK_DEV_HD_IDE + dep_tristate ' Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE + if [ "$CONFIG_BLK_DEV_IDEDISK" != "n" ]; then + bool ' Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE + fi + dep_tristate ' Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE + dep_tristate ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE + dep_tristate ' Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE + dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE + comment 'IDE chipset support/bugfixes' + if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then + bool ' CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640 + if [ "$CONFIG_BLK_DEV_CMD640" = "y" ]; then + bool ' CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED + fi + if [ "$CONFIG_PCI" = "y" ]; then + bool ' RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 + bool ' Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI + if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then + bool ' Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI + if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then + bool ' Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' Good-Bad DMA Model-Firmware (EXPERIMENTAL)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS + define_bool CONFIG_IDEDMA_PCI_EXPERIMENTAL y + else + define_bool CONFIG_IDEDMA_PCI_EXPERIMENTAL n + fi + fi + bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD + bool ' AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210 + if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_X86" = "y" ]; then + bool ' ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3 + fi + bool ' CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646 + bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693 + fi + if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then + bool ' HPT34X chipset support' CONFIG_BLK_DEV_HPT34X + if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a \ + "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then + bool ' HPT34X DMA support (DANGEROUS)' CONFIG_BLK_DEV_HPT34X_DMA + fi + bool ' HPT366 chipset support' CONFIG_BLK_DEV_HPT366 + fi + if [ "$CONFIG_X86" = "y" ]; then + bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX + if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a \ + "$CONFIG_BLK_DEV_PIIX" = "y" ]; then + bool ' PIIXn Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TUNING + fi + fi + if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then + bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 + fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 + fi + if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then + bool ' PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX + if [ "$CONFIG_EXPERIMENTAL" = "y" -a \ + "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then + bool ' Special UDMA Feature (EXPERIMENTAL)' CONFIG_PDC202XX_FORCE_BURST_BIT + bool ' Special Mode Feature (DANGEROUS)' CONFIG_PDC202XX_FORCE_MASTER_MODE + fi + fi + if [ "$CONFIG_X86" = "y" ]; then + bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 + fi + if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then + bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 + if [ "$CONFIG_X86" = "y" ]; then + bool ' VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586 + fi + fi + fi + if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then + bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 + fi + fi + if [ "$CONFIG_PMAC" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then + bool ' Builtin PowerMac IDE support' CONFIG_BLK_DEV_IDE_PMAC + if [ "$CONFIG_BLK_DEV_IDE_PMAC" != "n" ]; then + bool ' PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC + if [ "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" ]; then + bool ' Use DMA by default' CONFIG_IDEDMA_PMAC_AUTO + fi + fi + fi + if [ "$CONFIG_ARCH_ACORN" = "y" ]; then + bool ' ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE + if [ "$CONFIG_BLK_DEV_IDE_ICSIDE" = "y" ]; then + bool ' ICS DMA support' CONFIG_BLK_DEV_IDEDMA_ICS + if [ "$CONFIG_BLK_DEV_IDEDMA_ICS" = "y" ]; then + bool ' Use ICS DMA by default' CONFIG_IDEDMA_ICS_AUTO + fi + fi + bool ' RapIDE interface support' CONFIG_BLK_DEV_IDE_RAPIDE + fi + if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" -o \ + "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" -o \ + "$CONFIG_BLK_DEV_IDEDMA_ICS" = "y" ]; then + define_bool CONFIG_BLK_DEV_IDEDMA y + if [ "$CONFIG_IDEDMA_PCI_AUTO" = "y" -o \ + "$CONFIG_IDEDMA_PMAC_AUTO" = "y" -o \ + "$CONFIG_IDEDMA_ICS_AUTO" = "y" ]; then + define_bool CONFIG_IDEDMA_AUTO y + fi + fi + bool ' Other IDE chipset support' CONFIG_IDE_CHIPSETS + if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then + comment 'Note: most of these also require special kernel boot parameters' + bool ' Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES + bool ' ALI M14xx support' CONFIG_BLK_DEV_ALI14XX + bool ' DTC-2278 support' CONFIG_BLK_DEV_DTC2278 + bool ' Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B + if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a \ + "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030 + fi + bool ' QDI QD6580 support' CONFIG_BLK_DEV_QD6580 + bool ' UMC-8672 support' CONFIG_BLK_DEV_UMC8672 + fi + if [ "$CONFIG_AMIGA" = "y" ]; then + bool ' Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' Amiga IDE Doubler support (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE + fi + fi + if [ "$CONFIG_ZORRO" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' Buddha/Catweasel IDE interface support (EXPERIMENTAL)' CONFIG_BLK_DEV_BUDDHA + fi + if [ "$CONFIG_ATARI" = "y" ]; then + bool ' Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE + fi + if [ "$CONFIG_MAC" = "y" ]; then + bool ' Macintosh Quadra/Powerbook IDE interface support' CONFIG_BLK_DEV_MAC_IDE + fi + fi fi if [ "$CONFIG_MCA" = "y" ]; then - tristate 'PS/2 ESDI hard disk support' CONFIG_BLK_DEV_PS2 + tristate 'PS/2 ESDI hard disk support' CONFIG_BLK_DEV_PS2 fi if [ "$CONFIG_ZORRO" = "y" ]; then - tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM + tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM fi if [ "$CONFIG_ATARI" = "y" ]; then - tristate 'Atari ACSI support' CONFIG_ATARI_ACSI - if [ "$CONFIG_ATARI_ACSI" != "n" ]; then - comment 'Some devices (e.g. CD jukebox) support multiple LUNs' - bool 'Probe all LUNs on each ACSI device' CONFIG_ACSI_MULTI_LUN - dep_tristate 'Atari SLM laser printer support' CONFIG_ATARI_SLM $CONFIG_ATARI_ACSI - fi + tristate 'Atari ACSI support' CONFIG_ATARI_ACSI + if [ "$CONFIG_ATARI_ACSI" != "n" ]; then + comment 'Some devices (e.g. CD jukebox) support multiple LUNs' + bool ' Probe all LUNs on each ACSI device' CONFIG_ACSI_MULTI_LUN + tristate ' Atari SLM laser printer support' CONFIG_ATARI_SLM + fi +fi +if [ "$CONFIG_PCI" = "y" ]; then + tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA fi -tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA comment 'Additional Block Devices' tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP if [ "$CONFIG_NET" = "y" ]; then - tristate 'Network block device support' CONFIG_BLK_DEV_NBD + tristate 'Network block device support' CONFIG_BLK_DEV_NBD fi bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then - tristate ' Linear (append) mode' CONFIG_MD_LINEAR - tristate ' RAID-0 (striping) mode' CONFIG_MD_STRIPED - tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING - tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 + tristate ' Linear (append) mode' CONFIG_MD_LINEAR + tristate ' RAID-0 (striping) mode' CONFIG_MD_STRIPED + tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING + tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 fi if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then - bool ' Boot support (linear, striped)' CONFIG_MD_BOOT + bool ' Boot support (linear, striped)' CONFIG_MD_BOOT fi tristate 'RAM disk support' CONFIG_BLK_DEV_RAM if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then - bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD + bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD fi tristate 'XT hard disk support' CONFIG_BLK_DEV_XD @@ -205,14 +207,14 @@ # PARIDE must also be a module. The bogus CONFIG_PARIDE_PARPORT option # controls the choices given to the user ... -if [ "$CONFIG_PARPORT" = "y" -o "$CONFIG_PARPORT" = "n" ] ; then +if [ "$CONFIG_PARPORT" = "y" -o "$CONFIG_PARPORT" = "n" ]; then define_bool CONFIG_PARIDE_PARPORT y else define_bool CONFIG_PARIDE_PARPORT m fi dep_tristate 'Parallel port IDE device support' CONFIG_PARIDE $CONFIG_PARIDE_PARPORT if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then - source drivers/block/paride/Config.in + source drivers/block/paride/Config.in fi if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \ @@ -226,15 +228,15 @@ "$CONFIG_BLK_DEV_PIIX" = "y" -o \ "$CONFIG_BLK_DEV_SIS5513" = "y" -o \ "$CONFIG_BLK_DEV_SL82C105" = "y" ]; then - define_bool CONFIG_BLK_DEV_IDE_MODES y + define_bool CONFIG_BLK_DEV_IDE_MODES y else - define_bool CONFIG_BLK_DEV_IDE_MODES n + define_bool CONFIG_BLK_DEV_IDE_MODES n fi if [ "$CONFIG_BLK_DEV_HD_IDE" = "y" -o "$CONFIG_BLK_DEV_HD_ONLY" = "y" ]; then - define_bool CONFIG_BLK_DEV_HD y + define_bool CONFIG_BLK_DEV_HD y else - define_bool CONFIG_BLK_DEV_HD n + define_bool CONFIG_BLK_DEV_HD n fi endmenu diff -u --recursive --new-file v2.3.20/linux/drivers/block/Makefile linux/drivers/block/Makefile --- v2.3.20/linux/drivers/block/Makefile Tue Sep 7 12:14:06 1999 +++ linux/drivers/block/Makefile Mon Oct 11 10:06:34 1999 @@ -20,7 +20,7 @@ L_TARGET := block.a -L_OBJS := genhd.o cmos-probe.o +L_OBJS := genhd.o ide-geometry.o M_OBJS := MOD_LIST_NAME := BLOCK_MODULES LX_OBJS := ll_rw_blk.o blkpg.o @@ -248,7 +248,7 @@ else ifeq ($(CONFIG_BLK_DEV_IDE),m) MIX_OBJS += ide.o $(IDE_OBJS) - M_OBJS += ide-mod.o ide-probe.o + M_OBJS += ide-mod.o ide-probe-mod.o endif endif @@ -376,3 +376,7 @@ ide-mod.o: ide.o $(IDE_OBJS) $(LD) $(LD_RFLAG) -r -o $@ ide.o $(IDE_OBJS) + +ide-probe-mod.o: ide-probe.o ide-geometry.o + $(LD) $(LD_RFLAG) -r -o $@ ide-probe.o ide-geometry.o + diff -u --recursive --new-file v2.3.20/linux/drivers/block/cmos-probe.c linux/drivers/block/cmos-probe.c --- v2.3.20/linux/drivers/block/cmos-probe.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/cmos-probe.c Wed Dec 31 16:00:00 1969 @@ -1,78 +0,0 @@ -/* - * linux/drivers/block/cmos-probe.c Version 1.00 August 16, 1999 - * - * Copyright (C) 1994-1999 Linus Torvalds & authors (see below) - */ - -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include -#include -#include -#include - -/* - * 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 are the primary - * drives in the system -- the ones reflected as drive 1 or 2. The first - * drive is stored in the high nibble of CMOS byte 0x12, the second in the low - * nibble. This will be either a 4 bit drive type or 0xf indicating use byte - * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. A non-zero value - * means we have an AT controller hard disk for that drive. - * - * Of course, there is no guarantee that either drive is actually on the - * "primary" IDE interface, but we don't bother trying to sort that out here. - * If a drive is not actually on the primary interface, then these parameters - * will be ignored. This results in the user having to supply the logical - * drive geometry as a boot parameter for each drive not on the primary i/f. - * - * The only "perfect" way to handle this would be to modify the setup.[cS] code - * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info - * for us during initialization. I have the necessary docs -- any takers? -ml - */ -void probe_cmos_for_drives (ide_hwif_t *hwif) -{ -#ifdef __i386__ - extern struct drive_info_struct drive_info; - byte cmos_disks, *BIOS = (byte *) &drive_info; - int unit; - -#ifdef CONFIG_BLK_DEV_PDC4030 - if (hwif->chipset == ide_pdc4030 && hwif->channel != 0) - return; -#endif /* CONFIG_BLK_DEV_PDC4030 */ - outb_p(0x12,0x70); /* specify CMOS address 0x12 */ - cmos_disks = inb_p(0x71); /* read the data from 0x12 */ - /* Extract drive geometry from CMOS+BIOS if not already setup */ - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - if ((cmos_disks & (0xf0 >> (unit*4))) && !drive->present && !drive->nobios) { - drive->cyl = drive->bios_cyl = *(unsigned short *)BIOS; - drive->head = drive->bios_head = *(BIOS+2); - drive->sect = drive->bios_sect = *(BIOS+14); - drive->ctl = *(BIOS+8); - drive->present = 1; - } - BIOS += 16; - } -#endif -} diff -u --recursive --new-file v2.3.20/linux/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c --- v2.3.20/linux/drivers/block/cpqarray.c Fri Sep 10 23:57:29 1999 +++ linux/drivers/block/cpqarray.c Mon Oct 11 10:10:19 1999 @@ -212,6 +212,7 @@ */ static void ida_procinit(int i) { +#ifdef CONFIG_PROC_FS struct proc_dir_entry *pd; if (proc_array == NULL) { @@ -224,6 +225,7 @@ if (!pd) return; pd->read_proc = ida_proc_get_info; pd->data = hba[i]; +#endif } /* @@ -356,7 +358,9 @@ } } } +#ifdef CONFIG_PROC_FS remove_proc_entry("array", &proc_root); +#endif kfree(ida); kfree(ida_sizes); kfree(ida_hardsizes); diff -u --recursive --new-file v2.3.20/linux/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c --- v2.3.20/linux/drivers/block/ide-disk.c Mon Jul 5 20:13:59 1999 +++ linux/drivers/block/ide-disk.c Mon Oct 11 10:06:34 1999 @@ -94,42 +94,40 @@ * * Returns: 1 if lba_capacity looks sensible * 0 otherwise + * + * It is called only once for each drive. */ static int lba_capacity_is_ok (struct hd_driveid *id) { - unsigned long lba_sects = id->lba_capacity; - unsigned long chs_sects = id->cyls * id->heads * id->sectors; - unsigned long _10_percent = chs_sects / 10; + unsigned long lba_sects, chs_sects, head, tail; /* - * very large drives (8GB+) may lie about the number of cylinders - * This is a split test for drives 8 Gig and Bigger only. + * The ATA spec tells large drives to return + * C/H/S = 16383/16/63 independent of their size. + * Some drives can be jumpered to use 15 heads instead of 16. */ - if ((id->lba_capacity >= 16514064) && (id->cyls == 0x3fff) && - (id->heads == 16) && (id->sectors == 63)) { - id->cyls = lba_sects / (16 * 63); /* correct cyls */ - return 1; /* lba_capacity is our only option */ - } - /* - * ... and at least one TLA VBC has POS instead of brain and can't - * tell 16 from 15. - */ - if ((id->lba_capacity >= 15481935) && (id->cyls == 0x3fff) && - (id->heads == 15) && (id->sectors == 63)) { - id->cyls = lba_sects / (15 * 63); /* correct cyls */ - return 1; /* lba_capacity is our only option */ - } - /* perform a rough sanity check on lba_sects: within 10% is "okay" */ - if ((lba_sects - chs_sects) < _10_percent) { - return 1; /* lba_capacity is good */ - } + if (id->cyls == 16383 && id->sectors == 63 && + (id->heads == 15 || id->heads == 16) && + id->lba_capacity >= 16383*63*id->heads) + return 1; + + lba_sects = id->lba_capacity; + chs_sects = id->cyls * id->heads * id->sectors; + + /* perform a rough sanity check on lba_sects: within 10% is OK */ + if ((lba_sects - chs_sects) < chs_sects/10) + return 1; + /* some drives have the word order reversed */ - lba_sects = (lba_sects << 16) | (lba_sects >> 16); - if ((lba_sects - chs_sects) < _10_percent) { - id->lba_capacity = lba_sects; /* fix it */ + head = ((lba_sects >> 16) & 0xffff); + tail = (lba_sects & 0xffff); + lba_sects = (head | (tail << 16)); + if ((lba_sects - chs_sects) < chs_sects/10) { + id->lba_capacity = lba_sects; return 1; /* lba_capacity is (now) good */ } - return 0; /* lba_capacity value is bad */ + + return 0; /* lba_capacity value may be bad */ } /* @@ -450,24 +448,28 @@ } /* - * current_capacity() returns the capacity (in sectors) of a drive - * according to its current geometry/LBA settings. + * Compute drive->capacity, the full capacity of the drive + * Called with drive->id != NULL. */ -static unsigned long idedisk_capacity (ide_drive_t *drive) +static void init_idedisk_capacity (ide_drive_t *drive) { struct hd_driveid *id = drive->id; unsigned long capacity = drive->cyl * drive->head * drive->sect; drive->select.b.lba = 0; + /* Determine capacity, and use LBA if the drive properly supports it */ - if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) { - if (id->lba_capacity >= capacity) { - drive->cyl = id->lba_capacity / (drive->head * drive->sect); - capacity = id->lba_capacity; - drive->select.b.lba = 1; - } + if ((id->capability & 2) && lba_capacity_is_ok(id)) { + capacity = id->lba_capacity; + drive->cyl = capacity / (drive->head * drive->sect); + drive->select.b.lba = 1; } - return (capacity - drive->sect0); + drive->capacity = capacity; +} + +static unsigned long idedisk_capacity (ide_drive_t *drive) +{ + return (drive->capacity - drive->sect0); } static void idedisk_special (ide_drive_t *drive) @@ -628,7 +630,7 @@ int major = HWIF(drive)->major; int minor = drive->select.b.unit << PARTN_BITS; - ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_SHORT, 0, 65535, 1, 1, &drive->bios_cyl, NULL); + ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->bios_cyl, NULL); ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL); ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL); ide_add_setting(drive, "bswap", SETTING_READ, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->bswap, NULL); @@ -679,7 +681,7 @@ static void idedisk_setup (ide_drive_t *drive) { struct hd_driveid *id = drive->id; - unsigned long capacity, check; + unsigned long capacity; idedisk_add_settings(drive); @@ -705,66 +707,33 @@ drive->head = drive->bios_head = id->heads; drive->sect = drive->bios_sect = id->sectors; } + /* Handle logical geometry translation by the drive */ if ((id->field_valid & 1) && id->cur_cyls && id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) { - /* - * Extract the physical drive geometry for our use. - * Note that we purposely do *not* update the bios info. - * This way, programs that use it (like fdisk) will - * still have the same logical view as the BIOS does, - * which keeps the partition table from being screwed. - * - * An exception to this is the cylinder count, - * which we reexamine later on to correct for 1024 limitations. - */ drive->cyl = id->cur_cyls; drive->head = id->cur_heads; drive->sect = id->cur_sectors; - - /* check for word-swapped "capacity" field in id information */ - capacity = drive->cyl * drive->head * drive->sect; - check = (id->cur_capacity0 << 16) | id->cur_capacity1; - if (check == capacity) { /* was it swapped? */ - /* yes, bring it into little-endian order: */ - id->cur_capacity0 = (capacity >> 0) & 0xffff; - id->cur_capacity1 = (capacity >> 16) & 0xffff; - } } + /* Use physical geometry if what we have still makes no sense */ - if ((!drive->head || drive->head > 16) && - id->heads && id->heads <= 16) { - if ((id->lba_capacity > 16514064) || (id->cyls == 0x3fff)) { - id->cyls = ((int)(id->lba_capacity/(id->heads * id->sectors))); - } - drive->cyl = id->cur_cyls = id->cyls; - drive->head = id->cur_heads = id->heads; - drive->sect = id->cur_sectors = id->sectors; + if (drive->head > 16 && id->heads && id->heads <= 16) { + drive->cyl = id->cyls; + drive->head = id->heads; + drive->sect = id->sectors; } /* calculate drive capacity, and select LBA if possible */ - capacity = idedisk_capacity (drive); + init_idedisk_capacity (drive); /* * if possible, give fdisk access to more of the drive, * by correcting bios_cyls: */ + capacity = idedisk_capacity (drive); if ((capacity >= (drive->bios_cyl * drive->bios_sect * drive->bios_head)) && - (!drive->forced_geom) && drive->bios_sect && drive->bios_head) { + (!drive->forced_geom) && drive->bios_sect && drive->bios_head) drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head; -#ifdef DEBUG - printk("Fixing Geometry :: CHS=%d/%d/%d to CHS=%d/%d/%d\n", - drive->id->cur_cyls, - drive->id->cur_heads, - drive->id->cur_sectors, - drive->bios_cyl, - drive->bios_head, - drive->bios_sect); -#endif - drive->id->cur_cyls = drive->bios_cyl; - drive->id->cur_heads = drive->bios_head; - drive->id->cur_sectors = drive->bios_sect; - } #if 0 /* done instead for entire identify block in arch/ide.h stuff */ /* fix byte-ordering of buffer size field */ @@ -790,19 +759,6 @@ } } printk("\n"); - - if (drive->select.b.lba) { - if (*(int *)&id->cur_capacity0 < id->lba_capacity) { -#ifdef DEBUG - printk(" CurSects=%d, LBASects=%d, ", - *(int *)&id->cur_capacity0, id->lba_capacity); -#endif - *(int *)&id->cur_capacity0 = id->lba_capacity; -#ifdef DEBUG - printk( "Fixed CurSects=%d\n", *(int *)&id->cur_capacity0); -#endif - } - } drive->mult_count = 0; if (id->max_multsect) { diff -u --recursive --new-file v2.3.20/linux/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c --- v2.3.20/linux/drivers/block/ide-dma.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/ide-dma.c Mon Oct 11 10:06:34 1999 @@ -91,7 +91,7 @@ #include #include -#ifdef IDEDMA_NEW_DRIVE_LISTINGS +#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS struct drive_list_entry { char * id_model; @@ -130,7 +130,7 @@ return 0; } -#else /* !IDEDMA_NEW_DRIVE_LISTINGS */ +#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */ /* * good_dma_drives() lists the model names (from "hdparm -i") @@ -162,7 +162,7 @@ "WDC AC31600H", NULL}; -#endif /* IDEDMA_NEW_DRIVE_LISTINGS */ +#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */ /* * Our Physical Region Descriptor (PRD) table should be large enough @@ -314,7 +314,7 @@ { struct hd_driveid *id = drive->id; -#ifdef IDEDMA_NEW_DRIVE_LISTINGS +#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS if (good_bad) { return in_drive_list(id, drive_whitelist); } else { @@ -323,7 +323,7 @@ printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model); return(blacklist); } -#else /* !IDEDMA_NEW_DRIVE_LISTINGS */ +#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */ const char **list; if (good_bad) { @@ -344,7 +344,7 @@ } } } -#endif /* IDEDMA_NEW_DRIVE_LISTINGS */ +#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */ return 0; } diff -u --recursive --new-file v2.3.20/linux/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c --- v2.3.20/linux/drivers/block/ide-floppy.c Thu Aug 5 14:34:01 1999 +++ linux/drivers/block/ide-floppy.c Mon Oct 11 10:06:34 1999 @@ -1498,7 +1498,7 @@ int major = HWIF(drive)->major; int minor = drive->select.b.unit << PARTN_BITS; - ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_SHORT, 0, 1023, 1, 1, &drive->bios_cyl, NULL); + ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_INT, 0, 1023, 1, 1, &drive->bios_cyl, NULL); ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL); ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL); ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 2, &read_ahead[major], NULL); diff -u --recursive --new-file v2.3.20/linux/drivers/block/ide-geometry.c linux/drivers/block/ide-geometry.c --- v2.3.20/linux/drivers/block/ide-geometry.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/ide-geometry.c Mon Oct 11 10:06:34 1999 @@ -0,0 +1,225 @@ +/* + * linux/drivers/block/ide-geometry.c + */ +#include + +#include + +/* + * 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 are the primary + * drives in the system -- the ones reflected as drive 1 or 2. The first + * drive is stored in the high nibble of CMOS byte 0x12, the second in the low + * nibble. This will be either a 4 bit drive type or 0xf indicating use byte + * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. A non-zero value + * means we have an AT controller hard disk for that drive. + * + * Of course, there is no guarantee that either drive is actually on the + * "primary" IDE interface, but we don't bother trying to sort that out here. + * If a drive is not actually on the primary interface, then these parameters + * will be ignored. This results in the user having to supply the logical + * drive geometry as a boot parameter for each drive not on the primary i/f. + */ +/* + * The only "perfect" way to handle this would be to modify the setup.[cS] code + * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info + * for us during initialization. I have the necessary docs -- any takers? -ml + */ +/* + * I did this, but it doesnt work - there is no reasonable way to find the + * correspondence between the BIOS numbering of the disks and the Linux + * numbering. -aeb + * + * The code below is bad. One of the problems is that drives 1 and 2 + * may be SCSI disks (even when IDE disks are present), so that + * the geometry we read here from BIOS is attributed to the wrong disks. + * Consequently, also the "drive->present = 1" below is a mistake. + * + * Eventually the entire routine below should be removed. + */ +void probe_cmos_for_drives (ide_hwif_t *hwif) +{ +#ifdef __i386__ + extern struct drive_info_struct drive_info; + byte cmos_disks, *BIOS = (byte *) &drive_info; + int unit; + +#ifdef CONFIG_BLK_DEV_PDC4030 + if (hwif->chipset == ide_pdc4030 && hwif->channel != 0) + return; +#endif /* CONFIG_BLK_DEV_PDC4030 */ + outb_p(0x12,0x70); /* specify CMOS address 0x12 */ + cmos_disks = inb_p(0x71); /* read the data from 0x12 */ + /* Extract drive geometry from CMOS+BIOS if not already setup */ + for (unit = 0; unit < MAX_DRIVES; ++unit) { + ide_drive_t *drive = &hwif->drives[unit]; + if ((cmos_disks & (0xf0 >> (unit*4))) && + !drive->present && !drive->nobios) { + drive->cyl = drive->bios_cyl = *(unsigned short *)BIOS; + drive->head = drive->bios_head = *(BIOS+2); + drive->sect = drive->bios_sect = *(BIOS+14); + drive->ctl = *(BIOS+8); +#if 0 + drive->present = 1; +#endif + } + BIOS += 16; + } +#endif +} + + +/* + * If heads is nonzero: find a translation with this many heads and S=63. + * Otherwise: find out how OnTrack Disk Manager would translate the disk. + */ +static void +ontrack(ide_drive_t *drive, int heads, int *c, int *h, int *s) { + struct hd_driveid *id = drive->id; + static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0}; + const byte *headp = dm_head_vals; + unsigned long total, tracks; + + /* + * The specs say: take geometry as obtained from Identify, + * compute total capacity C*H*S from that, and truncate to + * 1024*255*63. Now take S=63, H the first in the sequence + * 4, 8, 16, 32, 64, 128, 255 such that 63*H*1024 >= total. + */ + if (id) + total = id->cyls * id->heads * id->sectors; + else + total = drive->cyl * drive->head * drive->sect; + + *s = 63; + + if (heads) { + *h = heads; + *c = total / (63 * heads); + return; + } + +#if 0 + while (63 * headp[0] * 1024 < total && headp[1] != 0) + headp++; + *h = headp[0]; + *c = total / (63 * headp[0]); +#else + /* The code below differs in two aspects: + (i) It will not produce geometries like C/H/S = 1024/64/63 + because of the `>='. This follows OnTracks text (which + claims that 512 <= C <= 1023), but not OnTracks code. + (ii) It starts dividing by 63, so that a rounding down occurs. + For example, with C=11159, H=10, S=37 we find total=4128830 + and DM would make C=512, H=128, S=63, but we make 1024/64/63 + if `>=' is replaced by `>'. + The reason we use this code is mainly that we have done so for + a long time without getting complaints. + */ + + tracks = total / 63; + while (*c >= 1024) { + *h = *headp; + *c = tracks / *h; + if (*++headp == 0) + break; + } +#endif +} + +/* + * This routine is called from the partition-table code in pt/msdos.c. + * It has two tasks: + * (i) to handle Ontrack DiskManager by offsetting everything by 63 sectors, + * or to handle EZdrive by remapping sector 0 to sector 1. + * (ii) to invent a translated geometry. + * Part (i) is suppressed if the user specifies the "noremap" option + * on the command line. + * Part (ii) is suppressed if the user specifies an explicit geometry. + * + * The ptheads parameter is either 0 or tells about the number of + * heads shown by the end of the first nonempty partition. + * If this is either 16, 32, 64, 128, 240 or 255 we'll believe it. + * + * The xparm parameter has the following meaning: + * 0 = convert to CHS with fewer than 1024 cyls + * using the same method as Ontrack DiskManager. + * 1 = same as "0", plus offset everything by 63 sectors. + * -1 = similar to "0", plus redirect sector 0 to sector 1. + * 2 = convert to a CHS geometry with "ptheads" heads. + * + * Returns 0 if the translation was not possible, if the device was not + * an IDE disk drive, or if a geometry was "forced" on the commandline. + * Returns 1 if the geometry translation was successful. + */ +int ide_xlate_1024 (kdev_t i_rdev, int xparm, int ptheads, const char *msg) +{ + ide_drive_t *drive; + const char *msg1 = ""; + int heads = 0; + int c, h, s; + int transl = 1; /* try translation */ + int ret = 0; + + drive = get_info_ptr(i_rdev); + if (!drive) + return 0; + + /* remap? */ + if (drive->remap_0_to_1 != 2) { + if (xparm == 1) { /* DM */ + drive->sect0 = 63; + msg1 = " [remap +63]"; + ret = 1; + } else if (xparm == -1) { /* EZ-Drive */ + if (drive->remap_0_to_1 == 0) { + drive->remap_0_to_1 = 1; + msg1 = " [remap 0->1]"; + ret = 1; + } + } + } + + /* There used to be code here that assigned drive->id->CHS + to drive->CHS and that to drive->bios_CHS. However, + some disks have id->C/H/S = 4092/16/63 but are larger than 2.1 GB. + In such cases that code was wrong. Moreover, + there seems to be no reason to do any of these things. */ + + /* translate? */ + if (drive->forced_geom) + transl = 0; + + /* does ptheads look reasonable? */ + if (ptheads == 32 || ptheads == 64 || ptheads == 128 || + ptheads == 240 || ptheads == 255) + heads = ptheads; + + if (xparm == 2) { + if (!heads || + (drive->bios_head >= heads && drive->bios_sect == 63)) + transl = 0; + } + if (xparm == -1) { + if (drive->bios_head > 16) + transl = 0; /* we already have a translation */ + } + + if (transl) { + ontrack(drive, heads, &c, &h, &s); + drive->bios_cyl = c; + drive->bios_head = h; + drive->bios_sect = s; + ret = 1; + } + + drive->part[0].nr_sects = current_capacity(drive); + + if (ret) + printk("%s%s [%d/%d/%d]", msg, msg1, + drive->bios_cyl, drive->bios_head, drive->bios_sect); + return ret; +} diff -u --recursive --new-file v2.3.20/linux/drivers/block/ide-pmac.c linux/drivers/block/ide-pmac.c --- v2.3.20/linux/drivers/block/ide-pmac.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/ide-pmac.c Mon Oct 11 10:10:19 1999 @@ -30,8 +30,9 @@ #include #include #ifdef CONFIG_PMAC_PBOOK -#include -#include +#include +#include +#include #endif #include "ide_modes.h" @@ -50,9 +51,9 @@ #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ #ifdef CONFIG_PMAC_PBOOK -static int idepmac_notify(struct notifier_block *, unsigned long, void *); -struct notifier_block idepmac_sleep_notifier = { - idepmac_notify +static int idepmac_notify(struct pmu_sleep_notifier *self, int when); +struct pmu_sleep_notifier idepmac_sleep_notifier = { + idepmac_notify, SLEEP_LEVEL_BLOCK, }; #endif /* CONFIG_PMAC_PBOOK */ @@ -224,7 +225,7 @@ pmac_ide_count = i; #ifdef CONFIG_PMAC_PBOOK - notifier_chain_register(&sleep_notifier_list, &idepmac_sleep_notifier); + pmu_register_sleep_notifier(&idepmac_sleep_notifier); #endif /* CONFIG_PMAC_PBOOK */ } @@ -384,29 +385,107 @@ #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ #ifdef CONFIG_PMAC_PBOOK -static int idepmac_notify(struct notifier_block *this, - unsigned long code, void *p) +static void idepmac_sleep_disk(int i, unsigned long base) { - int i, timeout; + int j; - switch (code) { - case PBOOK_SLEEP: - /* do anything here?? */ + /* Reset to PIO 0 */ + out_le32((unsigned *)(base + 0x200 + _IO_BASE), 0x2f8526); + + /* FIXME: We only handle the master IDE */ + if (ide_hwifs[i].drives[0].media == ide_disk) { + /* Spin down the drive */ + outb(0xa0, base+0x60); + outb(0x0, base+0x30); + outb(0x0, base+0x20); + outb(0x0, base+0x40); + outb(0x0, base+0x50); + outb(0xe0, base+0x70); + outb(0x2, base+0x160); + for (j = 0; j < 10; j++) { + int status; + mdelay(100); + status = inb(base+0x70); + if (!(status & BUSY_STAT) && (status & DRQ_STAT)) + break; + } + } +} + +static void idepmac_wake_disk(int i, unsigned long base) +{ + int j; + + /* Revive IDE disk and controller */ + feature_set(pmac_ide_node[i], FEATURE_IDE_enable); + mdelay(1); + feature_set(pmac_ide_node[i], FEATURE_IDE_DiskPower); + mdelay(100); + feature_set(pmac_ide_node[i], FEATURE_IDE_Reset); + mdelay(1); + /* Make sure we are still PIO0 */ + out_le32((unsigned *)(base + 0x200 + _IO_BASE), 0x2f8526); + mdelay(100); + + /* Wait up to 10 seconds (enough for recent drives) */ + for (j = 0; j < 100; j++) { + int status; + mdelay(100); + status = inb(base + 0x70); + if (!(status & BUSY_STAT)) + break; + } +} + +/* Here we handle media bay devices */ +static void +idepmac_wake_bay(int i, unsigned long base) +{ + int timeout; + + timeout = 5000; + while ((inb(base + 0x70) & BUSY_STAT) && timeout) { + mdelay(1); + --timeout; + } +} + +static int idepmac_notify(struct pmu_sleep_notifier *self, int when) +{ + int i, ret; + unsigned long base; + + switch (when) { + case PBOOK_SLEEP_REQUEST: + break; + case PBOOK_SLEEP_REJECT: + break; + case PBOOK_SLEEP_NOW: + for (i = 0; i < pmac_ide_count; ++i) { + if ((base = pmac_ide_regbase[i]) == 0) + continue; + /* Disable irq during sleep */ + disable_irq(pmac_ide_irq[i]); + ret = check_media_bay_by_base(base, MB_CD); + if (ret == -ENODEV) + /* not media bay - put the disk to sleep */ + idepmac_sleep_disk(i, base); + } break; case PBOOK_WAKE: - /* wait for the controller(s) to become ready */ - timeout = 5000; for (i = 0; i < pmac_ide_count; ++i) { - unsigned long base = pmac_ide_regbase[i]; - if (check_media_bay_by_base(base, MB_CD) == -EINVAL) + if ((base = pmac_ide_regbase[i]) == 0) continue; - while ((inb(base + 0x70) & BUSY_STAT) && timeout) { - mdelay(1); - --timeout; - } + /* We don't handle media bay devices this way */ + ret = check_media_bay_by_base(base, MB_CD); + if (ret == -ENODEV) + idepmac_wake_disk(i, base); + else if (ret == 0) + idepmac_wake_bay(i, base); + enable_irq(pmac_ide_irq[i]); } break; } - return NOTIFY_DONE; + return PBOOK_SLEEP_OK; } #endif /* CONFIG_PMAC_PBOOK */ diff -u --recursive --new-file v2.3.20/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.3.20/linux/drivers/block/ide.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/ide.c Mon Oct 11 10:06:34 1999 @@ -526,7 +526,7 @@ * current_capacity() returns the capacity (in sectors) of a drive * according to its current geometry/LBA settings. */ -static unsigned long current_capacity (ide_drive_t *drive) +unsigned long current_capacity (ide_drive_t *drive) { if (!drive->present) return 0; @@ -1067,13 +1067,16 @@ goto kill_rq; } block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0; -#if FAKE_FDISK_FOR_EZDRIVE - if (block == 0 && drive->remap_0_to_1) + + /* Yecch - this will shift the entire interval, + possibly killing some innocent following sector */ + if (block == 0 && drive->remap_0_to_1 == 1) block = 1; /* redirect MBR access to EZ-Drive partn table */ -#endif /* FAKE_FDISK_FOR_EZDRIVE */ + #if (DISK_RECOVERY_TIME > 0) while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME); #endif + SELECT_DRIVE(hwif, drive); if (ide_wait_stat(drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) { printk("%s: drive not ready for command\n", drive->name); @@ -1513,7 +1516,7 @@ * get_info_ptr() returns the (ide_drive_t *) for a given device number. * It returns NULL if the given device number does not match any present drives. */ -static ide_drive_t *get_info_ptr (kdev_t i_rdev) +ide_drive_t *get_info_ptr (kdev_t i_rdev) { int major = MAJOR(i_rdev); unsigned int h; @@ -1609,11 +1612,8 @@ } spin_unlock_irqrestore(&io_request_lock, flags); do_hwgroup_request(hwgroup); - save_flags(flags); /* all CPUs; overkill? */ - cli(); /* all CPUs; overkill? */ if (action == ide_wait && rq->rq_status != RQ_INACTIVE) down(&sem); /* wait for it to be serviced */ - restore_flags(flags); /* all CPUs; overkill? */ return rq->errors ? -EIO : 0; /* return -EIO if errors */ } @@ -2321,10 +2321,11 @@ case HDIO_GETGEO: { struct hd_geometry *loc = (struct hd_geometry *) arg; + unsigned short bios_cyl = drive->bios_cyl; /* truncate */ if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL; if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT; if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT; - if (put_user(drive->bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT; + if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT; if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect, (unsigned long *) &loc->start)) return -EFAULT; return 0; @@ -2343,7 +2344,8 @@ return -EINVAL; if (drive->id == NULL) return -ENOMSG; - if (copy_to_user((char *)arg, (char *)drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142)) + if (copy_to_user((char *)arg, (char *)drive->id, + (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142)) return -EFAULT; return 0; @@ -2629,6 +2631,7 @@ * "hdx=nowerr" : ignore the WRERR_STAT bit on this drive * "hdx=cdrom" : drive is present, and is a cdrom drive * "hdx=cyl,head,sect" : disk drive is present, with specified geometry + * "hdx=noremap" : do not remap 0->1 even though EZD was detected * "hdx=autotune" : driver will attempt to tune interface speed * to the fastest PIO mode supported, * if possible for this drive only. @@ -2735,7 +2738,8 @@ if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) { const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom", "serialize", "autotune", "noautotune", - "slow", "swapdata", "bswap", "flash", NULL}; + "slow", "swapdata", "bswap", "flash", + "remap", "noremap", NULL}; unit = s[2] - 'a'; hw = unit / MAX_DRIVES; unit = unit % MAX_DRIVES; @@ -2772,13 +2776,19 @@ case -8: /* "slow" */ drive->slow = 1; goto done; - case -9: /* swapdata or bswap */ + case -9: /* "swapdata" or "bswap" */ case -10: drive->bswap = 1; goto done; - case -11: + case -11: /* "flash" */ drive->ata_flash = 1; goto done; + case -12: /* "remap" */ + drive->remap_0_to_1 = 1; + goto done; + case -13: /* "noremap" */ + drive->remap_0_to_1 = 2; + goto done; case 3: /* cyl,head,sect */ drive->media = ide_disk; drive->cyl = drive->bios_cyl = vals[0]; @@ -3023,113 +3033,6 @@ } /* - * This routine is called from the partition-table code in genhd.c - * to "convert" a drive to a logical geometry with fewer than 1024 cyls. - * - * The second parameter, "xparm", determines exactly how the translation - * will be handled: - * 0 = convert to CHS with fewer than 1024 cyls - * using the same method as Ontrack DiskManager. - * 1 = same as "0", plus offset everything by 63 sectors. - * -1 = similar to "0", plus redirect sector 0 to sector 1. - * >1 = convert to a CHS geometry with "xparm" heads. - * - * Returns 0 if the translation was not possible, if the device was not - * an IDE disk drive, or if a geometry was "forced" on the commandline. - * Returns 1 if the geometry translation was successful. - */ - -int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg) -{ - ide_drive_t *drive; - - static const byte head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0}; - const byte *heads = head_vals; - unsigned long tracks; - - drive = get_info_ptr(i_rdev); - if (!drive) - return 0; - - if (drive->forced_geom) { - /* - * Update the current 3D drive values. - */ - drive->id->cur_cyls = drive->bios_cyl; - drive->id->cur_heads = drive->bios_head; - drive->id->cur_sectors = drive->bios_sect; - return 0; - } - - if (xparm > 1 && xparm <= drive->bios_head && drive->bios_sect == 63) { - /* - * Update the current 3D drive values. - */ - drive->id->cur_cyls = drive->bios_cyl; - drive->id->cur_heads = drive->bios_head; - drive->id->cur_sectors = drive->bios_sect; - return 0; /* we already have a translation */ - } - - printk("%s ", msg); - - if (xparm < 0 && (drive->bios_cyl * drive->bios_head * drive->bios_sect) < (1024 * 16 * 63)) { - /* - * Update the current 3D drive values. - */ - drive->id->cur_cyls = drive->bios_cyl; - drive->id->cur_heads = drive->bios_head; - drive->id->cur_sectors = drive->bios_sect; - return 0; /* small disk: no translation needed */ - } - - if (drive->id) { - drive->cyl = drive->id->cyls; - drive->head = drive->id->heads; - drive->sect = drive->id->sectors; - } - drive->bios_cyl = drive->cyl; - drive->bios_head = drive->head; - drive->bios_sect = drive->sect; - drive->special.b.set_geometry = 1; - - tracks = drive->bios_cyl * drive->bios_head * drive->bios_sect / 63; - drive->bios_sect = 63; - if (xparm > 1) { - drive->bios_head = xparm; - drive->bios_cyl = tracks / drive->bios_head; - } else { - while (drive->bios_cyl >= 1024) { - drive->bios_head = *heads; - drive->bios_cyl = tracks / drive->bios_head; - if (0 == *++heads) - break; - } -#if FAKE_FDISK_FOR_EZDRIVE - if (xparm == -1) { - drive->remap_0_to_1 = 1; - printk("[remap 0->1] "); - } else -#endif /* FAKE_FDISK_FOR_EZDRIVE */ - if (xparm == 1) { - drive->sect0 = 63; - drive->bios_cyl = (tracks - 1) / drive->bios_head; - printk("[remap +63] "); - } - } - - drive->part[0].nr_sects = current_capacity(drive); - printk("[%d/%d/%d]", drive->bios_cyl, drive->bios_head, drive->bios_sect); - /* - * Update the current 3D drive values. - */ - drive->id->cur_cyls = drive->bios_cyl; - drive->id->cur_heads = drive->bios_head; - drive->id->cur_sectors = drive->bios_sect; - return 1; -} - -/* * probe_for_hwifs() finds/initializes "known" IDE interfaces */ static void __init probe_for_hwifs (void) @@ -3523,6 +3426,9 @@ EXPORT_SYMBOL(ide_register); EXPORT_SYMBOL(ide_unregister); EXPORT_SYMBOL(ide_setup_ports); + +EXPORT_SYMBOL(get_info_ptr); +EXPORT_SYMBOL(current_capacity); /* * This is gets invoked once during initialization, to set *everything* up diff -u --recursive --new-file v2.3.20/linux/drivers/block/pdc202xx.c linux/drivers/block/pdc202xx.c --- v2.3.20/linux/drivers/block/pdc202xx.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/pdc202xx.c Mon Oct 11 10:10:19 1999 @@ -14,7 +14,7 @@ * 8 are UDMA supported and 4 are limited to DMA mode 2 multi-word. * The 8/4 ratio is a BIOS code limit by promise. * - * UNLESS you enable "PDC202XX_FORCE_BURST_BIT" + * UNLESS you enable "CONFIG_PDC202XX_FORCE_BURST_BIT" * * There is only one BIOS in the three contollers. * @@ -521,15 +521,15 @@ (primary_mode & 1) ? "MASTER" : "PCI", (secondary_mode & 1) ? "MASTER" : "PCI" ); -#ifdef PDC202XX_FORCE_BURST_BIT +#ifdef CONFIG_PDC202XX_FORCE_BURST_BIT if (!(udma_speed_flag & 1)) { printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1)); outb(udma_speed_flag|1, high_16 + 0x001f); printk("%sCTIVE\n", (inb(high_16 + 0x001f) & 1) ? "A" : "INA"); } -#endif /* PDC202XX_FORCE_BURST_BIT */ +#endif /* CONFIG_PDC202XX_FORCE_BURST_BIT */ -#ifdef PDC202XX_FORCE_MASTER_MODE +#ifdef CONFIG_PDC202XX_FORCE_MASTER_MODE if (!(primary_mode & 1)) { printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ", name, primary_mode, (primary_mode|1)); @@ -543,7 +543,7 @@ outb(secondary_mode|1, high_16 + 0x001b); printk("%s\n", (inb(high_16 + 0x001b) & 1) ? "MASTER" : "PCI"); } -#endif /* PDC202XX_FORCE_MASTER_MODE */ +#endif /* CONFIG_PDC202XX_FORCE_MASTER_MODE */ return dev->irq; } diff -u --recursive --new-file v2.3.20/linux/drivers/char/adbmouse.c linux/drivers/char/adbmouse.c --- v2.3.20/linux/drivers/char/adbmouse.c Fri Sep 10 23:57:29 1999 +++ linux/drivers/char/adbmouse.c Mon Oct 11 10:10:19 1999 @@ -35,8 +35,8 @@ #include #include #include +#include -#include #ifdef __powerpc__ #include #endif diff -u --recursive --new-file v2.3.20/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c --- v2.3.20/linux/drivers/char/busmouse.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/char/busmouse.c Mon Oct 11 10:10:19 1999 @@ -144,7 +144,7 @@ wake_up(&mse->wait); if (mse->fasyncptr) - kill_fasync(mse->fasyncptr, SIGIO); + kill_fasync(mse->fasyncptr, SIGIO, POLL_IN); } } @@ -450,13 +450,10 @@ #ifdef CONFIG_ATARIMOUSE atari_mouse_init(); #endif -#ifdef CONFIG_MAC_MOUSE - mac_mouse_init(); -#endif #ifdef CONFIG_SUN_MOUSE sun_mouse_init(); #endif -#ifdef CONFIG_ADBMOUSE +#ifdef CONFIG_ADB_MOUSE adb_mouse_init(); #endif #ifdef CONFIG_RPCMOUSE diff -u --recursive --new-file v2.3.20/linux/drivers/char/console.c linux/drivers/char/console.c --- v2.3.20/linux/drivers/char/console.c Thu Aug 26 13:05:35 1999 +++ linux/drivers/char/console.c Mon Oct 11 10:10:19 1999 @@ -681,7 +681,7 @@ else { unsigned short *p = (unsigned short *) kmalloc(ss, GFP_USER); if (!p) { - for (i = 0; i< currcons; i++) + for (i = first; i < currcons; i++) if (newscreens[i]) kfree_s(newscreens[i], ss); return -ENOMEM; diff -u --recursive --new-file v2.3.20/linux/drivers/char/dn_keyb.c linux/drivers/char/dn_keyb.c --- v2.3.20/linux/drivers/char/dn_keyb.c Mon Aug 9 12:32:28 1999 +++ linux/drivers/char/dn_keyb.c Mon Oct 11 10:10:19 1999 @@ -469,7 +469,7 @@ if (mouse_dy > 2048) mouse_dy = 2048; if (mouse_fasyncptr) - kill_fasync(mouse_fasyncptr, SIGIO); + kill_fasync(mouse_fasyncptr, SIGIO, POLL_IN); } mouse_byte_count=0; /* printk("mouse: %d, %d, %x\n",mouse_x,mouse_y,buttons); */ diff -u --recursive --new-file v2.3.20/linux/drivers/char/drm/fops.c linux/drivers/char/drm/fops.c --- v2.3.20/linux/drivers/char/drm/fops.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/char/drm/fops.c Mon Oct 11 10:10:19 1999 @@ -197,7 +197,7 @@ send -= count; } - if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO); + if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO, POLL_OUT); DRM_DEBUG("waking\n"); wake_up_interruptible(&dev->buf_readers); return 0; diff -u --recursive --new-file v2.3.20/linux/drivers/char/ftape/Config.in linux/drivers/char/ftape/Config.in --- v2.3.20/linux/drivers/char/ftape/Config.in Tue Dec 2 13:47:33 1997 +++ linux/drivers/char/ftape/Config.in Mon Oct 11 10:10:19 1999 @@ -1,17 +1,17 @@ # # Ftape configuration # -dep_tristate 'Zftape, the VFS interface' CONFIG_ZFTAPE $CONFIG_FTAPE +dep_tristate ' Zftape, the VFS interface' CONFIG_ZFTAPE $CONFIG_FTAPE if [ "$CONFIG_ZFTAPE" != "n" ]; then - int 'Default block size' CONFIG_ZFT_DFLT_BLK_SZ 10240 - comment 'The compressor will be built as a module only!' - define_bool CONFIG_ZFT_COMPRESSOR m + int ' Default block size' CONFIG_ZFT_DFLT_BLK_SZ 10240 + comment ' The compressor will be built as a module only!' + define_bool CONFIG_ZFT_COMPRESSOR m fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - int 'Number of ftape buffers (EXPERIMENTAL)' CONFIG_FT_NR_BUFFERS 3 + int ' Number of ftape buffers (EXPERIMENTAL)' CONFIG_FT_NR_BUFFERS 3 fi if [ "$CONFIG_PROC_FS" = "y" ]; then - bool 'Enable procfs status report (+2kb)' CONFIG_FT_PROC_FS y + bool ' Enable procfs status report (+2kb)' CONFIG_FT_PROC_FS fi choice 'Debugging output' \ "Normal CONFIG_FT_NORMAL_DEBUG \ @@ -25,14 +25,14 @@ FC-10/FC-20 CONFIG_FT_PROBE_FC10 \ Alt/82078 CONFIG_FT_ALT_FDC" Standard if [ "$CONFIG_FT_STD_FDC" != "y" ]; then - comment ' Consult the manuals of your tape drive for the correct settings!' - hex ' IO base of the floppy disk controller' CONFIG_FT_FDC_BASE 0 - int ' IRQ channel of the floppy disk controller' CONFIG_FT_FDC_IRQ 0 - int ' DMA channel of the floppy disk controller' CONFIG_FT_FDC_DMA 0 + comment ' Consult the manuals of your tape drive for the correct settings!' + hex ' IO base of the floppy disk controller' CONFIG_FT_FDC_BASE 0 + int ' IRQ channel of the floppy disk controller' CONFIG_FT_FDC_IRQ 0 + int ' DMA channel of the floppy disk controller' CONFIG_FT_FDC_DMA 0 fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - int 'Default FIFO threshold (EXPERIMENTAL)' CONFIG_FT_FDC_THR 8 - int 'Maximal data rate to use (EXPERIMENTAL)' CONFIG_FT_FDC_MAX_RATE 2000 + int ' Default FIFO threshold (EXPERIMENTAL)' CONFIG_FT_FDC_THR 8 + int ' Maximal data rate to use (EXPERIMENTAL)' CONFIG_FT_FDC_MAX_RATE 2000 fi comment 'ONLY for DEC Alpha architectures' -int 'CPU clock frequency of your DEC Alpha' CONFIG_FT_ALPHA_CLOCK 0 +int ' CPU clock frequency of your DEC Alpha' CONFIG_FT_ALPHA_CLOCK 0 diff -u --recursive --new-file v2.3.20/linux/drivers/char/joystick/Config.in linux/drivers/char/joystick/Config.in --- v2.3.20/linux/drivers/char/joystick/Config.in Wed Dec 16 13:38:18 1998 +++ linux/drivers/char/joystick/Config.in Mon Oct 11 10:10:19 1999 @@ -2,18 +2,18 @@ # Joystick lowlevel driver configuration # -dep_tristate ' Classic PC analog joysticks and gamepads' CONFIG_JOY_ANALOG $CONFIG_JOYSTICK -dep_tristate ' FPGaming and MadCatz A3D controllers' CONFIG_JOY_ASSASIN $CONFIG_JOYSTICK -dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_JOY_GRAVIS $CONFIG_JOYSTICK -dep_tristate ' Logitech Digital joysticks and gamepads' CONFIG_JOY_LOGITECH $CONFIG_JOYSTICK -dep_tristate ' Microsoft SideWinder, Genius Digital joysticks and gamepads' CONFIG_JOY_SIDEWINDER $CONFIG_JOYSTICK -dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_JOY_THRUSTMASTER $CONFIG_JOYSTICK -dep_tristate ' PDPI Lightning 4 gamecards' CONFIG_JOY_LIGHTNING $CONFIG_JOYSTICK +dep_tristate ' Classic PC analog joysticks and gamepads' CONFIG_JOY_ANALOG $CONFIG_JOYSTICK +dep_tristate ' FPGaming and MadCatz A3D controllers' CONFIG_JOY_ASSASIN $CONFIG_JOYSTICK +dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_JOY_GRAVIS $CONFIG_JOYSTICK +dep_tristate ' Logitech Digital joysticks and gamepads' CONFIG_JOY_LOGITECH $CONFIG_JOYSTICK +dep_tristate ' Microsoft SideWinder, Genius Digital joysticks and gamepads' CONFIG_JOY_SIDEWINDER $CONFIG_JOYSTICK +dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_JOY_THRUSTMASTER $CONFIG_JOYSTICK +dep_tristate ' PDPI Lightning 4 gamecards' CONFIG_JOY_LIGHTNING $CONFIG_JOYSTICK if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate ' NES, SNES, PSX, Multisystem joysticks and gamepads' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK $CONFIG_PARPORT - dep_tristate ' Sega, Multisystem joysticks and gamepads' CONFIG_JOY_DB9 $CONFIG_JOYSTICK $CONFIG_PARPORT - dep_tristate ' TurboGraFX Multisystem joystick interface' CONFIG_JOY_TURBOGRAFX $CONFIG_JOYSTICK $CONFIG_PARPORT + dep_tristate ' NES, SNES, PSX, Multisystem joysticks and gamepads' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK $CONFIG_PARPORT + dep_tristate ' Sega, Multisystem joysticks and gamepads' CONFIG_JOY_DB9 $CONFIG_JOYSTICK $CONFIG_PARPORT + dep_tristate ' TurboGraFX Multisystem joystick interface' CONFIG_JOY_TURBOGRAFX $CONFIG_JOYSTICK $CONFIG_PARPORT fi if [ "$CONFIG_AMIGA" = "y" ]; then - dep_tristate ' Amiga joysticks' CONFIG_JOY_AMIGA $CONFIG_JOYSTICK + dep_tristate ' Amiga joysticks' CONFIG_JOY_AMIGA $CONFIG_JOYSTICK fi diff -u --recursive --new-file v2.3.20/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c --- v2.3.20/linux/drivers/char/keyboard.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/char/keyboard.c Mon Oct 11 10:15:40 1999 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -155,7 +156,6 @@ #ifdef CONFIG_MAGIC_SYSRQ static int sysrq_pressed; -int sysrq_enabled = 1; #endif /* diff -u --recursive --new-file v2.3.20/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v2.3.20/linux/drivers/char/misc.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/char/misc.c Mon Oct 11 10:15:40 1999 @@ -259,6 +259,12 @@ #ifdef CONFIG_NWFLASH nwflash_init(); #endif +#ifdef CONFIG_SGI_NEWPORT_GFX + gfx_register (); +#endif +#ifdef CONFIG_SGI + streamable_init (); +#endif if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) { printk("unable to get major %d for misc devices\n", MISC_MAJOR); diff -u --recursive --new-file v2.3.20/linux/drivers/char/n_hdlc.c linux/drivers/char/n_hdlc.c --- v2.3.20/linux/drivers/char/n_hdlc.c Mon Jul 5 20:35:18 1999 +++ linux/drivers/char/n_hdlc.c Mon Oct 11 10:10:19 1999 @@ -9,7 +9,7 @@ * Al Longyear , Paul Mackerras * * Original release 01/11/99 - * ==FILEDATE 19990524== + * ==FILEDATE 19990901== * * This code is released under the GNU General Public License (GPL) * @@ -21,8 +21,13 @@ * 1. tty write calls represent one complete transmit frame of data * The device driver should accept the complete frame or none of * the frame (busy) in the write method. Each write call should have - * a byte count in the range of 2-4096 bytes (2 is min HDLC frame - * with 1 addr byte and 1 ctrl byte). + * a byte count in the range of 2-65535 bytes (2 is min HDLC frame + * with 1 addr byte and 1 ctrl byte). The max byte count of 65535 + * should include any crc bytes required. For example, when using + * CCITT CRC32, 4 crc bytes are required, so the maximum size frame + * the application may transmit is limited to 65531 bytes. For CCITT + * CRC16, the maximum application frame size would be 65533. + * * * 2. receive callbacks from the device driver represents * one received frame. The device driver should bypass @@ -73,7 +78,7 @@ */ #define HDLC_MAGIC 0x239e -#define HDLC_VERSION "1.2" +#define HDLC_VERSION "1.11" #include #include @@ -100,6 +105,7 @@ #include #include #include +#include /* to get the struct task_struct */ #include /* used in new tty drivers */ #include /* used in new tty drivers */ #include @@ -113,6 +119,13 @@ #include #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 #define GET_USER(error,value,addr) error = get_user(value,addr) @@ -189,18 +202,21 @@ /* * Buffers for individual HDLC frames */ -#define MAX_HDLC_FRAME_SIZE 4096 +#define MAX_HDLC_FRAME_SIZE 65535 #define DEFAULT_RX_BUF_COUNT 10 -#define MAX_RX_BUF_COUNT 30 +#define MAX_RX_BUF_COUNT 60 #define DEFAULT_TX_BUF_COUNT 1 + typedef struct _n_hdlc_buf { struct _n_hdlc_buf *link; int count; - char buf[MAX_HDLC_FRAME_SIZE]; + char buf[1]; } N_HDLC_BUF; +#define N_HDLC_BUF_SIZE (sizeof(N_HDLC_BUF)+maxframe) + typedef struct _n_hdlc_buf_list { N_HDLC_BUF *head; @@ -246,12 +262,16 @@ #if LINUX_VERSION_CODE >= VERSION(2,1,19) MODULE_PARM(debuglevel, "i"); +MODULE_PARM(maxframe, "i"); #endif /* debug level can be set by insmod for debugging purposes */ #define DEBUG_LEVEL_INFO 1 int debuglevel=0; +/* max frame size for memory allocations */ +ssize_t maxframe=4096; + /* TTY callbacks */ static rw_ret_t n_hdlc_tty_read(struct tty_struct *, @@ -353,6 +373,9 @@ printk (KERN_WARNING"n_hdlc: trying to close unopened tty!\n"); return; } +#if defined(TTY_NO_WRITE_SPLIT) + clear_bit(TTY_NO_WRITE_SPLIT,&tty->flags); +#endif tty->disc_data = NULL; if (tty == n_hdlc->backup_tty) n_hdlc->backup_tty = 0; @@ -383,7 +406,9 @@ struct n_hdlc *n_hdlc = tty2n_hdlc (tty); if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d)n_hdlc_tty_open() called\n",__FILE__,__LINE__); + printk("%s(%d)n_hdlc_tty_open() called (major=%u,minor=%u)\n", + __FILE__,__LINE__, + MAJOR(tty->device), MINOR(tty->device)); /* There should not be an existing table for this slot. */ if (n_hdlc) { @@ -399,9 +424,14 @@ tty->disc_data = n_hdlc; n_hdlc->tty = tty; - + MOD_INC_USE_COUNT; +#if defined(TTY_NO_WRITE_SPLIT) + /* change tty_io write() to not split large writes into 8K chunks */ + set_bit(TTY_NO_WRITE_SPLIT,&tty->flags); +#endif + /* Flush any pending characters in the driver and discipline. */ if (tty->ldisc.flush_buffer) @@ -597,18 +627,26 @@ return; } + if ( count>maxframe ) { + if (debuglevel >= DEBUG_LEVEL_INFO) + printk("%s(%d) rx count>maxframesize, data discarded\n", + __FILE__,__LINE__); + return; + } + /* get a free HDLC buffer */ buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list); if (!buf) { /* no buffers in free list, attempt to allocate another rx buffer */ /* unless the maximum count has been reached */ if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT) - buf = (N_HDLC_BUF*)kmalloc(sizeof(N_HDLC_BUF),GFP_ATOMIC); + buf = (N_HDLC_BUF*)kmalloc(N_HDLC_BUF_SIZE,GFP_ATOMIC); } if (!buf) { - printk("%s(%d) no more rx buffers, data discarded\n", - __FILE__,__LINE__); + if (debuglevel >= DEBUG_LEVEL_INFO) + printk("%s(%d) no more rx buffers, data discarded\n", + __FILE__,__LINE__); return; } @@ -622,7 +660,7 @@ /* wake up any blocked reads and perform async signalling */ wake_up_interruptible (&n_hdlc->read_wait); if (n_hdlc->tty->fasync != NULL) - kill_fasync (n_hdlc->tty->fasync, SIGIO); + kill_fasync (n_hdlc->tty->fasync, SIGIO, POLL_IN); } /* end of n_hdlc_tty_receive() */ @@ -678,12 +716,11 @@ if (file->f_flags & O_NONBLOCK) return -EAGAIN; - /* TODO: no timeout? current->timeout = 0;*/ interruptible_sleep_on (&n_hdlc->read_wait); if (signal_pending(current)) return -EINTR; } - + if (rbuf->count > nr) { /* frame too large for caller's buffer (discard frame) */ ret = (rw_ret_t)-EOVERFLOW; @@ -739,13 +776,13 @@ return -EIO; /* verify frame size */ - if (count > MAX_HDLC_FRAME_SIZE) { + if (count > maxframe ) { if (debuglevel & DEBUG_LEVEL_INFO) printk (KERN_WARNING "n_hdlc_tty_write: truncating user packet " "from %lu to %d\n", (unsigned long) count, - MAX_HDLC_FRAME_SIZE); - count = MAX_HDLC_FRAME_SIZE; + maxframe ); + count = maxframe; } /* Allocate transmit buffer */ @@ -754,8 +791,7 @@ /* sleep until transmit buffer available */ add_wait_queue(&n_hdlc->write_wait, &wait); while (!tbuf) { - /* TODO: no timeout? current->timeout = 0;*/ - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule(); n_hdlc = tty2n_hdlc (tty); @@ -773,7 +809,7 @@ tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list); } - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&n_hdlc->write_wait, &wait); } @@ -1000,16 +1036,20 @@ /* allocate free rx buffer list */ for(i=0;irx_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;itx_free_buf_list,buf); + else if (debuglevel >= DEBUG_LEVEL_INFO) + printk("%s(%d)n_hdlc_alloc(), kalloc() failed for tx buffer %d\n",__FILE__,__LINE__, i); } /* Initialize the control block */ @@ -1108,7 +1148,14 @@ static struct tty_ldisc n_hdlc_ldisc; int status; - printk("HDLC line discipline: version %s\n", szVersion); + /* range check maxframe arg */ + if ( maxframe<4096) + maxframe=4096; + else if ( maxframe>65535) + maxframe=65535; + + printk("HDLC line discipline: version %s, maxframe=%u\n", + szVersion, maxframe); /* Register the tty discipline */ diff -u --recursive --new-file v2.3.20/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c --- v2.3.20/linux/drivers/char/n_tty.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/char/n_tty.c Mon Oct 11 10:10:19 1999 @@ -604,7 +604,7 @@ tty->canon_head = tty->read_head; tty->canon_data++; if (tty->fasync) - kill_fasync(tty->fasync, SIGIO); + kill_fasync(tty->fasync, SIGIO, POLL_IN); if (waitqueue_active(&tty->read_wait)) wake_up_interruptible(&tty->read_wait); return; @@ -706,7 +706,7 @@ if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) { if (tty->fasync) - kill_fasync(tty->fasync, SIGIO); + kill_fasync(tty->fasync, SIGIO, POLL_IN); if (waitqueue_active(&tty->read_wait)) wake_up_interruptible(&tty->read_wait); } @@ -854,6 +854,7 @@ retval = 0; n = MIN(*nr, MIN(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail)); if (n) { + mb(); retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n); n -= retval; tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1); diff -u --recursive --new-file v2.3.20/linux/drivers/char/pc110pad.c linux/drivers/char/pc110pad.c --- v2.3.20/linux/drivers/char/pc110pad.c Wed Jun 2 11:29:13 1999 +++ linux/drivers/char/pc110pad.c Mon Oct 11 10:10:19 1999 @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #include "pc110pad.h" @@ -51,7 +53,7 @@ static wait_queue_head_t queue; static struct fasync_struct *asyncptr; static int active=0; /* number of concurrent open()s */ - +static struct semaphore read_lock; /* * Utility to reset a timer to go off some time in the future. @@ -75,7 +77,7 @@ { wake_up_interruptible(&queue); if(asyncptr) - kill_fasync(asyncptr, SIGIO); + kill_fasync(asyncptr, SIGIO, POLL_IN); } @@ -503,10 +505,13 @@ */ static int open_pad(struct inode * inode, struct file * file) { + unsigned long flags; + if (active++) return 0; MOD_INC_USE_COUNT; + save_flags(flags); cli(); outb(0x30, current_params.io+2); /* switch off digitiser */ pad_irq(0,0,0); /* read to flush any pending bytes */ @@ -522,7 +527,7 @@ synthesize_tap=0; del_timer(&bounce_timer); del_timer(&tap_timer); - sti(); + restore_flags(flags); return 0; } @@ -556,14 +561,19 @@ { int r; + down(&read_lock); for(r=0; r #include #include -#include #include #include #include @@ -34,14 +33,15 @@ #include #include -#include #include #include #include +#include + /* Some configuration switches are present in the include file... */ -#include "pc_keyb.h" +#include /* Simple translation table for the SysRq keys */ @@ -56,10 +56,11 @@ "\r\000/"; /* 0x60 - 0x6f */ #endif -static void kbd_write(int address, int data); -static unsigned char handle_kbd_event(void); +static void kbd_write_command_w(int data); +static void kbd_write_output_w(int data); spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; +static unsigned char handle_kbd_event(void); /* used only by send_data - set by keyboard_interrupt */ static volatile unsigned char reply_expected = 0; @@ -83,11 +84,6 @@ #define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT) #define MAX_RETRIES 60 /* some aux operations take long time*/ - -#ifndef AUX_IRQ -# define AUX_IRQ 12 -#endif - #endif /* CONFIG_PSMOUSE */ /* @@ -409,7 +405,7 @@ if (head != queue->tail) { queue->head = head; if (queue->fasync) - kill_fasync(queue->fasync, SIGIO); + kill_fasync(queue->fasync, SIGIO, POLL_IN); wake_up_interruptible(&queue->proc_list); } } @@ -425,22 +421,31 @@ */ static unsigned char handle_kbd_event(void) { - unsigned char status = inb(KBD_STATUS_REG); + unsigned char status = kbd_read_status(); + unsigned int work = 10000; while (status & KBD_STAT_OBF) { unsigned char scancode; - scancode = inb(KBD_DATA_REG); - + scancode = kbd_read_input(); if (status & KBD_STAT_MOUSE_OBF) { handle_mouse_event(scancode); } else { +#ifdef CONFIG_VT if (do_acknowledge(scancode)) handle_scancode(scancode, !(scancode & 0x80)); +#endif mark_bh(KEYBOARD_BH); } - status = inb(KBD_STATUS_REG); + status = kbd_read_status(); + + if(!work--) + { + printk(KERN_ERR "pc_keyb: controller jammed (0x%02X).\n", + status); + break; + } } return status; @@ -451,8 +456,9 @@ { unsigned long flags; +#ifdef CONFIG_VT kbd_pt_regs = regs; - +#endif spin_lock_irqsave(&kbd_controller_lock, flags); handle_kbd_event(); spin_unlock_irqrestore(&kbd_controller_lock, flags); @@ -475,7 +481,7 @@ acknowledge = 0; /* Set by interrupt routine on receipt of ACK. */ resend = 0; reply_expected = 1; - kbd_write(KBD_DATA_REG, data); + kbd_write_output_w(data); for (;;) { if (acknowledge) return 1; @@ -529,14 +535,14 @@ #define KBD_NO_DATA (-1) /* No data */ #define KBD_BAD_DATA (-2) /* Parity or other error */ -static int __init kbd_read_input(void) +static int __init kbd_read_data(void) { int retval = KBD_NO_DATA; unsigned char status; - status = inb(KBD_STATUS_REG); + status = kbd_read_status(); if (status & KBD_STAT_OBF) { - unsigned char data = inb(KBD_DATA_REG); + unsigned char data = kbd_read_input(); retval = data; if (status & (KBD_STAT_GTO | KBD_STAT_PERR)) @@ -550,7 +556,7 @@ int maxread = 100; /* Random number */ do { - if (kbd_read_input() == KBD_NO_DATA) + if (kbd_read_data() == KBD_NO_DATA) break; } while (--maxread); } @@ -560,7 +566,7 @@ long timeout = KBD_INIT_TIMEOUT; do { - int retval = kbd_read_input(); + int retval = kbd_read_data(); if (retval >= 0) return retval; mdelay(1); @@ -568,13 +574,23 @@ return -1; } -static void kbd_write(int address, int data) +static void kbd_write_command_w(int data) { unsigned long flags; spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); - outb(data, address); + kbd_write_command(data); + spin_unlock_irqrestore(&kbd_controller_lock, flags); +} + +static void kbd_write_output_w(int data) +{ + unsigned long flags; + + spin_lock_irqsave(&kbd_controller_lock, flags); + kb_wait(); + kbd_write_output(data); spin_unlock_irqrestore(&kbd_controller_lock, flags); } @@ -585,9 +601,9 @@ spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); - outb(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG); + kbd_write_command(KBD_CCMD_WRITE_MODE); kb_wait(); - outb(cmd, KBD_DATA_REG); + kbd_write_output(cmd); spin_unlock_irqrestore(&kbd_controller_lock, flags); } #endif /* CONFIG_PSMOUSE */ @@ -601,7 +617,7 @@ * This seems to be the only way to get it going. * If the test is successful a x55 is placed in the input buffer. */ - kbd_write(KBD_CNTL_REG, KBD_CCMD_SELF_TEST); + kbd_write_command_w(KBD_CCMD_SELF_TEST); if (kbd_wait_for_input() != 0x55) return "Keyboard failed self test"; @@ -610,14 +626,14 @@ * to test the keyboard clock and data lines. The results of the * test are placed in the input buffer. */ - kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_TEST); + kbd_write_command_w(KBD_CCMD_KBD_TEST); if (kbd_wait_for_input() != 0x00) return "Keyboard interface failed self test"; /* * Enable the keyboard by allowing the keyboard clock to run. */ - kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_ENABLE); + kbd_write_command_w(KBD_CCMD_KBD_ENABLE); /* * Reset keyboard. If the read times out @@ -628,7 +644,7 @@ * Set up to try again if the keyboard asks for RESEND. */ do { - kbd_write(KBD_DATA_REG, KBD_CMD_RESET); + kbd_write_output_w(KBD_CMD_RESET); status = kbd_wait_for_input(); if (status == KBD_REPLY_ACK) break; @@ -646,7 +662,7 @@ * Set up to try again if the keyboard asks for RESEND. */ do { - kbd_write(KBD_DATA_REG, KBD_CMD_DISABLE); + kbd_write_output_w(KBD_CMD_DISABLE); status = kbd_wait_for_input(); if (status == KBD_REPLY_ACK) break; @@ -654,37 +670,37 @@ return "Disable keyboard: no ACK"; } while (1); - kbd_write(KBD_CNTL_REG, KBD_CCMD_WRITE_MODE); - kbd_write(KBD_DATA_REG, KBD_MODE_KBD_INT + kbd_write_command_w(KBD_CCMD_WRITE_MODE); + kbd_write_output_w(KBD_MODE_KBD_INT | KBD_MODE_SYS | KBD_MODE_DISABLE_MOUSE | KBD_MODE_KCC); /* ibm powerpc portables need this to use scan-code set 1 -- Cort */ - kbd_write(KBD_CNTL_REG, KBD_CCMD_READ_MODE); + kbd_write_command_w(KBD_CCMD_READ_MODE); if (!(kbd_wait_for_input() & KBD_MODE_KCC)) { /* * If the controller does not support conversion, * Set the keyboard to scan-code set 1. */ - kbd_write(KBD_DATA_REG, 0xF0); + kbd_write_output_w(0xF0); kbd_wait_for_input(); - kbd_write(KBD_DATA_REG, 0x01); + kbd_write_output_w(0x01); kbd_wait_for_input(); } - kbd_write(KBD_DATA_REG, KBD_CMD_ENABLE); + kbd_write_output_w(KBD_CMD_ENABLE); if (kbd_wait_for_input() != KBD_REPLY_ACK) return "Enable keyboard: no ACK"; /* * Finally, set the typematic rate to maximum. */ - kbd_write(KBD_DATA_REG, KBD_CMD_SET_RATE); + kbd_write_output_w(KBD_CMD_SET_RATE); if (kbd_wait_for_input() != KBD_REPLY_ACK) return "Set rate: no ACK"; - kbd_write(KBD_DATA_REG, 0x00); + kbd_write_output_w(0x00); if (kbd_wait_for_input() != KBD_REPLY_ACK) return "Set rate: no ACK"; @@ -693,6 +709,8 @@ void __init pckbd_init_hw(void) { + kbd_request_region(); + /* Flush any pending input. */ kbd_clear_input(); @@ -707,7 +725,7 @@ #endif /* Ok, finally allocate the IRQ, and off we go.. */ - request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL); + kbd_request_irq(keyboard_interrupt); } #if defined CONFIG_PSMOUSE @@ -731,16 +749,16 @@ * controller has an Auxiliary Port (a.k.a. Mouse Port). */ kb_wait(); - outb(KBD_CCMD_WRITE_AUX_OBUF, KBD_CNTL_REG); + kbd_write_command(KBD_CCMD_WRITE_AUX_OBUF); kb_wait(); - outb(0x5a, KBD_DATA_REG); /* 0x5a is a random dummy value. */ + kbd_write_output(0x5a); /* 0x5a is a random dummy value. */ do { - unsigned char status = inb(KBD_STATUS_REG); + unsigned char status = kbd_read_status(); if (status & KBD_STAT_OBF) { - (void) inb(KBD_DATA_REG); + (void) kbd_read_input(); if (status & KBD_STAT_MOUSE_OBF) { printk(KERN_INFO "Detected PS/2 Mouse Port.\n"); retval = 1; @@ -763,9 +781,9 @@ spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); - outb(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG); + kbd_write_command(KBD_CCMD_WRITE_MOUSE); kb_wait(); - outb(val, KBD_DATA_REG); + kbd_write_output(val); spin_unlock_irqrestore(&kbd_controller_lock, flags); } @@ -778,9 +796,9 @@ spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); - outb(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG); + kbd_write_command(KBD_CCMD_WRITE_MOUSE); kb_wait(); - outb(val, KBD_DATA_REG); + kbd_write_output(val); /* we expect an ACK in response. */ mouse_reply_expected++; kb_wait(); @@ -827,8 +845,8 @@ if (--aux_count) return 0; kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints */ - kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_DISABLE); - free_irq(AUX_IRQ, AUX_DEV); + kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE); + aux_free_irq(AUX_DEV); return 0; } @@ -843,11 +861,11 @@ return 0; } queue->head = queue->tail = 0; /* Flush input queue */ - if (request_irq(AUX_IRQ, keyboard_interrupt, SA_SHIRQ, "PS/2 Mouse", AUX_DEV)) { + if (aux_request_irq(keyboard_interrupt, AUX_DEV)) { aux_count--; return -EBUSY; } - kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_ENABLE); /* Enable the + kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable the auxiliary port on controller. */ aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */ @@ -966,14 +984,14 @@ init_waitqueue_head(&queue->proc_list); #ifdef INITIALIZE_MOUSE - kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */ + kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */ aux_write_ack(AUX_SET_SAMPLE); aux_write_ack(100); /* 100 samples/sec */ aux_write_ack(AUX_SET_RES); aux_write_ack(3); /* 8 counts per mm */ aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */ #endif /* INITIALIZE_MOUSE */ - kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */ + kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */ kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */ return 0; diff -u --recursive --new-file v2.3.20/linux/drivers/char/pc_keyb.h linux/drivers/char/pc_keyb.h --- v2.3.20/linux/drivers/char/pc_keyb.h Tue May 11 14:37:40 1999 +++ linux/drivers/char/pc_keyb.h Wed Dec 31 16:00:00 1969 @@ -1,130 +0,0 @@ -/* - * linux/drivers/char/pc_keyb.h - * - * PC Keyboard And Keyboard Controller - * - * (c) 1997 Martin Mares - */ - -/* - * Configuration Switches - */ - -#undef KBD_REPORT_ERR /* Report keyboard errors */ -#define KBD_REPORT_UNKN /* Report unknown scan codes */ -#define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */ -#undef KBD_IS_FOCUS_9000 /* We have the brain-damaged FOCUS-9000 keyboard */ -#undef INITIALIZE_MOUSE /* Define if your PS/2 mouse needs initialization. */ - - - -#define KBD_INIT_TIMEOUT 1000 /* Timeout in ms for initializing the keyboard */ -#define KBC_TIMEOUT 250 /* Timeout in ms for sending to keyboard controller */ -#define KBD_TIMEOUT 1000 /* Timeout in ms for keyboard command acknowledge */ - -/* - * Internal variables of the driver - */ - -extern unsigned char pckbd_read_mask; -extern unsigned char aux_device_present; - -/* - * Keyboard Controller Registers - */ - -#define KBD_STATUS_REG 0x64 /* Status register (R) */ -#define KBD_CNTL_REG 0x64 /* Controller command register (W) */ -#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */ - -/* - * Keyboard Controller Commands - */ - -#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ -#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ -#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ -#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ -#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ -#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ -#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ -#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ -#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ -#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ -#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if - initiated by the auxiliary device */ -#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ - -/* - * Keyboard Commands - */ - -#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ -#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ -#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ -#define KBD_CMD_DISABLE 0xF5 /* Disable scanning */ -#define KBD_CMD_RESET 0xFF /* Reset */ - -/* - * Keyboard Replies - */ - -#define KBD_REPLY_POR 0xAA /* Power on reset */ -#define KBD_REPLY_ACK 0xFA /* Command ACK */ -#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ - -/* - * Status Register Bits - */ - -#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ -#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ -#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ -#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ -#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ -#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ -#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ -#define KBD_STAT_PERR 0x80 /* Parity error */ - -#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF) - -/* - * Controller Mode Register Bits - */ - -#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ -#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ -#define KBD_MODE_SYS 0x04 /* The system flag (?) */ -#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ -#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ -#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ -#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ -#define KBD_MODE_RFU 0x80 - -/* - * Mouse Commands - */ - -#define AUX_SET_RES 0xE8 /* Set resolution */ -#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ -#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ -#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ -#define AUX_SET_STREAM 0xEA /* Set stream mode */ -#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ -#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ -#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ -#define AUX_RESET 0xFF /* Reset aux device */ -#define AUX_ACK 0xFA /* Command byte ACK. */ - -#define AUX_BUF_SIZE 2048 /* This might be better divisible by - three to make overruns stay in sync - but then the read function would need - a lock etc - ick */ - -struct aux_queue { - unsigned long head; - unsigned long tail; - wait_queue_head_t proc_list; - struct fasync_struct *fasync; - unsigned char buf[AUX_BUF_SIZE]; -}; diff -u --recursive --new-file v2.3.20/linux/drivers/char/ppdev.h linux/drivers/char/ppdev.h --- v2.3.20/linux/drivers/char/ppdev.h Sat Oct 9 11:47:50 1999 +++ linux/drivers/char/ppdev.h Mon Oct 11 10:04:02 1999 @@ -75,7 +75,7 @@ #define PPSETPHASE _IOW(PP_IOCTL, 0x94, int) /* Set and get port timeout (struct timeval's) */ -#define PPGETTIME _IOW(PP_IOCTL, 0x95, struct timeval) -#define PPSETTIME _IOR(PP_IOCTL, 0x96, struct timeval) +#define PPGETTIME _IOR(PP_IOCTL, 0x95, struct timeval) +#define PPSETTIME _IOW(PP_IOCTL, 0x96, struct timeval) diff -u --recursive --new-file v2.3.20/linux/drivers/char/qpmouse.c linux/drivers/char/qpmouse.c --- v2.3.20/linux/drivers/char/qpmouse.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/char/qpmouse.c Mon Oct 11 11:42:59 1999 @@ -42,7 +42,7 @@ #include #include -#include "pc_keyb.h" /* mouse enable command.. */ +#include /* mouse enable command.. */ /* @@ -134,7 +134,7 @@ } queue->head = head; if (queue->fasync) - kill_fasync(queue->fasync, SIGIO); + kill_fasync(queue->fasync, SIGIO, POLL_IN); wake_up_interruptible(&queue->proc_list); } diff -u --recursive --new-file v2.3.20/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.3.20/linux/drivers/char/tty_io.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/char/tty_io.c Mon Oct 11 10:10:19 1999 @@ -661,25 +661,31 @@ if (down_interruptible(&inode->i_sem)) { return -ERESTARTSYS; } - for (;;) { - unsigned long size = PAGE_SIZE*2; - if (size > count) - size = count; + if ( test_bit(TTY_NO_WRITE_SPLIT, &tty->flags) ) { lock_kernel(); - ret = write(tty, file, buf, size); + written = write(tty, file, buf, count); unlock_kernel(); - if (ret <= 0) - break; - written += ret; - buf += ret; - count -= ret; - if (!count) - break; - ret = -ERESTARTSYS; - if (signal_pending(current)) - break; - if (current->need_resched) - schedule(); + } else { + for (;;) { + unsigned long size = PAGE_SIZE*2; + if (size > count) + size = count; + lock_kernel(); + ret = write(tty, file, buf, size); + unlock_kernel(); + if (ret <= 0) + break; + written += ret; + buf += ret; + count -= ret; + if (!count) + break; + ret = -ERESTARTSYS; + if (signal_pending(current)) + break; + if (current->need_resched) + schedule(); + } } if (written) { file->f_dentry->d_inode->i_mtime = CURRENT_TIME; @@ -1996,7 +2002,8 @@ { int retval; struct tty_driver *p; - int found = 0; + int i, found = 0; + struct termios *tp; const char *othername = NULL; if (*driver->refcount) @@ -2027,6 +2034,23 @@ if (driver->next) driver->next->prev = driver->prev; + /* + * Free the termios and termios_locked structures because + * we don't want to get memory leaks when modular tty + * drivers are removed from the kernel. + */ + for (i = 0; i < driver->num; i++) { + tp = driver->termios[i]; + if (tp) { + driver->termios[i] = NULL; + kfree_s(tp, sizeof(struct termios)); + } + tp = driver->termios_locked[i]; + if (tp) { + driver->termios_locked[i] = NULL; + kfree_s(tp, sizeof(struct termios)); + } + } proc_tty_unregister_driver(driver); return 0; } diff -u --recursive --new-file v2.3.20/linux/drivers/fc4/Config.in linux/drivers/fc4/Config.in --- v2.3.20/linux/drivers/fc4/Config.in Mon Mar 15 16:11:29 1999 +++ linux/drivers/fc4/Config.in Mon Oct 11 10:10:19 1999 @@ -6,22 +6,22 @@ tristate 'Fibre Channel and FC4 SCSI support' CONFIG_FC4 if [ ! "$CONFIG_FC4" = "n" ]; then - comment 'FC4 drivers' - if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then - tristate 'Sun SOC/Sbus' CONFIG_FC4_SOC - tristate 'Sun SOC+ (aka SOCAL)' CONFIG_FC4_SOCAL - fi - comment 'FC4 targets' - dep_tristate 'SparcSTORAGE Array 100 and 200 series' CONFIG_SCSI_PLUTO $CONFIG_SCSI - if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then - dep_tristate 'Sun Enterprise Network Array (A5000 and EX500)' CONFIG_SCSI_FCAL $CONFIG_SCSI - else - dep_tristate 'Generic FC-AL disk driver' CONFIG_SCSI_FCAL $CONFIG_SCSI - fi + comment 'FC4 drivers' + if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then + tristate 'Sun SOC/Sbus' CONFIG_FC4_SOC + tristate 'Sun SOC+ (aka SOCAL)' CONFIG_FC4_SOCAL + fi + comment 'FC4 targets' + dep_tristate 'SparcSTORAGE Array 100 and 200 series' CONFIG_SCSI_PLUTO $CONFIG_SCSI + if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then + dep_tristate 'Sun Enterprise Network Array (A5000 and EX500)' CONFIG_SCSI_FCAL $CONFIG_SCSI + else + dep_tristate 'Generic FC-AL disk driver' CONFIG_SCSI_FCAL $CONFIG_SCSI + fi else - define_bool CONFIG_FC4_SOC n - define_bool CONFIG_FC4_SOCAL n - define_bool CONFIG_SCSI_PLUTO n - define_bool CONFIG_SCSI_FCAL n + define_bool CONFIG_FC4_SOC n + define_bool CONFIG_FC4_SOCAL n + define_bool CONFIG_SCSI_PLUTO n + define_bool CONFIG_SCSI_FCAL n fi endmenu diff -u --recursive --new-file v2.3.20/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.3.20/linux/drivers/net/Config.in Fri Sep 10 23:57:29 1999 +++ linux/drivers/net/Config.in Mon Oct 11 12:51:33 1999 @@ -7,12 +7,12 @@ tristate 'ARCnet support' CONFIG_ARCNET if [ "$CONFIG_ARCNET" != "n" ]; then - bool ' Enable arc0e (ARCnet "Ether-Encap" packet format)' CONFIG_ARCNET_ETH - bool ' Enable arc0s (ARCnet RFC1051 packet format)' CONFIG_ARCNET_1051 - dep_tristate ' ARCnet COM90xx (normal) chipset driver' CONFIG_ARCNET_COM90xx $CONFIG_ARCNET - dep_tristate ' ARCnet COM90xx (IO mapped) chipset driver' CONFIG_ARCNET_COM90xxIO $CONFIG_ARCNET - dep_tristate ' ARCnet COM90xx (RIM I) chipset driver' CONFIG_ARCNET_RIM_I $CONFIG_ARCNET - dep_tristate ' ARCnet COM20020 chipset driver' CONFIG_ARCNET_COM20020 $CONFIG_ARCNET + bool ' Enable arc0e (ARCnet "Ether-Encap" packet format)' CONFIG_ARCNET_ETH + bool ' Enable arc0s (ARCnet RFC1051 packet format)' CONFIG_ARCNET_1051 + dep_tristate ' ARCnet COM90xx (normal) chipset driver' CONFIG_ARCNET_COM90xx $CONFIG_ARCNET + dep_tristate ' ARCnet COM90xx (IO mapped) chipset driver' CONFIG_ARCNET_COM90xxIO $CONFIG_ARCNET + dep_tristate ' ARCnet COM90xx (RIM I) chipset driver' CONFIG_ARCNET_RIM_I $CONFIG_ARCNET + dep_tristate ' ARCnet COM20020 chipset driver' CONFIG_ARCNET_COM20020 $CONFIG_ARCNET fi endmenu @@ -20,9 +20,9 @@ tristate 'Dummy net driver support' CONFIG_DUMMY tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_NETLINK" = "y" ]; then - tristate 'Ethertap network tap' CONFIG_ETHERTAP - fi + if [ "$CONFIG_NETLINK" = "y" ]; then + tristate 'Ethertap network tap (EXPERIMENTAL)' CONFIG_ETHERTAP + fi fi tristate 'General Instruments Surfboard 1000' CONFIG_NET_SB1000 @@ -36,145 +36,154 @@ bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET if [ "$CONFIG_NET_ETHERNET" = "y" ]; then - if [ "$CONFIG_ARM" = "y" ]; then - if [ "$CONFIG_ARCH_ACORN" != "y" ]; then - tristate 'AM79C961A support' CONFIG_ARM_AM79C961A - else - source drivers/acorn/net/Config.in - fi - fi - if [ "$CONFIG_PPC" = "y" ]; then - tristate 'MACE (Power Mac ethernet) support' CONFIG_MACE - tristate 'BMAC (G3 ethernet) support' CONFIG_BMAC - fi - if [ "$CONFIG_ZORRO" = "y" ]; then - tristate 'Ariadne support' CONFIG_ARIADNE - tristate 'Ariadne II support' CONFIG_ARIADNE2 - tristate 'A2065 support' CONFIG_A2065 - tristate 'Hydra support' CONFIG_HYDRA - fi - if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then - tristate 'MIPS JAZZ onboard SONIC Ethernet support' CONFIG_MIPS_JAZZ_SONIC - fi - bool '3COM cards' CONFIG_NET_VENDOR_3COM - if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then - tristate '3c501 support' CONFIG_EL1 - tristate '3c503 support' CONFIG_EL2 - tristate '3c505 support' CONFIG_ELPLUS - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate '3c507 support' CONFIG_EL16 + if [ "$CONFIG_ARM" = "y" ]; then + if [ "$CONFIG_ARCH_ACORN" != "y" ]; then + tristate ' AM79C961A support' CONFIG_ARM_AM79C961A + else + source drivers/acorn/net/Config.in + fi + fi + if [ "$CONFIG_PPC" = "y" ]; then + tristate ' MACE (Power Mac ethernet) support' CONFIG_MACE + tristate ' BMAC (G3 ethernet) support' CONFIG_BMAC + fi + if [ "$CONFIG_ZORRO" = "y" ]; then + tristate ' Ariadne support' CONFIG_ARIADNE + tristate ' Ariadne II support' CONFIG_ARIADNE2 + tristate ' A2065 support' CONFIG_A2065 + tristate ' Hydra support' CONFIG_HYDRA + fi + if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then + tristate ' MIPS JAZZ onboard SONIC Ethernet support' CONFIG_MIPS_JAZZ_SONIC + fi + bool ' 3COM cards' CONFIG_NET_VENDOR_3COM + if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then + tristate ' 3c501 support' CONFIG_EL1 + tristate ' 3c503 support' CONFIG_EL2 + tristate ' 3c505 support' CONFIG_ELPLUS + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate ' 3c507 support (EXPERIMENTAL)' CONFIG_EL16 + fi + tristate ' 3c509/3c529 (MCA)/3c579 support' CONFIG_EL3 + tristate ' 3c515 ISA Fast EtherLink' CONFIG_3C515 if [ "$CONFIG_MCA" = "y" ]; then - tristate '3c523 support' CONFIG_ELMC - tristate '3c527 support' CONFIG_ELMC_II + tristate ' 3c523 support' CONFIG_ELMC + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate ' 3c527 support (EXPERIMENTAL)' CONFIG_ELMC_II + fi fi - fi - tristate '3c509/3c579 support' CONFIG_EL3 - tristate '3c515 ISA Fast EtherLink' CONFIG_3C515 - tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX - fi - tristate 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE - bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC - if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then - tristate 'WD80*3 support' CONFIG_WD80x3 - if [ "$CONFIG_MCA" = "y" ]; then - tristate 'SMC Ultra MCA support' CONFIG_ULTRAMCA - fi - tristate 'SMC Ultra support' CONFIG_ULTRA - tristate 'SMC Ultra32 EISA support' CONFIG_ULTRA32 - tristate 'SMC 9194 support' CONFIG_SMC9194 + tristate ' 3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX + fi + tristate ' AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE + bool ' Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC + if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then + tristate ' WD80*3 support' CONFIG_WD80x3 + if [ "$CONFIG_MCA" = "y" ]; then + tristate ' SMC Ultra MCA support' CONFIG_ULTRAMCA + fi + tristate ' SMC Ultra support' CONFIG_ULTRA + tristate ' SMC Ultra32 EISA support' CONFIG_ULTRA32 + tristate ' SMC 9194 support' CONFIG_SMC9194 fi - bool 'Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL + bool ' Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL if [ "$CONFIG_NET_VENDOR_RACAL" = "y" ]; then if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'NI5010 support' CONFIG_NI5010 + tristate ' NI5010 support (EXPERIMENTAL)' CONFIG_NI5010 fi - tristate 'NI5210 support' CONFIG_NI52 - tristate 'NI6510 support' CONFIG_NI65 + tristate ' NI5210 support' CONFIG_NI52 + tristate ' NI6510 support' CONFIG_NI65 fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139 - tristate 'SiS 900 PCI Fast Ethernet Adapter support' CONFIG_SIS900 - tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN - tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC + # tristate ' Packet Engines Hamachi GNIC-II support (EXPERIMENTAL)' CONFIG_HAMACHI + tristate ' Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN + tristate ' RealTek 8129/8139 (not 8019/8029!) support (EXPERIMENTAL)' CONFIG_RTL8139 + tristate ' SiS 900 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_SIS900 + tristate ' DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102 + fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate ' AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700 + fi + tristate ' DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA + bool ' Other ISA cards' CONFIG_NET_ISA + if [ "$CONFIG_NET_ISA" = "y" ]; then + tristate ' Cabletron E21xx support' CONFIG_E2100 + tristate ' EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3 + tristate ' EtherExpress 16 support' CONFIG_EEXPRESS + tristate ' EtherExpressPro support' CONFIG_EEXPRESS_PRO + tristate ' FMV-181/182/183/184 support' CONFIG_FMV18X + tristate ' HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS + tristate ' HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN + tristate ' HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100 + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate ' ICL EtherTeam 16i/32 support (EXPERIMENTAL)' CONFIG_ETH16I + fi + tristate ' NE2000/NE1000 support' CONFIG_NE2000 + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate ' SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005 + fi + bool ' SK_G16 support' CONFIG_SK_G16 + fi + if [ "$CONFIG_MCA" = "y" ]; then + tristate ' SKnet MCA support' CONFIG_SKMC + tristate ' NE/2 (ne2000 MCA version) support' CONFIG_NE2_MCA + fi + bool ' EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA + if [ "$CONFIG_NET_EISA" = "y" ]; then + tristate ' AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32 +# if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +# tristate ' Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE +# fi + tristate ' Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC if [ "$CONFIG_ACENIC" != "n" ]; then - bool 'Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I + bool ' Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I + fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate ' Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 fi - fi - bool 'Other ISA cards' CONFIG_NET_ISA - if [ "$CONFIG_NET_ISA" = "y" ]; then - tristate 'AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700 - tristate 'Cabletron E21xx support' CONFIG_E2100 - tristate 'DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA - tristate 'EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3 - tristate 'EtherExpress 16 support' CONFIG_EEXPRESS - tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO - tristate 'FMV-181/182/183/184 support' CONFIG_FMV18X - tristate 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS - tristate 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN - tristate 'HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100 - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I - fi - tristate 'NE2000/NE1000 support' CONFIG_NE2000 - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005 - fi - bool 'SK_G16 support' CONFIG_SK_G16 - fi - if [ "$CONFIG_MCA" = "y" ]; then - tristate 'NE/2 (ne2000 MCA version) support' CONFIG_NE2_MCA - tristate 'SKnet MCA support' CONFIG_SKMC - fi - bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA - if [ "$CONFIG_NET_EISA" = "y" ]; then - tristate 'AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32 - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 - fi - tristate 'Apricot Xen-II on board Ethernet' CONFIG_APRICOT - tristate 'CS89x0 support' CONFIG_CS89x0 - tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 - tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP - tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS - tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100 - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 - tristate 'Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 - fi - tristate 'PCI NE2000 support' CONFIG_NE2K_PCI - tristate 'TI ThunderLAN support' CONFIG_TLAN - tristate 'VIA Rhine support' CONFIG_VIA_RHINE - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 - tristate 'SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100 - bool 'Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET - fi - tristate 'Adaptec Starfire support' CONFIG_ADAPTEC_STARFIRE - fi - bool 'Pocket and portable adaptors' CONFIG_NET_POCKET - if [ "$CONFIG_NET_POCKET" = "y" ]; then - bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP - tristate 'D-Link DE600 pocket adaptor support' CONFIG_DE600 - tristate 'D-Link DE620 pocket adaptor support' CONFIG_DE620 - fi + tristate ' Apricot Xen-II on board Ethernet' CONFIG_APRICOT + tristate ' CS89x0 support' CONFIG_CS89x0 + tristate ' Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 + tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP + tristate ' Digi Intl. RightSwitch SE-X support' CONFIG_DGRS + tristate ' EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100 + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate ' Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 + tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 + fi + tristate ' PCI NE2000 support' CONFIG_NE2K_PCI + # tristate ' Sundance Alta support' CONFIG_ALTA + tristate ' TI ThunderLAN support' CONFIG_TLAN + tristate ' VIA Rhine support' CONFIG_VIA_RHINE + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate ' Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 + tristate ' SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100 + bool ' Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET + fi + fi + bool ' Pocket and portable adapters' CONFIG_NET_POCKET + if [ "$CONFIG_NET_POCKET" = "y" ]; then + bool ' AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP + tristate ' D-Link DE600 pocket adapter support' CONFIG_DE600 + tristate ' D-Link DE620 pocket adapter support' CONFIG_DE620 + fi fi endmenu bool 'FDDI driver support' CONFIG_FDDI if [ "$CONFIG_FDDI" = "y" ]; then - bool 'Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX + bool ' Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI - if [ "$CONFIG_HIPPI" = "y" ]; then - tristate 'Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER - if [ "$CONFIG_ROADRUNNER" != "n" ]; then - bool ' Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS - fi - fi + bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI + if [ "$CONFIG_HIPPI" = "y" ]; then + tristate ' Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER + if [ "$CONFIG_ROADRUNNER" != "n" ]; then + bool ' Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS + fi + fi fi # @@ -182,133 +191,66 @@ # if [ "$CONFIG_ATALK" != "n" ]; then - mainmenu_option next_comment - comment 'Appletalk devices' - dep_tristate 'Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_ATALK - dep_tristate 'COPS LocalTalk PC support' CONFIG_COPS $CONFIG_ATALK - if [ "$CONFIG_COPS" != "n" ]; then - bool 'Dayna firmware support' CONFIG_COPS_DAYNA - bool 'Tangent firmware support' CONFIG_COPS_TANGENT - fi - dep_tristate 'Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_ATALK - if [ "$CONFIG_IPDDP" != "n" ]; then - bool 'IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP - bool 'Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP - fi - endmenu + mainmenu_option next_comment + comment 'Appletalk devices' + dep_tristate 'Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_ATALK + dep_tristate 'COPS LocalTalk PC support' CONFIG_COPS $CONFIG_ATALK + if [ "$CONFIG_COPS" != "n" ]; then + bool ' Dayna firmware support' CONFIG_COPS_DAYNA + bool ' Tangent firmware support' CONFIG_COPS_TANGENT + fi + dep_tristate 'Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_ATALK + if [ "$CONFIG_IPDDP" != "n" ]; then + bool ' IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP + bool ' Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP + fi + endmenu fi if [ ! "$CONFIG_PARPORT" = "n" ]; then - dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT + dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT fi tristate 'PPP (point-to-point protocol) support' CONFIG_PPP if [ ! "$CONFIG_PPP" = "n" ]; then - dep_tristate 'PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP - dep_tristate 'PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP - dep_tristate 'PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP m + dep_tristate ' PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP + dep_tristate ' PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP + dep_tristate ' PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP m fi tristate 'SLIP (serial line) support' CONFIG_SLIP if [ "$CONFIG_SLIP" != "n" ]; then - bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED - bool ' Keepalive and linefill' CONFIG_SLIP_SMART - bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6 + bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED + bool ' Keepalive and linefill' CONFIG_SLIP_SMART + bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6 fi +mainmenu_option next_comment +comment 'Wireless LAN (non-hamradio)' + bool 'Wireless LAN (non-hamradio)' CONFIG_NET_RADIO if [ "$CONFIG_NET_RADIO" = "y" ]; then - dep_tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET - tristate 'AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN - tristate 'Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN - -fi - -mainmenu_option next_comment -comment 'Token ring devices' + dep_tristate ' STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET + tristate ' AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN + tristate ' Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN -bool 'Token Ring driver support' CONFIG_TR -if [ "$CONFIG_TR" = "y" ]; then - tristate 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR -# tristate 'IBM Lanstreamer PCI adaptor support' CONFIG_IBMLS - tristate 'IBM Olympic chipset PCI adapter support' CONFIG_IBMOL - tristate 'SysKonnect adapter support' CONFIG_SKTR fi endmenu +source drivers/net/tokenring/Config.in + bool 'Fibre Channel driver support' CONFIG_NET_FC if [ "$CONFIG_NET_FC" = "y" ]; then - tristate 'Interphase 5526 Tachyon chipset based adaptor support' CONFIG_IPHASE5526 + dep_tristate ' Interphase 5526 Tachyon chipset based adapter support' CONFIG_IPHASE5526 $CONFIG_SCSI fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI - tristate 'Traffic Shaper (EXPERIMENTAL)' CONFIG_SHAPER -fi - -# -# WAN drivers support -# - -mainmenu_option next_comment -comment 'Wan interfaces' - - -# There is no way to detect a comtrol sv11 - force it modular for now. -# -dep_tristate 'Comtrol Hostess SV-11 support' CONFIG_HOSTESS_SV11 m -# -# The COSA/SRP driver has not been tested as non-modular yet. -# -dep_tristate 'COSA/SRP sync serial boards support' CONFIG_COSA m -# -# There is no way to detect a Sealevel board. Force it modular -# -dep_tristate 'Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m - -tristate 'Frame relay DLCI support' CONFIG_DLCI -if [ "$CONFIG_DLCI" != "n" ]; then - int ' Max open DLCI' CONFIG_DLCI_COUNT 24 - int ' Max DLCI per device' CONFIG_DLCI_MAX 8 - dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI + tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI + tristate 'Traffic Shaper (EXPERIMENTAL)' CONFIG_SHAPER fi -# -# Wan router core. -# - -if [ "$CONFIG_WAN_ROUTER" != "n" ]; then - bool 'WAN drivers' CONFIG_WAN_DRIVERS - if [ "$CONFIG_WAN_DRIVERS" = "y" ]; then - dep_tristate 'Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_DRIVERS - if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then - int ' Maximum number of cards' CONFIG_WANPIPE_CARDS 1 - bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25 - bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR - bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP - fi - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate 'Cyclom 2X(tm) multiprotocol cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_DRIVERS - if [ "$CONFIG_CYCLADES_SYNC" != "n" ]; then - bool ' Cyclom 2X X.25 support (EXPERIMENTAL)' CONFIG_CYCLOMX_X25 - fi - fi - fi -fi - -endmenu - - -# -# X.25 network drivers -# -if [ "$CONFIG_X25" != "n" ]; then -if [ "$CONFIG_LAPB" != "n" ]; then - dep_tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER $CONFIG_LAPB - dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB -fi -fi +source drivers/net/wan/Config.in if [ "$CONFIG_PCMCIA" != "n" ]; then source drivers/net/pcmcia/Config.in diff -u --recursive --new-file v2.3.20/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.3.20/linux/drivers/net/Makefile Fri Sep 10 23:57:29 1999 +++ linux/drivers/net/Makefile Mon Oct 11 10:10:19 1999 @@ -5,7 +5,7 @@ SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) hamradio irda fc pcmcia +ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan L_TARGET := net.a L_OBJS := auto_irq.o @@ -24,10 +24,6 @@ CONFIG_7990_MODULE := CONFIG_82596_BUILTIN := CONFIG_82596_MODULE := -CONFIG_85230_BUILTIN := -CONFIG_85230_MODULE := -CONFIG_SYNCPPP_BUILTIN := -CONFIG_SYNCPPP_MODULE := ifeq ($(CONFIG_PCMCIA),y) SUB_DIRS += pcmcia @@ -60,38 +56,6 @@ L_OBJS += seeq8005.o endif -ifeq ($(CONFIG_IBMTR),y) -L_OBJS += ibmtr.o -else - ifeq ($(CONFIG_IBMTR),m) - M_OBJS += ibmtr.o - endif -endif - -ifeq ($(CONFIG_IBMLS),y) -L_OBJS += lanstreamer.o -else - ifeq ($(CONFIG_IBMLS),m) - M_OBJS += lanstreamer.o - endif -endif - -ifeq ($(CONFIG_IBMOL),y) -L_OBJS += olympic.o -else - ifeq ($(CONFIG_IBMOL),m) - M_OBJS += olympic.o - endif -endif - -ifeq ($(CONFIG_SKTR),y) -L_OBJS += sktr.o -else - ifeq ($(CONFIG_SKTR),m) - M_OBJS += sktr.o - endif -endif - ifeq ($(CONFIG_ETHERTAP),y) L_OBJS += ethertap.o else @@ -123,6 +87,13 @@ endif endif +ifeq ($(CONFIG_PCMCIA_PCNET),y) +CONFIG_8390_BUILTIN = y +else + ifeq ($(CONFIG_PCMCIA_PCNET),m) + CONFIG_8390_MODULE = y + endif +endif ifeq ($(CONFIG_SHAPER),y) L_OBJS += shaper.o @@ -609,6 +580,15 @@ endif endif +ifeq ($(CONFIG_DM9102),y) +L_OBJS += dmfe.o +else + ifeq ($(CONFIG_DM9102),m) + M_OBJS += dmfe.o + endif +endif + + ifeq ($(CONFIG_YELLOWFIN),y) L_OBJS += yellowfin.o else @@ -811,14 +791,6 @@ endif endif -ifeq ($(CONFIG_LAPBETHER),y) -L_OBJS += lapbether.o -else - ifeq ($(CONFIG_LAPBETHER),m) - M_OBJS += lapbether.o - endif -endif - ifeq ($(CONFIG_EPIC100),y) L_OBJS += epic100.o else @@ -827,63 +799,6 @@ endif endif -ifeq ($(CONFIG_HOSTESS_SV11),y) -L_OBJS += hostess_sv11.o -CONFIG_85230_BUILTIN = y -CONFIG_SYNCPPP_BUILTIN = y -else - ifeq ($(CONFIG_HOSTESS_SV11),m) - CONFIG_85230_MODULE = y - CONFIG_SYNCPPP_MODULE = y - M_OBJS += hostess_sv11.o - endif -endif - -ifeq ($(CONFIG_SEALEVEL_4021),y) -L_OBJS += sealevel.o -CONFIG_85230_BUILTIN = y -CONFIG_SYNCPPP_BUILTIN = y -else - ifeq ($(CONFIG_SEALEVEL_4021),m) - CONFIG_85230_MODULE = y - CONFIG_SYNCPPP_MODULE = y - M_OBJS += sealevel.o - endif -endif - - -ifeq ($(CONFIG_COSA),y) -L_OBJS += cosa.o -CONFIG_SYNCPPP_BUILTIN = y -else - ifeq ($(CONFIG_COSA),m) - CONFIG_SYNCPPP_MODULE = y - M_OBJS += cosa.o - endif -endif - -# If anything built-in uses syncppp, then build it into the kernel also. -# If not, but a module uses it, build as a module. - -ifdef CONFIG_SYNCPPP_BUILTIN -LX_OBJS += syncppp.o -else - ifdef CONFIG_SYNCPPP_MODULE - MX_OBJS += syncppp.o - endif -endif - -# If anything built-in uses Z85230, then build it into the kernel also. -# If not, but a module uses it, build as a module. - -ifdef CONFIG_85230_BUILTIN -LX_OBJS += z85230.o -else - ifdef CONFIG_85230_MODULE - MX_OBJS += z85230.o - endif -endif - # If anything built-in uses slhc, then build it into the kernel also. # If not, but a module uses it, build as a module. ifdef CONFIG_SLHC_BUILTIN @@ -914,6 +829,14 @@ endif endif +ifeq ($(CONFIG_PCMCIA_PCNET),y) +CONFIG_8390_BUILTIN = y +else + ifeq ($(CONFIG_PCMCIA_PCNET),m) + CONFIG_8390_MODULE = y + endif +endif + # If anything built-in uses the 8390, then build it into the kernel also. # If not, but a module uses it, build as a module. ifdef CONFIG_8390_BUILTIN @@ -1036,22 +959,6 @@ endif endif -ifeq ($(CONFIG_SDLA),y) -L_OBJS += sdla.o -else - ifeq ($(CONFIG_SDLA),m) - M_OBJS += sdla.o - endif -endif - -ifeq ($(CONFIG_DLCI),y) -L_OBJS += dlci.o -else - ifeq ($(CONFIG_DLCI),m) - M_OBJS += dlci.o - endif -endif - ifeq ($(CONFIG_ARIADNE),y) L_OBJS += ariadne.o else @@ -1128,68 +1035,6 @@ endif endif -ifeq ($(CONFIG_ADAPTEC_STARFIRE),y) -L_OBJS += starfire.o -else - ifeq ($(CONFIG_ADAPTEC_STARFIRE),m) - M_OBJS += starfire.o - endif -endif - -ifeq ($(CONFIG_VENDOR_SANGOMA),y) - LX_OBJS += sdladrv.o - L_OBJS += sdlamain.o - ifeq ($(CONFIG_WANPIPE_X25),y) - L_OBJS += sdla_x25.o - endif - ifeq ($(CONFIG_WANPIPE_FR),y) - L_OBJS += sdla_fr.o - endif - ifeq ($(CONFIG_WANPIPE_PPP),y) - L_OBJS += sdla_ppp.o - endif -endif - -ifeq ($(CONFIG_VENDOR_SANGOMA),m) - MX_OBJS += sdladrv.o - M_OBJS += wanpipe.o - WANPIPE_OBJS = sdlamain.o - ifeq ($(CONFIG_WANPIPE_X25),y) - WANPIPE_OBJS += sdla_x25.o - endif - ifeq ($(CONFIG_WANPIPE_FR),y) - WANPIPE_OBJS += sdla_fr.o - endif - ifeq ($(CONFIG_WANPIPE_PPP),y) - WANPIPE_OBJS += sdla_ppp.o - endif -endif - -ifeq ($(CONFIG_CYCLADES_SYNC),y) - LX_OBJS += cycx_drv.o - L_OBJS += cycx_main.o - ifeq ($(CONFIG_CYCLOMX_X25),y) - L_OBJS += cycx_x25.o - endif -endif - -ifeq ($(CONFIG_CYCLADES_SYNC),m) - MX_OBJS += cycx_drv.o - M_OBJS += cyclomx.o - CYCLOMX_OBJS = cycx_main.o - ifeq ($(CONFIG_CYCLOMX_X25),y) - CYCLOMX_OBJS += cycx_x25.o - endif -endif - -ifeq ($(CONFIG_X25_ASY),y) -L_OBJS += x25_asy.o -else - ifeq ($(CONFIG_X25_ASY),m) - M_OBJS += x25_asy.o - endif -endif - # # HIPPI adapters # @@ -1211,6 +1056,24 @@ endif endif +ifeq ($(CONFIG_TR),y) +SUB_DIRS += tokenring +MOD_IN_SUB_DIRS += tokenring +else + ifeq ($(CONFIG_TR),m) + MOD_IN_SUB_DIRS += tokenring + endif +endif + +ifeq ($(CONFIG_WAN),y) +SUB_DIRS += wan +MOD_IN_SUB_DIRS += wan +else + ifeq ($(CONFIG_WAN),m) + MOD_IN_SUB_DIRS += wan + endif +endif + ifeq ($(CONFIG_NET_FC),y) SUB_DIRS += fc MOD_IN_SUB_DIRS += fc @@ -1224,12 +1087,6 @@ clean: rm -f core *.o *.a *.s - -wanpipe.o: $(WANPIPE_OBJS) - ld -r -o $@ $(WANPIPE_OBJS) - -cyclomx.o: $(CYCLOMX_OBJS) - ld -r -o $@ $(CYCLOMX_OBJS) rcpci.o: rcpci45.o rclanmtl.o $(LD) -r -o rcpci.o rcpci45.o rclanmtl.o diff -u --recursive --new-file v2.3.20/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.3.20/linux/drivers/net/Space.c Fri Sep 10 23:57:29 1999 +++ linux/drivers/net/Space.c Mon Oct 11 10:13:24 1999 @@ -12,6 +12,8 @@ * Donald J. Becker, * * Changelog: + * Arnaldo Carvalho de Melo - 09/1999 + * - fix sbni: s/device/net_device/ * Paul Gortmaker (06/98): * - sort probes in a sane way, make sure all (safe) probes * get run once & failed autoprobes don't autoprobe again. @@ -104,6 +106,7 @@ extern int tlan_probe(struct net_device *); extern int mace_probe(struct net_device *); extern int bmac_probe(struct net_device *); +extern int ncr885e_probe(struct net_device *); extern int cs89x0_probe(struct net_device *dev); extern int ethertap_probe(struct net_device *dev); extern int ether1_probe (struct net_device *dev); @@ -118,11 +121,12 @@ extern int dec_lance_probe(struct net_device *); extern int mvme147lance_probe(struct net_device *dev); extern int via_rhine_probe(struct net_device *dev); -extern int starfire_probe(struct net_device *dev); extern int tc515_probe(struct net_device *dev); extern int lance_probe(struct net_device *dev); +extern int starfire_probe(struct net_device *dev); extern int rcpci_probe(struct net_device *); extern int mac_onboard_sonic_probe(struct net_device *dev); +extern int dmfe_reg_board(struct net_device *); /* Gigabit Ethernet adapters */ extern int yellowfin_probe(struct net_device *dev); @@ -143,6 +147,9 @@ /* Fibre Channel adapters */ extern int iph5526_probe(struct net_device *dev); +/* SBNI adapters */ +extern int sbni_probe(struct net_device *); + struct devprobe { int (*probe)(struct net_device *dev); @@ -216,6 +223,11 @@ #ifdef CONFIG_SIS900 {sis900_probe, 0}, #endif + +#ifdef CONFIG_DM9102 + {dmfe_reg_board, 0}, +#endif + #ifdef CONFIG_YELLOWFIN {yellowfin_probe, 0}, #endif @@ -293,10 +305,10 @@ /* * ISA probes that touch addresses < 0x400 (including those that also - * look for EISA/PCI cards in addition to ISA cards). + * look for EISA/PCI/MCA cards in addition to ISA cards). */ struct devprobe isa_probes[] __initdata = { -#ifdef CONFIG_EL3 /* ISA, EISA (MCA someday) 3c5x9 */ +#ifdef CONFIG_EL3 /* ISA, EISA, MCA 3c5x9 */ {el3_probe, 0}, #endif #ifdef CONFIG_HP100 /* ISA, EISA & PCI */ @@ -458,6 +470,9 @@ #ifdef CONFIG_BMAC {bmac_probe, 0}, #endif +#ifdef CONFIG_NCR885E + {ncr885e_probe, 0}, +#endif {NULL, 0}, }; @@ -781,6 +796,7 @@ /* Token-ring device probe */ extern int ibmtr_probe(struct net_device *); extern int olympic_probe(struct net_device *); +extern int sktr_probe(struct net_device *); static int trif_probe(struct net_device *dev) @@ -876,6 +892,29 @@ # undef NEXT_DEV # define NEXT_DEV (&fc0_dev) #endif + + +#ifdef CONFIG_SBNI + static struct net_device sbni7_dev = + {"sbni7", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, sbni_probe}; + static struct net_device sbni6_dev = + {"sbni6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni7_dev, sbni_probe}; + static struct net_device sbni5_dev = + {"sbni5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni6_dev, sbni_probe}; + static struct net_device sbni4_dev = + {"sbni4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni5_dev, sbni_probe}; + static struct net_device sbni3_dev = + {"sbni3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni4_dev, sbni_probe}; + static struct net_device sbni2_dev = + {"sbni2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni3_dev, sbni_probe}; + static struct net_device sbni1_dev = + {"sbni1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni2_dev, sbni_probe}; + static struct net_device sbni0_dev = + {"sbni0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni1_dev, sbni_probe}; + +#undef NEXT_DEV +#define NEXT_DEV (&sbni0_dev) +#endif #ifdef CONFIG_NET_SB1000 diff -u --recursive --new-file v2.3.20/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c --- v2.3.20/linux/drivers/net/arcnet.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/net/arcnet.c Mon Oct 11 10:10:19 1999 @@ -474,10 +474,12 @@ lp->sdev=(struct net_device *)kmalloc(sizeof(struct net_device)+10,GFP_KERNEL); if(lp->sdev == NULL) { +#ifdef CONFIG_ARCNET_ETH if(lp->edev) kfree(lp->edev); lp->edev=NULL; return -ENOMEM; +#endif } memcpy(lp->sdev,dev,sizeof(struct net_device)); lp->sdev->name=(char *)(lp+1); diff -u --recursive --new-file v2.3.20/linux/drivers/net/cosa.c linux/drivers/net/cosa.c --- v2.3.20/linux/drivers/net/cosa.c Fri Sep 10 23:57:29 1999 +++ linux/drivers/net/cosa.c Wed Dec 31 16:00:00 1969 @@ -1,2038 +0,0 @@ -/* $Id: cosa.c,v 1.26 1999/07/09 15:02:37 kas Exp $ */ - -/* - * Copyright (C) 1995-1997 Jan "Yenya" Kasprzak - * - * 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 . 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 . - * - * 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 - * fixed a deadlock in cosa_sppp_open - */ - -/* ---------- Headers, macros, data structures ---------- */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#undef COSA_SLOW_IO /* for testing purposes only */ -#undef REALLY_SLOW_IO - -#include -#include -#include - -#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, "); -MODULE_DESCRIPTION("Modular driver for the COSA or SRP synchronous card"); -#endif - -/* I use this mainly for testing purposes */ -#ifdef COSA_SLOW_IO -#define cosa_outb outb_p -#define cosa_outw outw_p -#define cosa_inb inb_p -#define cosa_inw inw_p -#else -#define cosa_outb outb -#define cosa_outw outw -#define cosa_inb inb -#define cosa_inw inw -#endif - -#define is_8bit(cosa) (!(cosa->datareg & 0x08)) - -#define cosa_getstatus(cosa) (cosa_inb(cosa->statusreg)) -#define cosa_putstatus(cosa, stat) (cosa_outb(stat, cosa->statusreg)) -#define cosa_getdata16(cosa) (cosa_inw(cosa->datareg)) -#define cosa_getdata8(cosa) (cosa_inb(cosa->datareg)) -#define cosa_putdata16(cosa, dt) (cosa_outw(dt, cosa->datareg)) -#define cosa_putdata8(cosa, dt) (cosa_outb(dt, cosa->datareg)) - -/* Initialization stuff */ -static int cosa_probe(int ioaddr, int irq, int dma); - -/* HW interface */ -static void cosa_enable_rx(struct channel_data *chan); -static void cosa_disable_rx(struct channel_data *chan); -static int cosa_start_tx(struct channel_data *channel, char *buf, int size); -static void cosa_kick(struct cosa_data *cosa); -static int cosa_dma_able(struct channel_data *chan, char *buf, int data); - -/* SPPP/HDLC stuff */ -static void sppp_channel_init(struct channel_data *chan); -static void sppp_channel_delete(struct channel_data *chan); -static int cosa_sppp_open(struct net_device *d); -static int cosa_sppp_close(struct net_device *d); -static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *d); -static char *sppp_setup_rx(struct channel_data *channel, int size); -static int sppp_rx_done(struct channel_data *channel); -static int sppp_tx_done(struct channel_data *channel, int size); -static int cosa_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); -static struct net_device_stats *cosa_net_stats(struct net_device *dev); - -/* Character device */ -static void chardev_channel_init(struct channel_data *chan); -static char *chrdev_setup_rx(struct channel_data *channel, int size); -static int chrdev_rx_done(struct channel_data *channel); -static int chrdev_tx_done(struct channel_data *channel, int size); -static long long cosa_lseek(struct file *file, - long long offset, int origin); -static ssize_t cosa_read(struct file *file, - char *buf, size_t count, loff_t *ppos); -static ssize_t cosa_write(struct file *file, - const char *buf, size_t count, loff_t *ppos); -static unsigned int cosa_poll(struct file *file, poll_table *poll); -static int cosa_open(struct inode *inode, struct file *file); -static int cosa_release(struct inode *inode, struct file *file); -static int cosa_chardev_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); -#ifdef COSA_FASYNC_WORKING -static int cosa_fasync(struct inode *inode, struct file *file, int on); -#endif - -static struct file_operations cosa_fops = { - cosa_lseek, - cosa_read, - cosa_write, - NULL, /* readdir */ - cosa_poll, - cosa_chardev_ioctl, - NULL, /* mmap */ - cosa_open, - NULL, /* flush */ - cosa_release, - NULL, /* fsync */ -#ifdef COSA_FASYNC_WORKING - cosa_fasync, -#else - NULL, -#endif - NULL, /* check media change */ - NULL, /* revalidate */ - NULL /* lock */ -}; - -/* Ioctls */ -static int cosa_start(struct cosa_data *cosa, int address); -static int cosa_reset(struct cosa_data *cosa); -static int cosa_download(struct cosa_data *cosa, struct cosa_download *d); -static int cosa_readmem(struct cosa_data *cosa, struct cosa_download *d); - -/* COSA/SRP ROM monitor */ -static int download(struct cosa_data *cosa, char *data, int addr, int len); -static int startmicrocode(struct cosa_data *cosa, int address); -static int readmem(struct cosa_data *cosa, char *data, int addr, int len); -static int cosa_reset_and_read_id(struct cosa_data *cosa, char *id); - -/* Auxilliary functions */ -static int get_wait_data(struct cosa_data *cosa); -static int put_wait_data(struct cosa_data *cosa, int data); -static int puthexnumber(struct cosa_data *cosa, int number); -static void put_driver_status(struct cosa_data *cosa); -static void put_driver_status_nolock(struct cosa_data *cosa); - -/* Interrupt handling */ -static void cosa_interrupt(int irq, void *cosa, struct pt_regs *regs); - -/* I/O ops debugging */ -#ifdef DEBUG_IO -static void debug_data_in(struct cosa_data *cosa, int data); -static void debug_data_out(struct cosa_data *cosa, int data); -static void debug_data_cmd(struct cosa_data *cosa, int data); -static void debug_status_in(struct cosa_data *cosa, int status); -static void debug_status_out(struct cosa_data *cosa, int status); -#endif - - -/* ---------- Initialization stuff ---------- */ - -#ifdef MODULE -int init_module(void) -#else -static int __init cosa_init(void) -#endif -{ - int i; - printk(KERN_INFO "cosa v1.06 (c) 1997-8 Jan Kasprzak \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; inchannels; 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; inchannels; i++) { - cosa->chan[i].cosa = cosa; - cosa->chan[i].num = i; - channel_init(cosa->chan+i); - } - - printk (KERN_INFO "cosa%d: %s (%s at 0x%x irq %d dma %d), %d channels\n", - cosa->num, cosa->id_string, cosa->type, - cosa->datareg, cosa->irq, cosa->dma, cosa->nchannels); - - return nr_cards++; -} - - -/*---------- SPPP/HDLC netdevice ---------- */ - -static void sppp_channel_init(struct channel_data *chan) -{ - struct net_device *d; - sppp_attach(&chan->pppdev); - d=&chan->pppdev.dev; - d->name = chan->name; - d->base_addr = chan->cosa->datareg; - d->irq = chan->cosa->irq; - d->dma = chan->cosa->dma; - d->priv = chan; - d->init = NULL; - d->open = cosa_sppp_open; - d->stop = cosa_sppp_close; - d->hard_start_xmit = cosa_sppp_tx; - d->do_ioctl = cosa_sppp_ioctl; - d->get_stats = cosa_net_stats; - dev_init_buffers(d); - if (register_netdev(d) == -1) { - printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); - sppp_detach(&chan->pppdev.dev); - return; - } -} - -static void sppp_channel_delete(struct channel_data *chan) -{ - sppp_detach(&chan->pppdev.dev); - unregister_netdev(&chan->pppdev.dev); -} - - -static int cosa_sppp_open(struct net_device *d) -{ - struct channel_data *chan = d->priv; - int err, flags; - - spin_lock_irqsave(&chan->cosa->lock, flags); - if (chan->usage != 0) { - printk(KERN_WARNING "%s: sppp_open called with usage count %d\n", - chan->name, chan->usage); - spin_unlock_irqrestore(&chan->cosa->lock, flags); - return -EBUSY; - } - chan->setup_rx = sppp_setup_rx; - chan->tx_done = sppp_tx_done; - chan->rx_done = sppp_rx_done; - chan->usage=-1; - chan->cosa->usage++; - MOD_INC_USE_COUNT; - spin_unlock_irqrestore(&chan->cosa->lock, flags); - - err = sppp_open(d); - if (err) { - spin_lock_irqsave(&chan->cosa->lock, flags); - chan->usage=0; - chan->cosa->usage--; - MOD_DEC_USE_COUNT; - - spin_unlock_irqrestore(&chan->cosa->lock, flags); - return err; - } - - d->tbusy = 0; - cosa_enable_rx(chan); - return 0; -} - -static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *dev) -{ - struct channel_data *chan = dev->priv; - - if (dev->tbusy) { - if (time_before(jiffies, dev->trans_start+2*HZ)) - return 1; /* Two seconds timeout */ - if (test_bit(RXBIT, &chan->cosa->rxtx)) { - chan->stats.rx_errors++; - chan->stats.rx_missed_errors++; - } else { - chan->stats.tx_errors++; - chan->stats.tx_aborted_errors++; - } - cosa_kick(chan->cosa); - if (chan->tx_skb) { - dev_kfree_skb(chan->tx_skb); - chan->tx_skb = 0; - } - dev->tbusy = 0; - } - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); - return 1; - } - - chan->tx_skb = skb; - dev->trans_start = jiffies; - cosa_start_tx(chan, skb->data, skb->len); - return 0; -} - -static int cosa_sppp_close(struct net_device *d) -{ - struct channel_data *chan = d->priv; - int flags; - - sppp_close(d); - d->tbusy = 1; - cosa_disable_rx(chan); - spin_lock_irqsave(&chan->cosa->lock, flags); - if (chan->rx_skb) { - kfree_skb(chan->rx_skb); - chan->rx_skb = 0; - } - if (chan->tx_skb) { - kfree_skb(chan->tx_skb); - chan->tx_skb = 0; - } - chan->usage=0; - chan->cosa->usage--; - MOD_DEC_USE_COUNT; - spin_unlock_irqrestore(&chan->cosa->lock, flags); - return 0; -} - -static char *sppp_setup_rx(struct channel_data *chan, int size) -{ - /* - * We can safely fall back to non-dma-able memory, because we have - * the cosa->bouncebuf pre-allocated. - */ - if (chan->rx_skb) - kfree_skb(chan->rx_skb); - chan->rx_skb = dev_alloc_skb(size); - if (chan->rx_skb == NULL) { - printk(KERN_NOTICE "%s: Memory squeeze, dropping packet\n", - chan->name); - chan->stats.rx_dropped++; - return NULL; - } - chan->pppdev.dev.trans_start = jiffies; - return skb_put(chan->rx_skb, size); -} - -static int sppp_rx_done(struct channel_data *chan) -{ - if (!chan->rx_skb) { - printk(KERN_WARNING "%s: rx_done with empty skb!\n", - chan->name); - chan->stats.rx_errors++; - chan->stats.rx_frame_errors++; - return 0; - } - chan->rx_skb->protocol = htons(ETH_P_WAN_PPP); - chan->rx_skb->dev = &chan->pppdev.dev; - chan->rx_skb->mac.raw = chan->rx_skb->data; - chan->stats.rx_packets++; - chan->stats.rx_bytes += chan->cosa->rxsize; - netif_rx(chan->rx_skb); - chan->rx_skb = 0; - chan->pppdev.dev.trans_start = jiffies; - return 0; -} - -/* ARGSUSED */ -static int sppp_tx_done(struct channel_data *chan, int size) -{ - if (!chan->tx_skb) { - printk(KERN_WARNING "%s: tx_done with empty skb!\n", - chan->name); - chan->stats.tx_errors++; - chan->stats.tx_aborted_errors++; - return 1; - } - dev_kfree_skb(chan->tx_skb); - chan->tx_skb = 0; - chan->stats.tx_packets++; - chan->stats.tx_bytes += size; - chan->pppdev.dev.tbusy = 0; - mark_bh(NET_BH); - return 1; -} - -static struct net_device_stats *cosa_net_stats(struct net_device *dev) -{ - struct channel_data *chan = dev->priv; - return &chan->stats; -} - - -/*---------- Character device ---------- */ - -static void chardev_channel_init(struct channel_data *chan) -{ - init_MUTEX(&chan->rsem); - init_MUTEX(&chan->wsem); -} - -static long long cosa_lseek(struct file * file, - long long offset, int origin) -{ - return -ESPIPE; -} - -static ssize_t cosa_read(struct file *file, - char *buf, size_t count, loff_t *ppos) -{ - DECLARE_WAITQUEUE(wait, current); - int flags; - struct channel_data *chan = (struct channel_data *)file->private_data; - struct cosa_data *cosa = chan->cosa; - char *kbuf; - - if (down_interruptible(&chan->rsem)) - return -ERESTARTSYS; - - if ((chan->rxdata = kmalloc(COSA_MTU, GFP_DMA|GFP_KERNEL)) == NULL) { - printk(KERN_INFO "%s: cosa_read() - OOM\n", cosa->name); - up(&chan->rsem); - return -ENOMEM; - } - - chan->rx_status = 0; - cosa_enable_rx(chan); - spin_lock_irqsave(&cosa->lock, flags); - add_wait_queue(&chan->rxwaitq, &wait); - while(!chan->rx_status) { - current->state = TASK_INTERRUPTIBLE; - spin_unlock_irqrestore(&cosa->lock, flags); - schedule(); - spin_lock_irqsave(&cosa->lock, flags); - if (signal_pending(current) && chan->rx_status == 0) { - chan->rx_status = 1; - remove_wait_queue(&chan->rxwaitq, &wait); - current->state = TASK_RUNNING; - spin_unlock_irqrestore(&cosa->lock, flags); - up(&chan->rsem); - return -ERESTARTSYS; - } - } - remove_wait_queue(&chan->rxwaitq, &wait); - current->state = TASK_RUNNING; - kbuf = chan->rxdata; - count = chan->rxsize; - spin_unlock_irqrestore(&cosa->lock, flags); - up(&chan->rsem); - - if (copy_to_user(buf, kbuf, count)) { - kfree(buf); - return -EFAULT; - } - kfree(kbuf); - return count; -} - -static char *chrdev_setup_rx(struct channel_data *chan, int size) -{ - /* Expect size <= COSA_MTU */ - chan->rxsize = size; - return chan->rxdata; -} - -static int chrdev_rx_done(struct channel_data *chan) -{ - if (chan->rx_status) { /* Reader has died */ - kfree(chan->rxdata); - up(&chan->wsem); - } - chan->rx_status = 1; - wake_up_interruptible(&chan->rxwaitq); - return 1; -} - - -static ssize_t cosa_write(struct file *file, - const char *buf, size_t count, loff_t *ppos) -{ - struct channel_data *chan = (struct channel_data *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - struct cosa_data *cosa = chan->cosa; - unsigned int flags; - char *kbuf; - - if (down_interruptible(&chan->wsem)) - return -ERESTARTSYS; - - if (count > COSA_MTU) - count = COSA_MTU; - - /* Allocate the buffer */ - if ((kbuf = kmalloc(count, GFP_KERNEL|GFP_DMA)) == NULL) { - printk(KERN_NOTICE "%s: cosa_write() OOM - dropping packet\n", - cosa->name); - up(&chan->wsem); - return -ENOMEM; - } - if (copy_from_user(kbuf, buf, count)) { - up(&chan->wsem); - kfree(kbuf); - return -EFAULT; - } - chan->tx_status=0; - cosa_start_tx(chan, kbuf, count); - - spin_lock_irqsave(&cosa->lock, flags); - add_wait_queue(&chan->txwaitq, &wait); - while(!chan->tx_status) { - current->state = TASK_INTERRUPTIBLE; - spin_unlock_irqrestore(&cosa->lock, flags); - schedule(); - spin_lock_irqsave(&cosa->lock, flags); - if (signal_pending(current) && chan->tx_status == 0) { - chan->tx_status = 1; - remove_wait_queue(&chan->txwaitq, &wait); - current->state = TASK_RUNNING; - chan->tx_status = 1; - spin_unlock_irqrestore(&cosa->lock, flags); - return -ERESTARTSYS; - } - } - remove_wait_queue(&chan->txwaitq, &wait); - current->state = TASK_RUNNING; - up(&chan->wsem); - spin_unlock_irqrestore(&cosa->lock, flags); - kfree(kbuf); - return count; -} - -static int chrdev_tx_done(struct channel_data *chan, int size) -{ - if (chan->tx_status) { /* Writer was interrupted */ - kfree(chan->txbuf); - up(&chan->wsem); - } - chan->tx_status = 1; - wake_up_interruptible(&chan->txwaitq); - return 1; -} - -static unsigned int cosa_poll(struct file *file, poll_table *poll) -{ - printk(KERN_INFO "cosa_poll is here\n"); - return 0; -} - -static int cosa_open(struct inode *inode, struct file *file) -{ - struct cosa_data *cosa; - struct channel_data *chan; - unsigned long flags; - int n; - - if ((n=MINOR(file->f_dentry->d_inode->i_rdev)>>CARD_MINOR_BITS) - >= nr_cards) - return -ENODEV; - cosa = cosa_cards+n; - - if ((n=MINOR(file->f_dentry->d_inode->i_rdev) - & ((1<= cosa->nchannels) - return -ENODEV; - chan = cosa->chan + n; - - file->private_data = chan; - - spin_lock_irqsave(&cosa->lock, flags); - - if (chan->usage < 0) { /* in netdev mode */ - spin_unlock_irqrestore(&cosa->lock, flags); - return -EBUSY; - } - cosa->usage++; - chan->usage++; - - chan->tx_done = chrdev_tx_done; - chan->setup_rx = chrdev_setup_rx; - chan->rx_done = chrdev_rx_done; -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif - spin_unlock_irqrestore(&cosa->lock, flags); - return 0; -} - -static int cosa_release(struct inode *inode, struct file *file) -{ - struct channel_data *channel = (struct channel_data *)file->private_data; - struct cosa_data *cosa = channel->cosa; - unsigned long flags; - - spin_lock_irqsave(&cosa->lock, flags); - cosa->usage--; - channel->usage--; -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif - spin_unlock_irqrestore(&cosa->lock, flags); - return 0; -} - -#ifdef COSA_FASYNC_WORKING -static struct fasync_struct *fasync[256] = { NULL, }; - -/* To be done ... */ -static int cosa_fasync(struct inode *inode, struct file *file, int on) -{ - int port = MINOR(inode->i_rdev); - int rv = fasync_helper(inode, file, on, &fasync[port]); - return rv < 0 ? rv : 0; -} -#endif - - -/* ---------- Ioctls ---------- */ - -/* - * Ioctl subroutines can safely be made inline, because they are called - * only from cosa_ioctl(). - */ -static inline int cosa_reset(struct cosa_data *cosa) -{ - char idstring[COSA_MAX_ID_STRING]; - if (cosa->usage > 1) - printk(KERN_INFO "cosa%d: WARNING: reset requested with cosa->usage > 1 (%d). Odd things may happen.\n", - cosa->num, cosa->usage); - if (cosa_reset_and_read_id(cosa, idstring) < 0) { - printk(KERN_NOTICE "cosa%d: reset failed\n", cosa->num); - return -EIO; - } - printk(KERN_INFO "cosa%d: resetting device: %s\n", cosa->num, - idstring); - return 0; -} - -/* High-level function to download data into COSA memory. Calls download() */ -static inline int cosa_download(struct cosa_data *cosa, struct cosa_download *d) -{ - int i; - int addr, len; - char *code; - - if (cosa->usage > 1) - printk(KERN_INFO "cosa%d: WARNING: download of microcode requested with cosa->usage > 1 (%d). Odd things may happen.\n", - cosa->num, cosa->usage); -#if 0 - if (cosa->status != CARD_STATUS_RESETED && cosa->status != CARD_STATUS_DOWNLOADED) { - printk(KERN_NOTICE "cosa%d: reset the card first (status %d).\n", - cosa->num, cosa->status); - return -EPERM; - } -#endif - get_user_ret(addr, &(d->addr), -EFAULT); - get_user_ret(len, &(d->len), -EFAULT); - get_user_ret(code, &(d->code), -EFAULT); - - if (d->addr < 0 || d->addr > COSA_MAX_FIRMWARE_SIZE) - return -EINVAL; - if (d->len < 0 || d->len > COSA_MAX_FIRMWARE_SIZE) - return -EINVAL; - - if ((i=download(cosa, d->code, len, addr)) < 0) { - printk(KERN_NOTICE "cosa%d: microcode download failed: %d\n", - cosa->num, i); - return -EIO; - } - printk(KERN_INFO "cosa%d: downloading microcode - 0x%04x bytes at 0x%04x\n", - cosa->num, len, addr); - return 0; -} - -/* High-level function to read COSA memory. Calls readmem() */ -static inline int cosa_readmem(struct cosa_data *cosa, struct cosa_download *d) -{ - int i; - int addr, len; - char *code; - - if (cosa->usage > 1) - printk(KERN_INFO "cosa%d: WARNING: readmem requested with " - "cosa->usage > 1 (%d). Odd things may happen.\n", - cosa->num, cosa->usage); -#if 0 - if (cosa->status != CARD_STATUS_RESETED && - cosa->status != CARD_STATUS_DOWNLOADED) { - printk(KERN_NOTICE "cosa%d: reset the card first (status %d).\n", - cosa->num, cosa->status); - return -EPERM; - } -#endif - get_user_ret(addr, &(d->addr), -EFAULT); - get_user_ret(len, &(d->len), -EFAULT); - get_user_ret(code, &(d->code), -EFAULT); - - if ((i=readmem(cosa, d->code, len, addr)) < 0) { - printk(KERN_NOTICE "cosa%d: reading memory failed: %d\n", - cosa->num, i); - return -EIO; - } - printk(KERN_INFO "cosa%d: reading card memory - 0x%04x bytes at 0x%04x\n", - cosa->num, len, addr); - return 0; -} - -/* High-level function to start microcode. Calls startmicrocode(). */ -static inline int cosa_start(struct cosa_data *cosa, int address) -{ - int i; - - if (cosa->usage > 1) - printk(KERN_INFO "cosa%d: WARNING: start microcode requested with cosa->usage > 1 (%d). Odd things may happen.\n", - cosa->num, cosa->usage); -#if 0 - if (cosa->status != CARD_STATUS_DOWNLOADED) { - printk(KERN_NOTICE "cosa%d: download the microcode first (status %d).\n", - cosa->num, cosa->status); - return -EPERM; - } -#endif - if ((i=startmicrocode(cosa, address)) < 0) { - printk(KERN_NOTICE "cosa%d: start microcode at 0x%04x failed: %d\n", - cosa->num, address, i); - return -EIO; - } - printk(KERN_INFO "cosa%d: starting microcode at 0x%04x\n", - cosa->num, address); - cosa->startaddr = address; - return 0; -} - -/* Buffer of size at least COSA_MAX_ID_STRING is expected */ -static inline int cosa_getidstr(struct cosa_data *cosa, char *string) -{ - int l = strlen(cosa->id_string)+1; - copy_to_user_ret(string, cosa->id_string, l, -EFAULT); - return l; -} - -/* Buffer of size at least COSA_MAX_ID_STRING is expected */ -static inline int cosa_gettype(struct cosa_data *cosa, char *string) -{ - int l = strlen(cosa->type)+1; - copy_to_user_ret(string, cosa->type, l, -EFAULT); - return l; -} - -static int cosa_ioctl_common(struct cosa_data *cosa, - struct channel_data *channel, unsigned int cmd, unsigned long arg) -{ - switch(cmd) { - case COSAIORSET: /* Reset the device */ - if (!suser()) - return -EACCES; - return cosa_reset(cosa); - case COSAIOSTRT: /* Start the firmware */ - if (!suser()) - return -EACCES; - return cosa_start(cosa, arg); - case COSAIODOWNLD: /* Download the firmware */ - if (!suser()) - return -EACCES; - return cosa_download(cosa, (struct cosa_download *)arg); - case COSAIORMEM: - if (!suser()) - return -EACCES; - return cosa_readmem(cosa, (struct cosa_download *)arg); - case COSAIORTYPE: - return cosa_gettype(cosa, (char *)arg); - case COSAIORIDSTR: - return cosa_getidstr(cosa, (char *)arg); -/* - * These two are _very_ugly_hack_(tm). Don't even look at this. - * Implementing this saved me few reboots after some process segfaulted - * inside this module. - */ -#ifdef MODULE -#if 0 - case COSAIOMINC: - MOD_INC_USE_COUNT; - return 0; - case COSAIOMDEC: - MOD_DEC_USE_COUNT; - return 0; -#endif -#endif - case COSAIONRCARDS: - return nr_cards; - case COSAIONRCHANS: - return cosa->nchannels; - case COSAIOBMSET: - if (!suser()) - return -EACCES; - if (is_8bit(cosa)) - return -EINVAL; - if (arg != COSA_BM_OFF && arg != COSA_BM_ON) - return -EINVAL; - cosa->busmaster = arg; - return 0; - case COSAIOBMGET: - return cosa->busmaster; - } - return -ENOIOCTLCMD; -} - -static int cosa_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, - int cmd) -{ - int rv; - struct channel_data *chan = (struct channel_data *)dev->priv; - rv = cosa_ioctl_common(chan->cosa, chan, cmd, (int)ifr->ifr_data); - if (rv == -ENOIOCTLCMD) { - return sppp_do_ioctl(dev, ifr, cmd); - } - return rv; -} - -static int cosa_chardev_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct channel_data *channel = (struct channel_data *)file->private_data; - struct cosa_data *cosa = channel->cosa; - return cosa_ioctl_common(cosa, channel, cmd, arg); -} - - -/*---------- HW layer interface ---------- */ - -/* - * The higher layer can bind itself to the HW layer by setting the callbacks - * in the channel_data structure and by using these routines. - */ -static void cosa_enable_rx(struct channel_data *chan) -{ - struct cosa_data *cosa = chan->cosa; - - if (!test_and_set_bit(chan->num, &cosa->rxbitmap)) - put_driver_status(cosa); -} - -static void cosa_disable_rx(struct channel_data *chan) -{ - struct cosa_data *cosa = chan->cosa; - - if (test_and_clear_bit(chan->num, &cosa->rxbitmap)) - put_driver_status(cosa); -} - -/* - * FIXME: This routine probably should check for cosa_start_tx() called when - * the previous transmit is still unfinished. In this case the non-zero - * return value should indicate to the caller that the queuing(sp?) up - * the transmit has failed. - */ -static int cosa_start_tx(struct channel_data *chan, char *buf, int len) -{ - struct cosa_data *cosa = chan->cosa; - int flags; -#ifdef DEBUG_DATA - int i; - - printk(KERN_INFO "cosa%dc%d: starting tx(0x%x)", chan->cosa->num, - chan->num, len); - for (i=0; ilock, 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<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<rxbitmap|cosa->txbitmap) { - cosa_putstatus(cosa, SR_RX_INT_ENA); -#ifdef DEBUG_IO - debug_status_out(cosa, SR_RX_INT_ENA); -#endif - cosa->enabled = 1; - } else { - cosa_putstatus(cosa, 0); -#ifdef DEBUG_IO - debug_status_out(cosa, 0); -#endif - cosa->enabled = 0; - } - cosa_putdata8(cosa, status); -#ifdef DEBUG_IO - debug_data_cmd(cosa, status); -#endif -} - -/* - * The "kickme" function: When the DMA times out, this is called to - * clean up the driver status. - * FIXME: Preliminary support, the interface is probably wrong. - */ -static void cosa_kick(struct cosa_data *cosa) -{ - unsigned flags, flags1; - char *s = "Unknown"; - - if (test_bit(RXBIT, &cosa->rxtx)) - s = "RX"; - if (test_bit(TXBIT, &cosa->rxtx)) - s = "TX"; - - printk(KERN_INFO "%s: %s DMA timeout - restarting.\n", cosa->name, s); - spin_lock_irqsave(&cosa->lock, flags); - cosa->rxtx = 0; - - flags1 = claim_dma_lock(); - disable_dma(cosa->dma); - clear_dma_ff(cosa->dma); - release_dma_lock(flags1); - - /* FIXME: Anything else? */ - udelay(100); - cosa_putstatus(cosa, 0); - udelay(100); - (void) cosa_getdata8(cosa); - udelay(100); - cosa_putdata8(cosa, 0); - udelay(100); - put_driver_status_nolock(cosa); - spin_unlock_irqrestore(&cosa->lock, flags); -} - -/* - * Check if the whole buffer is DMA-able. It means it is below the 16M of - * physical memory and doesn't span the 64k boundary. For now it seems - * SKB's never do this, but we'll check this anyway. - */ -static int cosa_dma_able(struct channel_data *chan, char *buf, int len) -{ - static int count = 0; - unsigned long b = (unsigned long)buf; - if (b+len >= MAX_DMA_ADDRESS) - return 0; - if ((b^ (b+len)) & 0x10000) { - if (count++ < 5) - printk(KERN_INFO "%s: packet spanning a 64k boundary\n", - chan->name); - return 0; - } - return 1; -} - - -/* ---------- The SRP/COSA ROM monitor functions ---------- */ - -/* - * Downloading SRP microcode: say "w" to SRP monitor, it answers by "w=", - * drivers need to say 4-digit hex number meaning start address of the microcode - * separated by a single space. Monitor replies by saying " =". Now driver - * has to write 4-digit hex number meaning the last byte address ended - * by a single space. Monitor has to reply with a space. Now the download - * begins. After the download monitor replies with "\r\n." (CR LF dot). - */ -static int download(struct cosa_data *cosa, char *microcode, int length, int address) -{ - int i; - - if (put_wait_data(cosa, 'w') == -1) return -1; - if ((i=get_wait_data(cosa)) != 'w') { printk("dnld: 0x%04x\n",i); return -2;} - if (get_wait_data(cosa) != '=') return -3; - - if (puthexnumber(cosa, address) < 0) return -4; - if (put_wait_data(cosa, ' ') == -1) return -10; - if (get_wait_data(cosa) != ' ') return -11; - if (get_wait_data(cosa) != '=') return -12; - - if (puthexnumber(cosa, address+length-1) < 0) return -13; - if (put_wait_data(cosa, ' ') == -1) return -18; - if (get_wait_data(cosa) != ' ') return -19; - - while (length--) { - char c; -#ifndef SRP_DOWNLOAD_AT_BOOT - get_user_ret(c,microcode, -23); -#else - c = *microcode; -#endif - if (put_wait_data(cosa, c) == -1) - return -20; - microcode++; - } - - if (get_wait_data(cosa) != '\r') return -21; - if (get_wait_data(cosa) != '\n') return -22; - if (get_wait_data(cosa) != '.') return -23; -#if 0 - printk(KERN_DEBUG "cosa%d: download completed.\n", cosa->num); -#endif - return 0; -} - - -/* - * Starting microcode is done via the "g" command of the SRP monitor. - * The chat should be the following: "g" "g=" "" - * "". - */ -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=" " " " =" " " " " - * Then driver can read the data and the conversation is finished - * by SRP monitor sending "." (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; istate = TASK_INTERRUPTIBLE; - schedule_timeout(1); - } - printk(KERN_INFO "cosa: timeout in get_wait_data (status 0x%x)\n", - cosa_getstatus(cosa)); - return -1; -} - -/* - * This routine puts the data byte to the card waiting for the SR_TX_RDY - * bit to be set in a loop. It should be used in the exceptional cases - * only (for example when resetting the card or downloading the firmware). - */ -static int put_wait_data(struct cosa_data *cosa, int data) -{ - int retries = 1000; - while (--retries) { - /* read data and return them */ - if (cosa_getstatus(cosa) & SR_TX_RDY) { - cosa_putdata8(cosa, data); -#if 0 - printk(KERN_INFO "Putdata: %d retries\n", 999-retries); -#endif - return 0; - } -#if 0 - /* sleep if not ready to read */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); -#endif - } - printk(KERN_INFO "cosa%d: timeout in put_wait_data (status 0x%x)\n", - cosa->num, cosa_getstatus(cosa)); - return -1; -} - -/* - * The following routine puts the hexadecimal number into the SRP monitor - * and verifies the proper echo of the sent bytes. Returns 0 on success, - * negative number on failure (-1,-3,-5,-7) means that put_wait_data() failed, - * (-2,-4,-6,-8) means that reading echo failed. - */ -static int puthexnumber(struct cosa_data *cosa, int number) -{ - char temp[5]; - int i; - - /* Well, I should probably replace this by something faster. */ - sprintf(temp, "%04X", number); - for (i=0; i<4; i++) { - if (put_wait_data(cosa, temp[i]) == -1) { - printk(KERN_NOTICE "cosa%d: puthexnumber failed to write byte %d\n", - cosa->num, i); - return -1-2*i; - } - if (get_wait_data(cosa) != temp[i]) { - printk(KERN_NOTICE "cosa%d: puthexhumber failed to read echo of byte %d\n", - cosa->num, i); - return -2-2*i; - } - } - return 0; -} - - -/* ---------- Interrupt routines ---------- */ - -/* - * There are three types of interrupt: - * At the beginning of transmit - this handled is in tx_interrupt(), - * at the beginning of receive - it is in rx_interrupt() and - * at the end of transmit/receive - it is the eot_interrupt() function. - * These functions are multiplexed by cosa_interrupt() according to the - * COSA status byte. I have moved the rx/tx/eot interrupt handling into - * separate functions to make it more readable. These functions are inline, - * so there should be no overhead of function call. - * - * In the COSA bus-master mode, we need to tell the card the address of a - * buffer. Unfortunately, COSA may be too slow for us, so we must busy-wait. - * It's time to use the bottom half :-( - */ - -/* - * Transmit interrupt routine - called when COSA is willing to obtain - * data from the OS. The most tricky part of the routine is selection - * of channel we (OS) want to send packet for. For SRP we should probably - * use the round-robin approach. The newer COSA firmwares have a simple - * flow-control - in the status word has bits 2 and 3 set to 1 means that the - * channel 0 or 1 doesn't want to receive data. - * - * It seems there is a bug in COSA firmware (need to trace it further): - * When the driver status says that the kernel has no more data for transmit - * (e.g. at the end of TX DMA) and then the kernel changes its mind - * (e.g. new packet is queued to hard_start_xmit()), the card issues - * the TX interrupt but does not mark the channel as ready-to-transmit. - * The fix seems to be to push the packet to COSA despite its request. - * We first try to obey the card's opinion, and then fall back to forced TX. - */ -static inline void tx_interrupt(struct cosa_data *cosa, int status) -{ - unsigned long flags, flags1; -#ifdef DEBUG_IRQS - printk(KERN_INFO "cosa%d: SR_DOWN_REQUEST status=0x%04x\n", - cosa->num, status); -#endif - spin_lock_irqsave(&cosa->lock, flags); - set_bit(TXBIT, &cosa->rxtx); - if (!test_bit(IRQBIT, &cosa->rxtx)) { - /* flow control, see the comment above */ - int i=0; - if (!cosa->txbitmap) { - printk(KERN_WARNING "%s: No channel wants data " - "in TX IRQ. Expect DMA timeout.", - cosa->name); - put_driver_status_nolock(cosa); - clear_bit(TXBIT, &cosa->rxtx); - spin_unlock_irqrestore(&cosa->lock, flags); - return; - } - while(1) { - cosa->txchan++; - i++; - if (cosa->txchan >= cosa->nchannels) - cosa->txchan = 0; - if (!(cosa->txbitmap & (1<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; irxsize; i++) - printk (" %02x", cosa->rxbuf[i]&0xff); - printk("\n"); - } -#endif - /* Packet for unknown channel? */ - if (cosa->rxbuf == cosa->bouncebuf) - goto out; - if (!cosa_dma_able(cosa->rxchan, cosa->rxbuf, cosa->rxsize)) - memcpy(cosa->rxbuf, cosa->bouncebuf, cosa->rxsize); - if (cosa->rxchan->rx_done) - if (cosa->rxchan->rx_done(cosa->rxchan)) - clear_bit(cosa->rxchan->num, &cosa->rxbitmap); - } else { - printk(KERN_NOTICE "cosa%d: unexpected EOT interrupt\n", - cosa->num); - } - /* - * Clear the RXBIT, TXBIT and IRQBIT (the latest should be - * cleared anyway). We should do it as soon as possible - * so that we can tell the COSA we are done and to give it a time - * for recovery. - */ -out: - cosa->rxtx = 0; - put_driver_status_nolock(cosa); - spin_unlock_irqrestore(&cosa->lock, flags); -} - -static void cosa_interrupt(int irq, void *cosa_, struct pt_regs *regs) -{ - unsigned status; - int count = 0; - struct cosa_data *cosa = cosa_; -again: - status = cosa_getstatus(cosa); -#ifdef DEBUG_IRQS - printk(KERN_INFO "cosa%d: got IRQ, status 0x%02x\n", cosa->num, - status & 0xff); -#endif -#ifdef DEBUG_IO - debug_status_in(cosa, status); -#endif - switch (status & SR_CMD_FROM_SRP_MASK) { - case SR_DOWN_REQUEST: - tx_interrupt(cosa, status); - break; - case SR_UP_REQUEST: - rx_interrupt(cosa, status); - break; - case SR_END_OF_TRANSFER: - eot_interrupt(cosa, status); - break; - default: - /* We may be too fast for SRP. Try to wait a bit more. */ - if (count++ < 100) { - udelay(100); - goto again; - } - printk(KERN_INFO "cosa%d: unknown status 0x%02x in IRQ after %d retries\n", - cosa->num, status & 0xff, count); - } -#ifdef DEBUG_IRQS - if (count) - printk(KERN_INFO "%s: %d-times got unknown status in IRQ\n", - cosa->name, count); - else - printk(KERN_INFO "%s: returning from IRQ\n", cosa->name); -#endif -} - - -/* ---------- I/O debugging routines ---------- */ -/* - * These routines can be used to monitor COSA/SRP I/O and to printk() - * the data being transfered on the data and status I/O port in a - * readable way. - */ - -#ifdef DEBUG_IO -static void debug_status_in(struct cosa_data *cosa, int status) -{ - char *s; - switch(status & SR_CMD_FROM_SRP_MASK) { - case SR_UP_REQUEST: - s = "RX_REQ"; - break; - case SR_DOWN_REQUEST: - s = "TX_REQ"; - break; - case SR_END_OF_TRANSFER: - s = "ET_REQ"; - break; - default: - s = "NO_REQ"; - break; - } - printk(KERN_INFO "%s: IO: status -> 0x%02x (%s%s%s%s)\n", - cosa->name, - status, - status & SR_USR_RQ ? "USR_RQ|":"", - status & SR_TX_RDY ? "TX_RDY|":"", - status & SR_RX_RDY ? "RX_RDY|":"", - s); -} - -static void debug_status_out(struct cosa_data *cosa, int status) -{ - printk(KERN_INFO "%s: IO: status <- 0x%02x (%s%s%s%s%s%s)\n", - cosa->name, - status, - status & SR_RX_DMA_ENA ? "RXDMA|":"!rxdma|", - status & SR_TX_DMA_ENA ? "TXDMA|":"!txdma|", - status & SR_RST ? "RESET|":"", - status & SR_USR_INT_ENA ? "USRINT|":"!usrint|", - status & SR_TX_INT_ENA ? "TXINT|":"!txint|", - status & SR_RX_INT_ENA ? "RXINT":"!rxint"); -} - -static void debug_data_in(struct cosa_data *cosa, int data) -{ - printk(KERN_INFO "%s: IO: data -> 0x%04x\n", cosa->name, data); -} - -static void debug_data_out(struct cosa_data *cosa, int data) -{ - printk(KERN_INFO "%s: IO: data <- 0x%04x\n", cosa->name, data); -} - -static void debug_data_cmd(struct cosa_data *cosa, int data) -{ - printk(KERN_INFO "%s: IO: data <- 0x%04x (%s|%s)\n", - cosa->name, data, - data & SR_RDY_RCV ? "RX_RDY" : "!rx_rdy", - data & SR_RDY_SND ? "TX_RDY" : "!tx_rdy"); -} -#endif - -/* EOF -- this file has not been truncated */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/cosa.h linux/drivers/net/cosa.h --- v2.3.20/linux/drivers/net/cosa.h Sun Mar 7 15:47:46 1999 +++ linux/drivers/net/cosa.h Wed Dec 31 16:00:00 1969 @@ -1,111 +0,0 @@ -/* $Id: cosa.h,v 1.6 1999/01/06 14:02:44 kas Exp $ */ - -/* - * Copyright (C) 1995-1997 Jan "Yenya" Kasprzak - * - * 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 - -#ifdef __KERNEL__ -/* status register - output bits */ -#define SR_RX_DMA_ENA 0x04 /* receiver DMA enable bit */ -#define SR_TX_DMA_ENA 0x08 /* transmitter DMA enable bit */ -#define SR_RST 0x10 /* SRP reset */ -#define SR_USR_INT_ENA 0x20 /* user interrupt enable bit */ -#define SR_TX_INT_ENA 0x40 /* transmitter interrupt enable bit */ -#define SR_RX_INT_ENA 0x80 /* receiver interrupt enable bit */ - -/* status register - input bits */ -#define SR_USR_RQ 0x20 /* user interupt request pending */ -#define SR_TX_RDY 0x40 /* transmitter empty (ready) */ -#define SR_RX_RDY 0x80 /* receiver data ready */ - -#define SR_UP_REQUEST 0x02 /* request from SRP to transfer data - up to PC */ -#define SR_DOWN_REQUEST 0x01 /* SRP is able to transfer data down - from PC to SRP */ -#define SR_END_OF_TRANSFER 0x03 /* SRP signalize end of - transfer (up or down) */ - -#define SR_CMD_FROM_SRP_MASK 0x03 /* mask to get SRP command */ - -/* bits in driver status byte definitions : */ -#define SR_RDY_RCV 0x01 /* ready to receive packet */ -#define SR_RDY_SND 0x02 /* ready to send packet */ -#define SR_CMD_PND 0x04 /* command pending */ /* not currently used */ - -/* ???? */ -#define SR_PKT_UP 0x01 /* transfer of packet up in progress */ -#define SR_PKT_DOWN 0x02 /* transfer of packet down in progress */ - -#endif /* __KERNEL__ */ - -#define SR_LOAD_ADDR 0x4400 /* SRP microcode load address */ -#define SR_START_ADDR 0x4400 /* SRP microcode start address */ - -#define COSA_LOAD_ADDR 0x400 /* SRP microcode load address */ -#define COSA_MAX_FIRMWARE_SIZE 0x10000 - -/* ioctls */ -struct cosa_download { - int addr, len; - char *code; -}; - -/* Reset the device */ -#define COSAIORSET _IO('C',0xf0) - -/* Start microcode at given address */ -#define COSAIOSTRT _IOW('C',0xf1,sizeof(int)) - -/* Read the block from the device memory */ -#define COSAIORMEM _IOR('C',0xf2,sizeof(struct cosa_download *)) - -/* Write the block to the device memory (i.e. download the microcode) */ -#define COSAIODOWNLD _IOW('C',0xf2,sizeof(struct cosa_download *)) - -/* Read the device type (one of "srp", "cosa", and "cosa8" for now) */ -#define COSAIORTYPE _IOR('C',0xf3,sizeof(char *)) - -/* Read the device identification string */ -#define COSAIORIDSTR _IOR('C',0xf4,sizeof(char *)) -/* Maximum length of the identification string. */ -#define COSA_MAX_ID_STRING 128 - -/* Increment/decrement the module usage count :-) */ -/* #define COSAIOMINC _IO('C',0xf5) */ -/* #define COSAIOMDEC _IO('C',0xf6) */ - -/* Get the total number of cards installed */ -#define COSAIONRCARDS _IO('C',0xf7) - -/* Get the number of channels on this card */ -#define COSAIONRCHANS _IO('C',0xf8) - -/* Set the driver for the bus-master operations */ -#define COSAIOBMSET _IOW('C', 0xf9, sizeof(unsigned short)) - -#define COSA_BM_OFF 0 /* Bus-mastering off - use ISA DMA (default) */ -#define COSA_BM_ON 1 /* Bus-mastering on - faster but untested */ - -/* Gets the busmaster status */ -#define COSAIOBMGET _IO('C', 0xfa) - -#endif /* !COSA_H__ */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/cycx_drv.c linux/drivers/net/cycx_drv.c --- v2.3.20/linux/drivers/net/cycx_drv.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/net/cycx_drv.c Wed Dec 31 16:00:00 1969 @@ -1,660 +0,0 @@ -/* -* cycx_drv.c cycx Support Module. -* -* This module is a library of common hardware-specific -* functions used by all Cyclades sync and some async (8x & 16x) -* drivers. -* -* Copyright: (c) 1998, 1999 Arnaldo Carvalho de Melo -* -* Author: Arnaldo Carvalho de Melo -* -* Based on sdladrv.c by Gene Kozin -* -* 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 -#endif -#include -#else -#define EXPORT_SYMBOL(function) -#endif -#include /* printk(), and other useful stuff */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* for jiffies, HZ, etc. */ -#include /* API definitions */ -#include /* CYCX firmware module definitions */ -#include /* udelay */ -#include /* for inb(), outb(), etc. */ - -#define MOD_VERSION 0 -#define MOD_RELEASE 2 - -#ifdef MODULE -MODULE_AUTHOR("Arnaldo Carvalho de Melo"); -MODULE_DESCRIPTION("Cyclades Sync Cards Driver."); -#endif - -/* Function Prototypes */ -/* Module entry points. These are called by the OS and must be public. */ -int init_module (void); -void cleanup_module (void); - -/* Hardware-specific functions */ -static int cycx_detect (cycxhw_t *hw); -static int cycx_load (cycxhw_t *hw, cfm_t *cfm, u32 len); -static int cycx_init (cycxhw_t *hw); -static int cycx_reset (cycxhw_t *hw); -static void cycx_bootcfg (cycxhw_t *hw); - -static int init_cycx_2x (cycxhw_t *hw); -static int reset_cycx_2x (u32 addr); -static int detect_cycx_2x (u32 addr); - -/* Miscellaneous functions */ -static void delay_cycx (int sec); -static int get_option_index (u32 *optlist, u32 optval); -static u16 checksum (u8 *buf, u32 len); - -#define wait_cyc(addr) cycx_exec(addr + CMD_OFFSET) - -/* Global Data - * Note: All data must be explicitly initialized!!! */ - -/* private data */ -static char modname[] = "cycx_drv"; -static char fullname[] = "Cyclom X Support Module"; -static char copyright[] = "(c) 1998, 1999 Arnaldo Carvalho de Melo"; - -/* Hardware configuration options. - * These are arrays of configuration options used by verification routines. - * The first element of each array is its size (i.e. number of options). - */ -static u32 cycx_2x_dpmbase_options[] = -{ - 20, - 0xA0000, 0xA4000, 0xA8000, 0xAC000, 0xB0000, 0xB4000, 0xB8000, - 0xBC000, 0xC0000, 0xC4000, 0xC8000, 0xCC000, 0xD0000, 0xD4000, - 0xD8000, 0xDC000, 0xE0000, 0xE4000, 0xE8000, 0xEC000 -}; - -static u32 cycx_2x_irq_options[] = { 7, 3, 5, 9, 10, 11, 12, 15 }; - -/* Kernel Loadable Module Entry Points */ -/* Module 'insert' entry point. - * o print announcement - * o initialize static data - * - * Return: 0 Ok - * < 0 error. - * Context: process */ -#ifdef MODULE -int init_module (void) -{ - printk(KERN_INFO "%s v%u.%u %s\n", - fullname, MOD_VERSION, MOD_RELEASE, copyright); - return 0; -} -/* Module 'remove' entry point. - * o release all remaining system resources */ -void cleanup_module (void) -{ -} -#endif -/* Kernel APIs */ -/* Set up adapter. - * o detect adapter type - * o verify hardware configuration options - * o check for hardware conflicts - * o set up adapter shared memory - * o test adapter memory - * o load firmware - * Return: 0 ok. - * < 0 error */ -EXPORT_SYMBOL(cycx_setup); -int cycx_setup (cycxhw_t *hw, void *cfm, u32 len) -{ - u32 *irq_opt = NULL; /* IRQ options */ - u32 *dpmbase_opt = NULL;/* DPM window base options */ - int err = 0; - - if (cycx_detect(hw)) { - printk(KERN_ERR "%s: adapter Cyclom %uX not found at " - "address 0x%lX!\n", - modname, hw->type, (unsigned long) hw->dpmbase); - return -EINVAL; - } - - printk(KERN_INFO "%s: found Cyclom %uX card at address 0x%lx.\n", - modname, hw->type, (unsigned long) hw->dpmbase); - - switch (hw->type) { - case CYCX_2X: - irq_opt = cycx_2x_irq_options; - dpmbase_opt = cycx_2x_dpmbase_options; - break; - default: - printk(KERN_ERR "%s: unknown card.\n", modname); - return -EINVAL; - } - - /* Verify IRQ configuration options */ - if (!get_option_index(irq_opt, hw->irq)) { - printk (KERN_ERR "%s: IRQ %d is illegal!\n", modname, hw->irq); - return -EINVAL; - } - - /* Setup adapter dual-port memory window and test memory */ - if (!hw->dpmbase) { - printk(KERN_ERR "%s: you must specify the dpm address!\n", - modname); - return -EINVAL; - } - else if (!get_option_index(dpmbase_opt, hw->dpmbase)) { - printk(KERN_ERR "%s: memory address 0x%lX is illegal!\n", - modname, (unsigned long) hw->dpmbase); - return -EINVAL; - } - - hw->dpmsize = CYCX_WINDOWSIZE; - /* FIXME! Is this the only amount ever available? */ - hw->memory = 0x40000; - - cycx_init(hw); - - printk(KERN_INFO "%s: dual-port memory window is set at 0x%lX.\n", - modname, (unsigned long) hw->dpmbase); - printk(KERN_INFO "%s: found %luK bytes of on-board memory.\n", - modname, (unsigned long) hw->memory / 1024); - - /* Load firmware. If loader fails then shut down adapter */ - err = cycx_load(hw, cfm, len); - if (err) cycx_down(hw); /* shutdown adapter */ - return err; -} - -/* Shut down CYCX: disable shared memory access and interrupts, stop CPU,etc.*/ -EXPORT_SYMBOL(cycx_down); -int cycx_down (cycxhw_t *hw) -{ - return 0; /* FIXME: anything needed here? */ -} - -/* Enable interrupt generation. */ -EXPORT_SYMBOL(cycx_inten); -int cycx_inten (cycxhw_t *hw) -{ - switch (hw->type) { - case CYCX_2X: writeb (0, hw->dpmbase); break; - default: return -EINVAL; - } - - return 0; -} - -/* Generate an interrupt to adapter's CPU. */ -EXPORT_SYMBOL(cycx_intr); -int cycx_intr (cycxhw_t *hw) -{ - switch (hw->type) { - case CYCX_2X: - writew(0, hw->dpmbase + GEN_CYCX_INTR); - return 0; - default: return -EINVAL; - } - - return 0; -} - -/* Execute Adapter Command. - * o Set exec flag. - * o Busy-wait until flag is reset. */ -EXPORT_SYMBOL(cycx_exec); -int cycx_exec (u32 addr) -{ - u16 i = 0; - /* wait till addr content is zeroed */ - - while (readw(addr) != 0) { - udelay(1000); - if (++i > 50) return -1; - } - - return 0; -} - -/* Read absolute adapter memory. - * Transfer data from adapter's memory to data buffer. */ -EXPORT_SYMBOL(cycx_peek); -int cycx_peek (cycxhw_t *hw, u32 addr, void *buf, u32 len) -{ - if (len == 1) *(u8*)buf = readb (hw->dpmbase + addr); - else memcpy_fromio(buf, hw->dpmbase + addr, len); - - return 0; -} - -/* Write Absolute Adapter Memory. - * Transfer data from data buffer to adapter's memory. */ -EXPORT_SYMBOL(cycx_poke); -int cycx_poke (cycxhw_t *hw, u32 addr, void *buf, u32 len) -{ - if (len == 1) writeb (*(u8*)buf, hw->dpmbase + addr); - else memcpy_toio(hw->dpmbase + addr, buf, len); - - return 0; -} - -/* Hardware-Specific Functions */ -/* Detect adapter type. - * o if adapter type is specified then call detection routine for that adapter - * type. Otherwise call detection routines for every adapter types until - * adapter is detected. - * - * Notes: - * 1) Detection tests are destructive! Adapter will be left in shutdown state - * after the test. */ -static int cycx_detect (cycxhw_t *hw) -{ - int err = 0; - - if (!hw->dpmbase) return -EFAULT; - - switch (hw->type) { - case CYCX_2X: - if (!detect_cycx_2x(hw->dpmbase)) err = -ENODEV; - break; - default: - if (detect_cycx_2x(hw->dpmbase)) hw->type = CYCX_2X; - else err = -ENODEV; - } - - return err; -} - -/* Load Aux Routines */ -/* Reset board hardware. - return 1 if memory exists at addr and 0 if not. */ -static int memory_exists(u32 addr) -{ - int timeout = 0; - - for (; timeout < 3 ; timeout++) { - writew (TEST_PATTERN, addr + 0x10); - - if (readw (addr + 0x10) == TEST_PATTERN) - if (readw (addr + 0x10) == TEST_PATTERN) return 1; - - delay_cycx(1); - } - - return 0; -} - -/* Reset board hardware. */ -static int cycx_reset(cycxhw_t *hw) -{ - /* Reset board */ - switch (hw->type) { - case CYCX_2X: return reset_cycx_2x(hw->dpmbase); - } - - return -EINVAL; -} - -/* Load reset code. */ -static void reset_load(u32 addr, u8 *buffer, u32 cnt) -{ - u32 pt_code = addr + RESET_OFFSET; - u16 i, j; - - for ( i = 0 ; i < cnt ; i++) { - for (j = 0 ; j < 50 ; j++); /* Delay - FIXME busy waiting... */ - writeb(*buffer++, pt_code++); - } -} - -/* Load buffer using boot interface. - * o copy data from buffer to Cyclom-X memory - * o wait for reset code to copy it to right portion of memory */ -static int buffer_load(u32 addr, u8 *buffer, u32 cnt) -{ - memcpy_toio(addr + DATA_OFFSET, buffer, cnt); - writew(GEN_BOOT_DAT, addr + CMD_OFFSET); - return wait_cyc(addr); -} - -/* Set up entry point and kick start Cyclom-X CPU. */ -static void cycx_start (u32 addr) -{ - /* put in 0x30 offset the jump instruction to the code entry point */ - writeb(0xea, addr + 0x30); - writeb(0x00, addr + 0x31); - writeb(0xc4, addr + 0x32); - writeb(0x00, addr + 0x33); - writeb(0x00, addr + 0x34); - - /* cmd to start executing code */ - writew(GEN_START, addr + CMD_OFFSET); -} - -/* Load and boot reset code. */ -static void cycx_reset_boot(u32 addr, u8 *code, u32 len) -{ - u32 pt_start = addr + START_OFFSET; - - writeb(0xea, pt_start++); /* jmp to f000:3f00 */ - writeb(0x00, pt_start++); - writeb(0xfc, pt_start++); - writeb(0x00, pt_start++); - writeb(0xf0, pt_start); - reset_load(addr, code, len); - - /* 80186 was in hold, go */ - writeb(0, addr + START_CPU); - delay_cycx(1); -} - -/* Load data.bin file through boot (reset) interface. */ -static int cycx_data_boot(u32 addr, u8 *code, u32 len) -{ - u32 pt_boot_cmd = addr + CMD_OFFSET; - u32 i; - - /* boot buffer lenght */ - writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16)); - writew(GEN_DEFPAR, pt_boot_cmd); - - if (wait_cyc(addr) < 0) return 2; - - writew(0, pt_boot_cmd + sizeof(u16)); - writew(0x4000, pt_boot_cmd + 2 * sizeof(u16)); - writew(GEN_SET_SEG, pt_boot_cmd); - - if (wait_cyc(addr) < 0) return 2; - - for (i = 0 ; i < len ; i += CFM_LOAD_BUFSZ) - if (buffer_load(addr, code + i, - MIN(CFM_LOAD_BUFSZ, (len - i))) < 0) { - printk(KERN_ERR "%s: Error !!\n", modname); - return 4; - } - - return 0; -} - - -/* Load code.bin file through boot (reset) interface. */ -static int cycx_code_boot(u32 addr, u8 *code, u32 len) -{ - u32 pt_boot_cmd = addr + CMD_OFFSET; - u32 i; - - /* boot buffer lenght */ - writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16)); - writew(GEN_DEFPAR, pt_boot_cmd); - - if (wait_cyc(addr) == -1) return 2; - - writew(0x0000, pt_boot_cmd + sizeof(u16)); - writew(0xc400, pt_boot_cmd + 2 * sizeof(u16)); - writew(GEN_SET_SEG, pt_boot_cmd); - - if (wait_cyc(addr) == -1) return 1; - - for (i = 0 ; i < len ; i += CFM_LOAD_BUFSZ) - if (buffer_load(addr, code + i,MIN(CFM_LOAD_BUFSZ,(len - i)))) { - printk(KERN_ERR "%s: Error !!\n", modname); - return 4; - } - - return 0; -} - -/* Initialize CYCX hardware: setup memory window, IRQ, etc. */ -static int cycx_init (cycxhw_t *hw) -{ - switch (hw->type) { - case CYCX_2X: return init_cycx_2x(hw); - } - - return -EINVAL; -} - -/* Load adapter from the memory image of the CYCX firmware module. - * o verify firmware integrity and compatibility - * o start adapter up */ -static int cycx_load (cycxhw_t *hw, cfm_t *cfm, u32 len) -{ - int i, j, status; - cycx_header_t *img_hdr; - u8 *reset_image, - *data_image, - *code_image; - u32 pt_cycld = hw->dpmbase + 0x400; - u16 cksum; - - /* Announce */ - printk(KERN_INFO "%s: firmware signature=\"%s\"\n", - modname, cfm->signature); - - /* Verify firmware signature */ - if (strcmp(cfm->signature, CFM_SIGNATURE)) { - printk(KERN_ERR "%s:cycx_load: not Cyclom-2X firmware!\n", - modname); - return -EINVAL; - } - - printk(KERN_INFO "%s: firmware version=%u\n", modname, cfm->version); - - /* Verify firmware module format version */ - if (cfm->version != CFM_VERSION) { - printk(KERN_ERR "%s:cycx_load: firmware format %u rejected! " - "Expecting %u.\n", - modname, cfm->version, CFM_VERSION); - return -EINVAL; - } - - /* Verify firmware module length and checksum */ - cksum = checksum((u8*)&cfm->info, sizeof(cfm_info_t) + - cfm->info.codesize); -/* - FIXME cfm->info.codesize is off by 2 - if (((len - sizeof(cfm_t) - 1) != cfm->info.codesize) || -*/ - if (cksum != cfm->checksum) { - printk(KERN_ERR "%s:cycx_load: firmware corrupted!\n", modname); - printk(KERN_ERR " cdsize = 0x%x (expected 0x%lx)\n", - len - sizeof(cfm_t) - 1, cfm->info.codesize); - printk(KERN_ERR " chksum = 0x%x (expected 0x%x)\n", - cksum, cfm->checksum); - return -EINVAL; - } - - /* If everything is ok, set reset, data and code pointers */ - - img_hdr = (cycx_header_t*)(((u8*) cfm) + sizeof(cfm_t) - 1); -#ifdef FIRMWARE_DEBUG - printk(KERN_INFO "%s:cycx_load: image sizes\n", modname); - printk(KERN_INFO " reset=%lu\n", img_hdr->reset_size); - printk(KERN_INFO " data=%lu\n", img_hdr->data_size); - printk(KERN_INFO " code=%lu\n", img_hdr->code_size); -#endif - reset_image = ((u8 *) img_hdr) + sizeof(cycx_header_t); - data_image = reset_image + img_hdr->reset_size; - code_image = data_image + img_hdr->data_size; - - /*---- Start load ----*/ - /* Announce */ - printk(KERN_INFO "%s: loading firmware %s (ID=%u)...\n", modname, - (cfm->descr[0] != '\0') ? cfm->descr : "unknown firmware", - cfm->info.codeid); - - for (i = 0 ; i < 5 ; i++) { - /* Reset Cyclom hardware */ - if ((status = cycx_reset(hw)) != 0) { - printk(KERN_ERR "%s: dpm problem or board not " - "found (%d).\n", modname, status); - return -EINVAL; - } - - /* Load reset.bin */ - cycx_reset_boot(hw->dpmbase, reset_image, img_hdr->reset_size); - /* reset is waiting for boot */ - writew(GEN_POWER_ON, pt_cycld); - delay_cycx(1); - - for (j = 0 ; j < 3 ; j++) - if (!readw(pt_cycld)) goto reset_loaded; - else delay_cycx(1); - } - - printk(KERN_ERR "%s: reset not started.\n", modname); - return -EINVAL; -reset_loaded: - /* Load data.bin */ - if((status = cycx_data_boot(hw->dpmbase, data_image, - img_hdr->data_size)) != 0) { - printk(KERN_ERR "%s: cannot load data file (%d).\n", - modname, status); - return -EINVAL; - } - - /* Load code.bin */ - if((status = cycx_code_boot(hw->dpmbase, code_image, - img_hdr->code_size)) != 0) { - printk(KERN_ERR "%s: cannot load code file (%d).\n", - modname, status); - return -EINVAL; - } - - /* Prepare boot-time configuration data */ - cycx_bootcfg(hw); - - /* kick-off CPU */ - cycx_start(hw->dpmbase); - - /* Arthur Ganzert's tip: wait a while after the firmware loading... - seg abr 26 17:17:12 EST 1999 - acme */ - delay_cycx(7); - printk(KERN_INFO "%s: firmware loaded!\n", modname); - - /* enable interrupts */ - if (cycx_inten(hw)) { - printk(KERN_ERR "%s: adapter hardware failure!\n", modname); - return -EIO; - } - - return 0; -} - -/* Prepare boot-time firmware configuration data. - * o initialize configuration data area - From async.doc - V_3.4.0 - 07/18/1994 - - As of now, only static buffers are available to the user. - So, the bit VD_RXDIRC must be set in 'valid'. That means that user - wants to use the static transmission and reception buffers. */ -static void cycx_bootcfg (cycxhw_t *hw) -{ - /* use fixed buffers */ - writeb(FIXED_BUFFERS, hw->dpmbase + CONF_OFFSET); -} - -/* Initialize CYCX_2X adapter. */ -static int init_cycx_2x (cycxhw_t *hw) -{ - if (!detect_cycx_2x(hw->dpmbase)) return -ENODEV; - return 0; -} - -/* Detect Cyclom 2x adapter. - * Following tests are used to detect Cyclom 2x adapter: - * to be completed based on the tests done below - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. */ -static int detect_cycx_2x (u32 addr) -{ - printk(KERN_INFO "%s: looking for a cyclom 2x at 0x%lX...\n", - modname, (unsigned long) addr); - - reset_cycx_2x(addr); - return memory_exists(addr); -} - -/* Miscellaneous */ -/* Get option's index into the options list. - * Return option's index (1 .. N) or zero if option is invalid. */ -static int get_option_index (u32 *optlist, u32 optval) -{ - int i = 1; - for (; i <= optlist[0]; ++i) if (optlist[i] == optval) return i; - return 0; -} - -/* Reset adapter's CPU. */ -static int reset_cycx_2x (u32 addr) -{ - writeb (0, addr + RST_ENABLE); delay_cycx (2); - writeb (0, addr + RST_DISABLE); delay_cycx (2); - return memory_exists(addr) ? 0 : 1; -} - -/* Delay */ -static void delay_cycx (int sec) -{ -/* acme - Thu dez 31 21:45:16 EDT 1998 - FIXME I'll keep this comment here just in case, as of now I don't - know it all the contexts where this routine is used are interruptible... */ - - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(sec*HZ); -} - -/* Calculate 16-bit CRC using CCITT polynomial. */ -static u16 checksum (u8 *buf, u32 len) -{ - u16 crc = 0; - u16 mask, flag; - - for (; len; --len, ++buf) - for (mask = 0x80; mask; mask >>= 1) { - flag = (crc & 0x8000); - crc <<= 1; - crc |= ((*buf & mask) ? 1 : 0); - if (flag) crc ^= 0x1021; - } - - return crc; -} -/* End */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/cycx_main.c linux/drivers/net/cycx_main.c --- v2.3.20/linux/drivers/net/cycx_main.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/net/cycx_main.c Wed Dec 31 16:00:00 1969 @@ -1,379 +0,0 @@ -/* -* cycx_main.c Cyclades Cyclom X Multiprotocol WAN Link Driver. Main module. -* -* Author: Arnaldo Carvalho de Melo -* -* Copyright: (c) 1998, 1999 Arnaldo Carvalho de Melo -* -* Based on sdlamain.c by Gene Kozin & -* Jaspreet Singh -* -* 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 /* OS configuration options */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include /* kmalloc(), kfree() */ -#include /* printk(), and other useful stuff */ -#include /* support for loadable modules */ -#include /* request_region(), release_region() */ -#include /* for kernel task queues */ -#include /* WAN router definitions */ -#include /* cyclomx common user API definitions */ -#include /* kernel <-> user copy */ -#include /* __init (when not using as a module) */ - -#ifdef MODULE -MODULE_AUTHOR("Arnaldo Carvalho de Melo"); -MODULE_DESCRIPTION("Cyclades Sync Cards Driver."); -#endif - -/* Defines & Macros */ - -#define DRV_VERSION 0 /* version number */ -#define DRV_RELEASE 4 /* release (minor version) number */ -#define MAX_CARDS 1 /* max number of adapters */ - -#ifndef CONFIG_CYCLOMX_CARDS /* configurable option */ -#define CONFIG_CYCLOMX_CARDS 1 -#endif - -/* Function Prototypes */ - -/* Module entry points */ -int init_module (void); -void cleanup_module (void); - -/* WAN link driver entry points */ -static int setup (wan_device_t *wandev, wandev_conf_t *conf); -static int shutdown (wan_device_t *wandev); -static int ioctl (wan_device_t *wandev, unsigned cmd, unsigned long arg); - -/* Miscellaneous functions */ -static void cycx_isr (int irq, void *dev_id, struct pt_regs *regs); - -/* Global Data - * Note: All data must be explicitly initialized!!! - */ - -/* private data */ -static char drvname[] = "cyclomx"; -static char fullname[] = "CYCLOM X(tm) Multiprotocol Driver"; -static char copyright[] = "(c) 1998, 1999 Arnaldo Carvalho de Melo"; -static int ncards = CONFIG_CYCLOMX_CARDS; -static cycx_t *card_array = NULL; /* adapter data space */ - -/* Kernel Loadable Module Entry Points */ - -/* - * Module 'insert' entry point. - * o print announcement - * o allocate adapter data space - * o initialize static data - * o register all cards with WAN router - * o calibrate CYCX shared memory access delay. - * - * Return: 0 Ok - * < 0 error. - * Context: process - */ -#ifdef MODULE -int init_module (void) -#else -int __init cyclomx_init (void) -#endif -{ - int cnt, err = 0; - - printk(KERN_INFO "%s v%u.%u %s\n", - fullname, DRV_VERSION, DRV_RELEASE, copyright); - - /* Verify number of cards and allocate adapter data space */ - ncards = min(ncards, MAX_CARDS); - ncards = max(ncards, 1); - card_array = kmalloc(sizeof(cycx_t) * ncards, GFP_KERNEL); - - if (card_array == NULL) return -ENOMEM; - - memset(card_array, 0, sizeof(cycx_t) * ncards); - - /* Register adapters with WAN router */ - for (cnt = 0; cnt < ncards; ++cnt) { - cycx_t *card = &card_array[cnt]; - wan_device_t *wandev = &card->wandev; - - sprintf(card->devname, "%s%d", drvname, cnt + 1); - wandev->magic = ROUTER_MAGIC; - wandev->name = card->devname; - wandev->private = card; - wandev->setup = &setup; - wandev->shutdown = &shutdown; - wandev->ioctl = &ioctl; - err = register_wan_device(wandev); - - if (err) { - printk(KERN_ERR - "%s: %s registration failed with error %d!\n", - drvname, card->devname, err); - break; - } - } - - if (cnt) ncards = cnt; /* adjust actual number of cards */ - else { - kfree(card_array); - err = -ENODEV; - } - - return err; -} - -/* - * Module 'remove' entry point. - * o unregister all adapters from the WAN router - * o release all remaining system resources - */ -#ifdef MODULE -void cleanup_module (void) -{ - int i = 0; - - for (; i < ncards; ++i) { - cycx_t *card = &card_array[i]; - unregister_wan_device(card->devname); - } - - kfree(card_array); -} -#endif -/* WAN Device Driver Entry Points */ -/* - * Setup/confugure WAN link driver. - * o check adapter state - * o make sure firmware is present in configuration - * o allocate interrupt vector - * o setup CYCLOM X hardware - * o call appropriate routine to perform protocol-specific initialization - * o mark I/O region as used - * - * This function is called when router handles ROUTER_SETUP IOCTL. The - * configuration structure is in kernel memory (including extended data, if - * any). - */ -static int setup (wan_device_t *wandev, wandev_conf_t *conf) -{ - cycx_t *card; - int err = 0; - int irq; - - /* Sanity checks */ - if (!wandev || !wandev->private || !conf) return -EFAULT; - - card = wandev->private; - - if (wandev->state != WAN_UNCONFIGURED) return -EBUSY; - - if (!conf->data_size || (conf->data == NULL)) { - printk(KERN_ERR "%s: firmware not found in configuration " - "data!\n", wandev->name); - return -EINVAL; - } - - if (conf->irq <= 0) { - printk(KERN_ERR "%s: can't configure without IRQ!\n", - wandev->name); - return -EINVAL; - } - - /* Allocate IRQ */ - irq = conf->irq == 2 ? 9 : conf->irq; /* IRQ2 -> IRQ9 */ - - if (request_irq(irq, cycx_isr, 0, wandev->name, card)) { - printk(KERN_ERR "%s: can't reserve IRQ %d!\n", - wandev->name, irq); - return -EINVAL; - } - - /* Configure hardware, load firmware, etc. */ - memset(&card->hw, 0, sizeof(cycxhw_t)); - card->hw.irq = (conf->irq == 9) ? 2 : conf->irq; - card->hw.dpmbase = conf->maddr; - card->hw.dpmsize = CYCX_WINDOWSIZE; - card->hw.type = conf->hw_opt[0]; - card->hw.fwid = CFID_X25_2X; - card->lock = SPIN_LOCK_UNLOCKED; -#if LINUX_VERSION_CODE >= 0x020300 - init_waitqueue_head(&card->wait_stats); -#else - card->wait_stats = NULL; -#endif - err = cycx_setup(&card->hw, conf->data, conf->data_size); - - if (err) { - free_irq(irq, card); - return err; - } - - /* Intialize WAN device data space */ - wandev->irq = irq; - wandev->dma = wandev->ioport = 0; - wandev->maddr = (unsigned long*)card->hw.dpmbase; - wandev->msize = card->hw.dpmsize; - wandev->hw_opt[0] = card->hw.type; - wandev->hw_opt[1] = card->hw.pclk; - wandev->hw_opt[2] = card->hw.memory; - wandev->hw_opt[3] = card->hw.fwid; - - /* Protocol-specific initialization */ - switch (card->hw.fwid) { -#ifdef CONFIG_CYCLOMX_X25 - case CFID_X25_2X: err = cyx_init(card, conf); break; -#endif - default: - printk(KERN_ERR "%s: this firmware is not supported!\n", - wandev->name); - err = -EINVAL; - } - - if (err) { - cycx_down(&card->hw); - free_irq(irq, card); - return err; - } - - return 0; -} - -/* - * Shut down WAN link driver. - * o shut down adapter hardware - * o release system resources. - * - * This function is called by the router when device is being unregistered or - * when it handles ROUTER_DOWN IOCTL. - */ -static int shutdown (wan_device_t *wandev) -{ - cycx_t *card; - - /* sanity checks */ - if (!wandev || !wandev->private) return -EFAULT; - - if (wandev->state == WAN_UNCONFIGURED) return 0; - - card = wandev->private; - wandev->state = WAN_UNCONFIGURED; - cycx_down(&card->hw); - printk(KERN_INFO "%s: irq %d being freed!\n", wandev->name,wandev->irq); - free_irq(wandev->irq, card); - return 0; -} - -/* - * Driver I/O control. - * o verify arguments - * o perform requested action - * - * This function is called when router handles one of the reserved user - * IOCTLs. Note that 'arg' stil points to user address space. - */ -static int ioctl (wan_device_t *wandev, unsigned cmd, unsigned long arg) -{ - return -EINVAL; -} - -/* Miscellaneous */ -/* - * CYCX Interrupt Service Routine. - * o acknowledge CYCX hardware interrupt. - * o call protocol-specific interrupt service routine, if any. - */ -static void cycx_isr (int irq, void *dev_id, struct pt_regs *regs) -{ -#define card ((cycx_t*)dev_id) - if (!card || card->wandev.state == WAN_UNCONFIGURED) - return; - - if (card->in_isr) { - printk(KERN_WARNING "%s: interrupt re-entrancy on IRQ %d!\n", - card->devname, card->wandev.irq); - return; - } - - if (card->isr) - card->isr(card); -#undef card -} - -/* - * This routine is called by the protocol-specific modules when network - * interface is being open. The only reason we need this, is because we - * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's - * defined more than once into the same kernel module. - */ -void cyclomx_open (cycx_t *card) -{ - ++card->open_cnt; - MOD_INC_USE_COUNT; -} - -/* - * This routine is called by the protocol-specific modules when network - * interface is being closed. The only reason we need this, is because we - * have to call MOD_DEC_USE_COUNT, but cannot include 'module.h' where it's - * defined more than once into the same kernel module. - */ -void cyclomx_close (cycx_t *card) -{ - --card->open_cnt; - MOD_DEC_USE_COUNT; -} - -/* Set WAN device state. */ -void cyclomx_set_state (cycx_t *card, int state) -{ - unsigned long host_cpu_flags; - - spin_lock_irqsave(&card->lock, host_cpu_flags); - - if (card->wandev.state != state) { - switch (state) { - case WAN_CONNECTED: - printk (KERN_INFO "%s: link connected!\n", - card->devname); - break; - - case WAN_CONNECTING: - printk (KERN_INFO "%s: link connecting...\n", - card->devname); - break; - - case WAN_DISCONNECTED: - printk (KERN_INFO "%s: link disconnected!\n", - card->devname); - break; - } - - card->wandev.state = state; - } - - card->state_tick = jiffies; - spin_unlock_irqrestore(&card->lock, host_cpu_flags); -} - -/* End */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/cycx_x25.c linux/drivers/net/cycx_x25.c --- v2.3.20/linux/drivers/net/cycx_x25.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/cycx_x25.c Wed Dec 31 16:00:00 1969 @@ -1,1488 +0,0 @@ -/* -* cycx_x25.c CYCLOM X Multiprotocol WAN Link Driver. X.25 module. -* -* Author: Arnaldo Carvalho de Melo -* Copyright: (c) 1998, 1999 Arnaldo Carvalho de Melo -* -* Based on sdla_x25.c by Gene Kozin -* -* 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 -#include /* printk(), and other useful stuff */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include /* kmalloc(), kfree() */ -#include /* WAN router definitions */ -#include /* htons(), etc. */ -#include /* ARPHRD_X25 */ -#include /* CYCLOM X common user API definitions */ -#include /* X.25 firmware API definitions */ - -/* Defines & Macros */ -#define MAX_CMD_RETRY 5 -#define X25_CHAN_MTU 2048 /* unfragmented logical channel MTU */ - -/* Data Structures */ -/* This is an extention of the 'struct net_device' we create for each network - interface to keep the rest of X.25 channel-specific data. */ -typedef struct x25_channel { - char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ - char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ - char *local_addr; /* local media address, ASCIIZ - - svc thru crossover cable */ - s16 lcn; /* logical channel number/conn.req.key*/ - u8 link; - struct timer_list timer; /* timer used for svc channel disc. */ - u16 protocol; /* ethertype, 0 - multiplexed */ - u8 svc; /* 0 - permanent, 1 - switched */ - u8 state; /* channel state */ - u8 drop_sequence; /* mark sequence for dropping */ - u32 idle_tmout; /* sec, before disconnecting */ - struct sk_buff *rx_skb; /* receive socket buffer */ - cycx_t *card; /* -> owner */ - struct enet_statistics ifstats; /* interface statistics */ -} x25_channel_t; - -/* Function Prototypes */ -/* WAN link driver entry points. These are called by the WAN router module. */ -static int update (wan_device_t *wandev), - new_if (wan_device_t *wandev, struct net_device *dev,wanif_conf_t *conf), - del_if (wan_device_t *wandev, struct net_device *dev); - -/* Network device interface */ -static int if_init (struct net_device *dev), - if_open (struct net_device *dev), - if_close (struct net_device *dev), - if_header (struct sk_buff *skb, struct net_device *dev, - u16 type, void *daddr, void *saddr, unsigned len), - if_rebuild_hdr (struct sk_buff *skb), - if_send (struct sk_buff *skb, struct net_device *dev); - -static struct net_device_stats * if_stats (struct net_device *dev); - -/* Interrupt handlers */ -static void cyx_isr (cycx_t *card), - tx_intr (cycx_t *card, TX25Cmd *cmd), - rx_intr (cycx_t *card, TX25Cmd *cmd), - log_intr (cycx_t *card, TX25Cmd *cmd), - stat_intr (cycx_t *card, TX25Cmd *cmd), - connect_confirm_intr (cycx_t *card, TX25Cmd *cmd), - disconnect_confirm_intr (cycx_t *card, TX25Cmd *cmd), - connect_intr (cycx_t *card, TX25Cmd *cmd), - disconnect_intr (cycx_t *card, TX25Cmd *cmd), - spur_intr (cycx_t *card, TX25Cmd *cmd); - -/* X.25 firmware interface functions */ -static int x25_configure (cycx_t *card, TX25Config *conf), - x25_get_stats (cycx_t *card), - x25_send (cycx_t *card, u8 link, u8 lcn, u8 bitm, int len,void *buf), - x25_connect_response (cycx_t *card, x25_channel_t *chan), - x25_disconnect_response (cycx_t *card, u8 link, u8 lcn); - -/* Miscellaneous functions */ -static int chan_connect (struct net_device *dev), - chan_send (struct net_device *dev, struct sk_buff *skb); - -static void set_chan_state (struct net_device *dev, u8 state), - nibble_to_byte (u8 *s, u8 *d, u8 len, u8 nibble), - reset_timer (struct net_device *dev), - chan_disc (struct net_device *dev), - chan_timer (unsigned long d); - -static u8 bps_to_speed_code (u32 bps); -static u8 log2 (u32 n); - -static unsigned dec_to_uint (u8 *str, int len); - -static struct net_device *get_dev_by_lcn (wan_device_t *wandev, s16 lcn); -static struct net_device *get_dev_by_dte_addr (wan_device_t *wandev, char *dte); - -#ifdef CYCLOMX_X25_DEBUG -static void hex_dump(char *msg, unsigned char *p, int len); -static void x25_dump_config(TX25Config *conf); -static void x25_dump_stats(TX25Stats *stats); -static void x25_dump_devs(wan_device_t *wandev); -#define dprintk(format, a...) printk(format, ##a) -#else -#define hex_dump(msg, p, len) -#define x25_dump_config(conf) -#define x25_dump_stats(stats) -#define x25_dump_devs(wandev) -#define dprintk(format, a...) -#endif -/* Public Functions */ - -/* X.25 Protocol Initialization routine. - * - * This routine is called by the main CYCLOM X module during setup. At this - * point adapter is completely initialized and X.25 firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. - * - * Return: 0 o.k. - * < 0 failure. */ -int cyx_init (cycx_t *card, wandev_conf_t *conf) -{ - TX25Config cfg; - - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_X25) { - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); - return -EINVAL; - } - - /* Initialize protocol-specific fields */ - card->mbox = card->hw.dpmbase + X25_MBOX_OFFS; - card->u.x.connection_keys = 0; - card->u.x.lock = SPIN_LOCK_UNLOCKED; - - /* Configure adapter. Here we set resonable defaults, then parse - * device configuration structure and set configuration options. - * Most configuration options are verified and corrected (if - * necessary) since we can't rely on the adapter to do so and don't - * want it to fail either. */ - memset(&cfg, 0, sizeof(cfg)); - cfg.link = 0; - cfg.clock = conf->clocking == WANOPT_EXTERNAL ? 8 : 55; - cfg.speed = bps_to_speed_code(conf->bps); - cfg.n3win = 7; - cfg.n2win = 2; - cfg.n2 = 5; - cfg.nvc = 1; - cfg.npvc = 1; - cfg.flags = 0x02; /* default = V35 */ - cfg.t1 = 10; /* line carrier timeout */ - cfg.t2 = 29; /* tx timeout */ - cfg.t21 = 180; /* CALL timeout */ - cfg.t23 = 180; /* CLEAR timeout */ - - /* adjust MTU */ - if (!conf->mtu || conf->mtu >= 512) - card->wandev.mtu = 512; - else if (conf->mtu >= 256) - card->wandev.mtu = 256; - else if (conf->mtu >= 128) - card->wandev.mtu = 128; - else - card->wandev.mtu = 64; - - cfg.pktlen = log2(card->wandev.mtu); - - if (conf->station == WANOPT_DTE) { - cfg.locaddr = 3; /* DTE */ - cfg.remaddr = 1; /* DCE */ - } else { - cfg.locaddr = 1; /* DCE */ - cfg.remaddr = 3; /* DTE */ - } - - if (conf->interface == WANOPT_RS232) - cfg.flags = 0; /* FIXME just reset the 2nd bit */ - - if (conf->u.x25.hi_pvc) { - card->u.x.hi_pvc = min(conf->u.x25.hi_pvc, 4095); - card->u.x.lo_pvc = min(conf->u.x25.lo_pvc, card->u.x.hi_pvc); - } - - if (conf->u.x25.hi_svc) { - card->u.x.hi_svc = min(conf->u.x25.hi_svc, 4095); - card->u.x.lo_svc = min(conf->u.x25.lo_svc, card->u.x.hi_svc); - } - - if (card->u.x.lo_pvc == 255) - cfg.npvc = 0; - else - cfg.npvc = card->u.x.hi_pvc - card->u.x.lo_pvc + 1; - - cfg.nvc = card->u.x.hi_svc - card->u.x.lo_svc + 1 + cfg.npvc; - - if (conf->u.x25.hdlc_window) - cfg.n2win = min(conf->u.x25.hdlc_window, 7); - - if (conf->u.x25.pkt_window) - cfg.n3win = min(conf->u.x25.pkt_window, 7); - - if (conf->u.x25.t1) - cfg.t1 = min(conf->u.x25.t1, 30); - - if (conf->u.x25.t2) - cfg.t2 = min(conf->u.x25.t2, 30); - - if (conf->u.x25.t11_t21) - cfg.t21 = min(conf->u.x25.t11_t21, 30); - - if (conf->u.x25.t13_t23) - cfg.t23 = min(conf->u.x25.t13_t23, 30); - - if (conf->u.x25.n2) - cfg.n2 = min(conf->u.x25.n2, 30); - - /* initialize adapter */ - if (x25_configure(card, &cfg)) - return -EIO; - - /* Initialize protocol-specific fields of adapter data space */ - card->wandev.bps = conf->bps; - card->wandev.interface = conf->interface; - card->wandev.clocking = conf->clocking; - card->wandev.station = conf->station; - card->isr = &cyx_isr; - card->exec = NULL; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.state = WAN_DISCONNECTED; - return 0; -} - -/* WAN Device Driver Entry Points */ -/* Update device status & statistics. */ -static int update (wan_device_t *wandev) -{ - /* sanity checks */ - if (!wandev || !wandev->private) - return -EFAULT; - - if (wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - - x25_get_stats(wandev->private); - return 0; -} - -/* Create new logical channel. - * This routine is called by the router when ROUTER_IFNEW IOCTL is being - * handled. - * o parse media- and hardware-specific configuration - * o make sure that a new channel can be created - * o allocate resources, if necessary - * o prepare network device structure for registaration. - * - * Return: 0 o.k. - * < 0 failure (channel will not be created) */ -static int new_if (wan_device_t *wandev, struct net_device *dev, wanif_conf_t *conf) -{ - cycx_t *card = wandev->private; - x25_channel_t *chan; - int err = 0; - - if (conf->name[0] == '\0' || strlen(conf->name) > WAN_IFNAME_SZ) { - printk(KERN_INFO "%s: invalid interface name!\n",card->devname); - return -EINVAL; - } - - /* allocate and initialize private data */ - if ((chan = kmalloc(sizeof(x25_channel_t), GFP_KERNEL)) == NULL) - return -ENOMEM; - - memset(chan, 0, sizeof(x25_channel_t)); - strcpy(chan->name, conf->name); - chan->card = card; - chan->link = conf->port; - chan->protocol = ETH_P_IP; - chan->rx_skb = NULL; - /* only used in svc connected thru crossover cable */ - chan->local_addr = NULL; - - if (conf->addr[0] == '@') { /* SVC */ - int len = strlen(conf->local_addr); - - if (len) { - if (len > WAN_ADDRESS_SZ) { - printk(KERN_ERR "%s: %s local addr too long!\n", - wandev->name, chan->name); - kfree(chan); - return -EINVAL; - } else { - chan->local_addr = kmalloc(len + 1, GFP_KERNEL); - - if (!chan->local_addr) { - kfree(chan); - return ENOMEM; - } - } - - strncpy(chan->local_addr, conf->local_addr, - WAN_ADDRESS_SZ); - } - - chan->svc = 1; - strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ); - init_timer(&chan->timer); - chan->timer.function = chan_timer; - chan->timer.data = (unsigned long) dev; - - /* Set channel timeouts (default if not specified) */ - chan->idle_tmout = conf->idle_timeout ? conf->idle_timeout : 90; - } else if (is_digit(conf->addr[0])) { /* PVC */ - s16 lcn = dec_to_uint(conf->addr, 0); - - if (lcn >= card->u.x.lo_pvc && lcn <= card->u.x.hi_pvc) - chan->lcn = lcn; - else { - printk(KERN_ERR - "%s: PVC %u is out of range on interface %s!\n", - wandev->name, lcn, chan->name); - err = -EINVAL; - } - } else { - printk(KERN_ERR "%s: invalid media address on interface %s!\n", - wandev->name, chan->name); - err = -EINVAL; - } - - if (err) { - if (chan->local_addr) - kfree(chan->local_addr); - - kfree(chan); - return err; - } - - /* prepare network device data space for registration */ - dev->name = chan->name; - dev->init = &if_init; - dev->priv = chan; - return 0; -} - -/* Delete logical channel. */ -static int del_if (wan_device_t *wandev, struct net_device *dev) -{ - if (!dev) { - printk(KERN_ERR "cycx_x25:del_if:dev == NULL!\n"); - return 0; - } - - if (dev->priv) { - x25_channel_t *chan = dev->priv; - - if (chan->svc) { - if (chan->local_addr) - kfree(chan->local_addr); - - if (chan->state == WAN_CONNECTED) - del_timer(&chan->timer); - } - - kfree(chan); - dev->priv = NULL; - } - - return 0; -} - -/* Network Device Interface */ -/* Initialize Linux network interface. - * - * This routine is called only once for each interface, during Linux network - * interface registration. Returning anything but zero will fail interface - * registration. */ -static int if_init (struct net_device *dev) -{ - x25_channel_t *chan = dev->priv; - cycx_t *card = chan->card; - wan_device_t *wandev = &card->wandev; - - /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = &if_header; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; - - /* Initialize media-specific parameters */ - dev->mtu = X25_CHAN_MTU; - dev->type = ARPHRD_X25; /* ARP h/w type */ - dev->hard_header_len = 0; /* media header length */ - dev->addr_len = 0; /* hardware address length */ - - if (!chan->svc) - *(u16*)dev->dev_addr = htons(chan->lcn); - - /* Initialize hardware parameters (just for reference) */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = (unsigned long)wandev->maddr; - dev->mem_end = (unsigned long)(wandev->maddr + wandev->msize - 1); - dev->flags |= IFF_NOARP; - - /* Set transmit buffer queue length */ - dev->tx_queue_len = 10; - - /* Initialize socket buffers */ - dev_init_buffers(dev); - set_chan_state(dev, WAN_DISCONNECTED); - return 0; -} - -/* Open network interface. - * o prevent module from unloading by incrementing use count - * o if link is disconnected then initiate connection - * - * Return 0 if O.k. or errno. */ -static int if_open (struct net_device *dev) -{ - x25_channel_t *chan = dev->priv; - cycx_t *card = chan->card; - - if (dev->start) - return -EBUSY; /* only one open is allowed */ - - dev->interrupt = 0; - dev->tbusy = 0; - dev->start = 1; - cyclomx_open(card); - - return 0; -} - -/* Close network interface. - * o reset flags. - * o if there's no more open channels then disconnect physical link. */ -static int if_close (struct net_device *dev) -{ - x25_channel_t *chan = dev->priv; - cycx_t *card = chan->card; - - dev->start = 0; - - if (chan->state == WAN_CONNECTED || chan->state == WAN_CONNECTING) - chan_disc(dev); - - cyclomx_close(card); - return 0; -} - -/* Build media header. - * o encapsulate packet according to encapsulation type. - * - * The trick here is to put packet type (Ethertype) into 'protocol' field of - * the socket buffer, so that we don't forget it. If encapsulation fails, - * set skb->protocol to 0 and discard packet later. - * - * Return: media header length. */ -static int if_header (struct sk_buff *skb, struct net_device *dev, - u16 type, void *daddr, void *saddr, unsigned len) -{ - skb->protocol = type; - return dev->hard_header_len; -} - -/* * Re-build media header. - * Return: 1 physical address resolved. - * 0 physical address not resolved */ -static int if_rebuild_hdr (struct sk_buff *skb) -{ - return 1; -} - -/* Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission). - * o check link state. If link is not up, then drop the packet. - * o check channel status. If it's down then initiate a call. - * o pass a packet to corresponding WAN device. - * o free socket buffer - * - * Return: 0 complete (socket buffer must be freed) - * non-0 packet may be re-transmitted (tbusy must be set) - * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. */ -static int if_send (struct sk_buff *skb, struct net_device *dev) -{ - x25_channel_t *chan = dev->priv; - cycx_t *card = chan->card; - - if (dev->tbusy) { - ++chan->ifstats.rx_dropped; - return -EBUSY; - } - - if (!chan->svc) - chan->protocol = skb->protocol; - - if (card->wandev.state != WAN_CONNECTED) - ++chan->ifstats.tx_dropped; - else if (chan->svc && chan->protocol && - chan->protocol != skb->protocol) { - printk(KERN_INFO - "%s: unsupported Ethertype 0x%04X on interface %s!\n", - card->devname, skb->protocol, dev->name); - ++chan->ifstats.tx_errors; - } else switch (chan->state) { - case WAN_DISCONNECTED: - if (chan_connect(dev)) { - dev->tbusy = 1; - return -EBUSY; - } - /* fall thru */ - case WAN_CONNECTED: - reset_timer(dev); - dev->trans_start = jiffies; - dev->tbusy = 1; - - if (chan_send(dev, skb)) { - return -EBUSY; - } - break; - default: - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - } - - dev_kfree_skb(skb); - return 0; -} - -/* Get Ethernet-style interface statistics. - * Return a pointer to struct net_device_stats */ -static struct net_device_stats *if_stats (struct net_device *dev) -{ - x25_channel_t *chan = dev->priv; - - return chan ? &chan->ifstats : NULL; -} - -/* Interrupt Handlers */ -/* X.25 Interrupt Service Routine. */ -static void cyx_isr (cycx_t *card) -{ - TX25Cmd cmd; - u16 z = 0; - - card->in_isr = 1; - card->buff_int_mode_unbusy = 0; - cycx_peek(&card->hw, X25_RXMBOX_OFFS, &cmd, sizeof(cmd)); - - switch (cmd.command) { - case X25_DATA_INDICATION: - rx_intr(card, &cmd); - break; - case X25_ACK_FROM_VC: - tx_intr(card, &cmd); - break; - case X25_LOG: - log_intr(card, &cmd); - break; - case X25_STATISTIC: - stat_intr(card, &cmd); - break; - case X25_CONNECT_CONFIRM: - connect_confirm_intr(card, &cmd); - break; - case X25_CONNECT_INDICATION: - connect_intr(card, &cmd); - break; - case X25_DISCONNECT_INDICATION: - disconnect_intr(card, &cmd); - break; - case X25_DISCONNECT_CONFIRM: - disconnect_confirm_intr(card, &cmd); - break; - case X25_LINE_ON: - cyclomx_set_state(card, WAN_CONNECTED); - break; - case X25_LINE_OFF: - cyclomx_set_state(card, WAN_DISCONNECTED); - break; - default: - spur_intr(card, &cmd); /* unwanted interrupt */ - } - - cycx_poke(&card->hw, 0, &z, sizeof(z)); - cycx_poke(&card->hw, X25_RXMBOX_OFFS, &z, sizeof(z)); - card->in_isr = 0; - - if (card->buff_int_mode_unbusy) - mark_bh(NET_BH); -} - -/* Transmit interrupt handler. - * o Release socket buffer - * o Clear 'tbusy' flag */ -static void tx_intr (cycx_t *card, TX25Cmd *cmd) -{ - struct net_device *dev; - wan_device_t *wandev = &card->wandev; - u8 lcn; - - cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn)); - - /* unbusy device and then dev_tint(); */ - if ((dev = get_dev_by_lcn (wandev, lcn)) != NULL) { - card->buff_int_mode_unbusy = 1; - dev->tbusy = 0; - } else - printk(KERN_ERR "%s:ackvc for inexistent lcn %d\n", - card->devname, lcn); -} - -/* Receive interrupt handler. - * This routine handles fragmented IP packets using M-bit according to the - * RFC1356. - * o map ligical channel number to network interface. - * o allocate socket buffer or append received packet to the existing one. - * o if M-bit is reset (i.e. it's the last packet in a sequence) then - * decapsulate packet and pass socket buffer to the protocol stack. - * - * Notes: - * 1. When allocating a socket buffer, if M-bit is set then more data is - * comming and we have to allocate buffer for the maximum IP packet size - * expected on this channel. - * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no - * socket buffers available) the whole packet sequence must be discarded. */ -static void rx_intr (cycx_t *card, TX25Cmd *cmd) -{ - wan_device_t *wandev = &card->wandev; - struct net_device *dev; - x25_channel_t *chan; - struct sk_buff *skb; - u8 bitm, lcn; - int pktlen = cmd->len - 5; - - cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn)); - cycx_peek(&card->hw, cmd->buf + 4, &bitm, sizeof(bitm)); - bitm &= 0x10; - - if ((dev = get_dev_by_lcn(wandev, lcn)) == NULL) { - /* Invalid channel, discard packet */ - printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n", - card->devname, lcn); - return; - } - - chan = dev->priv; - reset_timer(dev); - - if (chan->drop_sequence) { - if (!bitm) - chan->drop_sequence = 0; - else - return; - } - - if ((skb = chan->rx_skb) == NULL) { - /* Allocate new socket buffer */ - int bufsize = bitm ? dev->mtu : pktlen; - - if ((skb = dev_alloc_skb(bufsize + - dev->hard_header_len)) == NULL) { - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - chan->drop_sequence = 1; - ++chan->ifstats.rx_dropped; - return; - } - - skb->dev = dev; - skb->protocol = htons(chan->protocol); - chan->rx_skb = skb; - } - - if (skb_tailroom(skb) < pktlen) { - /* No room for the packet. Call off the whole thing! */ - dev_kfree_skb(skb); - chan->rx_skb = NULL; - - if (bitm) - chan->drop_sequence = 1; - - printk(KERN_INFO "%s: unexpectedly long packet sequence " - "on interface %s!\n", card->devname, dev->name); - ++chan->ifstats.rx_length_errors; - return; - } - - /* Append packet to the socket buffer */ - cycx_peek(&card->hw, cmd->buf + 5, skb_put(skb, pktlen), pktlen); - - if (bitm) - return; /* more data is coming */ - - dev->last_rx = jiffies; /* timestamp */ - chan->rx_skb = NULL; /* dequeue packet */ - - skb->protocol = htons(ETH_P_IP); - skb->dev = dev; - skb->mac.raw = skb->data; - netif_rx(skb); - ++chan->ifstats.rx_packets; - chan->ifstats.rx_bytes += skb->len; -} - -/* Connect interrupt handler. */ -static void connect_intr (cycx_t *card, TX25Cmd *cmd) -{ - wan_device_t *wandev = &card->wandev; - struct net_device *dev = NULL; - x25_channel_t *chan; - u8 d[32], - loc[24], - rem[24]; - u8 lcn, sizeloc, sizerem; - - cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn)); - cycx_peek(&card->hw, cmd->buf + 5, &sizeloc, sizeof(sizeloc)); - cycx_peek(&card->hw, cmd->buf + 6, d, cmd->len - 6); - - sizerem = sizeloc >> 4; - sizeloc &= 0x0F; - - loc[0] = rem[0] = '\0'; - - if (sizeloc) - nibble_to_byte(d, loc, sizeloc, 0); - - if (sizerem) - nibble_to_byte(d + (sizeloc >> 1), rem, sizerem, sizeloc & 1); - - dprintk(KERN_INFO "connect_intr:lcn=%d, local=%s, remote=%s\n", - lcn, loc, rem); - if ((dev = get_dev_by_dte_addr(wandev, rem)) == NULL) { - /* Invalid channel, discard packet */ - printk(KERN_INFO "%s: connect not expected: remote %s!\n", - card->devname, rem); - return; - } - - chan = dev->priv; - chan->lcn = lcn; - x25_connect_response(card, chan); - set_chan_state(dev, WAN_CONNECTED); -} - -/* Connect confirm interrupt handler. */ -static void connect_confirm_intr (cycx_t *card, TX25Cmd *cmd) -{ - wan_device_t *wandev = &card->wandev; - struct net_device *dev; - x25_channel_t *chan; - u8 lcn, key; - - cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn)); - cycx_peek(&card->hw, cmd->buf + 1, &key, sizeof(key)); - dprintk(KERN_INFO "%s: connect_confirm_intr:lcn=%d, key=%d\n", - card->devname, lcn, key); - if ((dev = get_dev_by_lcn(wandev, -key)) == NULL) { - /* Invalid channel, discard packet */ - clear_bit(--key, (void*)&card->u.x.connection_keys); - printk(KERN_INFO "%s: connect confirm not expected: lcn %d, " - "key=%d!\n", card->devname, lcn, key); - return; - } - - clear_bit(--key, (void*)&card->u.x.connection_keys); - chan = dev->priv; - chan->lcn = lcn; - set_chan_state(dev, WAN_CONNECTED); -} - -/* Disonnect confirm interrupt handler. */ -static void disconnect_confirm_intr (cycx_t *card, TX25Cmd *cmd) -{ - wan_device_t *wandev = &card->wandev; - struct net_device *dev; - u8 lcn; - - cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn)); - dprintk(KERN_INFO "%s: disconnect_confirm_intr:lcn=%d\n", - card->devname, lcn); - if ((dev = get_dev_by_lcn(wandev, lcn)) == NULL) { - /* Invalid channel, discard packet */ - printk(KERN_INFO "%s:disconnect confirm not expected!:lcn %d\n", - card->devname, lcn); - return; - } - - set_chan_state(dev, WAN_DISCONNECTED); -} - -/* disconnect interrupt handler. */ -static void disconnect_intr (cycx_t *card, TX25Cmd *cmd) -{ - wan_device_t *wandev = &card->wandev; - struct net_device *dev; - u8 lcn; - - cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn)); - dprintk(KERN_INFO "disconnect_intr:lcn=%d\n", lcn); - - if ((dev = get_dev_by_lcn(wandev, lcn)) != NULL) { - x25_channel_t *chan = dev->priv; - - x25_disconnect_response(card, chan->link, lcn); - set_chan_state(dev, WAN_DISCONNECTED); - } else - x25_disconnect_response(card, 0, lcn); -} - -/* LOG interrupt handler. */ -static void log_intr (cycx_t *card, TX25Cmd *cmd) -{ -#if CYCLOMX_X25_DEBUG - char bf[20]; - u16 size, toread, link, msg_code; - u8 code, routine; - - cycx_peek(&card->hw, cmd->buf, &msg_code, sizeof(msg_code)); - cycx_peek(&card->hw, cmd->buf + 2, &link, sizeof(link)); - cycx_peek(&card->hw, cmd->buf + 4, &size, sizeof(size)); - /* at most 20 bytes are available... thanx to Daniela :) */ - toread = size < 20 ? size : 20; - cycx_peek(&card->hw, cmd->buf + 10, &bf, toread); - cycx_peek(&card->hw, cmd->buf + 10 + toread, &code, 1); - cycx_peek(&card->hw, cmd->buf + 10 + toread + 1, &routine, 1); - - printk(KERN_INFO "cyx_isr: X25_LOG (0x4500) indic.:\n"); - printk(KERN_INFO "cmd->buf=0x%X\n", cmd->buf); - printk(KERN_INFO "Log message code=0x%X\n", msg_code); - printk(KERN_INFO "Link=%d\n", link); - printk(KERN_INFO "log code=0x%X\n", code); - printk(KERN_INFO "log routine=0x%X\n", routine); - printk(KERN_INFO "Message size=%d\n", size); - hex_dump("Message", bf, toread); -#endif -} - -/* STATISTIC interrupt handler. */ -static void stat_intr (cycx_t *card, TX25Cmd *cmd) -{ - cycx_peek(&card->hw, cmd->buf, &card->u.x.stats, - sizeof(card->u.x.stats)); - hex_dump("stat_intr", (unsigned char*)&card->u.x.stats, - sizeof(card->u.x.stats)); - x25_dump_stats(&card->u.x.stats); - wake_up_interruptible(&card->wait_stats); -} - -/* Spurious interrupt handler. - * o print a warning - * If number of spurious interrupts exceeded some limit, then ??? */ -static void spur_intr (cycx_t *card, TX25Cmd *cmd) -{ - printk(KERN_INFO "%s: spurious interrupt (0x%X)!\n", - card->devname, cmd->command); -} -#ifdef CYCLOMX_X25_DEBUG -static void hex_dump(char *msg, unsigned char *p, int len) -{ - unsigned char hex[1024], - * phex = hex; - - if (len >= (sizeof(hex) / 2)) - len = (sizeof(hex) / 2) - 1; - - while (len--) { - sprintf(phex, "%02x", *p++); - phex += 2; - } - - printk(KERN_INFO "%s: %s\n", msg, hex); -} -#endif -/* CYCLOM X Firmware-Specific Functions */ -/* Exec x25 command. */ -static int x25_exec (cycx_t *card, int command, int link, - void *d1, int len1, void *d2, int len2) -{ - TX25Cmd c; - unsigned long flags; - u32 addr = 0x1200 + 0x2E0 * link + 0x1E2; - u8 retry = MAX_CMD_RETRY; - int err = 0; - - c.command = command; - c.link = link; - c.len = len1 + len2; - - spin_lock_irqsave(&card->u.x.lock, flags); - - /* write command */ - cycx_poke(&card->hw, X25_MBOX_OFFS, &c, sizeof(c) - sizeof(c.buf)); - - /* write x25 data */ - if (d1) { - cycx_poke(&card->hw, addr, d1, len1); - - if (d2) { - if (len2 > 254) { - u32 addr1 = 0xA00 + 0x400 * link; - - cycx_poke(&card->hw, addr + len1, d2, 249); - cycx_poke(&card->hw, addr1, ((u8*) d2) + 249, - len2 - 249); - } else - cycx_poke(&card->hw, addr + len1, d2, len2); - } - } - - /* generate interruption, executing command */ - cycx_intr(&card->hw); - - /* wait till card->mbox == 0 */ - do { - err = cycx_exec(card->mbox); - } while (retry-- && err); - - spin_unlock_irqrestore(&card->u.x.lock, flags); - - return err; -} - -/* Configure adapter. */ -static int x25_configure (cycx_t *card, TX25Config *conf) -{ - struct { - u16 nlinks; - TX25Config conf[2]; - } x25_cmd_conf; - - memset (&x25_cmd_conf, 0, sizeof(x25_cmd_conf)); - x25_cmd_conf.nlinks = 2; - x25_cmd_conf.conf[0] = *conf; - /* FIXME: we need to find a way in the wanrouter framework - to configure the second link, for now lets use it - with the same config from the first link, fixing - the interface type to RS232, the speed in 38400 and - the clock to external */ - x25_cmd_conf.conf[1] = *conf; - x25_cmd_conf.conf[1].link = 1; - x25_cmd_conf.conf[1].speed = 5; /* 38400 */ - x25_cmd_conf.conf[1].clock = 8; - x25_cmd_conf.conf[1].flags = 0; /* default = RS232 */ - - x25_dump_config(&x25_cmd_conf.conf[0]); - x25_dump_config(&x25_cmd_conf.conf[1]); - - return x25_exec(card, X25_CONFIG, 0, - &x25_cmd_conf, sizeof(x25_cmd_conf), NULL, 0); -} - -/* Get protocol statistics. */ -static int x25_get_stats (cycx_t *card) -{ - /* the firmware expects 20 in the size field!!! - thanx to Daniela */ - int err = x25_exec(card, X25_STATISTIC, 0, NULL, 20, NULL, 0); - - if (err) - return err; - - interruptible_sleep_on(&card->wait_stats); - - if (signal_pending(current)) - return -EINTR; - - card->wandev.stats.rx_packets = card->u.x.stats.n2_rx_frames; - card->wandev.stats.rx_over_errors = card->u.x.stats.rx_over_errors; - card->wandev.stats.rx_crc_errors = card->u.x.stats.rx_crc_errors; - card->wandev.stats.rx_length_errors = 0; /* not available from fw */ - card->wandev.stats.rx_frame_errors = 0; /* not available from fw */ - card->wandev.stats.rx_missed_errors = card->u.x.stats.rx_aborts; - card->wandev.stats.rx_dropped = 0; /* not available from fw */ - card->wandev.stats.rx_errors = 0; /* not available from fw */ - card->wandev.stats.tx_packets = card->u.x.stats.n2_tx_frames; - card->wandev.stats.tx_aborted_errors = card->u.x.stats.tx_aborts; - card->wandev.stats.tx_dropped = 0; /* not available from fw */ - card->wandev.stats.collisions = 0; /* not available from fw */ - card->wandev.stats.tx_errors = 0; /* not available from fw */ - - x25_dump_devs(&card->wandev); - return 0; -} - -/* return the number of nibbles */ -static int byte_to_nibble(u8 *s, u8 *d, char *nibble) -{ - int i = 0; - - if (*nibble && *s) { - d[i] |= *s++ - '0'; - *nibble = 0; - ++i; - } - - while (*s) { - d[i] = (*s - '0') << 4; - if (*(s + 1)) - d[i] |= *(s + 1) - '0'; - else { - *nibble = 1; - break; - } - ++i; - s += 2; - } - - return i; -} - -static void nibble_to_byte(u8 *s, u8 *d, u8 len, u8 nibble) -{ - if (nibble) { - *d++ = '0' + (*s++ & 0x0F); - --len; - } - - while (len) { - *d++ = '0' + (*s >> 4); - - if (--len) { - *d++ = '0' + (*s & 0x0F); - --len; - } else break; - - ++s; - } - - *d = '\0'; -} - -/* Place X.25 call. */ -static int x25_place_call (cycx_t *card, x25_channel_t *chan) -{ - int err = 0, - len; - char d[64], - nibble = 0, - mylen = chan->local_addr ? strlen(chan->local_addr) : 0, - remotelen = strlen(chan->addr); - u8 key; - - if (card->u.x.connection_keys == ~0UL) { - printk(KERN_INFO "%s: too many simultaneous connection " - "requests!\n", card->devname); - return -EAGAIN; - } - - key = ffz(card->u.x.connection_keys); - set_bit(key, (void*)&card->u.x.connection_keys); - ++key; - dprintk(KERN_INFO "%s:x25_place_call:key=%d\n", card->devname, key); - memset(d, 0, sizeof(d)); - d[1] = key; /* user key */ - d[2] = 0x10; - d[4] = 0x0B; - - len = byte_to_nibble(chan->addr, d + 6, &nibble); - - if (chan->local_addr) - len += byte_to_nibble(chan->local_addr, d + 6 + len, &nibble); - - if (nibble) - ++len; - - d[5] = mylen << 4 | remotelen; - d[6 + len + 1] = 0xCC; /* TCP/IP over X.25, thanx to Daniela :) */ - - if ((err = x25_exec(card, X25_CONNECT_REQUEST, chan->link, - &d, 7 + len + 1, NULL, 0)) != 0) - clear_bit(--key, (void*)&card->u.x.connection_keys); - else { - chan->lcn = -key; - chan->protocol = ETH_P_IP; - } - - return err; -} - -/* Place X.25 CONNECT RESPONSE. */ -static int x25_connect_response (cycx_t *card, x25_channel_t *chan) -{ - u8 d[8]; - - memset(d, 0, sizeof(d)); - d[0] = d[3] = chan->lcn; - d[2] = 0x10; - d[4] = 0x0F; - d[7] = 0xCC; /* TCP/IP over X.25, thanx Daniela */ - - return x25_exec(card, X25_CONNECT_RESPONSE, chan->link, &d, 8, NULL, 0); -} - -/* Place X.25 DISCONNECT RESPONSE. */ -static int x25_disconnect_response (cycx_t *card, u8 link, u8 lcn) -{ - char d[5]; - - memset(d, 0, sizeof(d)); - d[0] = d[3] = lcn; - d[2] = 0x10; - d[4] = 0x17; - return x25_exec(card, X25_DISCONNECT_RESPONSE, link, &d, 5, NULL, 0); -} - -/* Clear X.25 call. */ -static int x25_clear_call (cycx_t *card, u8 link, u8 lcn, u8 cause, u8 diagn) -{ - u8 d[7]; - - memset(d, 0, sizeof(d)); - d[0] = d[3] = lcn; - d[2] = 0x10; - d[4] = 0x13; - d[5] = cause; - d[6] = diagn; - - return x25_exec(card, X25_DISCONNECT_REQUEST, link, d, 7, NULL, 0); -} - -/* Send X.25 data packet. */ -static int x25_send (cycx_t *card, u8 link, u8 lcn, u8 bitm, int len, void *buf) -{ - u8 d[] = "?\xFF\x10??"; - - d[0] = d[3] = lcn; - d[4] = bitm; - - return x25_exec(card, X25_DATA_REQUEST, link, &d, 5, buf, len); -} - -/* Miscellaneous */ -/* Find network device by its channel number. */ -static struct net_device *get_dev_by_lcn (wan_device_t *wandev, s16 lcn) -{ - struct net_device *dev = wandev->dev; - - for (; dev; dev = dev->slave) - if (((x25_channel_t*)dev->priv)->lcn == lcn) - break; - return dev; -} - -/* Find network device by its remote dte address. */ -static struct net_device *get_dev_by_dte_addr (wan_device_t *wandev, char *dte) -{ - struct net_device *dev = wandev->dev; - - for (; dev; dev = dev->slave) - if (!strcmp (((x25_channel_t*)dev->priv)->addr, dte)) - break; - return dev; -} - -/* Initiate connection on the logical channel. - * o for PVC we just get channel configuration - * o for SVCs place an X.25 call - * - * Return: 0 connected - * >0 connection in progress - * <0 failure */ -static int chan_connect (struct net_device *dev) -{ - x25_channel_t *chan = dev->priv; - cycx_t *card = chan->card; - - if (chan->svc) { - if (!chan->addr[0]) - return -EINVAL; /* no destination address */ - dprintk(KERN_INFO "%s: placing X.25 call to %s...\n", - card->devname, chan->addr); - if (x25_place_call(card, chan)) - return -EIO; - set_chan_state(dev, WAN_CONNECTING); - return 1; - } else - set_chan_state(dev, WAN_CONNECTED); - - return 0; -} - -/* Disconnect logical channel. - * o if SVC then clear X.25 call */ -static void chan_disc (struct net_device *dev) -{ - x25_channel_t *chan = dev->priv; - - if (chan->svc) { - x25_clear_call(chan->card, chan->link, chan->lcn, 0, 0); - set_chan_state(dev, WAN_DISCONNECTING); - } else - set_chan_state(dev, WAN_DISCONNECTED); -} - -/* Called by kernel timer */ -static void chan_timer (unsigned long d) -{ - struct net_device *dev = (struct net_device*) d; - x25_channel_t *chan = dev->priv; - - switch (chan->state) { - case WAN_CONNECTED: - chan_disc(dev); - break; - default: - printk (KERN_ERR "%s: chan_timer for svc (%s) not " - "connected!\n", - chan->card->devname, dev->name); - } -} - -/* Set logical channel state. */ -static void set_chan_state (struct net_device *dev, u8 state) -{ - x25_channel_t *chan = dev->priv; - cycx_t *card = chan->card; - u32 flags = 0; - - spin_lock_irqsave(&card->lock, flags); - - if (chan->state != state) { - if (chan->svc && chan->state == WAN_CONNECTED) - del_timer(&chan->timer); - - switch (state) { - case WAN_CONNECTED: - printk (KERN_INFO "%s: interface %s " - "connected!\n", - card->devname, dev->name); - *(u16*)dev->dev_addr = htons(chan->lcn); - dev->tbusy = 0; - reset_timer(dev); - break; - - case WAN_CONNECTING: - printk (KERN_INFO "%s: interface %s " - "connecting...\n", - card->devname, dev->name); - break; - - case WAN_DISCONNECTING: - printk (KERN_INFO "%s: interface %s " - "disconnecting...\n", - card->devname, dev->name); - break; - - case WAN_DISCONNECTED: - printk (KERN_INFO "%s: interface %s " - "disconnected!\n", - card->devname, dev->name); - if (chan->svc) { - *(unsigned short*)dev->dev_addr = 0; - chan->lcn = 0; - } - dev->tbusy = 0; - break; - } - - chan->state = state; - } - - spin_unlock_irqrestore(&card->lock, flags); -} - -/* Send packet on a logical channel. - * When this function is called, tx_skb field of the channel data space - * points to the transmit socket buffer. When transmission is complete, - * release socket buffer and reset 'tbusy' flag. - * - * Return: 0 - transmission complete - * 1 - busy - * - * Notes: - * 1. If packet length is greater than MTU for this channel, we'll fragment - * the packet into 'complete sequence' using M-bit. - * 2. When transmission is complete, an event notification should be issued - * to the router. */ -static int chan_send (struct net_device *dev, struct sk_buff *skb) -{ - x25_channel_t *chan = dev->priv; - cycx_t *card = chan->card; - int bitm = 0; /* final packet */ - unsigned len = skb->len; - - if (skb->len > card->wandev.mtu) { - len = card->wandev.mtu; - bitm = 0x10; /* set M-bit (more data) */ - } - - if (x25_send(card, chan->link, chan->lcn, bitm, len, skb->data)) - return 1; - - if (bitm) { - skb_pull(skb, len); - return 1; - } - - ++chan->ifstats.tx_packets; - chan->ifstats.tx_bytes += len; - return 0; -} - -/* Convert line speed in bps to a number used by cyclom 2x code. */ -static u8 bps_to_speed_code (u32 bps) -{ - u8 number = 0; /* defaults to the lowest (1200) speed ;> */ - - if (bps >= 512000) number = 8; - else if (bps >= 256000) number = 7; - else if (bps >= 64000) number = 6; - else if (bps >= 38400) number = 5; - else if (bps >= 19200) number = 4; - else if (bps >= 9600) number = 3; - else if (bps >= 4800) number = 2; - else if (bps >= 2400) number = 1; - - return number; -} - -/* log base 2 */ -static u8 log2 (u32 n) -{ - u8 log = 0; - - if (!n) - return 0; - - while (n > 1) { - n >>= 1; - ++log; - } - - return log; -} - -/* Convert decimal string to unsigned integer. - * If len != 0 then only 'len' characters of the string are converted. */ -static unsigned dec_to_uint (u8 *str, int len) -{ - unsigned val = 0; - - if (!len) - len = strlen(str); - - for (; len && is_digit(*str); ++str, --len) - val = (val * 10) + (*str - (unsigned)'0'); - - return val; -} - -static void reset_timer(struct net_device *dev) -{ - x25_channel_t *chan = dev->priv; - - if (!chan->svc) - return; - - del_timer(&chan->timer); - chan->timer.expires = jiffies + chan->idle_tmout * HZ; - add_timer(&chan->timer); -} -#ifdef CYCLOMX_X25_DEBUG -static void x25_dump_config(TX25Config *conf) -{ - printk (KERN_INFO "x25 configuration\n"); - printk (KERN_INFO "-----------------\n"); - printk (KERN_INFO "link number=%d\n", conf->link); - printk (KERN_INFO "line speed=%d\n", conf->speed); - printk (KERN_INFO "clock=%sternal\n", conf->clock == 8 ? "Ex" : "In"); - printk (KERN_INFO "# level 2 retransm.=%d\n", conf->n2); - printk (KERN_INFO "level 2 window=%d\n", conf->n2win); - printk (KERN_INFO "level 3 window=%d\n", conf->n3win); - printk (KERN_INFO "# logical channels=%d\n", conf->nvc); - printk (KERN_INFO "level 3 pkt len=%d\n", conf->pktlen); - printk (KERN_INFO "my address=%d\n", conf->locaddr); - printk (KERN_INFO "remote address=%d\n", conf->remaddr); - printk (KERN_INFO "t1=%d seconds\n", conf->t1); - printk (KERN_INFO "t2=%d seconds\n", conf->t2); - printk (KERN_INFO "t21=%d seconds\n", conf->t21); - printk (KERN_INFO "# PVCs=%d\n", conf->npvc); - printk (KERN_INFO "t23=%d seconds\n", conf->t23); - printk (KERN_INFO "flags=0x%x\n", conf->flags); -} - -static void x25_dump_stats(TX25Stats *stats) -{ - printk (KERN_INFO "x25 statistics\n"); - printk (KERN_INFO "--------------\n"); - printk (KERN_INFO "rx_crc_errors=%d\n", stats->rx_crc_errors); - printk (KERN_INFO "rx_over_errors=%d\n", stats->rx_over_errors); - printk (KERN_INFO "n2_tx_frames=%d\n", stats->n2_tx_frames); - printk (KERN_INFO "n2_rx_frames=%d\n", stats->n2_rx_frames); - printk (KERN_INFO "tx_timeouts=%d\n", stats->tx_timeouts); - printk (KERN_INFO "rx_timeouts=%d\n", stats->rx_timeouts); - printk (KERN_INFO "n3_tx_packets=%d\n", stats->n3_tx_packets); - printk (KERN_INFO "n3_rx_packets=%d\n", stats->n3_rx_packets); - printk (KERN_INFO "tx_aborts=%d\n", stats->tx_aborts); - printk (KERN_INFO "rx_aborts=%d\n", stats->rx_aborts); -} - -static void x25_dump_devs(wan_device_t *wandev) -{ - struct net_device *dev = wandev->dev; - - printk (KERN_INFO "x25 dev states\n"); - printk (KERN_INFO "name: addr: tbusy:\n"); - printk (KERN_INFO "----------------------------\n"); - - for (; dev; dev = dev->slave) { - x25_channel_t *chan = dev->priv; - - printk (KERN_INFO "%-5.5s %-15.15s %ld\n", - chan->name, chan->addr, dev->tbusy); - } -} - -#endif /* CYCLOMX_X25_DEBUG */ -/* End */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/dlci.c linux/drivers/net/dlci.c --- v2.3.20/linux/drivers/net/dlci.c Thu Aug 26 13:05:38 1999 +++ linux/drivers/net/dlci.c Wed Dec 31 16:00:00 1969 @@ -1,634 +0,0 @@ -/* - * DLCI Implementation of Frame Relay protocol for Linux, according to - * RFC 1490. This generic device provides en/decapsulation for an - * underlying hardware driver. Routes & IPs are assigned to these - * interfaces. Requires 'dlcicfg' program to create usable - * interfaces, the initial one, 'dlci' is for IOCTL use only. - * - * Version: @(#)dlci.c 0.35 4 Jan 1997 - * - * Author: Mike McLagan - * - * 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 /* for CONFIG_DLCI_COUNT */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include - -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;ipriv; - - 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;idevname, 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;iname = 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;ipriv); - 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "syncppp.h" -#include "z85230.h" - -static int dma; - -struct sv11_device -{ - struct z8530_dev sync; - struct ppp_device netdev; - char name[16]; -}; - -/* - * Network driver support routines - */ - -/* - * Frame receive. Simple for our card as we do sync ppp and there - * is no funny garbage involved - */ - -static void hostess_input(struct z8530_channel *c, struct sk_buff *skb) -{ - /* Drop the CRC - its not a good idea to try and negotiate it ;) */ - skb_trim(skb, skb->len-2); - skb->protocol=htons(ETH_P_WAN_PPP); - skb->mac.raw=skb->data; - skb->dev=c->netdevice; - /* - * Send it to the PPP layer. We dont have time to process - * it right now. - */ - netif_rx(skb); -} - -/* - * We've been placed in the UP state - */ - -static int hostess_open(struct net_device *d) -{ - struct sv11_device *sv11=d->priv; - int err = -1; - - /* - * Link layer up - */ - switch(dma) - { - case 0: - err=z8530_sync_open(d, &sv11->sync.chanA); - break; - case 1: - err=z8530_sync_dma_open(d, &sv11->sync.chanA); - break; - case 2: - err=z8530_sync_txdma_open(d, &sv11->sync.chanA); - break; - } - - if(err) - return err; - /* - * Begin PPP - */ - err=sppp_open(d); - if(err) - { - switch(dma) - { - case 0: - z8530_sync_close(d, &sv11->sync.chanA); - break; - case 1: - z8530_sync_dma_close(d, &sv11->sync.chanA); - break; - case 2: - z8530_sync_txdma_close(d, &sv11->sync.chanA); - break; - } - return err; - } - sv11->sync.chanA.rx_function=hostess_input; - - /* - * Go go go - */ - d->tbusy=0; - MOD_INC_USE_COUNT; - return 0; -} - -static int hostess_close(struct net_device *d) -{ - struct sv11_device *sv11=d->priv; - /* - * Discard new frames - */ - sv11->sync.chanA.rx_function=z8530_null_rx; - /* - * PPP off - */ - sppp_close(d); - /* - * Link layer down - */ - d->tbusy=1; - - switch(dma) - { - case 0: - z8530_sync_close(d, &sv11->sync.chanA); - break; - case 1: - z8530_sync_dma_close(d, &sv11->sync.chanA); - break; - case 2: - z8530_sync_txdma_close(d, &sv11->sync.chanA); - break; - } - MOD_DEC_USE_COUNT; - return 0; -} - -static int hostess_ioctl(struct net_device *d, struct ifreq *ifr, int cmd) -{ - /* struct sv11_device *sv11=d->priv; - z8530_ioctl(d,&sv11->sync.chanA,ifr,cmd) */ - return sppp_do_ioctl(d, ifr,cmd); -} - -static struct enet_statistics *hostess_get_stats(struct net_device *d) -{ - struct sv11_device *sv11=d->priv; - if(sv11) - return z8530_get_stats(&sv11->sync.chanA); - else - return NULL; -} - -/* - * Passed PPP frames, fire them downwind. - */ - -static int hostess_queue_xmit(struct sk_buff *skb, struct net_device *d) -{ - struct sv11_device *sv11=d->priv; - return z8530_queue_xmit(&sv11->sync.chanA, skb); -} - -#ifdef LINUX_21 -static int hostess_neigh_setup(struct neighbour *n) -{ - if (n->nud_state == NUD_NONE) { - n->ops = &arp_broken_ops; - n->output = n->ops->output; - } - return 0; -} - -static int hostess_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) -{ - if (p->tbl->family == AF_INET) { - p->neigh_setup = hostess_neigh_setup; - p->ucast_probes = 0; - p->mcast_probes = 0; - } - return 0; -} - -#else - -static int return_0(struct net_device *d) -{ - return 0; -} - -#endif - -/* - * Description block for a Comtrol Hostess SV11 card - */ - -static struct sv11_device *sv11_init(int iobase, int irq) -{ - struct z8530_dev *dev; - struct sv11_device *sv; - int i; - unsigned long flags; - - /* - * Get the needed I/O space - */ - - if(check_region(iobase, 8)) - { - printk(KERN_WARNING "hostess: I/O 0x%X already in use.\n", iobase); - return NULL; - } - request_region(iobase, 8, "Comtrol SV11"); - - sv=(struct sv11_device *)kmalloc(sizeof(struct sv11_device), GFP_KERNEL); - if(!sv) - goto fail3; - - memset(sv, 0, sizeof(*sv)); - - dev=&sv->sync; - - /* - * Stuff in the I/O addressing - */ - - dev->active = 0; - - dev->chanA.ctrlio=iobase+1; - dev->chanA.dataio=iobase+3; - dev->chanB.ctrlio=-1; - dev->chanB.dataio=-1; - dev->chanA.irqs=&z8530_nop; - dev->chanB.irqs=&z8530_nop; - - outb(0, iobase+4); /* DMA off */ - - /* We want a fast IRQ for this device. Actually we'd like an even faster - IRQ ;) - This is one driver RtLinux is made for */ - - if(request_irq(irq, &z8530_interrupt, SA_INTERRUPT, "Hostess SV/11", dev)<0) - { - printk(KERN_WARNING "hostess: IRQ %d already in use.\n", irq); - goto fail2; - } - - dev->irq=irq; - dev->chanA.private=sv; - dev->chanA.netdevice=&sv->netdev.dev; - dev->chanA.dev=dev; - dev->chanB.dev=dev; - dev->name=sv->name; - - if(dma) - { - /* - * You can have DMA off or 1 and 3 thats the lot - * on the Comtrol. - */ - dev->chanA.txdma=3; - dev->chanA.rxdma=1; - outb(0x03|0x08, iobase+4); /* DMA on */ - if(request_dma(dev->chanA.txdma, "Hostess SV/11 (TX)")!=0) - goto fail; - - if(dma==1) - { - if(request_dma(dev->chanA.rxdma, "Hostess SV/11 (RX)")!=0) - goto dmafail; - } - } - save_flags(flags); - cli(); - - /* - * Begin normal initialise - */ - - if(z8530_init(dev)!=0) - { - printk(KERN_ERR "Z8530 series device not found.\n"); - goto dmafail2; - } - z8530_channel_load(&dev->chanB, z8530_dead_port); - if(dev->type==Z85C30) - z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream); - else - z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream_85230); - - restore_flags(flags); - - - /* - * Now we can take the IRQ - */ - - for(i=0;i<999;i++) - { - sprintf(sv->name,"hdlc%d", i); - if(dev_get(sv->name)==NULL) - { - struct net_device *d=dev->chanA.netdevice; - - /* - * Initialise the PPP components - */ - sppp_attach(&sv->netdev); - - /* - * Local fields - */ - sprintf(sv->name,"hdlc%d", i); - - d->name = sv->name; - d->base_addr = iobase; - d->irq = irq; - d->priv = sv; - d->init = NULL; - - d->open = hostess_open; - d->stop = hostess_close; - d->hard_start_xmit = hostess_queue_xmit; - d->get_stats = hostess_get_stats; - d->set_multicast_list = NULL; - d->do_ioctl = hostess_ioctl; -#ifdef LINUX_21 - d->neigh_setup = hostess_neigh_setup_dev; - dev_init_buffers(d); -#else - d->init = return_0; -#endif - d->set_mac_address = NULL; - - if(register_netdev(d)==-1) - { - printk(KERN_ERR "%s: unable to register device.\n", - sv->name); - goto fail; - } - - z8530_describe(dev, "I/O", iobase); - dev->active=1; - return sv; - } - } -dmafail2: - if(dma==1) - free_dma(dev->chanA.rxdma); -dmafail: - if(dma) - free_dma(dev->chanA.txdma); -fail: - free_irq(irq, dev); -fail2: - kfree(sv); -fail3: - release_region(iobase,8); - return NULL; -} - -static void sv11_shutdown(struct sv11_device *dev) -{ - sppp_detach(&dev->netdev.dev); - z8530_shutdown(&dev->sync); - unregister_netdev(&dev->netdev.dev); - free_irq(dev->sync.irq, dev); - if(dma) - { - if(dma==1) - free_dma(dev->sync.chanA.rxdma); - free_dma(dev->sync.chanA.txdma); - } - release_region(dev->sync.chanA.ctrlio-1, 8); -} - -#ifdef MODULE - -static int io=0x200; -static int irq=9; - -#ifdef LINUX_21 -MODULE_PARM(io,"i"); -MODULE_PARM_DESC(io, "The I/O base of the Comtrol Hostess SV11 card"); -MODULE_PARM(dma,"i"); -MODULE_PARM_DESC(dma, "Set this to 1 to use DMA1/DMA3 for TX/RX"); -MODULE_PARM(irq,"i"); -MODULE_PARM_DESC(irq, "The interrupt line setting for the Comtrol Hostess SV11 card"); - -MODULE_AUTHOR("Bulding Number Three Ltd"); -MODULE_DESCRIPTION("Modular driver for the Comtrol Hostess SV11"); -#endif - -static struct sv11_device *sv11_unit; - -int init_module(void) -{ - printk(KERN_INFO "SV-11 Z85230 Synchronous Driver v 0.02.\n"); - printk(KERN_INFO "(c) Copyright 1998, Building Number Three Ltd.\n"); - if((sv11_unit=sv11_init(io,irq))==NULL) - return -ENODEV; - return 0; -} - -void cleanup_module(void) -{ - if(sv11_unit) - sv11_shutdown(sv11_unit); -} - -#endif - diff -u --recursive --new-file v2.3.20/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c --- v2.3.20/linux/drivers/net/ibmtr.c Fri Sep 10 23:57:30 1999 +++ linux/drivers/net/ibmtr.c Wed Dec 31 16:00:00 1969 @@ -1,1769 +0,0 @@ -/* ibmtr.c: A shared-memory IBM Token Ring 16/4 driver for linux - * - * Written 1993 by Mark Swanson and Peter De Schrijver. - * This software may be used and distributed according to the terms - * of the GNU Public License, incorporated herein by reference. - * - * This device driver should work with Any IBM Token Ring Card that does - * not use DMA. - * - * I used Donald Becker's (becker@cesdis.gsfc.nasa.gov) device driver work - * as a base for most of my initial work. - * - * Changes by Peter De Schrijver (Peter.Deschrijver@linux.cc.kuleuven.ac.be) : - * - * + changed name to ibmtr.c in anticipation of other tr boards. - * + changed reset code and adapter open code. - * + added SAP open code. - * + a first attempt to write interrupt, transmit and receive routines. - * - * Changes by David W. Morris (dwm@shell.portal.com) : - * 941003 dwm: - Restructure tok_probe for multiple adapters, devices. - * + Add comments, misc reorg for clarity. - * + Flatten interrupt handler levels. - * - * Changes by Farzad Farid (farzy@zen.via.ecp.fr) - * and Pascal Andre (andre@chimay.via.ecp.fr) (March 9 1995) : - * + multi ring support clean up. - * + RFC1042 compliance enhanced. - * - * Changes by Pascal Andre (andre@chimay.via.ecp.fr) (September 7 1995) : - * + bug correction in tr_tx - * + removed redundant information display - * + some code reworking - * - * Changes by Michel Lespinasse (walken@via.ecp.fr), - * Yann Doussot (doussot@via.ecp.fr) and Pascal Andre (andre@via.ecp.fr) - * (February 18, 1996) : - * + modified shared memory and mmio access port the driver to - * alpha platform (structure access -> readb/writeb) - * - * Changes by Steve Kipisz (bungy@ibm.net or kipisz@vnet.ibm.com) - * (January 18 1996): - * + swapped WWOR and WWCR in ibmtr.h - * + moved some init code from tok_probe into trdev_init. The - * PCMCIA code can call trdev_init to complete initializing - * the driver. - * + added -DPCMCIA to support PCMCIA - * + detecting PCMCIA Card Removal in interrupt handler. If - * ISRP is FF, then a PCMCIA card has been removed - * - * Changes by Paul Norton (pnorton@cts.com) : - * + restructured the READ.LOG logic to prevent the transmit SRB - * from being rudely overwritten before the transmit cycle is - * complete. (August 15 1996) - * + completed multiple adapter support. (November 20 1996) - * + implemented csum_partial_copy in tr_rx and increased receive - * buffer size and count. Minor fixes. (March 15, 1997) - * - * Changes by Christopher Turcksin - * + 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 : - * + 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 - -#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 \n" -" v2.2.0 12/30/98 Joel Sloan \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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#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;idev_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; isrb+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; iinit_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; immio + 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_waitedtrans_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] && (ibase_addr = io[i]; - dev_ibmtr[i]->irq = irq[i]; - dev_ibmtr[i]->mem_start = mem[i]; - dev_ibmtr[i]->init = &ibmtr_probe; - - if (register_trdev(dev_ibmtr[i]) != 0) { - kfree_s(dev_ibmtr[i], sizeof(struct net_device)); - dev_ibmtr[i] = NULL; - if (i == 0) { - printk("ibmtr: register_trdev() returned non-zero.\n"); - return -EIO; - } else { - return 0; - } - } - } - return 0; -} - -void cleanup_module(void) -{ - int i; - - for (i = 0; i < IBMTR_MAX_ADAPTERS; i++) - if (dev_ibmtr[i]) { - unregister_trdev(dev_ibmtr[i]); - free_irq(dev_ibmtr[i]->irq, dev_ibmtr[i]); - release_region(dev_ibmtr[i]->base_addr, IBMTR_IO_EXTENT); - kfree_s(dev_ibmtr[i]->priv, sizeof(struct tok_info)); - kfree_s(dev_ibmtr[i], sizeof(struct net_device)); - dev_ibmtr[i] = NULL; - } -} -#endif /* MODULE */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/ibmtr.h linux/drivers/net/ibmtr.h --- v2.3.20/linux/drivers/net/ibmtr.h Wed May 12 13:27:37 1999 +++ linux/drivers/net/ibmtr.h Wed Dec 31 16:00:00 1969 @@ -1,449 +0,0 @@ -/* Definitions for an IBM Token Ring card. */ -/* This file is distributed under the GNU GPL */ - -/* ported to the Alpha architecture 02/20/96 (just used the HZ macro) */ - -#define TR_RETRY_INTERVAL (5*HZ) /* 500 on PC = 5 s */ -#define TR_RESET_INTERVAL (HZ/20) /* 5 on PC = 50 ms */ -#define TR_BUSY_INTERVAL (HZ/5) /* 5 on PC = 200 ms */ -#define TR_SPIN_INTERVAL (3*HZ) /* 3 seconds before init timeout */ -#define TR_RETRIES 6 /* number of open retries */ - -#define TR_ISA 1 -#define TR_MCA 2 -#define TR_ISAPNP 3 -#define NOTOK 0 -#define TOKDEBUG 1 - -#define IBMTR_SHARED_RAM_SIZE 0x10000 -#define IBMTR_IO_EXTENT 4 -#define IBMTR_MAX_ADAPTERS 2 - -#define CHANNEL_ID 0X1F30 -#define AIP 0X1F00 -#define AIPCHKSUM1 0X1F60 -#define AIPCHKSUM2 0X1FF0 -#define AIPADAPTYPE 0X1FA0 -#define AIPDATARATE 0X1FA2 -#define AIPEARLYTOKEN 0X1FA4 -#define AIPAVAILSHRAM 0X1FA6 -#define AIPSHRAMPAGE 0X1FA8 -#define AIP4MBDHB 0X1FAA -#define AIP16MBDHB 0X1FAC -#define AIPFID 0X1FBA - -/* Note, 0xA20 == 0x220 since motherboard decodes 10 bits. I left everything - the way my documentation had it, ie: 0x0A20. */ -#define ADAPTINTCNTRL 0x02f0 /* Adapter interrupt control */ -#define ADAPTRESET 0x1 /* Control Adapter reset (add to base) */ -#define ADAPTRESETREL 0x2 /* Release Adapter from reset ( """) */ -#define ADAPTINTREL 0x3 /* Adapter interrupt release */ - -#define MMIOStartLocP 0x0a20 /* Primary adapter's starting MMIO area */ -#define MMIOStartLocA 0x0a24 /* Alternate adapter's starting MMIO area */ - -#define GLOBAL_INT_ENABLE 0x02f0 - -/* MMIO bits 0-4 select register */ -#define RRR_EVEN 0x00 /* Shared RAM relocation registers - even and odd */ -/* Used to set the starting address of shared RAM */ -/* Bits 1 through 7 of this register map to bits 13 through 19 of the shared RAM address.*/ -/* ie: 0x02 sets RAM address to ...ato! issy su wazzoo !! GODZILLA!!! */ -#define RRR_ODD 0x01 -/* Bits 2 and 3 of this register can be read to determine shared RAM size */ -/* 00 for 8k, 01 for 16k, 10 for 32k, 11 for 64k */ -#define WRBR_EVEN 0x02 /* Write region base registers - even and odd */ -#define WRBR_ODD 0x03 -#define WWOR_EVEN 0x04 /* Write window open registers - even and odd */ -#define WWOR_ODD 0x05 -#define WWCR_EVEN 0x06 /* Write window close registers - even and odd */ -#define WWCR_ODD 0x07 - -/* Interrupt status registers - PC system - even and odd */ -#define ISRP_EVEN 0x08 - -#define TCR_INT 0x10 /* Bit 4 - Timer interrupt. The TVR_EVEN timer has - expired. */ -#define ERR_INT 0x08 /* Bit 3 - Error interrupt. The adapter has had an - internal error. */ -#define ACCESS_INT 0x04 /* Bit 2 - Access interrupt. You have attempted to - write to an invalid area of shared RAM or an invalid - register within the MMIO. */ -/* In addition, the following bits within ISRP_EVEN can be turned on or off by you */ -/* to control the interrupt processing: */ -#define INT_IRQ 0x80 /* Bit 7 - If 0 the adapter will issue a CHCK, if 1 and - IRQ. This should normally be set (by you) to 1. */ -#define INT_ENABLE 0x40 /* Bit 6 - Interrupt enable. If 0, no interrupts will - occur. If 1, interrupts will occur normally. - Normally set to 1. */ -/* Bit 0 - Primary or alternate adapter. Set to zero if this adapter is the primary adapter,*/ -/* 1 if this adapter is the alternate adapter. */ - - -#define ISRP_ODD 0x09 - -#define ADAP_CHK_INT 0x40 /* Bit 6 - Adapter check. the adapter has - encountered a serious problem and has closed - itself. Whoa. */ -#define SRB_RESP_INT 0x20 /* Bit 5 - SRB response. The adapter has accepted - an SRB request and set the return code within - the SRB. */ -#define ASB_FREE_INT 0x10 /* Bit 4 - ASB free. The adapter has read the ASB - and this area can be safely reused. This interrupt - is only used if your application has set the ASB - free request bit in ISRA_ODD or if an error was - detected in your response. */ -#define ARB_CMD_INT 0x08 /* Bit 3 - ARB command. The adapter has given you a - command for action. The command is located in the - ARB area of shared memory. */ -#define SSB_RESP_INT 0x04 /* Bit 2 - SSB response. The adapter has posted a - response to your SRB (the response is located in - the SSB area of shared memory). */ -/* Bit 1 - Bridge frame forward complete. */ - - - -#define ISRA_EVEN 0x0A /* Interrupt status registers - adapter - even and odd */ -/* Bit 7 - Internal parity error (on adapter's internal bus) */ -/* Bit 6 - Timer interrupt pending */ -/* Bit 5 - Access interrupt (attempt by adapter to access illegal address) */ -/* Bit 4 - Adapter microcode problem (microcode dead-man timer expired) */ -/* Bit 3 - Adapter processor check status */ -/* Bit 2 - Reserved */ -/* Bit 1 - Adapter hardware interrupt mask (prevents internal interrupts) */ -/* Bit 0 - Adapter software interrupt mask (prevents internal software interrupts) */ - -#define ISRA_ODD 0x0B -#define CMD_IN_SRB 0x20 /* Bit 5 - Indicates that you have placed a new - command in the SRB and are ready for the adapter to - process the command. */ -#define RESP_IN_ASB 0x10 /* Bit 4 - Indicates that you have placed a response - (an ASB) in the shared RAM which is available for - the adapter's use. */ -/* Bit 3 - Indicates that you are ready to put an SRB in the shared RAM, but that a previous */ -/* command is still pending. The adapter will then interrupt you when the previous */ -/* command is completed */ -/* Bit 2 - Indicates that you are ready to put an ASB in the shared RAM, but that a previous */ -/* ASB is still pending. The adapter will then interrupt you when the previous ASB */ -/* is copied. */ -#define ARB_FREE 0x2 -#define SSB_FREE 0x1 - -#define TCR_EVEN 0x0C /* Timer control registers - even and odd */ -#define TCR_ODD 0x0D -#define TVR_EVEN 0x0E /* Timer value registers - even and odd */ -#define TVR_ODD 0x0F -#define SRPR_EVEN 0x10 /* Shared RAM paging registers - even and odd */ -#define SRPR_ENABLE_PAGING 0xc0 -#define SRPR_ODD 0x11 /* Not used. */ -#define TOKREAD 0x60 -#define TOKOR 0x40 -#define TOKAND 0x20 -#define TOKWRITE 0x00 - -/* MMIO bits 5-6 select operation */ -/* 00 is used to write to a register */ -/* 01 is used to bitwise AND a byte with a register */ -/* 10 is used to bitwise OR a byte with a register */ -/* 11 is used to read from a register */ - -/* MMIO bits 7-8 select area of interest.. see below */ -/* 00 selects attachment control area. */ -/* 01 is reserved. */ -/* 10 selects adapter identification area A containing the adapter encoded address. */ -/* 11 selects the adapter identification area B containing test patterns. */ - -#define PCCHANNELID 5049434F3631313039393020 -#define MCCHANNELID 4D4152533633583435313820 - -#define ACA_OFFSET 0x1e00 -#define ACA_SET 0x40 -#define ACA_RESET 0x20 -#define ACA_RW 0x00 - -#ifdef ENABLE_PAGING -#define SET_PAGE(x) (writeb(((x>>8)&ti.page_mask), \ - ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN)) -#else -#define SET_PAGE(x) -#endif - -typedef enum { IN_PROGRESS, SUCCESS, FAILURE, CLOSED } open_state; - -/* do_tok_int possible values */ -#define FIRST_INT 1 -#define NOT_FIRST 2 - -struct tok_info { - unsigned char irq; - __u32 mmio; - unsigned char hw_address[32]; - unsigned char adapter_type; - unsigned char data_rate; - unsigned char token_release; - unsigned char avail_shared_ram; - unsigned char shared_ram_paging; - unsigned short dhb_size4mb; - unsigned short rbuf_len4; - unsigned short rbuf_cnt4; - unsigned short maxmtu4; - unsigned short dhb_size16mb; - unsigned short rbuf_len16; - unsigned short rbuf_cnt16; - unsigned short maxmtu16; - /* Additions by David Morris */ - unsigned char do_tok_int; - wait_queue_head_t wait_for_tok_int; - wait_queue_head_t wait_for_reset; - unsigned char sram_base; - /* Additions by Peter De Schrijver */ - unsigned char page_mask; /* mask to select RAM page to Map*/ - unsigned char mapped_ram_size; /* size of RAM page */ - __u32 sram; /* Shared memory base address */ - __u32 init_srb; /* Initial System Request Block address */ - __u32 srb; /* System Request Block address */ - __u32 ssb; /* System Status Block address */ - __u32 arb; /* Adapter Request Block address */ - __u32 asb; /* Adapter Status Block address */ - unsigned short exsap_station_id; - unsigned short global_int_enable; - struct sk_buff *current_skb; - struct net_device_stats tr_stats; - unsigned char auto_ringspeedsave; - open_state open_status; - unsigned char readlog_pending; - unsigned short adapter_int_enable; /* Adapter-specific int enable */ - struct timer_list tr_timer; - unsigned char ring_speed; - __u32 func_addr; - unsigned int retry_count; - spinlock_t lock; /* SMP protection */ -}; - -/* token ring adapter commands */ -#define DIR_INTERRUPT 0x00 /* struct srb_interrupt */ -#define DIR_MOD_OPEN_PARAMS 0x01 -#define DIR_OPEN_ADAPTER 0x03 /* struct dir_open_adapter */ -#define DIR_CLOSE_ADAPTER 0x04 -#define DIR_SET_GRP_ADDR 0x06 -#define DIR_SET_FUNC_ADDR 0x07 /* struct srb_set_funct_addr */ -#define DIR_READ_LOG 0x08 /* struct srb_read_log */ -#define DLC_OPEN_SAP 0x15 /* struct dlc_open_sap */ -#define DLC_CLOSE_SAP 0x16 -#define DATA_LOST 0x20 /* struct asb_rec */ -#define REC_DATA 0x81 /* struct arb_rec_req */ -#define XMIT_DATA_REQ 0x82 /* struct arb_xmit_req */ -#define DLC_STATUS 0x83 /* struct arb_dlc_status */ -#define RING_STAT_CHANGE 0x84 /* struct dlc_open_sap ??? */ - -/* DIR_OPEN_ADAPTER options */ -#define OPEN_PASS_BCON_MAC 0x0100 -#define NUM_RCV_BUF 2 -#define RCV_BUF_LEN 1024 -#define DHB_LENGTH 2048 -#define NUM_DHB 2 -#define DLC_MAX_SAP 2 -#define DLC_MAX_STA 1 - -/* DLC_OPEN_SAP options */ -#define MAX_I_FIELD 0x0088 -#define SAP_OPEN_IND_SAP 0x04 -#define SAP_OPEN_PRIORITY 0x20 -#define SAP_OPEN_STATION_CNT 0x1 -#define XMIT_DIR_FRAME 0x0A -#define XMIT_UI_FRAME 0x0d -#define XMIT_XID_CMD 0x0e -#define XMIT_TEST_CMD 0x11 - -/* srb close return code */ -#define SIGNAL_LOSS 0x8000 -#define HARD_ERROR 0x4000 -#define XMIT_BEACON 0x1000 -#define LOBE_FAULT 0x0800 -#define AUTO_REMOVAL 0x0400 -#define REMOVE_RECV 0x0100 -#define LOG_OVERFLOW 0x0080 -#define RING_RECOVER 0x0020 - -struct srb_init_response { - unsigned char command; - unsigned char init_status; - unsigned char init_status_2; - unsigned char reserved[3]; - __u16 bring_up_code; - __u16 encoded_address; - __u16 level_address; - __u16 adapter_address; - __u16 parms_address; - __u16 mac_address; -}; - -struct dir_open_adapter { - unsigned char command; - char reserved[7]; - __u16 open_options; - unsigned char node_address[6]; - unsigned char group_address[4]; - unsigned char funct_address[4]; - __u16 num_rcv_buf; - __u16 rcv_buf_len; - __u16 dhb_length; - unsigned char num_dhb; - char reserved2; - unsigned char dlc_max_sap; - unsigned char dlc_max_sta; - unsigned char dlc_max_gsap; - unsigned char dlc_max_gmem; - unsigned char dlc_t1_tick_1; - unsigned char dlc_t2_tick_1; - unsigned char dlc_ti_tick_1; - unsigned char dlc_t1_tick_2; - unsigned char dlc_t2_tick_2; - unsigned char dlc_ti_tick_2; - unsigned char product_id[18]; -}; - -struct srb_open_response { - unsigned char command; - unsigned char reserved1; - unsigned char ret_code; - unsigned char reserved2[3]; - __u16 error_code; - __u16 asb_addr; - __u16 srb_addr; - __u16 arb_addr; - __u16 ssb_addr; -}; - -struct dlc_open_sap { - unsigned char command; - unsigned char reserved1; - unsigned char ret_code; - unsigned char reserved2; - __u16 station_id; - unsigned char timer_t1; - unsigned char timer_t2; - unsigned char timer_ti; - unsigned char maxout; - unsigned char maxin; - unsigned char maxout_incr; - unsigned char max_retry_count; - unsigned char gsap_max_mem; - __u16 max_i_field; - unsigned char sap_value; - unsigned char sap_options; - unsigned char station_count; - unsigned char sap_gsap_mem; - unsigned char gsap[0]; -}; - -struct srb_xmit { - unsigned char command; - unsigned char cmd_corr; - unsigned char ret_code; - unsigned char reserved1; - __u16 station_id; -}; - -struct srb_interrupt { - unsigned char command; - unsigned char cmd_corr; - unsigned char ret_code; -}; - -struct srb_read_log { - unsigned char command; - unsigned char reserved1; - unsigned char ret_code; - unsigned char reserved2; - unsigned char line_errors; - unsigned char internal_errors; - unsigned char burst_errors; - unsigned char A_C_errors; - unsigned char abort_delimiters; - unsigned char reserved3; - unsigned char lost_frames; - unsigned char recv_congest_count; - unsigned char frame_copied_errors; - unsigned char frequency_errors; - unsigned char token_errors; -}; - -struct asb_xmit_resp { - unsigned char command; - unsigned char cmd_corr; - unsigned char ret_code; - unsigned char reserved; - __u16 station_id; - __u16 frame_length; - unsigned char hdr_length; - unsigned char rsap_value; -}; - -struct arb_xmit_req { - unsigned char command; - unsigned char cmd_corr; - unsigned char reserved1[2]; - __u16 station_id; - __u16 dhb_address; -}; - -struct arb_rec_req { - unsigned char command; - unsigned char reserved1[3]; - __u16 station_id; - __u16 rec_buf_addr; - unsigned char lan_hdr_len; - unsigned char dlc_hdr_len; - __u16 frame_len; - unsigned char msg_type; -}; - -struct asb_rec { - unsigned char command; - unsigned char reserved1; - unsigned char ret_code; - unsigned char reserved2; - __u16 station_id; - __u16 rec_buf_addr; -}; - -struct rec_buf { - /* unsigned char reserved1[2]; */ - __u16 buf_ptr; - unsigned char reserved2; - __u16 buf_len; - unsigned char data[0]; -}; - -struct arb_dlc_status { - unsigned char command; - unsigned char reserved1[3]; - __u16 station_id; - __u16 status; - unsigned char frmr_data[5]; - unsigned char access_prio; - unsigned char rem_addr[TR_ALEN]; - unsigned char rsap_value; -}; - -struct arb_ring_stat_change { - unsigned char command; - unsigned char reserved1[5]; - __u16 ring_status; -}; - -struct srb_close_adapter { - unsigned char command; - unsigned char reserved1; - unsigned char ret_code; -}; - -struct srb_set_funct_addr { - unsigned char command; - unsigned char reserved1; - unsigned char ret_code; - unsigned char reserved2[3]; - __u32 funct_address; -}; - diff -u --recursive --new-file v2.3.20/linux/drivers/net/lapbether.c linux/drivers/net/lapbether.c --- v2.3.20/linux/drivers/net/lapbether.c Thu Aug 26 13:05:38 1999 +++ linux/drivers/net/lapbether.c Wed Dec 31 16:00:00 1969 @@ -1,571 +0,0 @@ -/* - * "LAPB via ethernet" driver release 001 - * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * This is a "pseudo" network driver to allow LAPB over Ethernet. - * - * This driver can use any ethernet destination address, and can be - * limited to accept frames from one dedicated ethernet card only. - * - * History - * LAPBETH 001 Jonathan Naylor Cloned from bpqether.c - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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 "); -MODULE_DESCRIPTION("The unofficial LAPB over Ethernet driver"); - -int init_module(void) -{ - return lapbeth_init(); -} - -void cleanup_module(void) -{ - struct lapbethdev *lapbeth; - - dev_remove_pack(&lapbeth_packet_type); - - unregister_netdevice_notifier(&lapbeth_dev_notifier); - - for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth->next) - unregister_netdev(&lapbeth->axdev); -} -#endif diff -u --recursive --new-file v2.3.20/linux/drivers/net/ncr885_debug.h linux/drivers/net/ncr885_debug.h --- v2.3.20/linux/drivers/net/ncr885_debug.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/ncr885_debug.h Mon Oct 11 10:13:24 1999 @@ -0,0 +1,54 @@ +#ifndef _H_NCR885_DEBUG +#define _H_NCR885_DEBUG + +struct ncr885e_regs { + unsigned long tx_status; + unsigned long rx_status; + unsigned long mac_config; + unsigned long tx_control; + unsigned long rx_control; + unsigned long tx_cmd_ptr; + unsigned long rx_cmd_ptr; + unsigned long int_status; +}; + +#ifndef __KERNEL__ + +struct ncr885e_private { + + struct dbdma_cmd *head; + struct dbdma_cmd *tx_cmds; + struct dbdma_cmd *rx_cmds; + struct dbdma_cmd *stop_cmd; + + struct sk_buff *tx_skbufs[NR_TX_RING]; + struct sk_buff *rx_skbufs[NR_RX_RING]; + + int rx_current; + int rx_dirty; + + int tx_dirty; + int tx_current; + + unsigned short tx_status[NR_TX_RING]; + + unsigned char tx_fullup; + unsigned char tx_active; + + struct net_device_stats stats; + + struct device *dev; + + struct timer_list tx_timeout; + int timeout_active; + + spinlock_t lock; +}; + +#endif /* __KERNEL__ */ + + +#define NCR885E_GET_PRIV _IOR('N',1,sizeof( struct ncr885e_private )) +#define NCR885E_GET_REGS _IOR('N',2,sizeof( struct ncr885e_regs )) + +#endif diff -u --recursive --new-file v2.3.20/linux/drivers/net/ncr885e.c linux/drivers/net/ncr885e.c --- v2.3.20/linux/drivers/net/ncr885e.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/ncr885e.c Mon Oct 11 10:13:25 1999 @@ -0,0 +1,1458 @@ +/* + * An Ethernet driver for the dual-function NCR 53C885 SCSI/Ethernet + * controller. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +static const char *version = +"ncr885e.c:v0.8 11/30/98 dan@synergymicro.com\n"; + +#include + +#ifdef MODULE +#ifdef MODVERSIONS +#include +#endif +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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: + */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/ncr885e.h linux/drivers/net/ncr885e.h --- v2.3.20/linux/drivers/net/ncr885e.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/ncr885e.h Mon Oct 11 10:13:25 1999 @@ -0,0 +1,367 @@ +#ifndef _NET_H_SYMBA +#define _NET_H_SYMBA + +/* transmit status bit definitions */ +#define TX_STATUS_TXOK (1<<13) /* success */ +#define TX_STATUS_TDLC (1<<12) /* dropped for late colls */ +#define TX_STATUS_TCXSDFR (1<<11) /* excessive deferral */ +#define TX_STATUS_TDEC (1<<10) /* excessive collisions */ +#define TX_STATUS_TAUR (1<<9) /* abort on underrun/"jumbo" */ +#define TX_STATUS_PDFRD (1<<8) /* packet deferred */ +#define TX_STATUS_BCAST (1<<7) /* broadcast ok */ +#define TX_STATUS_MCAST (1<<6) /* multicast ok */ +#define TX_STATUS_CRCERR (1<<5) /* CRC error */ +#define TX_STATUS_LC (1<<4) /* late collision */ +#define TX_STATUS_CCNT_MASK 0xf /* collision count */ + +#define T_TXOK (1<<13) +#define T_TDLC (1<<12) +#define T_TCXSDFR (1<<11) +#define T_TDEC (1<<10) +#define T_TAUR (1<<9) +#define T_PDFRD (1<<8) +#define T_BCAST (1<<7) +#define T_MCAST (1<<6) +#define T_LC (1<<4) +#define T_CCNT_MASK 0xf + +/* receive status bit definitions */ +#define RX_STATUS_RXOVRN (1<<23) /* overrun */ +#define RX_STATUS_CEPS (1<<22) /* carrier event already seen */ +#define RX_STATUS_RXOK (1<<21) /* success */ +#define RX_STATUS_BCAST (1<<20) /* broadcast ok */ +#define RX_STATUS_MCAST (1<<19) /* multicast ok */ +#define RX_STATUS_CRCERR (1<<18) /* CRC error */ +#define RX_STATUS_DR (1<<17) /* dribble nibble */ +#define RX_STATUS_RCV (1<<16) /* rx code violation */ +#define RX_STATUS_PTL (1<<15) /* pkt > 1518 bytes */ +#define RX_STATUS_PTS (1<<14) /* pkt < 64 bytes */ +#define RX_STATUS_LEN_MASK 0x1fff /* length mask */ + +#define EEPROM_LENGTH 100 + + +/* Serial EEPROM interface */ +#define EE_STATUS 0xf0 +#define EE_CONTROL 0xf1 +#define EE_WORD_ADDR 0xf2 +#define EE_READ_DATA 0xf3 +#define EE_WRITE_DATA 0xf4 +#define EE_FEATURE_ENB 0xf5 + +/* Use on EE_STATUS */ +#define EE_SEB (1<<8) +#define EE_SEE 1 + +/* Serial EEPROM commands */ +#define EE_CONTROL_SEQ_READB (1<<4) +#define EE_CONTROL_RND_WRITEB (1<<5) +#define EE_CONTROL_RND_READB ((1<<4)|(1<<5)) + +/* Enable writing to serial EEPROM */ +#define EE_WRITE_ENB 1 + +/* The 885 configuration register */ +#define MAC_CONFIG 0xa0 +#define MAC_CONFIG_SRST 1<<15 +#define MAC_CONFIG_ITXA 1<<13 +#define MAC_CONFIG_RXEN 1<<12 +#define MAC_CONFIG_INTLB 1<<10 +#define MAC_CONFIG_MODE_MASK (1<<8|1<<9) +#define MAC_CONFIG_MODE_TP 1<<8 +#define MAC_CONFIG_HUGEN 1<<5 +#define MAC_CONFIG_RETRYL 1<<4 +#define MAC_CONFIG_CRCEN 1<<3 +#define MAC_CONFIG_PADEN 1<<2 +#define MAC_CONFIG_FULLD 1<<1 +#define MAC_CONFIG_NOCFR 1<<0 + + + + + +#define TX_WAIT_SELECT 0x18 +#define RX_CHANNEL_CONTROL 0x40 + +/* Tx channel status */ +#define TX_DBDMA_REG 0x00 +#define TX_CHANNEL_CONTROL 0x00 +#define TX_CHANNEL_STATUS 0x04 +#define TX_STATUS_RUN 1<<15 +#define TX_STATUS_PAUSE 1<<14 +#define TX_STATUS_WAKE 1<<12 +#define TX_STATUS_DEAD 1<<11 +#define TX_STATUS_ACTIVE 1<<10 +#define TX_STATUS_BT 1<<8 +#define TX_STATUS_TXABORT 1<<7 +#define TX_STATUS_TXSR 1<<6 + +#define TX_CHANNEL_RUN TX_STATUS_RUN +#define TX_CHANNEL_PAUSE TX_STATUS_PAUSE +#define TX_CHANNEL_WAKE TX_STATUS_WAKE +#define TX_CHANNEL_DEAD TX_STATUS_DEAD +#define TX_CHANNEL_ACTIVE TX_STATUS_ACTIVE +#define TX_CHANNEL_BT TX_STATUS_BT +#define TX_CHANNEL_TXABORT TX_STATUS_TXABORT +#define TX_CHANNEL_TXSR TX_STATUS_TXSR + +#define TX_DBDMA_ENABLE (TX_CHANNEL_WAKE | TX_CHANNEL_PAUSE | \ + TX_CHANNEL_RUN ) + +/* Transmit command ptr lo register */ +#define TX_CMD_PTR_LO 0x0c + +/* Transmit interrupt select register */ +#define TX_INT_SELECT 0x10 + +/* Transmit branch select register */ +#define TX_BRANCH_SELECT 0x14 + +/* Transmit wait select register */ +#define TX_WAIT_SELECT 0x18 +#define TX_WAIT_STAT_RECV 0x40 + +/* Rx channel status */ +#define RX_DBDMA_REG 0x40 +#define RX_CHANNEL_CONTROL 0x40 +#define RX_CHANNEL_STATUS 0x44 +#define RX_STATUS_RUN 1<<15 +#define RX_STATUS_PAUSE 1<<14 +#define RX_STATUS_WAKE 1<<12 +#define RX_STATUS_DEAD 1<<11 +#define RX_STATUS_ACTIVE 1<<10 +#define RX_STATUS_BT 1<<8 +#define RX_STATUS_EOP 1<<6 + +#define RX_CHANNEL_RUN RX_STATUS_RUN +#define RX_CHANNEL_PAUSE RX_STATUS_PAUSE +#define RX_CHANNEL_WAKE RX_STATUS_WAKE +#define RX_CHANNEL_DEAD RX_STATUS_DEAD +#define RX_CHANNEL_ACTIVE RX_STATUS_ACTIVE +#define RX_CHANNEL_BT RX_STATUS_BT +#define RX_CHANNEL_EOP RX_STATUS_EOP + +#define RX_DBDMA_ENABLE (RX_CHANNEL_WAKE | RX_CHANNEL_PAUSE | \ + RX_CHANNEL_RUN) + +/* Receive command ptr lo */ +#define RX_CMD_PTR_LO 0x4c + +/* Receive interrupt select register */ +#define RX_INT_SELECT 0x50 +#define RX_INT_SELECT_EOP 0x40 + +/* Receive branch select */ +#define RX_BRANCH_SELECT 0x54 +#define RX_BRANCH_SELECT_EOP 0x40 + +/* Receive wait select */ +#define RX_WAIT_SELECT 0x58 +#define RX_WAIT_SELECT_EOP 0x40 + +/* Event status register */ +#define EVENT_STATUS 0x80 +#define EVENT_TXSR 1<<2 +#define EVENT_EOP 1<<1 +#define EVENT_TXABORT 1<<0 + +/* Interrupt enable register */ +#define INTERRUPT_ENABLE 0x82 + +/* Interrupt clear register */ +#define INTERRUPT_CLEAR 0x84 + +/* Interrupt status register */ +#define INTERRUPT_STATUS_REG 0x86 + +/* bits for the above three interrupt registers */ +#define INTERRUPT_INTE 1<<15 /* interrupt enable */ +#define INTERRUPT_WI 1<<9 /* wakeup interrupt */ +#define INTERRUPT_ERI 1<<8 /* early recieve interrupt */ +#define INTERRUPT_PPET 1<<7 /* PCI Tx parity error */ +#define INTERRUPT_PBFT 1<<6 /* PCI Tx bus fault */ +#define INTERRUPT_IIDT 1<<5 /* illegal instruction Tx */ +#define INTERRUPT_DIT 1<<4 /* DBDMA Tx interrupt */ +#define INTERRUPT_PPER 1<<3 /* PCI Rx parity error */ +#define INTERRUPT_PBFR 1<<2 /* PCI Rx bus fault */ +#define INTERRUPT_IIDR 1<<1 /* illegal instruction Rx */ +#define INTERRUPT_DIR 1<<0 /* DBDMA Rx interrupt */ + +#define INTERRUPT_TX_MASK (INTERRUPT_PBFT|INTERRUPT_IIDT| \ + INTERRUPT_PPET|INTERRUPT_DIT) +#define INTERRUPT_RX_MASK (INTERRUPT_PBFR|INTERRUPT_IIDR| \ + INTERRUPT_PPER|INTERRUPT_DIR) + +/* chip revision register */ +#define CHIP_REVISION_REG 0x8c +#define CHIP_PCIREV_MASK (0xf<<16) +#define CHIP_PCIDEV_MASK 0xff + +/* Tx threshold register */ +#define TX_THRESHOLD 0x94 + +/* General purpose register */ +#define GEN_PURPOSE_REG 0x9e + +/* General purpose pin control reg */ +#define GEN_PIN_CONTROL_REG 0x9f + +/* DBDMA control register */ +#define DBDMA_CONTROL 0x90 +#define DBDMA_SRST 1<<31 +#define DBDMA_TDPCE 1<<23 +#define DBDMA_BE 1<<22 +#define DBDMA_TAP_MASK (1<<19|1<<20|1<<21) +#define DBDMA_RAP_MASK (1<<16|1<<17|1<<18) +#define DBDMA_DPMRLE 1<<15 +#define DBDMA_WIE 1<<14 +#define DBDMA_MP 1<<13 +#define DBDMA_SME 1<<12 +#define DBDMA_CME 1<<11 +#define DBDMA_DDPE 1<<10 +#define DBDMA_TDPE 1<<9 +#define DBDMA_EXTE 1<<8 +#define DBDMA_BST_MASK (1<<4|1<<5|1<<6) +#define DBDMA_BSR_MASK (1<<0|1<<1|1<<2) + +#define DBDMA_BURST_1 (0x00) +#define DBDMA_BURST_2 (0x01) +#define DBDMA_BURST_4 (0x02) +#define DBDMA_BURST_8 (0x03) +#define DBDMA_BURST_16 (0x04) +#define DBDMA_BURST_32 (0x05) +#define DBDMA_BURST_64 (0x06) +#define DBDMA_BURST_128 (0x07) + +#define DBDMA_TX_BST_SHIFT (4) +#define DBDMA_RX_BST_SHIFT (0) + +#define DBDMA_TX_ARBITRATION_DEFAULT ( 1 << 19 ) +#define DBDMA_RX_ARBITRATION_DEFAULT ( 2 << 16 ) + + +/* Back-to-back interpacket gap register */ +#define BTOB_INTP_GAP 0xa2 +#define BTOB_INTP_DEFAULT 0x18 + +/* Non-back-to-back interpacket gap register */ +#define NBTOB_INTP_GAP 0xa4 + +/* MIIM command register */ +#define MIIM_COMMAND 0xa6 +#define MIIM_SCAN 1<<1 +#define MIIM_RSTAT 1<<0 + +/* MII address register */ +#define MII_ADDRESS 0xa8 +#define MII_FIAD_MASK (1<<8|1<<9|1<<10|1<<11|1<<12) +#define MII_RGAD_MASK (1<<0|1<<1|1<<2|1<<3|1<<4) + +#define TPPMD_CONTROL_REG 0xa8 +#define TPPMD_FO 1<<1 +#define TPPMD_LB 1<<0 + +/* MII read and write registers */ +#define MII_WRITE_DATA 0xaa +#define MII_READ_DATA 0xac + +/* MII indicators */ +#define MII_INDICATOR 0xae +#define MII_NVALID 1<<2 +#define MII_SCAN 1<<1 +#define MII_BUSY 1<<0 + +/* Address filter */ +#define ADDRESS_FILTER 0xd0 +#define ADDRESS_RPPRM 1<<3 /* multicast promis. mode */ +#define ADDRESS_RPPRO 1<<2 /* promiscuous mode */ +#define ADDRESS_RPAMC 1<<1 /* accept multicasts */ +#define ADDRESS_RPABC 1<<0 /* accept broadcasts */ + +/* Station addresses + + Note that if the serial EEPROM is disabled, these values are all + zero. If, like us, you get the chips when they're fresh, they're + also zero and you have to initialize the address */ +#define STATION_ADDRESS_0 0xd2 +#define STATION_ADDRESS_1 0xd4 +#define STATION_ADDRESS_2 0xd6 + +/* Hash tables */ +#define HASH_TABLE_0 0xd8 +#define HASH_TABLE_1 0xda +#define HASH_TABLE_2 0xdc +#define HASH_TABLE_3 0xde + +/* PHY indentifiers */ +#define PHY_IDENTIFIER_0 0xe4 +#define PHY_IDENTIFIER_1 0xe6 + +/* MII Auto-negotiation register definitions */ + +#define MII_AUTO_NEGOTIATION_CONTROL (0x0000) +#define MANC_PHY_RESET (0x8000) +#define MANC_PHY_LOOPBACK_ENABLE (0x4000) +#define MANC_PHY_LOOPBACK_DISABLE (0x0000) +#define MANC_PHY_SPEED_100 (0x2000) +#define MANC_PHY_SPEED_10 (0x0000) +#define MANC_AUTO_NEGOTIATION_ENABLE (0x1000) +#define MANC_AUTO_NEGOTIATION_DISABLE (0x0000) +#define MANC_PHY_POWER_DOWN (0x0800) +#define MANC_PHY_POWER_UP (0x0000) +#define MANC_ISOLATE_ENABLE (0x0400) +#define MANC_ISOLATE_DISABLE (0x0000) +#define MANC_RESTART_AUTO_NEGOTIATION (0x0200) +#define MANC_FULL_DUPLEX (0x0100) +#define MANC_HALF_DUPLEX (0x0000) + +#define MII_AUTO_NEGOTIATION_STATUS (0x0001) +#define MANS_100BASE_T4_HALF_DUPLEX (0x8000) +#define MANS_100BASE_X_FULL_DUPLEX (0x4000) +#define MANS_100BASE_X_HALF_DUPLEX (0x2000) +#define MANS_10MBS_FULL_DUPLEX (0x1000) +#define MANS_10MBS_HALF_DUPLEX (0x0800) +#define MANS_AUTO_NEGOTIATION_COMPLETE (0x0020) +#define MANS_REMOTE_FAULT (0x0010) +#define MANS_AUTO_NEGOTIATION_ABILITY (0x0008) +#define MANS_LINK_STATUS (0x0004) +#define MANS_JABBER_DETECT (0x0002) +#define MANS_EXTENDED_CAPABILITY (0x0001) + +#define MII_PHY_IDENTIFIER_1 (0x0002) +#define MII_PHY_IDENTIFIER_2 (0x0003) + +#define MII_AUTO_NEGOTIATION_ADVERTISEMENT (0x0004) +#define MANA_NEXT_PAGE (0x8000) +#define MANA_REMOTE_FAULT (0x2000) +#define MANA_TECHNOLOGY_ABILITY_MASK (0x1FE0) +#define MANATECH_10BASET_HALF_DUPLEX (0x0020) +#define MANATECH_10BASET_FULL_DUPLEX (0x0040) +#define MANATECH_100BASETX_HALF_DUPLEX (0x0080) +#define MANATECH_100BASETX_FULL_DUPLEX (0x0100) +#define MANATECH_100BASET4 (0x0200) +#define MANA_SELECTOR_MASK (0x001F) +#define MANASELECTOR_802_3 (0x0001) + +#define MII_AUTO_NEGOTIATION_LINK_PARTNER (0x0005) +#define MANLP_NEXT_PAGE (0x8000) +#define MANLP_ACKNOWLEDGE (0x4000) +#define MANLP_REMOTE_FAULT (0x2000) +#define MANLP_TECHNOLOGY_ABILITY_MASK (0x1FE0) +#define MANLP_SELECTOR_MASK (0x001F) + +#define MII_AUTO_NEGOTIATION_EXPANSION (0x0006) +#define MANE_PARALLEL_DETECTION_FAULT (0x0010) +#define MANE_LINK_PARTNER_NEXT_PAGE_ABLE (0x0008) +#define MANE_NEXT_PAGE_ABLE (0x0004) +#define MANE_PAGE_RECEIVED (0x0002) +#define MANE_LINK_PARTNER_AUTO_ABLE (0x0001) + +#define MII_AUTO_NEGOTIATION_NEXT_PAGE_TRANSMIT (0x0007) +#define MANNPT_NEXT_PAGE (0x8000) +#define MANNPT_MESSAGE_PAGE (0x2000) +#define MANNPT_ACKNOWLEDGE_2 (0x1000) +#define MANNPT_TOGGLE (0x0800) +#define MANNPT_MESSAGE_FIELD_MASK (0x07FF) + +#endif diff -u --recursive --new-file v2.3.20/linux/drivers/net/olympic.c linux/drivers/net/olympic.c --- v2.3.20/linux/drivers/net/olympic.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/net/olympic.c Wed Dec 31 16:00:00 1969 @@ -1,1667 +0,0 @@ -/* - * olympic.c (c) 1999 Peter De Schrijver All Rights Reserved - * 1999 Mike Phillips (phillim@amtrak.com) - * - * Linux driver for IBM PCI tokenring cards based on the Pit/Pit-Phy/Olympic - * chipset. - * - * Base Driver Skeleton: - * Written 1993-94 by Donald Becker. - * - * Copyright 1993 United States Government as represented by the - * Director, National Security Agency. - * - * Thanks to Erik De Cock, Adrian Bridgett and Frank Fiene for their - * assistance and perserverance with the testing of this driver. - * - * This software may be used and distributed according to the terms - * of the GNU Public License, incorporated herein by reference. - * - * 4/27/99 - Alpha Release 0.1.0 - * First release to the public - * - * 6/8/99 - Official Release 0.2.0 - * Merged into the kernel code - * 8/18/99 - Updated driver for 2.3.13 kernel to use new pci - * resource. Driver also reports the card name returned by - * the pci resource. - * - * To Do: - * - * Sanitize for smp - * - * If Problems do Occur - * Most problems can be rectified by either closing and opening the interface - * (ifconfig down and up) or rmmod and insmod'ing the driver (a bit difficult - * if compiled into the kernel). - */ - -/* Change OLYMPIC_DEBUG to 1 to get verbose, and I mean really verbose, messages */ - -#define OLYMPIC_DEBUG 0 - -/* Change OLYMPIC_NETWORK_MONITOR to receive mac frames through the arb channel. - * Will also create a /proc/net/olympic_tr entry if proc_fs is compiled into the - * kernel. - * Intended to be used to create a ring-error reporting network module - * i.e. it will give you the source address of beaconers on the ring - */ - -#define OLYMPIC_NETWORK_MONITOR 0 - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#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;iolympic_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;ipkt_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;iolympic_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;irx_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(posoffset+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; (iinit = &olympic_probe; - - if (register_trdev(dev_olympic[i]) != 0) { - kfree_s(dev_olympic[i], sizeof(struct net_device)); - dev_olympic[i] = NULL; - if (i == 0) { - printk("Olympic: No IBM PCI Token Ring cards found in system.\n"); - return -EIO; - } else { - printk("Olympic: %d IBM PCI Token Ring card(s) found in system.\n",i) ; - return 0; - } - } - } - - return 0; -} - -void cleanup_module(void) -{ - int i; - - for (i = 0; i < OLYMPIC_MAX_ADAPTERS; i++) - if (dev_olympic[i]) { - unregister_trdev(dev_olympic[i]); - release_region(dev_olympic[i]->base_addr, OLYMPIC_IO_SPACE); - kfree_s(dev_olympic[i]->priv, sizeof(struct olympic_private)); - kfree_s(dev_olympic[i], sizeof(struct net_device)); - dev_olympic[i] = NULL; - } - -#if OLYMPIC_NETWORK_MONITOR -#ifdef CONFIG_PROC_FS - remove_proc_entry("net/olympic_tr", NULL) ; -#endif -#endif -} -#endif /* MODULE */ - diff -u --recursive --new-file v2.3.20/linux/drivers/net/olympic.h linux/drivers/net/olympic.h --- v2.3.20/linux/drivers/net/olympic.h Wed Aug 18 16:24:11 1999 +++ linux/drivers/net/olympic.h Wed Dec 31 16:00:00 1969 @@ -1,304 +0,0 @@ -/* - * olympic.h (c) 1999 Peter De Schrijver All Rights Reserved - * 1999 Mike Phillips (phillim@amtrak.com) - * - * Linux driver for IBM PCI tokenring cards based on the olympic and the PIT/PHY chipset. - * - * Base Driver Skeleton: - * Written 1993-94 by Donald Becker. - * - * Copyright 1993 United States Government as represented by the - * Director, National Security Agency. - * - * This software may be used and distributed according to the terms - * of the GNU Public License, incorporated herein by reference. - */ - -#define CID 0x4e - -#define BCTL 0x70 -#define BCTL_SOFTRESET (1<<15) -#define BCTL_MIMREB (1<<6) - -#define GPR 0x4a -#define GPR_OPTI_BF (1<<6) -#define GPR_NEPTUNE_BF (1<<4) -#define GPR_AUTOSENSE (1<<2) -#define GPR_16MBPS (1<<3) - -#define PAG 0x85 -#define LBC 0x8e - -#define LISR 0x10 -#define LISR_SUM 0x14 -#define LISR_RWM 0x18 - -#define LISR_LIE (1<<15) -#define LISR_SLIM (1<<13) -#define LISR_SLI (1<<12) -#define LISR_PCMSRMASK (1<<11) -#define LISR_PCMSRINT (1<<10) -#define LISR_WOLMASK (1<<9) -#define LISR_WOL (1<<8) -#define LISR_SRB_CMD (1<<5) -#define LISR_ASB_REPLY (1<<4) -#define LISR_ASB_FREE_REQ (1<<2) -#define LISR_ARB_FREE (1<<1) -#define LISR_TRB_FRAME (1<<0) - -#define SISR 0x20 -#define SISR_SUM 0x24 -#define SISR_RWM 0x28 -#define SISR_RR 0x2C -#define SISR_RESMASK 0x30 -#define SISR_MASK 0x54 -#define SISR_MASK_SUM 0x58 -#define SISR_MASK_RWM 0x5C - -#define SISR_TX2_IDLE (1<<31) -#define SISR_TX2_HALT (1<<29) -#define SISR_TX2_EOF (1<<28) -#define SISR_TX1_IDLE (1<<27) -#define SISR_TX1_HALT (1<<25) -#define SISR_TX1_EOF (1<<24) -#define SISR_TIMEOUT (1<<23) -#define SISR_RX_NOBUF (1<<22) -#define SISR_RX_STATUS (1<<21) -#define SISR_RX_HALT (1<<18) -#define SISR_RX_EOF_EARLY (1<<16) -#define SISR_MI (1<<15) -#define SISR_PI (1<<13) -#define SISR_ERR (1<<9) -#define SISR_ADAPTER_CHECK (1<<6) -#define SISR_SRB_REPLY (1<<5) -#define SISR_ASB_FREE (1<<4) -#define SISR_ARB_CMD (1<<3) -#define SISR_TRB_REPLY (1<<2) - -#define EISR 0x34 -#define EISR_RWM 0x38 -#define EISR_MASK 0x3c - -#define LAPA 0x60 -#define LAPWWO 0x64 -#define LAPWWC 0x68 -#define LAPCTL 0x6C -#define LAIPD 0x78 -#define LAIPDDINC 0x7C - -#define TIMER 0x50 - -#define CLKCTL 0x74 - -#define PM_CON 0x4 - -#define BMCTL_SUM 0x40 -#define BMCTL_RWM 0x44 -#define BMCTL_TX2_DIS (1<<30) -#define BMCTL_TX1_DIS (1<<26) -#define BMCTL_RX_DIS (1<<22) - -#define BMASR 0xcc - -#define RXDESCQ 0x90 -#define RXDESCQCNT 0x94 -#define RXCDA 0x98 -#define RXENQ 0x9C -#define RXSTATQ 0xA0 -#define RXSTATQCNT 0xA4 -#define RXCSA 0xA8 -#define RXCLEN 0xAC -#define RXHLEN 0xAE - -#define TXDESCQ_1 0xb0 -#define TXDESCQ_2 0xd0 -#define TXDESCQCNT_1 0xb4 -#define TXDESCQCNT_2 0xd4 -#define TXCDA_1 0xb8 -#define TXCDA_2 0xd8 -#define TXENQ_1 0xbc -#define TXENQ_2 0xdc -#define TXSTATQ_1 0xc0 -#define TXSTATQ_2 0xe0 -#define TXSTATQCNT_1 0xc4 -#define TXSTATQCNT_2 0xe4 -#define TXCSA_1 0xc8 -#define TXCSA_2 0xe8 - -#define OLYMPIC_IO_SPACE 256 - -#define SRB_COMMAND_SIZE 50 - -#define OLYMPIC_MAX_ADAPTERS 8 /* 0x08 __MODULE_STRING can't hand 0xnn */ - -/* Defines for LAN STATUS CHANGE reports */ -#define LSC_SIG_LOSS 0x8000 -#define LSC_HARD_ERR 0x4000 -#define LSC_SOFT_ERR 0x2000 -#define LSC_TRAN_BCN 0x1000 -#define LSC_LWF 0x0800 -#define LSC_ARW 0x0400 -#define LSC_FPE 0x0200 -#define LSC_RR 0x0100 -#define LSC_CO 0x0080 -#define LSC_SS 0x0040 -#define LSC_RING_REC 0x0020 -#define LSC_SR_CO 0x0010 -#define LSC_FDX_MODE 0x0004 - -/* Defines for OPEN ADAPTER command */ - -#define OPEN_ADAPTER_EXT_WRAP (1<<15) -#define OPEN_ADAPTER_DIS_HARDEE (1<<14) -#define OPEN_ADAPTER_DIS_SOFTERR (1<<13) -#define OPEN_ADAPTER_PASS_ADC_MAC (1<<12) -#define OPEN_ADAPTER_PASS_ATT_MAC (1<<11) -#define OPEN_ADAPTER_ENABLE_EC (1<<10) -#define OPEN_ADAPTER_CONTENDER (1<<8) -#define OPEN_ADAPTER_PASS_BEACON (1<<7) -#define OPEN_ADAPTER_ENABLE_FDX (1<<6) -#define OPEN_ADAPTER_ENABLE_RPL (1<<5) -#define OPEN_ADAPTER_INHIBIT_ETR (1<<4) -#define OPEN_ADAPTER_INTERNAL_WRAP (1<<3) -#define OPEN_ADAPTER_USE_OPTS2 (1<<0) - -#define OPEN_ADAPTER_2_ENABLE_ONNOW (1<<15) - -/* Defines for SRB Commands */ - -#define SRB_ACCESS_REGISTER 0x1f -#define SRB_CLOSE_ADAPTER 0x04 -#define SRB_CONFIGURE_BRIDGE 0x0c -#define SRB_CONFIGURE_WAKEUP_EVENT 0x1a -#define SRB_MODIFY_BRIDGE_PARMS 0x15 -#define SRB_MODIFY_OPEN_OPTIONS 0x01 -#define SRB_MODIFY_RECEIVE_OPTIONS 0x17 -#define SRB_NO_OPERATION 0x00 -#define SRB_OPEN_ADAPTER 0x03 -#define SRB_READ_LOG 0x08 -#define SRB_READ_SR_COUNTERS 0x16 -#define SRB_RESET_GROUP_ADDRESS 0x02 -#define SRB_SAVE_CONFIGURATION 0x1b -#define SRB_SET_BRIDGE_PARMS 0x09 -#define SRB_SET_BRIDGE_TARGETS 0x10 -#define SRB_SET_FUNC_ADDRESS 0x07 -#define SRB_SET_GROUP_ADDRESS 0x06 -#define SRB_SET_GROUP_ADDR_OPTIONS 0x11 -#define SRB_UPDATE_WAKEUP_PATTERN 0x19 - -/* Clear return code */ - -#define OLYMPIC_CLEAR_RET_CODE 0xfe - -/* ARB Commands */ -#define ARB_RECEIVE_DATA 0x81 -#define ARB_LAN_CHANGE_STATUS 0x84 -/* ASB Response commands */ - -#define ASB_RECEIVE_DATA 0x81 - - -/* Olympic defaults for buffers */ - -#define OLYMPIC_RX_RING_SIZE 16 /* should be a power of 2 */ -#define OLYMPIC_TX_RING_SIZE 8 /* should be a power of 2 */ - -#define PKT_BUF_SZ 4096 /* Default packet size */ - -/* Olympic data structures */ - -struct olympic_tx_desc { - __u32 buffer; - __u32 status_length; -}; - -struct olympic_tx_status { - __u32 status; -}; - -struct olympic_rx_desc { - __u32 buffer; - __u32 res_length ; -}; - -struct olympic_rx_status { - __u32 fragmentcnt_framelen; - __u32 status_buffercnt; -}; - -struct mac_receive_buffer { - __u16 next ; - __u8 padding ; - __u8 frame_status ; - __u16 buffer_length ; - __u8 frame_data ; -}; - -struct olympic_private { - - __u16 srb; - __u16 trb; - __u16 arb; - __u16 asb; - - __u8 *olympic_mmio; - __u8 *olympic_lap; - char *olympic_card_name ; - - volatile int srb_queued; /* True if an SRB is still posted */ - wait_queue_head_t srb_wait; - - volatile int asb_queued; /* True if an ASB is posted */ - - volatile int trb_queued; /* True if a TRB is posted */ - wait_queue_head_t trb_wait ; - - struct olympic_rx_desc olympic_rx_ring[OLYMPIC_RX_RING_SIZE]; - struct olympic_tx_desc olympic_tx_ring[OLYMPIC_TX_RING_SIZE]; - struct olympic_rx_status olympic_rx_status_ring[OLYMPIC_RX_RING_SIZE]; - struct olympic_tx_status olympic_tx_status_ring[OLYMPIC_TX_RING_SIZE]; - struct sk_buff *tx_ring_skb[OLYMPIC_TX_RING_SIZE], *rx_ring_skb[OLYMPIC_RX_RING_SIZE]; - int tx_ring_free, tx_ring_last_status, rx_ring_last_received,rx_status_last_received, free_tx_ring_entries; - - struct net_device_stats olympic_stats ; - __u16 olympic_lan_status ; - __u8 olympic_ring_speed ; - __u16 pkt_buf_sz ; - __u8 olympic_receive_options, olympic_copy_all_options, olympic_message_level; - __u8 olympic_multicast_set ; - __u16 olympic_addr_table_addr, olympic_parms_addr ; - __u8 olympic_laa[6] ; -}; - -struct olympic_adapter_addr_table { - - __u8 node_addr[6] ; - __u8 reserved[4] ; - __u8 func_addr[4] ; -} ; - -struct olympic_parameters_table { - - __u8 phys_addr[4] ; - __u8 up_node_addr[6] ; - __u8 up_phys_addr[6] ; - __u8 poll_addr[6] ; - __u16 reserved ; - __u16 acc_priority ; - __u16 auth_source_class ; - __u16 att_code ; - __u8 source_addr[6] ; - __u16 beacon_type ; - __u16 major_vector ; - __u16 lan_status ; - __u16 soft_error_time ; - __u16 reserved1 ; - __u16 local_ring ; - __u16 mon_error ; - __u16 beacon_transmit ; - __u16 beacon_receive ; - __u16 frame_correl ; - __u8 beacon_naun[6] ; - __u32 reserved2 ; - __u8 beacon_phys[4] ; -}; diff -u --recursive --new-file v2.3.20/linux/drivers/net/sdla.c linux/drivers/net/sdla.c --- v2.3.20/linux/drivers/net/sdla.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/sdla.c Wed Dec 31 16:00:00 1969 @@ -1,1696 +0,0 @@ -/* - * SDLA An implementation of a driver for the Sangoma S502/S508 series - * multi-protocol PC interface card. Initial offering is with - * the DLCI driver, providing Frame Relay support for linux. - * - * Global definitions for the Frame relay interface. - * - * Version: @(#)sdla.c 0.30 12 Sep 1996 - * - * Credits: Sangoma Technologies, for the use of 2 cards for an extended - * period of time. - * David Mandelstam 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 - * - * 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 /* for CONFIG_DLCI_MAX */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -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;imaster[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;imaster[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;imaster[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;imaster[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;imaster[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;idlci[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;idlci[i]) - dlcis[len++] = abs(flp->dlci[i]); - len *= 2; - - if (flp->config.station == FRAD_STATION_NODE) - { - for(i=0;idlci[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;idlci[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;idlci[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;idlci[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;imaster[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;idlci[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;ibase_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;ibase_addr + i) != byte) - break; - - if (i == SDLA_IO_EXTENTS) - { - outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL); - if ((inb(dev->base_addr + SDLA_S502_STS) & 0x7E) == 0x30) - { - outb(SDLA_S507_ENABLE, dev->base_addr + SDLA_REG_CONTROL); - if ((inb(dev->base_addr + SDLA_S502_STS) & 0x7E) == 0x32) - { - outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL); - flp->type = SDLA_S507; - } - } - } - } - - if (flp->type == SDLA_UNKNOWN) - { - outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL); - if ((inb(dev->base_addr + SDLA_S508_STS) & 0x3F) == 0x00) - { - outb(SDLA_S508_INTEN, dev->base_addr + SDLA_REG_CONTROL); - if ((inb(dev->base_addr + SDLA_S508_STS) & 0x3F) == 0x10) - { - outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL); - flp->type = SDLA_S508; - } - } - } - - if (flp->type == SDLA_UNKNOWN) - { - outb(SDLA_S502A_HALT, dev->base_addr + SDLA_REG_CONTROL); - if (inb(dev->base_addr + SDLA_S502_STS) == 0x40) - { - outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL); - if (inb(dev->base_addr + SDLA_S502_STS) == 0x40) - { - outb(SDLA_S502A_INTEN, dev->base_addr + SDLA_REG_CONTROL); - if (inb(dev->base_addr + SDLA_S502_STS) == 0x44) - { - outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL); - flp->type = SDLA_S502A; - } - } - } - } - - if (flp->type == SDLA_UNKNOWN) - { - printk(KERN_NOTICE "%s: Unknown card type\n", dev->name); - return(-ENODEV); - } - - switch(dev->base_addr) - { - case 0x270: - case 0x280: - case 0x380: - case 0x390: - if ((flp->type != SDLA_S508) && (flp->type != SDLA_S507)) - return(-EINVAL); - } - - switch (map->irq) - { - case 2: - if (flp->type != SDLA_S502E) - return(-EINVAL); - break; - - case 10: - case 11: - case 12: - case 15: - case 4: - if ((flp->type != SDLA_S508) && (flp->type != SDLA_S507)) - return(-EINVAL); - - case 3: - case 5: - case 7: - if (flp->type == SDLA_S502A) - return(-EINVAL); - break; - - default: - return(-EINVAL); - } - dev->irq = map->irq; - - if (request_irq(dev->irq, &sdla_isr, 0, dev->name, dev)) - return(-EAGAIN); - - if (flp->type == SDLA_S507) - { - switch(dev->irq) - { - case 3: - flp->state = SDLA_S507_IRQ3; - break; - case 4: - flp->state = SDLA_S507_IRQ4; - break; - case 5: - flp->state = SDLA_S507_IRQ5; - break; - case 7: - flp->state = SDLA_S507_IRQ7; - break; - case 10: - flp->state = SDLA_S507_IRQ10; - break; - case 11: - flp->state = SDLA_S507_IRQ11; - break; - case 12: - flp->state = SDLA_S507_IRQ12; - break; - case 15: - flp->state = SDLA_S507_IRQ15; - break; - } - } - - for(i=0;i < sizeof(valid_mem) / sizeof (int) ; i++) - if (valid_mem[i] == map->mem_start) - break; - - if (i == sizeof(valid_mem) / sizeof(int)) - /* - * FIXME: - * BUG BUG BUG: MUST RELEASE THE IRQ WE ALLOCATED IN - * ALL THESE CASES - * - */ - return(-EINVAL); - - if ((flp->type == SDLA_S502A) && (((map->mem_start & 0xF000) >> 12) == 0x0E)) - return(-EINVAL); - - if ((flp->type != SDLA_S507) && ((map->mem_start >> 16) == 0x0B)) - return(-EINVAL); - - if ((flp->type == SDLA_S507) && ((map->mem_start >> 16) == 0x0D)) - return(-EINVAL); - - dev->mem_start = map->mem_start; - dev->mem_end = dev->mem_start + 0x2000; - - byte = flp->type != SDLA_S508 ? SDLA_8K_WINDOW : 0; - byte |= (map->mem_start & 0xF000) >> (12 + (flp->type == SDLA_S508 ? 1 : 0)); - switch(flp->type) - { - case SDLA_S502A: - case SDLA_S502E: - switch (map->mem_start >> 16) - { - case 0x0A: - byte |= SDLA_S502_SEG_A; - break; - case 0x0C: - byte |= SDLA_S502_SEG_C; - break; - case 0x0D: - byte |= SDLA_S502_SEG_D; - break; - case 0x0E: - byte |= SDLA_S502_SEG_E; - break; - } - break; - case SDLA_S507: - switch (map->mem_start >> 16) - { - case 0x0A: - byte |= SDLA_S507_SEG_A; - break; - case 0x0B: - byte |= SDLA_S507_SEG_B; - break; - case 0x0C: - byte |= SDLA_S507_SEG_C; - break; - case 0x0E: - byte |= SDLA_S507_SEG_E; - break; - } - break; - case SDLA_S508: - switch (map->mem_start >> 16) - { - case 0x0A: - byte |= SDLA_S508_SEG_A; - break; - case 0x0C: - byte |= SDLA_S508_SEG_C; - break; - case 0x0D: - byte |= SDLA_S508_SEG_D; - break; - case 0x0E: - byte |= SDLA_S508_SEG_E; - break; - } - break; - } - - /* set the memory bits, and enable access */ - outb(byte, dev->base_addr + SDLA_REG_PC_WINDOW); - - switch(flp->type) - { - case SDLA_S502E: - flp->state = SDLA_S502E_ENABLE; - break; - case SDLA_S507: - flp->state |= SDLA_MEMEN; - break; - case SDLA_S508: - flp->state = SDLA_MEMEN; - break; - } - outb(flp->state, dev->base_addr + SDLA_REG_CONTROL); - - flp->initialized = 1; - return(0); -} - -static struct net_device_stats *sdla_stats(struct net_device *dev) -{ - struct frad_local *flp; - flp = dev->priv; - - return(&flp->stats); -} - -int __init sdla_init(struct net_device *dev) -{ - struct frad_local *flp; - - /* allocate the private data structure */ - flp = kmalloc(sizeof(struct frad_local), GFP_KERNEL); - if (!flp) - return(-ENOMEM); - - memset(flp, 0, sizeof(struct frad_local)); - dev->priv = flp; - - dev->flags = 0; - dev->open = sdla_open; - dev->stop = sdla_close; - dev->do_ioctl = sdla_ioctl; - dev->set_config = sdla_set_config; - dev->get_stats = sdla_stats; - dev->hard_start_xmit = sdla_transmit; - dev->change_mtu = sdla_change_mtu; - - dev->type = 0xFFFF; - dev->hard_header_len = 0; - dev->addr_len = 0; - dev->mtu = SDLA_MAX_MTU; - - dev_init_buffers(dev); - - flp->activate = sdla_activate; - flp->deactivate = sdla_deactivate; - flp->assoc = sdla_assoc; - flp->deassoc = sdla_deassoc; - flp->dlci_conf = sdla_dlci_conf; - - init_timer(&flp->timer); - flp->timer.expires = 1; - flp->timer.data = (unsigned long) dev; - flp->timer.function = sdla_poll; - - return(0); -} - -void __init sdla_setup(void) -{ - printk("%s.\n", version); - register_frad(devname); -} - -#ifdef MODULE -static struct net_device sdla0 = {"sdla0", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, sdla_init}; - -int init_module(void) -{ - int result; - - sdla_setup(); - if ((result = register_netdev(&sdla0)) != 0) - return result; - return 0; -} - -void cleanup_module(void) -{ - unregister_netdev(&sdla0); - if (sdla0.priv) - kfree(sdla0.priv); - if (sdla0.irq) - free_irq(sdla0.irq, &sdla0); -} -#endif /* MODULE */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/sdla_fr.c linux/drivers/net/sdla_fr.c --- v2.3.20/linux/drivers/net/sdla_fr.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/sdla_fr.c Wed Dec 31 16:00:00 1969 @@ -1,3127 +0,0 @@ -/***************************************************************************** -* sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module. -* -* Author(s): Gene Kozin -* Jaspreet Singh -* -* 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 /* printk(), and other useful stuff */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include /* kmalloc(), kfree() */ -#include /* WAN router definitions */ -#include /* WANPIPE common user API definitions */ -#include /* ARPHRD_* defines */ -#include /* htons(), etc. */ -#include /* for inb(), outb(), etc. */ -#include /* for do_gettimeofday */ -#define _GNUC_ -#include /* frame relay firmware API definitions */ -#include - -/****** Defines & Macros ****************************************************/ - -#define MAX_CMD_RETRY 10 /* max number of firmware retries */ -#define FR_HEADER_LEN 8 /* max encapsulation header size */ -#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ - -/* Q.922 frame types */ - -#define Q922_UI 0x03 /* Unnumbered Info frame */ -#define Q922_XID 0xAF /* ??? */ - -/* DLCI configured or not */ - -#define DLCI_NOT_CONFIGURED 0x00 -#define DLCI_CONFIG_PENDING 0x01 -#define DLCI_CONFIGURED 0x02 - -/* CIR enabled or not */ - -#define CIR_ENABLED 0x00 -#define CIR_DISABLED 0x01 - -/* Interrupt mode for DLCI = 0 */ - -#define BUFFER_INTR_MODE 0x00 -#define DLCI_LIST_INTR_MODE 0x01 - -/* Transmit Interrupt Status */ - -#define DISABLED 0x00 -#define WAITING_TO_BE_ENABLED 0x01 - -/* For handle_IPXWAN() */ - -#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) - -/****** Data Structures *****************************************************/ - -/* This is an extention of the 'struct net_device' we create for each network - * interface to keep the rest of channel-specific data. - */ -typedef struct fr_channel { - char name[WAN_IFNAME_SZ + 1]; /* interface name, ASCIIZ */ - unsigned dlci_configured; /* check whether configured or not */ - unsigned cir_status; /* check whether CIR enabled or not */ - unsigned dlci; /* logical channel number */ - unsigned cir; /* committed information rate */ - unsigned bc; /* committed burst size */ - unsigned be; /* excess burst size */ - unsigned mc; /* multicast support on or off */ - unsigned tx_int_status; /* Transmit Interrupt Status */ - unsigned short pkt_length; /* Packet Length */ - unsigned long router_start_time; /* Router start time in seconds */ - unsigned long tick_counter; /* counter for transmit time out */ - char dev_pending_devtint; /* interface pending dev_tint() */ - char state; /* channel state */ - void *dlci_int_interface; /* pointer to the DLCI Interface */ - unsigned long IB_addr; /* physical address of Interface Byte */ - unsigned long state_tick; /* time of the last state change */ - sdla_t *card; /* -> owner */ - struct net_device_stats ifstats; /* interface statistics */ - unsigned long if_send_entry; - unsigned long if_send_skb_null; - unsigned long if_send_broadcast; - unsigned long if_send_multicast; - unsigned long if_send_critical_ISR; - unsigned long if_send_critical_non_ISR; - unsigned long if_send_busy; - unsigned long if_send_busy_timeout; - unsigned long if_send_FPIPE_request; - unsigned long if_send_DRVSTATS_request; - unsigned long if_send_wan_disconnected; - unsigned long if_send_dlci_disconnected; - unsigned long if_send_no_bfrs; - unsigned long if_send_adptr_bfrs_full; - unsigned long if_send_bfrs_passed_to_adptr; - unsigned long rx_intr_no_socket; - unsigned long rx_intr_dev_not_started; - unsigned long rx_intr_FPIPE_request; - unsigned long rx_intr_DRVSTATS_request; - unsigned long rx_intr_bfr_not_passed_to_stack; - unsigned long rx_intr_bfr_passed_to_stack; - unsigned long UDP_FPIPE_mgmt_kmalloc_err; - unsigned long UDP_FPIPE_mgmt_direction_err; - unsigned long UDP_FPIPE_mgmt_adptr_type_err; - unsigned long UDP_FPIPE_mgmt_adptr_cmnd_OK; - unsigned long UDP_FPIPE_mgmt_adptr_cmnd_timeout; - unsigned long UDP_FPIPE_mgmt_adptr_send_passed; - unsigned long UDP_FPIPE_mgmt_adptr_send_failed; - unsigned long UDP_FPIPE_mgmt_not_passed_to_stack; - unsigned long UDP_FPIPE_mgmt_passed_to_stack; - unsigned long UDP_FPIPE_mgmt_no_socket; - unsigned long UDP_DRVSTATS_mgmt_kmalloc_err; - unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK; - unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; - unsigned long UDP_DRVSTATS_mgmt_adptr_send_passed; - unsigned long UDP_DRVSTATS_mgmt_adptr_send_failed; - unsigned long UDP_DRVSTATS_mgmt_not_passed_to_stack; - unsigned long UDP_DRVSTATS_mgmt_passed_to_stack; - unsigned long UDP_DRVSTATS_mgmt_no_socket; - unsigned long router_up_time; -} fr_channel_t; - -typedef struct dlci_status { - unsigned short dlci PACKED; - unsigned char state PACKED; -} dlci_status_t; - -typedef struct dlci_IB_mapping { - unsigned short dlci PACKED; - unsigned long addr_value PACKED; -} dlci_IB_mapping_t; - -/* This structure is used for DLCI list Tx interrupt mode. It is used to - enable interrupt bit and set the packet length for transmission - */ - -typedef struct fr_dlci_interface { - unsigned char gen_interrupt PACKED; - unsigned short packet_length PACKED; - unsigned char reserved PACKED; -} fr_dlci_interface_t; - -static unsigned short num_frames; -static unsigned long curr_trace_addr; -static unsigned long start_trace_addr; -static unsigned short available_buffer_space; -static char TracingEnabled; /* variable for keeping track of enabling/disabling FT1 monitor status */ -static int rCount = 0; -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -/* variable for keeping track of number of interrupts generated during - * interrupt test routine - */ -static int Intr_test_counter; - -/****** Function Prototypes *************************************************/ - -/* WAN link driver entry points. These are called by the WAN router module. */ -static int update(wan_device_t * wandev); -static int new_if(wan_device_t * wandev, struct net_device *dev, - wanif_conf_t * conf); -static int del_if(wan_device_t * wandev, struct net_device *dev); -/* WANPIPE-specific entry points */ -static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data); -/* Network device interface */ -static int if_init(struct net_device *dev); -static int if_open(struct net_device *dev); -static int if_close(struct net_device *dev); -static int if_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len); -static int if_rebuild_hdr(struct sk_buff *skb); -static int if_send(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *if_stats(struct net_device *dev); -/* Interrupt handlers */ -static void fr502_isr(sdla_t * card); -static void fr508_isr(sdla_t * card); -static void fr502_rx_intr(sdla_t * card); -static void fr508_rx_intr(sdla_t * card); -static void tx_intr(sdla_t * card); -static void spur_intr(sdla_t * card); -/* Background polling routines */ -static void wpf_poll(sdla_t * card); -/* Frame relay firmware interface functions */ -static int fr_read_version(sdla_t * card, char *str); -static int fr_configure(sdla_t * card, fr_conf_t * conf); -static int fr_dlci_configure(sdla_t * card, fr_dlc_conf_t * conf, unsigned dlci); -static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu); -static int fr_comm_enable(sdla_t * card); -static int fr_comm_disable(sdla_t * card); -static int fr_get_err_stats(sdla_t * card); -static int fr_get_stats(sdla_t * card); -static int fr_add_dlci(sdla_t * card, int dlci, int num); -static int fr_activate_dlci(sdla_t * card, int dlci, int num); -static int fr_issue_isf(sdla_t * card, int isf); -static int fr502_send(sdla_t * card, int dlci, int attr, int len, void *buf); -static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf); -/* Firmware asynchronous event handlers */ -static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox); -static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox); -static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox); -/* Miscellaneous functions */ -static int update_chan_state(struct net_device *dev); -static void set_chan_state(struct net_device *dev, int state); -static struct net_device *find_channel(sdla_t * card, unsigned dlci); -static int is_tx_ready(sdla_t * card, fr_channel_t * chan); -static unsigned int dec_to_uint(unsigned char *str, int len); -static int reply_udp(unsigned char *data, unsigned int mbox_len); -static int intr_test(sdla_t * card); -static void init_chan_statistics(fr_channel_t * chan); -static void init_global_statistics(sdla_t * card); -static void read_DLCI_IB_mapping(sdla_t * card, fr_channel_t * chan); -/* Udp management functions */ -static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, int dlci, fr_channel_t * chan); -static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, int dlci, fr_channel_t * chan); -static int udp_pkt_type(struct sk_buff *skb, sdla_t * card); -/* IPX functions */ -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number); - -/****** Public Functions ****************************************************/ - -/*============================================================================ - * Frame relay protocol initialization routine. - * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. - * - * Return: 0 o.k. - * < 0 failure. - */ -int wpf_init(sdla_t * card, wandev_conf_t * conf) -{ - union { - char str[80]; - fr_conf_t cfg; - } u; - int i; - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_FR) - { - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); - return -EINVAL; - } - /* Initialize protocol-specific fields of adapter data space */ - switch (card->hw.fwid) - { - case SFID_FR502: - card->mbox = (void *) (card->hw.dpmbase + FR502_MBOX_OFFS); - card->rxmb = (void *) (card->hw.dpmbase + FR502_RXMB_OFFS); - card->flags = (void *) (card->hw.dpmbase + FR502_FLAG_OFFS); - card->isr = &fr502_isr; - break; - case SFID_FR508: - card->mbox = (void *) (card->hw.dpmbase + FR508_MBOX_OFFS); - card->flags = (void *) (card->hw.dpmbase + FR508_FLAG_OFFS); - card->isr = &fr508_isr; - break; - default: - return -EINVAL; - } - /* Read firmware version. Note that when adapter initializes, it - * clears the mailbox, so it may appear that the first command was - * executed successfully when in fact it was merely erased. To work - * around this, we execute the first command twice. - */ - if (fr_read_version(card, NULL) || fr_read_version(card, u.str)) - return -EIO; - printk(KERN_INFO "%s: running frame relay firmware v%s\n", - card->devname, u.str); - /* Adjust configuration */ - conf->mtu = max(min(conf->mtu, 4080), FR_CHANNEL_MTU + FR_HEADER_LEN); - conf->bps = min(conf->bps, 2048000); - /* Configure adapter firmware */ - memset(&u.cfg, 0, sizeof(u.cfg)); - u.cfg.mtu = conf->mtu; - u.cfg.kbps = conf->bps / 1000; - u.cfg.cir_fwd = u.cfg.cir_bwd = 16; - u.cfg.bc_fwd = u.cfg.bc_bwd = 16; - if (conf->station == WANOPT_CPE) - { - u.cfg.options = 0x0080; - printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname); - } - else - { - u.cfg.options = 0x0081; - } - switch (conf->u.fr.signalling) - { - case WANOPT_FR_Q933: - u.cfg.options |= 0x0200; - break; - case WANOPT_FR_LMI: - u.cfg.options |= 0x0400; - break; - } - if (conf->station == WANOPT_CPE) - { - u.cfg.options |= 0x8000; /* auto config DLCI */ - card->u.f.dlci_num = 0; - } - else - { - u.cfg.station = 1; /* switch emulation mode */ - /* For switch emulation we have to create a list of dlci(s) - * that will be sent to be global SET_DLCI_CONFIGURATION - * command in fr_configure() routine. - */ - card->u.f.dlci_num = min(max(conf->u.fr.dlci_num, 1), 100); - for (i = 0; i < card->u.f.dlci_num; i++) - { - card->u.f.node_dlci[i] = (unsigned short) - conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16; - } - } - if (conf->clocking == WANOPT_INTERNAL) - u.cfg.port |= 0x0001; - if (conf->interface == WANOPT_RS232) - u.cfg.port |= 0x0002; - if (conf->u.fr.t391) - u.cfg.t391 = min(conf->u.fr.t391, 30); - else - u.cfg.t391 = 5; - if (conf->u.fr.t392) - u.cfg.t392 = min(conf->u.fr.t392, 30); - else - u.cfg.t392 = 15; - if (conf->u.fr.n391) - u.cfg.n391 = min(conf->u.fr.n391, 255); - else - u.cfg.n391 = 2; - if (conf->u.fr.n392) - u.cfg.n392 = min(conf->u.fr.n392, 10); - else - u.cfg.n392 = 3; - if (conf->u.fr.n393) - u.cfg.n393 = min(conf->u.fr.n393, 10); - else - u.cfg.n393 = 4; - if (fr_configure(card, &u.cfg)) - return -EIO; - if (card->hw.fwid == SFID_FR508) - { - fr_buf_info_t *buf_info = - (void *) (card->hw.dpmbase + FR508_RXBC_OFFS); - card->rxmb = (void *) (buf_info->rse_next - FR_MB_VECTOR + card->hw.dpmbase); - card->u.f.rxmb_base = (void *) (buf_info->rse_base - FR_MB_VECTOR + card->hw.dpmbase); - card->u.f.rxmb_last = (void *) (buf_info->rse_base + (buf_info->rse_num - 1) * - sizeof(fr_buf_ctl_t) - FR_MB_VECTOR + card->hw.dpmbase); - card->u.f.rx_base = buf_info->buf_base; - card->u.f.rx_top = buf_info->buf_top; - } - card->wandev.mtu = conf->mtu; - card->wandev.bps = conf->bps; - card->wandev.interface = conf->interface; - card->wandev.clocking = conf->clocking; - card->wandev.station = conf->station; - card->poll = &wpf_poll; - card->exec = &wpf_exec; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.state = WAN_DISCONNECTED; - card->wandev.ttl = conf->ttl; - card->wandev.udp_port = conf->udp_port; - card->wandev.enable_tx_int = 0; - card->irq_dis_if_send_count = 0; - card->irq_dis_poll_count = 0; - card->wandev.enable_IPX = conf->enable_IPX; - if (conf->network_number) - card->wandev.network_number = conf->network_number; - else - card->wandev.network_number = 0xDEADBEEF; - /* Intialize global statistics for a card */ - init_global_statistics(card); - TracingEnabled = 0; - return 0; -} - -/******* WAN Device Driver Entry Points *************************************/ - -/*============================================================================ - * Update device status & statistics. - */ - -static int update(wan_device_t * wandev) -{ - sdla_t *card; - /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - if (wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - if (test_and_set_bit(0, (void *) &wandev->critical)) - return -EAGAIN; - card = wandev->private; - fr_get_err_stats(card); - fr_get_stats(card); - wandev->critical = 0; - return 0; -} - -/*============================================================================ - * Create new logical channel. - * This routine is called by the router when ROUTER_IFNEW IOCTL is being - * handled. - * o parse media- and hardware-specific configuration - * o make sure that a new channel can be created - * o allocate resources, if necessary - * o prepare network device structure for registaration. - * - * Return: 0 o.k. - * < 0 failure (channel will not be created) - */ - -static int new_if(wan_device_t * wandev, struct net_device *dev, wanif_conf_t * conf) -{ - sdla_t *card = wandev->private; - fr_channel_t *chan; - int err = 0; - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) - { - printk(KERN_INFO "%s: invalid interface name!\n", - card->devname); - return -EINVAL; - } - /* allocate and initialize private data */ - chan = kmalloc(sizeof(fr_channel_t), GFP_KERNEL); - if (chan == NULL) - return -ENOMEM; - memset(chan, 0, sizeof(fr_channel_t)); - strcpy(chan->name, conf->name); - chan->card = card; - /* verify media address */ - if (is_digit(conf->addr[0])) - { - int dlci = dec_to_uint(conf->addr, 0); - if (dlci && (dlci <= 4095)) - { - chan->dlci = dlci; - } - else - { - printk(KERN_ERR "%s: invalid DLCI %u on interface %s!\n", - wandev->name, dlci, chan->name); - err = -EINVAL; - } - } - else - { - printk(KERN_ERR "%s: invalid media address on interface %s!\n", - wandev->name, chan->name); - err = -EINVAL; - } - if (err) - { - kfree(chan); - return err; - } - /* place cir,be,bc and other channel specific information into the - * chan structure - */ - if (conf->cir) - { - chan->cir = max(1, min(conf->cir, 512)); - chan->cir_status = CIR_ENABLED; - if (conf->bc) - chan->bc = max(1, min(conf->bc, 512)); - if (conf->be) - chan->be = max(0, min(conf->be, 511)); - } - else - chan->cir_status = CIR_DISABLED; - chan->mc = conf->mc; - chan->dlci_configured = DLCI_NOT_CONFIGURED; - chan->tx_int_status = DISABLED; - init_chan_statistics(chan); - /* prepare network device data space for registration */ - dev->name = chan->name; - dev->init = &if_init; - dev->priv = chan; - return 0; -} -/*============================================================================ - * Delete logical channel. - */ -static int del_if(wan_device_t * wandev, struct net_device *dev) -{ - if (dev->priv) - { - kfree(dev->priv); - dev->priv = NULL; - } - return 0; -} - -/****** WANPIPE-specific entry points ***************************************/ - -/*============================================================================ - * Execute adapter interface command. - */ -static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data) -{ - fr_mbox_t *mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err, len; - fr_cmd_t cmd; - if(copy_from_user((void *) &cmd, u_cmd, sizeof(cmd))) - return -EFAULT; - /* execute command */ - do - { - memcpy(&mbox->cmd, &cmd, sizeof(cmd)); - if (cmd.length) - { - if(copy_from_user((void *) &mbox->data, u_data, cmd.length)) - return -EFAULT; - } - if (sdla_exec(mbox)) - err = mbox->cmd.result; - else - return -EIO; - } - while (err && retry-- && fr_event(card, err, mbox)); - - /* return result */ - - if(copy_to_user(u_cmd, (void *) &mbox->cmd, sizeof(fr_cmd_t))) - return -EFAULT; - len = mbox->cmd.length; - if (len && u_data && copy_to_user(u_data, (void *) &mbox->data, len)) - return -EFAULT; - return 0; -} - -/****** Network Device Interface ********************************************/ -/*============================================================================ - * Initialize Linux network interface. - * - * This routine is called only once for each interface, during Linux network - * interface registration. Returning anything but zero will fail interface - * registration. - */ -static int if_init(struct net_device *dev) -{ - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - wan_device_t *wandev = &card->wandev; - - /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = &if_header; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; - /* Initialize media-specific parameters */ - dev->type = ARPHRD_DLCI; /* ARP h/w type */ - dev->mtu = FR_CHANNEL_MTU; - dev->hard_header_len = FR_HEADER_LEN; /* media header length */ - dev->addr_len = 2; /* hardware address length */ - *(unsigned short *) dev->dev_addr = htons(chan->dlci); - /* Initialize hardware parameters (just for reference) */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = (unsigned long)wandev->maddr; - dev->mem_end = dev->mem_start + wandev->msize - 1; - /* Set transmit buffer queue length */ - dev->tx_queue_len = 10; - /* Initialize socket buffers */ - dev_init_buffers(dev); - set_chan_state(dev, WAN_DISCONNECTED); - return 0; -} - -/*============================================================================ - * Open network interface. - * o if this is the first open, then enable communications and interrupts. - * o prevent module from unloading by incrementing use count - * - * Return 0 if O.k. or errno. - */ - -static int if_open(struct net_device *dev) -{ - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - struct net_device *dev2; - int err = 0; - fr508_flags_t *flags = card->flags; - struct timeval tv; - if (dev->start) - return -EBUSY; /* only one open is allowed */ - if (test_and_set_bit(0, (void *) &card->wandev.critical)) - return -EAGAIN; - if (!card->open_cnt) - { - Intr_test_counter = 0; - card->intr_mode = INTR_TEST_MODE; - err = intr_test(card); - if ((err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) { - printk(KERN_INFO - "%s: Interrupt Test Failed, Counter: %i\n", - card->devname, Intr_test_counter); - err = -EIO; - card->wandev.critical = 0; - return err; - } - printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n" - ,card->devname, Intr_test_counter); - /* The following allocates and intializes a circular - * link list of interfaces per card. - */ - card->devs_struct = kmalloc(sizeof(load_sharing_t), GFP_KERNEL); - if (card->devs_struct == NULL) - return -ENOMEM; - card->dev_to_devtint_next = card->devs_struct; - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { - (card->devs_struct)->dev_ptr = dev2; - if (dev2->slave == NULL) - (card->devs_struct)->next = card->dev_to_devtint_next; - else { - (card->devs_struct)->next = kmalloc( - sizeof(load_sharing_t), GFP_KERNEL); - if ((card->devs_struct)->next == NULL) - return -ENOMEM; - card->devs_struct = (card->devs_struct)->next; - } - } - card->devs_struct = card->dev_to_devtint_next; - card->intr_mode = BUFFER_INTR_MODE; - /* - check all the interfaces for the device to see if CIR has - been enabled for any DLCI(s). If so then use the DLCI list - Interrupt mode for fr_set_intr_mode(), otherwise use the default global interrupt mode - */ - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { - if (((fr_channel_t *) dev2->priv)->cir_status - == CIR_ENABLED) { - card->intr_mode = DLCI_LIST_INTR_MODE; - break; - } - } - /* - If you enable comms and then set ints, you get a Tx int as you - perform the SET_INT_TRIGGERS command. So, we only set int - triggers and then adjust the interrupt mask (to disable Tx ints) before enabling comms. - */ - if (card->intr_mode == BUFFER_INTR_MODE) { - if (fr_set_intr_mode(card, 0x03, card->wandev.mtu)) { - err = -EIO; - card->wandev.critical = 0; - return err; - } - printk(KERN_INFO - "%s: Global Buffering Tx Interrupt Mode\n" - ,card->devname); - } else if (card->intr_mode == DLCI_LIST_INTR_MODE) { - if (fr_set_intr_mode(card, 0x83, card->wandev.mtu)) { - err = -EIO; - card->wandev.critical = 0; - return err; - } - printk(KERN_INFO - "%s: DLCI list Tx Interrupt Mode\n", - card->devname); - } - flags->imask &= ~0x02; - if (fr_comm_enable(card)) { - err = -EIO; - card->wandev.critical = 0; - return err; - } - wanpipe_set_state(card, WAN_CONNECTED); - if (card->wandev.station == WANOPT_CPE) { - /* CPE: issue full status enquiry */ - fr_issue_isf(card, FR_ISF_FSE); - } else { /* FR switch: activate DLCI(s) */ - /* For Switch emulation we have to ADD and ACTIVATE - * the DLCI(s) that were configured with the SET_DLCI_ - * CONFIGURATION command. Add and Activate will fail if - * DLCI specified is not included in the list. - * - * Also If_open is called once for each interface. But - * it does not get in here for all the interface. So - * we have to pass the entire list of DLCI(s) to add - * activate routines. - */ - fr_add_dlci(card, - card->u.f.node_dlci[0], card->u.f.dlci_num); - fr_activate_dlci(card, - card->u.f.node_dlci[0], card->u.f.dlci_num); - } - } - dev->mtu = min(dev->mtu, card->wandev.mtu - FR_HEADER_LEN); - dev->interrupt = 0; - dev->tbusy = 0; - dev->start = 1; - wanpipe_open(card); - update_chan_state(dev); - do_gettimeofday(&tv); - chan->router_start_time = tv.tv_sec; - card->wandev.critical = 0; - return err; -} - -/*============================================================================ - * Close network interface. - * o if this is the last open, then disable communications and interrupts. - * o reset flags. - */ - -static int if_close(struct net_device *dev) -{ - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) - return -EAGAIN; - dev->start = 0; - wanpipe_close(card); - if (!card->open_cnt) - { - wanpipe_set_state(card, WAN_DISCONNECTED); - fr_set_intr_mode(card, 0, 0); - fr_comm_disable(card); - } - card->wandev.critical = 0; - return 0; -} - -/*============================================================================ - * Build media header. - * o encapsulate packet according to encapsulation type. - * - * The trick here is to put packet type (Ethertype) into 'protocol' field of - * the socket buffer, so that we don't forget it. If encapsulation fails, - * set skb->protocol to 0 and discard packet later. - * - * Return: media header length. - */ - -static int if_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - int hdr_len = 0; - skb->protocol = type; - hdr_len = wanrouter_encapsulate(skb, dev); - if (hdr_len < 0) - { - hdr_len = 0; - skb->protocol = 0; - } - skb_push(skb, 1); - skb->data[0] = Q922_UI; - ++hdr_len; - return hdr_len; -} - -/*============================================================================ - * Re-build media header. - * - * Return: 1 physical address resolved. - * 0 physical address not resolved - */ - -static int if_rebuild_hdr(struct sk_buff *skb) -{ - struct net_device *dev=skb->dev; - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name); - return 1; -} - -/*============================================================================ - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission) to block a timer-based - * transmit from overlapping. - * o check link state. If link is not up, then drop the packet. - * o check channel status. If it's down then initiate a call. - * o pass a packet to corresponding WAN device. - * o free socket buffer - * - * Return: 0 complete (socket buffer must be freed) - * non-0 packet may be re-transmitted (tbusy must be set) - * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. - */ - -static int if_send(struct sk_buff *skb, struct net_device *dev) -{ - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - int retry = 0, err; - unsigned char *sendpacket; - struct net_device *dev2; - unsigned long check_braddr, check_mcaddr; - fr508_flags_t *adptr_flags = card->flags; - int udp_type, send_data; - fr_dlci_interface_t *dlci_interface = chan->dlci_int_interface; - unsigned long host_cpu_flags; - ++chan->if_send_entry; - - if (dev->tbusy) - { - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this * is only used as a last resort. - */ - ++chan->if_send_busy; - ++chan->ifstats.collisions; - if ((jiffies - chan->tick_counter) < (5 * HZ)) - return 1; - - printk(KERN_INFO "%s: Transmit timed out\n", chan->name); - ++chan->if_send_busy_timeout; - /* unbusy all the interfaces on the card */ - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) - dev2->tbusy = 0; - } - sendpacket = skb->data; - udp_type = udp_pkt_type(skb, card); - if (udp_type == UDP_DRVSTATS_TYPE) - { - ++chan->if_send_DRVSTATS_request; - process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev, 0, - chan); - dev_kfree_skb(skb); - return 0; - } - else if (udp_type == UDP_FPIPE_TYPE) - ++chan->if_send_FPIPE_request; - /* retreive source address in two forms: broadcast & multicast */ - check_braddr = sendpacket[17]; - check_mcaddr = sendpacket[14]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[16]; - check_mcaddr |= sendpacket[15]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[15]; - check_mcaddr |= sendpacket[16]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[14]; - check_mcaddr |= sendpacket[17]; - /* if the Source Address is a Multicast address */ - if ((chan->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001) && - (check_mcaddr <= 0xFFFFFFFE)) - { - printk(KERN_INFO "%s: Multicast Src. Addr. silently discarded\n" - ,card->devname); - dev_kfree_skb(skb); - ++chan->ifstats.tx_dropped; - ++chan->if_send_multicast; - return 0; - } - disable_irq(card->hw.irq); - ++card->irq_dis_if_send_count; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) - { - if (card->wandev.critical == CRITICAL_IN_ISR) - { - ++chan->if_send_critical_ISR; - if (card->intr_mode == DLCI_LIST_INTR_MODE) - { - /* The enable_tx_int flag is set here so that if - * the critical flag is set due to an interrupt - * then we want to enable transmit interrupts - * again. - */ - card->wandev.enable_tx_int = 1; - /* Setting this flag to WAITING_TO_BE_ENABLED - * specifies that interrupt bit has to be - * enabled for that particular interface. - * (delayed interrupt) - */ - chan->tx_int_status = WAITING_TO_BE_ENABLED; - /* This is used for enabling dynamic calculation - * of CIRs relative to the packet length. - */ - chan->pkt_length = skb->len; - dev->tbusy = 1; - chan->tick_counter = jiffies; - } - else - { - card->wandev.enable_tx_int = 1; - dev->tbusy = 1; - chan->tick_counter = jiffies; - } - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - return 1; - } - ++chan->if_send_critical_non_ISR; - ++chan->ifstats.tx_dropped; - dev_kfree_skb(skb); - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - return 0; - } - card->wandev.critical = 0x21; - if (udp_type == UDP_FPIPE_TYPE) - { - err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, - dev, 0, chan); - } - else if (card->wandev.state != WAN_CONNECTED) - { - ++chan->if_send_wan_disconnected; - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - } - else if (chan->state != WAN_CONNECTED) - { - ++chan->if_send_dlci_disconnected; - update_chan_state(dev); - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - } - else if (!is_tx_ready(card, chan)) - { - if (card->intr_mode == DLCI_LIST_INTR_MODE) - { - dlci_interface->gen_interrupt |= 0x40; - dlci_interface->packet_length = skb->len; - } - dev->tbusy = 1; - chan->tick_counter = jiffies; - adptr_flags->imask |= 0x02; - ++chan->if_send_no_bfrs; - retry = 1; - } - else - { - send_data = 1; - /* If it's an IPX packet */ - if (sendpacket[1] == 0x00 && - sendpacket[2] == 0x80 && - sendpacket[6] == 0x81 && - sendpacket[7] == 0x37) - { - if (card->wandev.enable_IPX) - { - switch_net_numbers(sendpacket, - card->wandev.network_number, 0); - } - else - { - /* increment some statistic here! */ - send_data = 0; - } - } - if (send_data) - { - err = (card->hw.fwid == SFID_FR508) ? - fr508_send(card, chan->dlci, 0, skb->len, skb->data) : - fr502_send(card, chan->dlci, 0, skb->len, skb->data); - if (err) - { - if (card->intr_mode == DLCI_LIST_INTR_MODE) - { - dlci_interface->gen_interrupt |= 0x40; - dlci_interface->packet_length = skb->len; - } - dev->tbusy = 1; - chan->tick_counter = jiffies; - adptr_flags->imask |= 0x02; - retry = 1; - ++chan->if_send_adptr_bfrs_full; - ++chan->ifstats.tx_errors; - ++card->wandev.stats.tx_errors; - } - else - { - ++chan->if_send_bfrs_passed_to_adptr; - ++chan->ifstats.tx_packets; - ++card->wandev.stats.tx_packets; - chan->ifstats.tx_bytes += skb->len; - card->wandev.stats.tx_bytes += skb->len; - } - } - } - if (!retry) - dev_kfree_skb(skb); - - card->wandev.critical = 0; - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - return retry; -} - -/*============================================================================ - * Reply to UDP Management system. - * Return nothing. - */ - -static int reply_udp(unsigned char *data, unsigned int mbox_len) -{ - unsigned short len, udp_length, temp, i, ip_length; - unsigned long sum; - /* Set length of packet */ - len = mbox_len + 62; - /* fill in UDP reply */ - data[38] = 0x02; - /* fill in UDP length */ - udp_length = mbox_len + 40; - /* put it on an even boundary */ - if (udp_length & 0x0001) - { - udp_length += 1; - len += 1; - } - temp = (udp_length << 8) | (udp_length >> 8); - memcpy(&data[26], &temp, 2); - /* swap UDP ports */ - memcpy(&temp, &data[22], 2); - memcpy(&data[22], &data[24], 2); - memcpy(&data[24], &temp, 2); - /* add UDP pseudo header */ - temp = 0x1100; - memcpy(&data[udp_length + 22], &temp, 2); - temp = (udp_length << 8) | (udp_length >> 8); - memcpy(&data[udp_length + 24], &temp, 2); - /* calculate UDP checksum */ - data[28] = data[29] = 0; - sum = 0; - for (i = 0; i < udp_length + 12; i += 2) - { - memcpy(&temp, &data[14 + i], 2); - sum += (unsigned long) temp; - } - while (sum >> 16) - sum = (sum & 0xffffUL) + (sum >> 16); - - temp = (unsigned short) sum; - temp = ~temp; - if (temp == 0) - temp = 0xffff; - memcpy(&data[28], &temp, 2); - /* fill in IP length */ - ip_length = udp_length + 20; - temp = (ip_length << 8) | (ip_length >> 8); - memcpy(&data[4], &temp, 2); - /* swap IP addresses */ - memcpy(&temp, &data[14], 2); - memcpy(&data[14], &data[18], 2); - memcpy(&data[18], &temp, 2); - memcpy(&temp, &data[16], 2); - memcpy(&data[16], &data[20], 2); - memcpy(&data[20], &temp, 2); - /* fill in IP checksum */ - data[12] = data[13] = 0; - sum = 0; - for (i = 0; i < 20; i += 2) - { - memcpy(&temp, &data[2 + i], 2); - sum += (unsigned long) temp; - } - while (sum >> 16) - sum = (sum & 0xffffUL) + (sum >> 16); - temp = (unsigned short) sum; - temp = ~temp; - if (temp == 0) - temp = 0xffff; - memcpy(&data[12], &temp, 2); - return len; -} /* reply_udp */ -/* - If incoming is 0 (outgoing)- if the net numbers is ours make it 0 - if incoming is 1 - if the net number is 0 make it ours - */ - -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) -{ - unsigned long pnetwork_number; - pnetwork_number = (unsigned long) ((sendpacket[14] << 24) + - (sendpacket[15] << 16) + (sendpacket[16] << 8) + - sendpacket[17]); - if (!incoming) { - /* If the destination network number is ours, make it 0 */ - if (pnetwork_number == network_number) { - sendpacket[14] = sendpacket[15] = sendpacket[16] = - sendpacket[17] = 0x00; - } - } else { - /* If the incoming network is 0, make it ours */ - if (pnetwork_number == 0) - { - sendpacket[14] = (unsigned char) (network_number >> 24); - sendpacket[15] = (unsigned char) ((network_number & - 0x00FF0000) >> 16); - sendpacket[16] = (unsigned char) ((network_number & - 0x0000FF00) >> 8); - sendpacket[17] = (unsigned char) (network_number & - 0x000000FF); - } - } - pnetwork_number = (unsigned long) ((sendpacket[26] << 24) + - (sendpacket[27] << 16) + (sendpacket[28] << 8) + - sendpacket[29]); - if (!incoming) { - /* If the source network is ours, make it 0 */ - if (pnetwork_number == network_number) - { - sendpacket[26] = sendpacket[27] = sendpacket[28] = - sendpacket[29] = 0x00; - } - } else { - /* If the source network is 0, make it ours */ - if (pnetwork_number == 0) { - sendpacket[26] = (unsigned char) (network_number >> 24); - sendpacket[27] = (unsigned char) ((network_number & - 0x00FF0000) >> 16); - sendpacket[28] = (unsigned char) ((network_number & - 0x0000FF00) >> 8); - sendpacket[29] = (unsigned char) (network_number & - 0x000000FF); - } - } -} /* switch_net_numbers */ - -/*============================================================================ - * Get Ethernet-style interface statistics. - * Return a pointer to struct net_device_stats. - */ - -static struct net_device_stats *if_stats(struct net_device *dev) -{ - fr_channel_t *chan = dev->priv; - if(chan==NULL) - return NULL; - - return &chan->ifstats; -} - -/****** Interrupt Handlers **************************************************/ -/*============================================================================ - * S502 frame relay interrupt service routine. - */ - -static void fr502_isr(sdla_t * card) -{ - fr502_flags_t *flags = card->flags; - switch (flags->iflag) - { - case 0x01: /* receive interrupt */ - fr502_rx_intr(card); - break; - case 0x02: /* transmit interrupt */ - flags->imask &= ~0x02; - tx_intr(card); - break; - default: - spur_intr(card); - } - flags->iflag = 0; -} -/*============================================================================ - * S508 frame relay interrupt service routine. - */ - -static void fr508_isr(sdla_t * card) -{ - fr508_flags_t *flags = card->flags; - fr_buf_ctl_t *bctl; - char *ptr = &flags->iflag; - struct net_device *dev = card->wandev.dev; - struct net_device *dev2; - int i; - unsigned long host_cpu_flags; - unsigned disable_tx_intr = 1; - fr_channel_t *chan; - fr_dlci_interface_t *dlci_interface; - /* This flag prevents nesting of interrupts. See sdla_isr() routine - * in sdlamain.c. - */ - card->in_isr = 1; - ++card->statistics.isr_entry; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) - { - printk(KERN_INFO "fr508_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, flags->iflag); - ++card->statistics.isr_already_critical; - card->in_isr = 0; - return; - } - /* For all interrupts set the critical flag to CRITICAL_RX_INTR. - * If the if_send routine is called with this flag set it will set - * the enable transmit flag to 1. (for a delayed interrupt) - */ - card->wandev.critical = CRITICAL_IN_ISR; - card->dlci_int_mode_unbusy = 0; - card->buff_int_mode_unbusy = 0; - switch (flags->iflag) - { - case 0x01: /* receive interrupt */ - ++card->statistics.isr_rx; - fr508_rx_intr(card); - break; - case 0x02: /* transmit interrupt */ - ++card->statistics.isr_tx; - bctl = (void *) (flags->tse_offs - FR_MB_VECTOR + - card->hw.dpmbase); - bctl->flag = 0xA0; - if (card->intr_mode == DLCI_LIST_INTR_MODE) - { - /* Find the structure and make it unbusy */ - dev = find_channel(card, flags->dlci); - dev->tbusy = 0; - /* This is used to perform devtint at the - * end of the isr - */ - card->dlci_int_mode_unbusy = 1; - /* check to see if any other interfaces are - * busy. If so then do not disable the tx - * interrupts - */ - for (dev2 = card->wandev.dev; dev2; - dev2 = dev2->slave) - { - if (dev2->tbusy == 1) - { - disable_tx_intr = 0; - break; - } - } - if (disable_tx_intr) - flags->imask &= ~0x02; - } - else if (card->intr_mode == BUFFER_INTR_MODE) - { - for (dev2 = card->wandev.dev; dev2; - dev2 = dev2->slave) - { - if (!dev2 || !dev2->start) - { - ++card->statistics.tx_intr_dev_not_started; - continue; - } - if (dev2->tbusy) - { - card->buff_int_mode_unbusy = 1; - ((fr_channel_t *) dev2->priv)->dev_pending_devtint = 1; - dev2->tbusy = 0; - } - else - ((fr_channel_t *) dev2->priv)->dev_pending_devtint = 0; - } - flags->imask &= ~0x02; - } - break; - case 0x08: - Intr_test_counter++; - ++card->statistics.isr_intr_test; - break; - default: - ++card->statistics.isr_spurious; - spur_intr(card); - printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n", - card->devname, flags->iflag); - printk(KERN_INFO "%s: ID Bytes = ", card->devname); - for (i = 0; i < 8; i++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); - break; - } - card->wandev.critical = CRITICAL_INTR_HANDLED; - if (card->wandev.enable_tx_int) - { - if (card->intr_mode == DLCI_LIST_INTR_MODE) - { - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) - { - chan = dev2->priv; - if (chan->tx_int_status == WAITING_TO_BE_ENABLED) - { - dlci_interface = chan->dlci_int_interface; - dlci_interface->gen_interrupt |= 0x40; - dlci_interface->packet_length = chan->pkt_length; - chan->tx_int_status = DISABLED; - } - } - } - card->wandev.enable_tx_int = 0; - flags->imask |= 0x02; - ++card->statistics.isr_enable_tx_int; - } - save_flags(host_cpu_flags); - cli(); - card->in_isr = 0; - card->wandev.critical = 0xD1; - flags->iflag = 0; - card->wandev.critical = 0; - restore_flags(host_cpu_flags); - /* Device is now ready to send. The instant this is executed the If_Send - routine is called. That is why this is put at the bottom of the ISR - to prevent a endless loop condition caused by repeated Interrupts and - enable_tx_int flag. - */ - if (card->dlci_int_mode_unbusy) - mark_bh(NET_BH); - if (card->buff_int_mode_unbusy) - { - for (;;) - { - if (((fr_channel_t *) ((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint == 1) - { - ((fr_channel_t *) ((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint = 0; - mark_bh(NET_BH); - } - if ((card->devs_struct)->next == card->dev_to_devtint_next) - break; - card->devs_struct = (card->devs_struct)->next; - } - card->devs_struct = (card->dev_to_devtint_next)->next; - card->dev_to_devtint_next = card->devs_struct; - } -} -/*============================================================================ - * Receive interrupt handler. - */ - -static void fr502_rx_intr(sdla_t * card) -{ - fr_mbox_t *mbox = card->rxmb; - struct sk_buff *skb; - struct net_device *dev; - fr_channel_t *chan; - unsigned dlci, len; - void *buf; - unsigned char *sendpacket; - unsigned char buf2[3]; - int udp_type; - sdla_mapmem(&card->hw, FR502_RX_VECTOR); - dlci = mbox->cmd.dlci; - len = mbox->cmd.length; - /* Find network interface for this packet */ - dev = find_channel(card, dlci); - if (dev == NULL) - { - /* Invalid channel, discard packet */ - printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n", - card->devname, dlci); - sdla_mapmem(&card->hw, FR_MB_VECTOR); - } - chan = dev->priv; - if (!dev->start) - { - ++chan->ifstats.rx_dropped; - sdla_mapmem(&card->hw, FR_MB_VECTOR); - } - /* Allocate socket buffer */ - skb = dev_alloc_skb(len); - if (skb == NULL) - { - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - ++chan->ifstats.rx_dropped; - sdla_mapmem(&card->hw, FR_MB_VECTOR); - } - /* Copy data to the socket buffer */ - buf = skb_put(skb, len); - memcpy(buf, mbox->data, len); - sdla_mapmem(&card->hw, FR_MB_VECTOR); - /* Check if it's a UDP management packet */ - sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - udp_type = udp_pkt_type(skb, card); - if ((udp_type == UDP_FPIPE_TYPE) || (udp_type == UDP_DRVSTATS_TYPE)) - { - if (udp_type == UDP_DRVSTATS_TYPE) - { - ++chan->rx_intr_DRVSTATS_request; - process_udp_driver_call(UDP_PKT_FRM_NETWORK, card, skb, - dev, dlci, chan); - } - else - { - ++chan->rx_intr_FPIPE_request; - process_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, card, skb, - dev, dlci, chan); - } - } - else - { - /* Decapsulate packet and pass it up the protocol stack */ - skb->dev = dev; - buf = skb_pull(skb, 1); /* remove hardware header */ - if (!wanrouter_type_trans(skb, dev)) - { - /* can't decapsulate packet */ - dev_kfree_skb(skb); - ++chan->ifstats.rx_errors; - ++card->wandev.stats.rx_errors; - } - else - { - netif_rx(skb); - ++chan->ifstats.rx_packets; - ++card->wandev.stats.rx_packets; - chan->ifstats.rx_bytes += skb->len; - card->wandev.stats.rx_bytes += skb->len; - } - } - sdla_mapmem(&card->hw, FR_MB_VECTOR); -} -/*============================================================================ - * Receive interrupt handler. - */ - -static void fr508_rx_intr(sdla_t * card) -{ - fr_buf_ctl_t *frbuf = card->rxmb; - struct sk_buff *skb; - struct net_device *dev; - fr_channel_t *chan; - unsigned dlci, len, offs; - void *buf; - unsigned rx_count = 0; - fr508_flags_t *flags = card->flags; - char *ptr = &flags->iflag; - int i, err, udp_type; - if (frbuf->flag != 0x01) - { - printk(KERN_INFO - "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", - card->devname, (unsigned) frbuf, frbuf->flag); - printk(KERN_INFO "%s: ID Bytes = ", card->devname); - for (i = 0; i < 8; i++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); - ++card->statistics.rx_intr_corrupt_rx_bfr; - return; - } - - do - { - len = frbuf->length; - dlci = frbuf->dlci; - offs = frbuf->offset; - /* Find network interface for this packet */ - dev = find_channel(card, dlci); - chan = dev->priv; - if (dev == NULL) - { - /* Invalid channel, discard packet */ - printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n" - ,card->devname, dlci); - ++card->statistics.rx_intr_on_orphaned_DLCI; - } - else - { - skb = dev_alloc_skb(len); - if (!dev->start || (skb == NULL)) - { - ++chan->ifstats.rx_dropped; - if (dev->start) - { - printk(KERN_INFO - "%s: no socket buffers available!\n", - card->devname); - ++chan->rx_intr_no_socket; - } else - ++chan->rx_intr_dev_not_started; - } - else - { - /* Copy data to the socket buffer */ - if ((offs + len) > card->u.f.rx_top + 1) - { - unsigned tmp = card->u.f.rx_top - offs + 1; - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, offs, buf, tmp); - offs = card->u.f.rx_base; - len -= tmp; - } - buf = skb_put(skb, len); - sdla_peek(&card->hw, offs, buf, len); - udp_type = udp_pkt_type(skb, card); - if (udp_type == UDP_DRVSTATS_TYPE) - { - ++chan->rx_intr_DRVSTATS_request; - process_udp_driver_call( - UDP_PKT_FRM_NETWORK, card, skb, - dev, dlci, chan); - } - else if (udp_type == UDP_FPIPE_TYPE) - { - ++chan->rx_intr_FPIPE_request; - err = process_udp_mgmt_pkt( - UDP_PKT_FRM_NETWORK, card, - skb, dev, dlci, chan); - } - else if (handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number)) - { - if (card->wandev.enable_IPX) - fr508_send(card, dlci, 0, skb->len, skb->data); - } - else - { - /* Decapsulate packet and pass it up the - protocol stack */ - skb->dev = dev; - /* remove hardware header */ - buf = skb_pull(skb, 1); - if (!wanrouter_type_trans(skb, dev)) - { - /* can't decapsulate packet */ - dev_kfree_skb(skb); - ++chan-> - rx_intr_bfr_not_passed_to_stack; - ++chan-> - ifstats.rx_errors; - ++card-> - wandev.stats.rx_errors; - } - else - { - netif_rx(skb); - ++chan->rx_intr_bfr_passed_to_stack; - ++chan->ifstats.rx_packets; - ++card->wandev.stats.rx_packets; - chan->ifstats.rx_bytes += skb->len; - card->wandev.stats.rx_bytes += skb->len; - } - } - } - } - /* Release buffer element and calculate a pointer to the next - one */ - frbuf->flag = 0; - card->rxmb = ++frbuf; - if ((void *) frbuf > card->u.f.rxmb_last) - card->rxmb = card->u.f.rxmb_base; - /* The loop put in is temporary, that is why the break is - * placed here. (?????) - */ - break; - frbuf = card->rxmb; - } - while (frbuf->flag && ((++rx_count) < 4)); -} -/*============================================================================ - * Transmit interrupt handler. - * o print a warning - * o - * If number of spurious interrupts exceeded some limit, then ??? - */ -static void tx_intr(sdla_t * card) -{ - struct net_device *dev = card->wandev.dev; - if (card->intr_mode == BUFFER_INTR_MODE) - { - for (; dev; dev = dev->slave) - { - if (!dev || !dev->start) - { - ++card->statistics.tx_intr_dev_not_started; - continue; - } - dev->tbusy = 0; - mark_bh(NET_BH); - } - } - else - { - dev->tbusy = 0; - mark_bh(NET_BH); - } -} - -/*============================================================================ - * Spurious interrupt handler. - * o print a warning - * o - * If number of spurious interrupts exceeded some limit, then ??? - */ - -static void spur_intr(sdla_t * card) -{ - printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); -} - -/* - Return 0 for non-IPXWAN packet - 1 for IPXWAN packet or IPX is not enabled! - */ - -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number) -{ - int i; - if (sendpacket[1] == 0x00 && - sendpacket[2] == 0x80 && - sendpacket[6] == 0x81 && - sendpacket[7] == 0x37) - { - /* It's an IPX packet */ - if (!enable_IPX) { - /* Return 1 so we don't pass it up the stack. */ - return 1; - } - } - else - { - /* It's not IPX so return and pass it up the stack. */ - return 0; - } - if (sendpacket[24] == 0x90 && - sendpacket[25] == 0x04) - { - /* It's IPXWAN */ - if (sendpacket[10] == 0x02 && - sendpacket[42] == 0x00) - { - /* It's a timer request packet */ - printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", devname); - /* Go through the routing options and answer no to every */ - /* option except Unnumbered RIP/SAP */ - for (i = 49; sendpacket[i] == 0x00; i += 5) - { - /* 0x02 is the option for Unnumbered RIP/SAP */ - if (sendpacket[i + 4] != 0x02) - { - sendpacket[i + 1] = 0; - } - } - /* Skip over the extended Node ID option */ - if (sendpacket[i] == 0x04) - i += 8; - /* We also want to turn off all header compression opt. */ - for (; sendpacket[i] == 0x80;) - { - sendpacket[i + 1] = 0; - i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; - } - /* Set the packet type to timer response */ - sendpacket[42] = 0x01; - printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", devname); - } - else if (sendpacket[42] == 0x02) - { - /* This is an information request packet */ - printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n", devname); - /* Set the packet type to information response */ - sendpacket[42] = 0x03; - /* Set the router name */ - sendpacket[59] = 'F'; - sendpacket[60] = 'P'; - sendpacket[61] = 'I'; - sendpacket[62] = 'P'; - sendpacket[63] = 'E'; - sendpacket[64] = '-'; - sendpacket[65] = CVHexToAscii(network_number >> 28); - sendpacket[66] = CVHexToAscii((network_number & 0x0F000000) >> 24); - sendpacket[67] = CVHexToAscii((network_number & 0x00F00000) >> 20); - sendpacket[68] = CVHexToAscii((network_number & 0x000F0000) >> 16); - sendpacket[69] = CVHexToAscii((network_number & 0x0000F000) >> 12); - sendpacket[70] = CVHexToAscii((network_number & 0x00000F00) >> 8); - sendpacket[71] = CVHexToAscii((network_number & 0x000000F0) >> 4); - sendpacket[72] = CVHexToAscii(network_number & 0x0000000F); - for (i = 73; i < 107; i += 1) - sendpacket[i] = 0; - printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", devname); - } - else - { - printk(KERN_INFO "%s: Unknown IPXWAN packet!\n", devname); - return 0; - } - /* Set the WNodeID to our network address */ - sendpacket[43] = (unsigned char) (network_number >> 24); - sendpacket[44] = (unsigned char) ((network_number & 0x00FF0000) >> 16); - sendpacket[45] = (unsigned char) ((network_number & 0x0000FF00) >> 8); - sendpacket[46] = (unsigned char) (network_number & 0x000000FF); - return 1; - } - /* If we get here, its an IPX-data packet so it'll get passed up the stack. */ - /* switch the network numbers */ - switch_net_numbers(sendpacket, network_number, 1); - return 0; -} - -/****** Background Polling Routines ****************************************/ - -/*============================================================================ - * Main polling routine. - * This routine is repeatedly called by the WANPIPE 'thead' to allow for - * time-dependent housekeeping work. - * - * o fetch asynchronous network events. - * - * Notes: - * 1. This routine may be called on interrupt context with all interrupts - * enabled. Beware! - */ - -static void wpf_poll(sdla_t * card) -{ -/* struct net_device* dev = card->wandev.dev; */ - fr508_flags_t *flags = card->flags; - unsigned long host_cpu_flags; - ++card->statistics.poll_entry; - if (((jiffies - card->state_tick) < HZ) || - (card->intr_mode == INTR_TEST_MODE)) - return; - disable_irq(card->hw.irq); - ++card->irq_dis_poll_count; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) - { - ++card->statistics.poll_already_critical; - save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && - (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - return; - } - card->wandev.critical = 0x11; - ++card->statistics.poll_processed; - /* This is to be changed later ??? */ - /* - if( dev && dev->tbusy && !(flags->imask & 0x02) ) { - printk(KERN_INFO "%s: Wpf_Poll: tbusy = 0x01, imask = 0x%02X\n", card->devname, flags->imask); - } - */ - if (flags->event) - { - fr_mbox_t *mbox = card->mbox; - int err; - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - mbox->cmd.command = FR_READ_STATUS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) - fr_event(card, err, mbox); - } - card->wandev.critical = 0; - save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - card->state_tick = jiffies; -} - -/****** Frame Relay Firmware-Specific Functions *****************************/ - -/*============================================================================ - * Read firmware code version. - * o fill string str with firmware version info. - */ - -static int fr_read_version(sdla_t * card, char *str) -{ - fr_mbox_t *mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - do - { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - mbox->cmd.command = FR_READ_CODE_VERSION; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if (!err && str) - { - int len = mbox->cmd.length; - memcpy(str, mbox->data, len); - str[len] = '\0'; - } - return err; -} -/*============================================================================ - * Set global configuration. - */ - -static int fr_configure(sdla_t * card, fr_conf_t * conf) -{ - fr_mbox_t *mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int dlci_num = card->u.f.dlci_num; - int err, i; - do - { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - memcpy(mbox->data, conf, sizeof(fr_conf_t)); - if (dlci_num) - for (i = 0; i < dlci_num; ++i) - ((fr_conf_t *) mbox->data)->dlci[i] = - card->u.f.node_dlci[i]; - mbox->cmd.command = FR_SET_CONFIG; - mbox->cmd.length = - sizeof(fr_conf_t) + dlci_num * sizeof(short); - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} -/*============================================================================ - * Set DLCI configuration. - */ -static int fr_dlci_configure(sdla_t * card, fr_dlc_conf_t * conf, unsigned dlci) -{ - fr_mbox_t *mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - do - { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - memcpy(mbox->data, conf, sizeof(fr_dlc_conf_t)); - mbox->cmd.dlci = (unsigned short) dlci; - mbox->cmd.command = FR_SET_CONFIG; - mbox->cmd.length = 0x0E; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry--); - return err; -} -/*============================================================================ - * Set interrupt mode. - */ -static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu) -{ - fr_mbox_t *mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - do - { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - if (card->hw.fwid == SFID_FR502) - { - fr502_intr_ctl_t *ictl = (void *) mbox->data; - memset(ictl, 0, sizeof(fr502_intr_ctl_t)); - ictl->mode = mode; - ictl->tx_len = mtu; - mbox->cmd.length = sizeof(fr502_intr_ctl_t); - } - else - { - fr508_intr_ctl_t *ictl = (void *) mbox->data; - memset(ictl, 0, sizeof(fr508_intr_ctl_t)); - ictl->mode = mode; - ictl->tx_len = mtu; - ictl->irq = card->hw.irq; - mbox->cmd.length = sizeof(fr508_intr_ctl_t); - } - mbox->cmd.command = FR_SET_INTR_MODE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} -/*============================================================================ - * Enable communications. - */ -static int fr_comm_enable(sdla_t * card) -{ - fr_mbox_t *mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - do - { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - mbox->cmd.command = FR_COMM_ENABLE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} -/*============================================================================ - * Disable communications. - */ -static int fr_comm_disable(sdla_t * card) -{ - fr_mbox_t *mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - do - { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - mbox->cmd.command = FR_COMM_DISABLE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} -/*============================================================================ - * Get communications error statistics. - */ -static int fr_get_err_stats(sdla_t * card) -{ - fr_mbox_t *mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - mbox->cmd.command = FR_READ_ERROR_STATS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) - { - fr_comm_stat_t *stats = (void *) mbox->data; - card->wandev.stats.rx_over_errors = stats->rx_overruns; - card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; - card->wandev.stats.rx_missed_errors = stats->rx_aborts; - card->wandev.stats.rx_length_errors = stats->rx_too_long; - card->wandev.stats.tx_aborted_errors = stats->tx_aborts; - } - return err; -} -/*============================================================================ - * Get statistics. - */ -static int fr_get_stats(sdla_t * card) -{ - fr_mbox_t *mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - do - { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - mbox->cmd.command = FR_READ_STATISTICS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) - { - fr_link_stat_t *stats = (void *) mbox->data; - card->wandev.stats.rx_frame_errors = stats->rx_bad_format; - card->wandev.stats.rx_dropped = stats->rx_dropped + stats->rx_dropped2; - } - return err; -} -/*============================================================================ - * Add DLCI(s) (Access Node only!). - * This routine will perform the ADD_DLCIs command for the specified DLCI. - */ -static int fr_add_dlci(sdla_t * card, int dlci, int num) -{ - fr_mbox_t *mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err, i; - do - { - unsigned short *dlci_list = (void *) mbox->data; - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - for (i = 0; i < num; ++i) - dlci_list[i] = card->u.f.node_dlci[i]; - mbox->cmd.length = num * sizeof(short); - mbox->cmd.command = FR_ADD_DLCI; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} -/*============================================================================ - * Activate DLCI(s) (Access Node only!). - * This routine will perform the ACTIVATE_DLCIs command with a list of DLCIs. - */ -static int fr_activate_dlci(sdla_t * card, int dlci, int num) -{ - fr_mbox_t *mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err, i; - do - { - unsigned short *dlci_list = (void *) mbox->data; - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - for (i = 0; i < num; ++i) - dlci_list[i] = card->u.f.node_dlci[i]; - mbox->cmd.length = num * sizeof(short); - mbox->cmd.command = FR_ACTIVATE_DLCI; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} -/*============================================================================ - * Issue in-channel signalling frame. - */ -static int fr_issue_isf(sdla_t * card, int isf) -{ - fr_mbox_t *mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - do - { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - mbox->data[0] = isf; - mbox->cmd.length = 1; - mbox->cmd.command = FR_ISSUE_IS_FRAME; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} -/*============================================================================ - * Send a frame (S502 version). - */ -static int fr502_send(sdla_t * card, int dlci, int attr, int len, void *buf) -{ - fr_mbox_t *mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - memcpy(mbox->data, buf, len); - mbox->cmd.dlci = dlci; - mbox->cmd.attr = attr; - mbox->cmd.length = len; - mbox->cmd.command = FR_WRITE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} -/*============================================================================ - * Send a frame (S508 version). - */ -static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf) -{ - fr_mbox_t *mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - mbox->cmd.dlci = dlci; - mbox->cmd.attr = attr; - mbox->cmd.length = len; - mbox->cmd.command = FR_WRITE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) - { - fr_buf_ctl_t *frbuf = (void *) (*(unsigned long *) mbox->data - - FR_MB_VECTOR + card->hw.dpmbase); - sdla_poke(&card->hw, frbuf->offset, buf, len); - frbuf->flag = 0x01; - } - return err; -} - -/****** Firmware Asynchronous Event Handlers ********************************/ - -/*============================================================================ - * Main asynchronous event/error handler. - * This routine is called whenever firmware command returns non-zero - * return code. - * - * Return zero if previous command has to be cancelled. - */ - -static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox) -{ - fr508_flags_t *flags = card->flags; - char *ptr = &flags->iflag; - int i; - switch (event) - { - case FRRES_MODEM_FAILURE: - return fr_modem_failure(card, mbox); - case FRRES_CHANNEL_DOWN: - wanpipe_set_state(card, WAN_DISCONNECTED); - return 1; - case FRRES_CHANNEL_UP: - wanpipe_set_state(card, WAN_CONNECTED); - return 1; - case FRRES_DLCI_CHANGE: - return fr_dlci_change(card, mbox); - case FRRES_DLCI_MISMATCH: - printk(KERN_INFO "%s: DLCI list mismatch!\n", - card->devname); - return 1; - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, mbox->cmd.command); - printk(KERN_INFO "%s: ID Bytes = ", card->devname); - for (i = 0; i < 8; i++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); - break; - case FRRES_DLCI_INACTIVE: - printk(KERN_ERR "%s: DLCI %u is inactive!\n", - card->devname, mbox->cmd.dlci); - break; - case FRRES_CIR_OVERFLOW: - break; - case FRRES_BUFFER_OVERFLOW: - break; - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" - ,card->devname, mbox->cmd.command, event); - } - return 0; -} - -/*============================================================================ - * Handle modem error. - * - * Return zero if previous command has to be cancelled. - */ -static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox) -{ - printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)\n", - card->devname, mbox->data[0]); - switch (mbox->cmd.command) - { - case FR_WRITE: - case FR_READ: - return 0; - } - return 1; -} -/*============================================================================ - * Handle DLCI status change. - * - * Return zero if previous command has to be cancelled. - */ -static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox) -{ - dlci_status_t *status = (void *) mbox->data; - int cnt = mbox->cmd.length / sizeof(dlci_status_t); - fr_dlc_conf_t cfg; - fr_channel_t *chan; - struct net_device *dev2; - for (; cnt; --cnt, ++status) - { - unsigned short dlci = status->dlci; - struct net_device *dev = find_channel(card, dlci); - if (dev == NULL) - { - printk(KERN_INFO - "%s: CPE contains unconfigured DLCI= %d\n", - card->devname, dlci); - } - else - { - if (status->state & 0x01) - { - printk(KERN_INFO - "%s: DLCI %u has been deleted!\n", - card->devname, dlci); - if (dev && dev->start) - set_chan_state(dev, WAN_DISCONNECTED); - } - else if (status->state & 0x02) - { - printk(KERN_INFO - "%s: DLCI %u becomes active!\n", - card->devname, dlci); - chan = dev->priv; - /* This flag is used for configuring specific - DLCI(s) when they become active. - */ - chan->dlci_configured = DLCI_CONFIG_PENDING; - if (dev && dev->start) - set_chan_state(dev, WAN_CONNECTED); - } - } - } - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) - { - chan = dev2->priv; - if (chan->dlci_configured == DLCI_CONFIG_PENDING) - { - memset(&cfg, 0, sizeof(cfg)); - if (chan->cir_status == CIR_DISABLED) - { - cfg.cir_fwd = cfg.cir_bwd = 16; - cfg.bc_fwd = cfg.bc_bwd = 16; - cfg.conf_flags = 0x0001; - printk(KERN_INFO "%s: CIR Disabled for %s\n", - card->devname, chan->name); - } else if (chan->cir_status == CIR_ENABLED) { - cfg.cir_fwd = cfg.cir_bwd = chan->cir; - cfg.bc_fwd = cfg.bc_bwd = chan->bc; - cfg.be_fwd = cfg.be_bwd = chan->be; - cfg.conf_flags = 0x0000; - printk(KERN_INFO "%s: CIR Enabled for %s\n", - card->devname, chan->name); - } - if (fr_dlci_configure(card, &cfg, chan->dlci)) - { - printk(KERN_INFO - "%s: DLCI Configure failed for %d\n", - card->devname, chan->dlci); - return 1; - } - chan->dlci_configured = DLCI_CONFIGURED; - /* Read the interface byte mapping into the channel - structure. - */ - if (card->intr_mode == DLCI_LIST_INTR_MODE) - read_DLCI_IB_mapping(card, chan); - } - } - return 1; -} -/******* Miscellaneous ******************************************************/ - -/*============================================================================ - * Update channel state. - */ -static int update_chan_state(struct net_device *dev) -{ - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - fr_mbox_t *mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - int dlci_found = 0; - - do - { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - mbox->cmd.command = FR_LIST_ACTIVE_DLCI; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) - { - unsigned short *list = (void *) mbox->data; - int cnt = mbox->cmd.length / sizeof(short); - for (; cnt; --cnt, ++list) - { - if (*list == chan->dlci) - { - dlci_found = 1; - set_chan_state(dev, WAN_CONNECTED); - break; - } - } - if (!dlci_found) - printk(KERN_INFO "%s: DLCI %u is inactive\n", - card->devname, chan->dlci); - } - - return err; -} -/*============================================================================ - * Set channel state. - */ -static void set_chan_state(struct net_device *dev, int state) -{ - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - unsigned long flags; - - save_flags(flags); - cli(); - - if (chan->state != state) - { - switch (state) - { - case WAN_CONNECTED: - printk(KERN_INFO "%s: interface %s connected!\n" - ,card->devname, dev->name); - break; - case WAN_CONNECTING: - printk(KERN_INFO - "%s: interface %s connecting...\n", - card->devname, dev->name); - break; - case WAN_DISCONNECTED: - printk(KERN_INFO - "%s: interface %s disconnected!\n", - card->devname, dev->name); - break; - } - chan->state = state; - } - chan->state_tick = jiffies; - restore_flags(flags); -} - -/*============================================================================ - * Find network device by its channel number. - */ -static struct net_device *find_channel(sdla_t * card, unsigned dlci) -{ - struct net_device *dev; - for (dev = card->wandev.dev; dev; dev = dev->slave) - if (((fr_channel_t *) dev->priv)->dlci == dlci) - break; - return dev; -} -/*============================================================================ - * Check to see if a frame can be sent. If no transmit buffers available, - * enable transmit interrupts. - * - * Return: 1 - Tx buffer(s) available - * 0 - no buffers available - */ - -static int is_tx_ready(sdla_t * card, fr_channel_t * chan) -{ - if (card->hw.fwid == SFID_FR508) - { - unsigned char sb = inb(card->hw.port); - if (sb & 0x02) - return 1; - } - else - { - fr502_flags_t *flags = card->flags; - if (flags->tx_ready) - return 1; - flags->imask |= 0x02; - } - return 0; -} - -/*============================================================================ - * Convert decimal string to unsigned integer. - * If len != 0 then only 'len' characters of the string are converted. - */ -static unsigned int dec_to_uint(unsigned char *str, int len) -{ - unsigned val; - if (!len) - len = strlen(str); - for (val = 0; len && is_digit(*str); ++str, --len) - val = (val * 10) + (*str - (unsigned) '0'); - return val; -} - -/*============================================================================== - * Process UDP call of type FPIPE8ND - */ - -static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, int dlci, fr_channel_t * chan) -{ - int c_retry = MAX_CMD_RETRY; - unsigned char *data; - unsigned char *buf; - unsigned char buf2[5]; - unsigned int loops, frames, len; - unsigned long data_ptr; - unsigned short real_len, buffer_length; - struct sk_buff *new_skb; - unsigned char *sendpacket; - fr_mbox_t *mbox = card->mbox; - int err; - struct timeval tv; - int udp_mgmt_req_valid = 1; - sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) - { - printk(KERN_INFO - "%s: Error allocating memory for UDP management cmnd 0x%02X", - card->devname, data[47]); - ++chan->UDP_FPIPE_mgmt_kmalloc_err; - return 1; - } - memcpy(data, sendpacket, skb->len); - switch (data[47]) - { - /* FPIPE_ENABLE_TRACE */ - case 0x41: - /* FPIPE_DISABLE_TRACE */ - case 0x42: - /* FPIPE_GET_TRACE_INFO */ - case 0x43: - /* SET FT1 MODE */ - case 0x81: - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) - { - ++chan->UDP_FPIPE_mgmt_direction_err; - udp_mgmt_req_valid = 0; - break; - } - /* FPIPE_FT1_READ_STATUS */ - case 0x44: - /* FT1 MONITOR STATUS */ - case 0x80: - if (card->hw.fwid != SFID_FR508) - { - ++chan->UDP_FPIPE_mgmt_adptr_type_err; - udp_mgmt_req_valid = 0; - } - break; - default: - break; - } - if (!udp_mgmt_req_valid) - { - /* set length to 0 */ - data[48] = data[49] = 0; - /* set return code */ - data[50] = (card->hw.fwid != SFID_FR508) ? 0x1F : 0xCD; - } - else - { - switch (data[47]) - { - /* FPIPE_ENABLE_TRACE */ - case 0x41: - if (!TracingEnabled) - { - do - { - /* SET_TRACE_CONFIGURATION */ - mbox->cmd.command = 0x60; - mbox->cmd.length = 1; - mbox->cmd.dlci = 0x00; - mbox->data[0] = 0x37; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - } - while (err && c_retry-- && fr_event(card, err, mbox)); - - if (err) - { - TracingEnabled = 0; - /* set the return code */ - data[50] = mbox->cmd.result; - mbox->cmd.length = 0; - break; - } - /* get num_frames */ - sdla_peek(&card->hw, 0x9000, &num_frames, 2); - sdla_peek(&card->hw, 0x9002, &curr_trace_addr,4); - start_trace_addr = curr_trace_addr; - /* MAX_SEND_BUFFER_SIZE - - * sizeof(UDP_MGMT_PACKET) - 41 */ - available_buffer_space = 1926; - /* set return code */ - data[50] = 0; - } - else - { - /* set return code to line trace already - enabled */ - data[50] = 1; - } - mbox->cmd.length = 0; - TracingEnabled = 1; - break; - /* FPIPE_DISABLE_TRACE */ - case 0x42: - if (TracingEnabled) - { - do - { - /* SET_TRACE_CONFIGURATION */ - mbox->cmd.command = 0x60; - mbox->cmd.length = 1; - mbox->cmd.dlci = 0x00; - mbox->data[0] = 0x36; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && c_retry-- && fr_event(card, err, mbox)); - } - /* set return code */ - data[50] = 0; - mbox->cmd.length = 0; - TracingEnabled = 0; - break; - /* FPIPE_GET_TRACE_INFO */ - case 0x43: - /* Line trace cannot be performed on the 502 */ - if (!TracingEnabled) - { - /* set return code */ - data[50] = 1; - mbox->cmd.length = 0; - break; - } - buffer_length = 0; - loops = (num_frames < 20) ? num_frames : 20; - for (frames = 0; frames < loops; frames += 1) - { - sdla_peek(&card->hw, curr_trace_addr, &buf2, 1); - /* no data on board so exit */ - if (buf2[0] == 0x00) - break; - /* 1+sizeof(FRAME_DATA) = 9 */ - if ((available_buffer_space - buffer_length) < 9) - { - /* indicate we have more frames on board - and exit */ - data[62] |= 0x02; - break; - } - /* get frame status */ - sdla_peek(&card->hw, curr_trace_addr + 0x05, &data[62 + buffer_length], 1); - /* get time stamp */ - sdla_peek(&card->hw, curr_trace_addr + 0x06, &data[66 + buffer_length], 2); - /* get frame length */ - sdla_peek(&card->hw, curr_trace_addr + 0x01, &data[64 + buffer_length], 2); - /* get pointer to real data */ - sdla_peek(&card->hw, curr_trace_addr + 0x0C,&data_ptr, 4); - /* see if we can fit the frame into the user buffer */ - memcpy(&real_len, &data[64 + buffer_length], 2); - if (data_ptr == 0 || real_len + 8 > available_buffer_space) - { - data[63 + buffer_length] = 0x00; - } - else - { - /* we can take it next time */ - if (available_buffer_space - buffer_length < real_len + 8) - { - data[62] |= 0x02; - break; - } - /* ok, get the frame */ - data[63 + buffer_length] = 0x01; - /* get the data */ - sdla_peek(&card->hw, data_ptr, &data[68 + buffer_length], real_len); - /* zero the opp flag to show we got the frame */ - buf2[0] = 0x00; - sdla_poke(&card->hw, curr_trace_addr, &buf2, 1); - /* now move onto the next frame */ - curr_trace_addr += 16; - /* check if we passed the last address */ - if (curr_trace_addr >= (start_trace_addr + num_frames * 16)) - curr_trace_addr = start_trace_addr; - /* update buffer length and make sure - its even */ - if (data[63 + buffer_length] == 0x01) - buffer_length += real_len - 1; - /* for the header */ - buffer_length += 8; - if (buffer_length & 0x0001) - buffer_length += 1; - } - } - /* ok now set the total number of frames passed in the - high 5 bits */ - data[62] = (frames << 3) | data[62]; - /* set the data length */ - mbox->cmd.length = buffer_length; - memcpy(&data[48], &buffer_length, 2); - data[50] = 0; - break; - /* FPIPE_FT1_READ_STATUS */ - case 0x44: - sdla_peek(&card->hw, 0xF020, &data[62], 2); - data[48] = 2; - data[49] = 0; - data[50] = 0; - mbox->cmd.length = 2; - break; - /* FPIPE_FLUSH_DRIVER_STATS */ - case 0x48: - init_chan_statistics(chan); - init_global_statistics(card); - mbox->cmd.length = 0; - break; - case 0x49: - do_gettimeofday(&tv); - chan->router_up_time = tv.tv_sec - chan->router_start_time; - *(unsigned long *) &data[62] = chan->router_up_time; - mbox->cmd.length = 4; - break; - /* FPIPE_KILL_BOARD */ - case 0x50: - break; - /* FT1 MONITOR STATUS */ - case 0x80: - if (data[62] == 1) - { - if (rCount++ != 0) - { - data[50] = 0; - mbox->cmd.length = 1; - break; - } - } - /* Disable FT1 MONITOR STATUS */ - if (data[62] == 0) - { - if (--rCount != 0) - { - data[50] = 0; - mbox->cmd.length = 1; - break; - } - } - default: - do - { - memcpy(&mbox->cmd, &sendpacket[47], sizeof(fr_cmd_t)); - if (mbox->cmd.length) - memcpy(&mbox->data, &sendpacket[62],mbox->cmd.length); - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && c_retry-- && fr_event(card, err, mbox)); - - if (!err) - { - ++chan->UDP_FPIPE_mgmt_adptr_cmnd_OK; - memcpy(data, sendpacket, skb->len); - memcpy(&data[47], &mbox->cmd, sizeof(fr_cmd_t)); - if (mbox->cmd.length) - { - memcpy(&data[62], &mbox->data,mbox->cmd.length); - } - } - else - { - ++chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout; - } - } - } - /* Fill UDP TTL */ - data[10] = card->wandev.ttl; - len = reply_udp(data, mbox->cmd.length); - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) - { - err = fr508_send(card, dlci, 0, len, data); - if (err) - ++chan->UDP_FPIPE_mgmt_adptr_send_passed; - else - ++chan->UDP_FPIPE_mgmt_adptr_send_failed; - dev_kfree_skb(skb); - } - else - { - /* Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) - { - /* copy data into new_skb */ - buf = skb_put(new_skb, len); - memcpy(buf, data, len); - /* Decapsulate packet and pass it up the protocol - stack */ - new_skb->dev = dev; - buf = skb_pull(new_skb, 1); /* remove hardware header */ - if (!wanrouter_type_trans(new_skb, dev)) - { - ++chan->UDP_FPIPE_mgmt_not_passed_to_stack; - /* can't decapsulate packet */ - dev_kfree_skb(new_skb); - } - else - { - ++chan->UDP_FPIPE_mgmt_passed_to_stack; - netif_rx(new_skb); - } - } - else - { - ++chan->UDP_FPIPE_mgmt_no_socket; - printk(KERN_INFO - "%s: UDP mgmt cmnd, no socket buffers available!\n", - card->devname); - } - } - kfree(data); - return 0; -} -/*============================================================================== - * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_ - * TEST_COUNTER times. - */ - -static int intr_test(sdla_t * card) -{ - fr_mbox_t *mb = card->mbox; - int err, i; - /* The critical flag is unset here because we want to get into the - ISR without the flag already set. The If_open sets the flag. - */ - card->wandev.critical = 0; - err = fr_set_intr_mode(card, 0x08, card->wandev.mtu); - if (err == CMD_OK) - { - for (i = 0; i < MAX_INTR_TEST_COUNTER; i++) - { - /* Run command READ_CODE_VERSION */ - memset(&mb->cmd, 0, sizeof(fr_cmd_t)); - mb->cmd.length = 0; - mb->cmd.command = 0x40; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) - fr_event(card, err, mb); - } - } - else - { - return err; - } - err = fr_set_intr_mode(card, 0, card->wandev.mtu); - if (err != CMD_OK) - return err; - card->wandev.critical = 1; - return 0; -} -/*============================================================================ - * Process UDP call of type DRVSTATS. - */ -static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, int dlci, fr_channel_t * chan) -{ - int c_retry = MAX_CMD_RETRY; - unsigned char *sendpacket; - unsigned char buf2[5]; - unsigned char *data; - unsigned char *buf; - unsigned int len; - fr_mbox_t *mbox = card->mbox; - struct sk_buff *new_skb; - int err; - sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) - { - printk(KERN_INFO - "%s: Error allocating memory for UDP DRIVER STATS cmnd0x%02X" - ,card->devname, data[45]); - ++chan->UDP_DRVSTATS_mgmt_kmalloc_err; - return 1; - } - memcpy(data, sendpacket, skb->len); - switch (data[47]) - { - case 0x45: - *(unsigned long *) &data[62] = chan->if_send_entry; - *(unsigned long *) &data[66] = chan->if_send_skb_null; - *(unsigned long *) &data[70] = chan->if_send_broadcast; - *(unsigned long *) &data[74] = chan->if_send_multicast; - *(unsigned long *) &data[78] = chan->if_send_critical_ISR; - *(unsigned long *) &data[82] = chan->if_send_critical_non_ISR; - *(unsigned long *) &data[86] = chan->if_send_busy; - *(unsigned long *) &data[90] = chan->if_send_busy_timeout; - *(unsigned long *) &data[94] = chan->if_send_DRVSTATS_request; - *(unsigned long *) &data[98] = chan->if_send_FPIPE_request; - *(unsigned long *) &data[102] = chan->if_send_wan_disconnected; - *(unsigned long *) &data[106] = chan->if_send_dlci_disconnected; - *(unsigned long *) &data[110] = chan->if_send_no_bfrs; - *(unsigned long *) &data[114] = chan->if_send_adptr_bfrs_full; - *(unsigned long *) &data[118] = chan->if_send_bfrs_passed_to_adptr; - *(unsigned long *) &data[120] = card->irq_dis_if_send_count; - mbox->cmd.length = 62; - break; - case 0x46: - *(unsigned long *) &data[62] = card->statistics.isr_entry; - *(unsigned long *) &data[66] = card->statistics.isr_already_critical; - *(unsigned long *) &data[70] = card->statistics.isr_rx; - *(unsigned long *) &data[74] = card->statistics.isr_tx; - *(unsigned long *) &data[78] = card->statistics.isr_intr_test; - *(unsigned long *) &data[82] = card->statistics.isr_spurious; - *(unsigned long *) &data[86] = card->statistics.isr_enable_tx_int; - *(unsigned long *) &data[90] = card->statistics.tx_intr_dev_not_started; - *(unsigned long *) &data[94] = card->statistics.rx_intr_corrupt_rx_bfr; - *(unsigned long *) &data[98] = card->statistics.rx_intr_on_orphaned_DLCI; - *(unsigned long *) &data[102] = chan->rx_intr_no_socket; - *(unsigned long *) &data[106] = chan->rx_intr_dev_not_started; - *(unsigned long *) &data[110] = chan->rx_intr_DRVSTATS_request; - *(unsigned long *) &data[114] = chan->rx_intr_FPIPE_request; - *(unsigned long *) &data[118] = chan->rx_intr_bfr_not_passed_to_stack; - *(unsigned long *) &data[122] = chan->rx_intr_bfr_passed_to_stack; - mbox->cmd.length = 64; - break; - case 0x47: - *(unsigned long *) &data[62] = chan->UDP_FPIPE_mgmt_kmalloc_err; - *(unsigned long *) &data[66] = chan->UDP_FPIPE_mgmt_adptr_type_err; - *(unsigned long *) &data[70] = chan->UDP_FPIPE_mgmt_direction_err; - *(unsigned long *) &data[74] = chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout; - *(unsigned long *) &data[78] = chan->UDP_FPIPE_mgmt_adptr_cmnd_OK; - *(unsigned long *) &data[82] = chan->UDP_FPIPE_mgmt_adptr_send_passed; - *(unsigned long *) &data[86] = chan->UDP_FPIPE_mgmt_adptr_send_failed; - *(unsigned long *) &data[90] = chan->UDP_FPIPE_mgmt_no_socket; - *(unsigned long *) &data[94] = chan->UDP_FPIPE_mgmt_not_passed_to_stack; - *(unsigned long *) &data[98] = chan->UDP_FPIPE_mgmt_passed_to_stack; - *(unsigned long *) &data[102] = chan->UDP_DRVSTATS_mgmt_kmalloc_err; - *(unsigned long *) &data[106] = chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; - *(unsigned long *) &data[110] = chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; - *(unsigned long *) &data[114] = chan->UDP_DRVSTATS_mgmt_adptr_send_passed; - *(unsigned long *) &data[118] = chan->UDP_DRVSTATS_mgmt_adptr_send_failed; - *(unsigned long *) &data[122] = chan->UDP_DRVSTATS_mgmt_no_socket; - *(unsigned long *) &data[126] = chan->UDP_DRVSTATS_mgmt_not_passed_to_stack; - *(unsigned long *) &data[130] = chan->UDP_DRVSTATS_mgmt_passed_to_stack; - *(unsigned long *) &data[134] = card->statistics.poll_entry; - *(unsigned long *) &data[138] = card->statistics.poll_already_critical; - *(unsigned long *) &data[142] = card->statistics.poll_processed; - *(unsigned long *) &data[144] = card->irq_dis_poll_count; - mbox->cmd.length = 86; - break; - default: - do - { - memcpy(&mbox->cmd, &sendpacket[47], sizeof(fr_cmd_t)); - if (mbox->cmd.length) - memcpy(&mbox->data, &sendpacket[62], mbox->cmd.length); - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && c_retry-- && fr_event(card, err, mbox)); - - if (!err) - { - ++chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; - memcpy(data, sendpacket, skb->len); - memcpy(&data[47], &mbox->cmd, sizeof(fr_cmd_t)); - if (mbox->cmd.length) - memcpy(&data[62], &mbox->data, mbox->cmd.length); - } - else - { - ++chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; - } - } - /* Fill UDP TTL */ - data[10] = card->wandev.ttl; - len = reply_udp(data, mbox->cmd.length); - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) - { - err = fr508_send(card, dlci, 0, len, data); - if (err) - ++chan->UDP_DRVSTATS_mgmt_adptr_send_failed; - else - ++chan->UDP_DRVSTATS_mgmt_adptr_send_passed; - dev_kfree_skb(skb); - } - else - { - /* Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) - { - /* copy data into new_skb */ - buf = skb_put(new_skb, len); - memcpy(buf, data, len); - /* Decapsulate packet and pass it up the - protocol stack */ - new_skb->dev = dev; - /* remove hardware header */ - buf = skb_pull(new_skb, 1); - if (!wanrouter_type_trans(new_skb, dev)) - { - /* can't decapsulate packet */ - ++chan->UDP_DRVSTATS_mgmt_not_passed_to_stack; - dev_kfree_skb(new_skb); - } - else - { - ++chan->UDP_DRVSTATS_mgmt_passed_to_stack; - netif_rx(new_skb); - } - } - else - { - ++chan->UDP_DRVSTATS_mgmt_no_socket; - printk(KERN_INFO "%s: UDP mgmt cmnd, no socket buffers available!\n", card->devname); - } - } - kfree(data); - return 0; -} - -/*============================================================================== - * Determine what type of UDP call it is. DRVSTATS or FPIPE8ND ? - */ - -static int udp_pkt_type(struct sk_buff *skb, sdla_t * card) -{ - unsigned char *sendpacket; - unsigned char buf2[5]; - sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - if (sendpacket[2] == 0x45 && /* IP packet */ - sendpacket[11] == 0x11 && /* UDP packet */ - sendpacket[24] == buf2[1] && /* UDP Port */ - sendpacket[25] == buf2[0] && - sendpacket[38] == 0x01) - { - if (sendpacket[30] == 0x46 && /* FPIPE8ND: Signature */ - sendpacket[31] == 0x50 && - sendpacket[32] == 0x49 && - sendpacket[33] == 0x50 && - sendpacket[34] == 0x45 && - sendpacket[35] == 0x38 && - sendpacket[36] == 0x4E && - sendpacket[37] == 0x44) - { - return UDP_FPIPE_TYPE; - } else if (sendpacket[30] == 0x44 && /* DRVSTATS: Signature */ - sendpacket[31] == 0x52 && - sendpacket[32] == 0x56 && - sendpacket[33] == 0x53 && - sendpacket[34] == 0x54 && - sendpacket[35] == 0x41 && - sendpacket[36] == 0x54 && - sendpacket[37] == 0x53) - { - return UDP_DRVSTATS_TYPE; - } - else - return UDP_INVALID_TYPE; - } - else - return UDP_INVALID_TYPE; -} -/*============================================================================== - * Initializes the Statistics values in the fr_channel structure. - */ - -void init_chan_statistics(fr_channel_t * chan) -{ - chan->if_send_entry = 0; - chan->if_send_skb_null = 0; - chan->if_send_broadcast = 0; - chan->if_send_multicast = 0; - chan->if_send_critical_ISR = 0; - chan->if_send_critical_non_ISR = 0; - chan->if_send_busy = 0; - chan->if_send_busy_timeout = 0; - chan->if_send_FPIPE_request = 0; - chan->if_send_DRVSTATS_request = 0; - chan->if_send_wan_disconnected = 0; - chan->if_send_dlci_disconnected = 0; - chan->if_send_no_bfrs = 0; - chan->if_send_adptr_bfrs_full = 0; - chan->if_send_bfrs_passed_to_adptr = 0; - chan->rx_intr_no_socket = 0; - chan->rx_intr_dev_not_started = 0; - chan->rx_intr_FPIPE_request = 0; - chan->rx_intr_DRVSTATS_request = 0; - chan->rx_intr_bfr_not_passed_to_stack = 0; - chan->rx_intr_bfr_passed_to_stack = 0; - chan->UDP_FPIPE_mgmt_kmalloc_err = 0; - chan->UDP_FPIPE_mgmt_direction_err = 0; - chan->UDP_FPIPE_mgmt_adptr_type_err = 0; - chan->UDP_FPIPE_mgmt_adptr_cmnd_OK = 0; - chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout = 0; - chan->UDP_FPIPE_mgmt_adptr_send_passed = 0; - chan->UDP_FPIPE_mgmt_adptr_send_failed = 0; - chan->UDP_FPIPE_mgmt_not_passed_to_stack = 0; - chan->UDP_FPIPE_mgmt_passed_to_stack = 0; - chan->UDP_FPIPE_mgmt_no_socket = 0; - chan->UDP_DRVSTATS_mgmt_kmalloc_err = 0; - chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK = 0; - chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout = 0; - chan->UDP_DRVSTATS_mgmt_adptr_send_passed = 0; - chan->UDP_DRVSTATS_mgmt_adptr_send_failed = 0; - chan->UDP_DRVSTATS_mgmt_not_passed_to_stack = 0; - chan->UDP_DRVSTATS_mgmt_passed_to_stack = 0; - chan->UDP_DRVSTATS_mgmt_no_socket = 0; -} -/*============================================================================== - * Initializes the Statistics values in the Sdla_t structure. - */ - -void init_global_statistics(sdla_t * card) -{ - /* Intialize global statistics for a card */ - card->statistics.isr_entry = 0; - card->statistics.isr_already_critical = 0; - card->statistics.isr_rx = 0; - card->statistics.isr_tx = 0; - card->statistics.isr_intr_test = 0; - card->statistics.isr_spurious = 0; - card->statistics.isr_enable_tx_int = 0; - card->statistics.rx_intr_corrupt_rx_bfr = 0; - card->statistics.rx_intr_on_orphaned_DLCI = 0; - card->statistics.tx_intr_dev_not_started = 0; - card->statistics.poll_entry = 0; - card->statistics.poll_already_critical = 0; - card->statistics.poll_processed = 0; -} - -static void read_DLCI_IB_mapping(sdla_t * card, fr_channel_t * chan) -{ - fr_mbox_t *mbox = card->mbox; - int retry = MAX_CMD_RETRY; - dlci_IB_mapping_t *result; - int err, counter, found; - do - { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - mbox->cmd.command = FR_READ_DLCI_IB_MAPPING; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - - if (mbox->cmd.result != 0) - printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", chan->name); - - counter = mbox->cmd.length / sizeof(dlci_IB_mapping_t); - result = (void *) mbox->data; - found = 0; - for (; counter; --counter, ++result) - { - if (result->dlci == chan->dlci) - { - printk(KERN_INFO "%s: DLCI= %d, IB addr = %lx for %s\n" - ,card->devname, result->dlci, result->addr_value ,chan->name); - chan->IB_addr = result->addr_value; - chan->dlci_int_interface = (void *) (card->hw.dpmbase + - (chan->IB_addr & 0x00001FFF)); - found = 1; - break; - } - } - if (!found) - printk(KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n", - card->devname, chan->dlci); -} - -/****** End *****************************************************************/ diff -u --recursive --new-file v2.3.20/linux/drivers/net/sdla_ppp.c linux/drivers/net/sdla_ppp.c --- v2.3.20/linux/drivers/net/sdla_ppp.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/sdla_ppp.c Wed Dec 31 16:00:00 1969 @@ -1,2261 +0,0 @@ -/***************************************************************************** -* sdla_ppp.c WANPIPE(tm) Multiprotocol WAN Link Driver. PPP module. -* -* Author: Jaspreet Singh -* -* 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 /* printk(), and other useful stuff */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include /* kmalloc(), kfree() */ -#include /* WAN router definitions */ -#include /* WANPIPE common user API definitions */ -#include /* ARPHRD_* defines */ -#include /* htons(), etc. */ -#include /* copyto/from user */ -#define _GNUC_ -#include /* PPP firmware API definitions */ - -/****** Defines & Macros ****************************************************/ - -#ifdef _DEBUG_ -#define STATIC -#else -#define STATIC static -#endif -#define PPP_DFLT_MTU 1500 /* default MTU */ -#define PPP_MAX_MTU 4000 /* maximum MTU */ -#define PPP_HDR_LEN 1 -#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ -#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ - -/* For handle_IPXWAN() */ -#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) - -/******Data Structures*****************************************************/ -/* This structure is placed in the private data area of the device structure. - * The card structure used to occupy the private area but now the following - * structure will incorporate the card structure along with PPP specific data - */ - -typedef struct ppp_private_area -{ - sdla_t *card; - unsigned long router_start_time; /*router start time in sec */ - unsigned long tick_counter; /*used for 5 second counter */ - unsigned mc; /*multicast support on or off */ - /* PPP specific statistics */ - unsigned long if_send_entry; - unsigned long if_send_skb_null; - unsigned long if_send_broadcast; - unsigned long if_send_multicast; - unsigned long if_send_critical_ISR; - unsigned long if_send_critical_non_ISR; - unsigned long if_send_busy; - unsigned long if_send_busy_timeout; - unsigned long if_send_DRVSTATS_request; - unsigned long if_send_PTPIPE_request; - unsigned long if_send_wan_disconnected; - unsigned long if_send_adptr_bfrs_full; - unsigned long if_send_protocol_error; - unsigned long if_send_tx_int_enabled; - unsigned long if_send_bfr_passed_to_adptr; - unsigned long rx_intr_no_socket; - unsigned long rx_intr_DRVSTATS_request; - unsigned long rx_intr_PTPIPE_request; - unsigned long rx_intr_bfr_not_passed_to_stack; - unsigned long rx_intr_bfr_passed_to_stack; - unsigned long UDP_PTPIPE_mgmt_kmalloc_err; - unsigned long UDP_PTPIPE_mgmt_adptr_type_err; - unsigned long UDP_PTPIPE_mgmt_direction_err; - unsigned long UDP_PTPIPE_mgmt_adptr_cmnd_timeout; - unsigned long UDP_PTPIPE_mgmt_adptr_cmnd_OK; - unsigned long UDP_PTPIPE_mgmt_passed_to_adptr; - unsigned long UDP_PTPIPE_mgmt_passed_to_stack; - unsigned long UDP_PTPIPE_mgmt_no_socket; - unsigned long UDP_DRVSTATS_mgmt_kmalloc_err; - unsigned long UDP_DRVSTATS_mgmt_adptr_type_err; - unsigned long UDP_DRVSTATS_mgmt_direction_err; - unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; - unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK; - unsigned long UDP_DRVSTATS_mgmt_passed_to_adptr; - unsigned long UDP_DRVSTATS_mgmt_passed_to_stack; - unsigned long UDP_DRVSTATS_mgmt_no_socket; - unsigned long router_up_time; -} ppp_private_area_t; - -/* variable for keeping track of enabling/disabling FT1 monitor status */ - -static int rCount = 0; -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -/****** Function Prototypes *************************************************/ - -/* WAN link driver entry points. These are called by the WAN router module. */ -static int update(wan_device_t * wandev); -static int new_if(wan_device_t * wandev, struct net_device *dev, - wanif_conf_t * conf); -static int del_if(wan_device_t * wandev, struct net_device *dev); -/* WANPIPE-specific entry points */ -static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data); -/* Network device interface */ -static int if_init(struct net_device *dev); -static int if_open(struct net_device *dev); -static int if_close(struct net_device *dev); -static int if_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len); -static int if_rebuild_hdr(struct sk_buff *skb); -static int if_send(struct sk_buff *skb, struct net_device *dev); -static struct enet_statistics *if_stats(struct net_device *dev); -/* PPP firmware interface functions */ -static int ppp_read_version(sdla_t * card, char *str); -static int ppp_configure(sdla_t * card, void *data); -static int ppp_set_intr_mode(sdla_t * card, unsigned mode); -static int ppp_comm_enable(sdla_t * card); -static int ppp_comm_disable(sdla_t * card); -static int ppp_get_err_stats(sdla_t * card); -static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto); -static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb); -/* Interrupt handlers */ -STATIC void wpp_isr(sdla_t * card); -static void rx_intr(sdla_t * card); -static void tx_intr(sdla_t * card); -/* Background polling routines */ -static void wpp_poll(sdla_t * card); -static void poll_active(sdla_t * card); -static void poll_connecting(sdla_t * card); -static void poll_disconnected(sdla_t * card); -/* Miscellaneous functions */ -static int config502(sdla_t * card); -static int config508(sdla_t * card); -static void show_disc_cause(sdla_t * card, unsigned cause); -static unsigned char bps_to_speed_code(unsigned long bps); -static int reply_udp(unsigned char *data, unsigned int mbox_len); -static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, ppp_private_area_t * ppp_priv_area); -static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, ppp_private_area_t * ppp_priv_area); -static void init_ppp_tx_rx_buff(sdla_t * card); -static int intr_test(sdla_t * card); -static int udp_pkt_type(struct sk_buff *skb, sdla_t * card); -static void init_ppp_priv_struct(ppp_private_area_t * ppp_priv_area); -static void init_global_statistics(sdla_t * card); -static int Intr_test_counter; -static char TracingEnabled; -static unsigned long curr_trace_addr; -static unsigned long start_trace_addr; -static unsigned short available_buffer_space; -/* IPX functions */ -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto); - -/****** Public Functions ****************************************************/ - -/*============================================================================ - * PPP protocol initialization routine. - * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. - * - * Return: 0 o.k. - * < 0 failure. - */ -int wpp_init(sdla_t * card, wandev_conf_t * conf) -{ - union { - char str[80]; - } u; - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_PPP) { - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); - return -EINVAL; - } - /* Initialize protocol-specific fields */ - switch (card->hw.fwid) { - case SFID_PPP502: - card->mbox = (void *) (card->hw.dpmbase + PPP502_MB_OFFS); - card->flags = (void *) (card->hw.dpmbase + PPP502_FLG_OFFS); - break; - case SFID_PPP508: - card->mbox = (void *) (card->hw.dpmbase + PPP508_MB_OFFS); - card->flags = (void *) (card->hw.dpmbase + PPP508_FLG_OFFS); - break; - default: - return -EINVAL; - } - /* Read firmware version. Note that when adapter initializes, it - * clears the mailbox, so it may appear that the first command was - * executed successfully when in fact it was merely erased. To work - * around this, we execute the first command twice. - */ - if (ppp_read_version(card, NULL) || ppp_read_version(card, u.str)) - return -EIO; - printk(KERN_INFO "%s: running PPP firmware v%s\n", card->devname, u.str); - /* Adjust configuration and set defaults */ - card->wandev.mtu = (conf->mtu) ? - min(conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU; - card->wandev.bps = conf->bps; - card->wandev.interface = conf->interface; - card->wandev.clocking = conf->clocking; - card->wandev.station = conf->station; - card->isr = &wpp_isr; - card->poll = &wpp_poll; - card->exec = &wpp_exec; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.state = WAN_DISCONNECTED; - card->wandev.udp_port = conf->udp_port; - card->wandev.ttl = conf->ttl; - card->irq_dis_if_send_count = 0; - card->irq_dis_poll_count = 0; - TracingEnabled = 0; - card->wandev.enable_IPX = conf->enable_IPX; - if (conf->network_number) - card->wandev.network_number = conf->network_number; - else - card->wandev.network_number = 0xDEADBEEF; - /* initialize global statistics */ - init_global_statistics(card); - return 0; -} - -/******* WAN Device Driver Entry Points *************************************/ - -/*============================================================================ - * Update device status & statistics. - */ -static int update(wan_device_t * wandev) -{ - sdla_t *card; - /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - if (wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - if (test_and_set_bit(0, (void *) &wandev->critical)) - return -EAGAIN; - card = wandev->private; - ppp_get_err_stats(card); - wandev->critical = 0; - return 0; -} - -/*============================================================================ - * Create new logical channel. - * This routine is called by the router when ROUTER_IFNEW IOCTL is being - * handled. - * o parse media- and hardware-specific configuration - * o make sure that a new channel can be created - * o allocate resources, if necessary - * o prepare network device structure for registaration. - * - * Return: 0 o.k. - * < 0 failure (channel will not be created) - */ - -static int new_if(wan_device_t * wandev, struct net_device *dev, wanif_conf_t * conf) -{ - sdla_t *card = wandev->private; - ppp_private_area_t *ppp_priv_area; - if (wandev->ndev) - return -EEXIST; - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { - printk(KERN_INFO "%s: invalid interface name!\n", - card->devname); - return -EINVAL; - } - /* allocate and initialize private data */ - ppp_priv_area = kmalloc(sizeof(ppp_private_area_t), GFP_KERNEL); - if (ppp_priv_area == NULL) - return -ENOMEM; - memset(ppp_priv_area, 0, sizeof(ppp_private_area_t)); - ppp_priv_area->card = card; - /* initialize data */ - strcpy(card->u.p.if_name, conf->name); - /* initialize data in ppp_private_area structure */ - init_ppp_priv_struct(ppp_priv_area); - ppp_priv_area->mc = conf->mc; - /* prepare network device data space for registration */ - dev->name = card->u.p.if_name; - dev->init = &if_init; - dev->priv = ppp_priv_area; - return 0; -} - -/*============================================================================ - * Delete logical channel. - */ - -static int del_if(wan_device_t * wandev, struct net_device *dev) -{ - if (dev->priv) { - kfree(dev->priv); - dev->priv = NULL; - } - return 0; -} - -/****** WANPIPE-specific entry points ***************************************/ - -/*============================================================================ - * Execute adapter interface command. - */ - -static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data) -{ - ppp_mbox_t *mbox = card->mbox; - int len; - if(copy_from_user((void *) &mbox->cmd, u_cmd, sizeof(ppp_cmd_t))) - return -EFAULT; - len = mbox->cmd.length; - if (len) { - if(copy_from_user((void *) &mbox->data, u_data, len)) - return -EFAULT; - } - /* execute command */ - if (!sdla_exec(mbox)) - return -EIO; - /* return result */ - if(copy_to_user(u_cmd, (void *) &mbox->cmd, sizeof(ppp_cmd_t))) - return -EFAULT; - len = mbox->cmd.length; - if (len && u_data && copy_to_user(u_data, (void *) &mbox->data, len)) - return -EFAULT; - return 0; -} - -/****** Network Device Interface ********************************************/ - -/*============================================================================ - * Initialize Linux network interface. - * - * This routine is called only once for each interface, during Linux network - * interface registration. Returning anything but zero will fail interface - * registration. - */ - -static int if_init(struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - wan_device_t *wandev = &card->wandev; - - /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = &if_header; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; - /* Initialize media-specific parameters */ - dev->type = ARPHRD_PPP; /* ARP h/w type */ - dev->mtu = wandev->mtu; - dev->hard_header_len = PPP_HDR_LEN; /* media header length */ - /* Initialize hardware parameters (just for reference) */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = (unsigned long)wandev->maddr; - dev->mem_end = dev->mem_start + wandev->msize - 1; - /* Set transmit buffer queue length */ - dev->tx_queue_len = 100; - /* Initialize socket buffers */ - dev_init_buffers(dev); - return 0; -} - -/*============================================================================ - * Open network interface. - * o enable communications and interrupts. - * o prevent module from unloading by incrementing use count - * - * Return 0 if O.k. or errno. - */ - -static int if_open(struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - ppp_flags_t *flags = card->flags; - struct timeval tv; - int err = 0; - if (dev->start) - return -EBUSY; /* only one open is allowed */ - if (test_and_set_bit(0, (void *) &card->wandev.critical)) - return -EAGAIN; - if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card)) { - err = -EIO; - card->wandev.critical = 0; - return err; - } - Intr_test_counter = 0; - err = intr_test(card); - if ((err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) { - printk(KERN_INFO "%s: Interrupt Test Failed, Counter: %i\n", - card->devname, Intr_test_counter); - err = -EIO; - card->wandev.critical = 0; - return err; - } - printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", - card->devname, Intr_test_counter); - /* Initialize Rx/Tx buffer control fields */ - init_ppp_tx_rx_buff(card); - if (ppp_set_intr_mode(card, 0x03)) { - err = -EIO; - card->wandev.critical = 0; - return err; - } - flags->imask &= ~0x02; - if (ppp_comm_enable(card)) { - err = -EIO; - card->wandev.critical = 0; - return err; - } - wanpipe_set_state(card, WAN_CONNECTING); - wanpipe_open(card); - dev->mtu = min(dev->mtu, card->wandev.mtu); - dev->interrupt = 0; - dev->tbusy = 0; - dev->start = 1; - do_gettimeofday(&tv); - ppp_priv_area->router_start_time = tv.tv_sec; - card->wandev.critical = 0; - return err; -} - -/*============================================================================ - * Close network interface. - * o if this is the last open, then disable communications and interrupts. - * o reset flags. - */ - -static int if_close(struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) - return -EAGAIN; - dev->start = 0; - wanpipe_close(card); - wanpipe_set_state(card, WAN_DISCONNECTED); - ppp_set_intr_mode(card, 0); - ppp_comm_disable(card); - card->wandev.critical = 0; - return 0; -} - -/*============================================================================ - * Build media header. - * - * The trick here is to put packet type (Ethertype) into 'protocol' field of - * the socket buffer, so that we don't forget it. If packet type is not - * supported, set skb->protocol to 0 and discard packet later. - * - * Return: media header length. - */ - -static int if_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - switch (type) - { - case ETH_P_IP: - case ETH_P_IPX: - skb->protocol = type; - break; - default: - skb->protocol = 0; - } - return PPP_HDR_LEN; -} - -/*============================================================================ - * Re-build media header. - * - * Return: 1 physical address resolved. - * 0 physical address not resolved - */ - -static int if_rebuild_hdr(struct sk_buff *skb) -{ - struct net_device *dev=skb->dev; - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name); - return 1; -} - -/*============================================================================ - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission) to block a timer-based - * transmit from overlapping. - * o check link state. If link is not up, then drop the packet. - * o execute adapter send command. - * o free socket buffer - * - * Return: 0 complete (socket buffer must be freed) - * non-0 packet may be re-transmitted (tbusy must be set) - * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. - */ - -static int if_send(struct sk_buff *skb, struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - unsigned char *sendpacket; - unsigned long check_braddr, check_mcaddr; - unsigned long host_cpu_flags; - ppp_flags_t *flags = card->flags; - int retry = 0; - int err, udp_type; - ++ppp_priv_area->if_send_entry; - if (skb == NULL) { - /* If we get here, some higher layer thinks we've missed an - * tx-done interrupt. - */ - printk(KERN_INFO "%s: interface %s got kicked!\n", - card->devname, dev->name); - ++ppp_priv_area->if_send_skb_null; - mark_bh(NET_BH); - return 0; - } - if (dev->tbusy) { - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this - * is only used as a last resort. - */ - ++ppp_priv_area->if_send_busy; - ++card->wandev.stats.collisions; - if ((jiffies - ppp_priv_area->tick_counter) < (5 * HZ)) { - return 1; - } - printk(KERN_INFO "%s: Transmit times out\n", card->devname); - ++ppp_priv_area->if_send_busy_timeout; - /* unbusy the card (because only one interface per card) */ - dev->tbusy = 0; - } - sendpacket = skb->data; - udp_type = udp_pkt_type(skb, card); - if (udp_type == UDP_DRVSTATS_TYPE) { - ++ppp_priv_area->if_send_DRVSTATS_request; - process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev, - ppp_priv_area); - dev_kfree_skb(skb); - return 0; - } else if (udp_type == UDP_PTPIPE_TYPE) - ++ppp_priv_area->if_send_PTPIPE_request; - /* retreive source address in two forms: broadcast & multicast */ - check_braddr = sendpacket[15]; - check_mcaddr = sendpacket[12]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[14]; - check_mcaddr |= sendpacket[13]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[13]; - check_mcaddr |= sendpacket[14]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[12]; - check_mcaddr |= sendpacket[15]; - /* if the Source Address is a Multicast address */ - if ((ppp_priv_area->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001) - && (check_mcaddr <= 0xFFFFFFFE)) { - printk(KERN_INFO "%s: Mutlicast Src. Addr. silently discarded\n" - ,card->devname); - dev_kfree_skb(skb); - ++ppp_priv_area->if_send_multicast; - ++card->wandev.stats.tx_dropped; - return 0; - } - disable_irq(card->hw.irq); - ++card->irq_dis_if_send_count; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) { - if (card->wandev.critical == CRITICAL_IN_ISR) { - /* If the critical flag is set due to an Interrupt - * then set enable transmit interrupt flag to enable - * transmit interrupt. (delay interrupt) - */ - card->wandev.enable_tx_int = 1; - dev->tbusy = 1; - /* set the counter to see if we get the interrupt in - * 5 seconds. - */ - ppp_priv_area->tick_counter = jiffies; - ++ppp_priv_area->if_send_critical_ISR; - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - return 1; - } - dev_kfree_skb(skb); - ++ppp_priv_area->if_send_critical_non_ISR; - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - return 0; - } - if (udp_type == UDP_PTPIPE_TYPE) { - err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, - dev, ppp_priv_area); - } else if (card->wandev.state != WAN_CONNECTED) { - ++ppp_priv_area->if_send_wan_disconnected; - ++card->wandev.stats.tx_dropped; - } else if (!skb->protocol) { - ++ppp_priv_area->if_send_protocol_error; - ++card->wandev.stats.tx_errors; - } else { - /*If it's IPX change the network numbers to 0 if they're ours. */ - if (skb->protocol == ETH_P_IPX) { - if (card->wandev.enable_IPX) { - switch_net_numbers(skb->data, - card->wandev.network_number, 0); - } else { - ++card->wandev.stats.tx_dropped; - goto tx_done; - } - } - if (ppp_send(card, skb->data, skb->len, skb->protocol)) { - retry = 1; - dev->tbusy = 1; - ++ppp_priv_area->if_send_adptr_bfrs_full; - ++ppp_priv_area->if_send_tx_int_enabled; - ppp_priv_area->tick_counter = jiffies; - ++card->wandev.stats.tx_errors; - flags->imask |= 0x02; /* unmask Tx interrupts */ - } else { - ++ppp_priv_area->if_send_bfr_passed_to_adptr; - ++card->wandev.stats.tx_packets; - card->wandev.stats.tx_bytes += skb->len; - } - } -tx_done: - if (!retry) { - dev_kfree_skb(skb); - } - card->wandev.critical = 0; - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - return retry; -} - -/*============================================================================ - * Reply to UDP Management system. - * Return length of reply. - */ - -static int reply_udp(unsigned char *data, unsigned int mbox_len) -{ - unsigned short len, udp_length, temp, i, ip_length; - unsigned long sum; - /* Set length of packet */ - len = mbox_len + 60; - /* fill in UDP reply */ - data[36] = 0x02; - /* fill in UDP length */ - udp_length = mbox_len + 40; - /* put it on an even boundary */ - if (udp_length & 0x0001) { - udp_length += 1; - len += 1; - } - temp = (udp_length << 8) | (udp_length >> 8); - memcpy(&data[24], &temp, 2); - /* swap UDP ports */ - memcpy(&temp, &data[20], 2); - memcpy(&data[20], &data[22], 2); - memcpy(&data[22], &temp, 2); - /* add UDP pseudo header */ - temp = 0x1100; - memcpy(&data[udp_length + 20], &temp, 2); - temp = (udp_length << 8) | (udp_length >> 8); - memcpy(&data[udp_length + 22], &temp, 2); - /* calculate UDP checksum */ - data[26] = data[27] = 0; - sum = 0; - for (i = 0; i < udp_length + 12; i += 2) { - memcpy(&temp, &data[12 + i], 2); - sum += (unsigned long) temp; - } - while (sum >> 16) { - sum = (sum & 0xffffUL) + (sum >> 16); - } - temp = (unsigned short) sum; - temp = ~temp; - if (temp == 0) - temp = 0xffff; - memcpy(&data[26], &temp, 2); - /* fill in IP length */ - ip_length = udp_length + 20; - temp = (ip_length << 8) | (ip_length >> 8); - memcpy(&data[2], &temp, 2); - /* swap IP addresses */ - memcpy(&temp, &data[12], 2); - memcpy(&data[12], &data[16], 2); - memcpy(&data[16], &temp, 2); - memcpy(&temp, &data[14], 2); - memcpy(&data[14], &data[18], 2); - memcpy(&data[18], &temp, 2); - /* fill in IP checksum */ - data[10] = data[11] = 0; - sum = 0; - for (i = 0; i < 20; i += 2) { - memcpy(&temp, &data[i], 2); - sum += (unsigned long) temp; - } - while (sum >> 16) { - sum = (sum & 0xffffUL) + (sum >> 16); - } - temp = (unsigned short) sum; - temp = ~temp; - if (temp == 0) - temp = 0xffff; - memcpy(&data[10], &temp, 2); - return len; -} /* reply_udp */ - -/* - If incoming is 0 (outgoing)- if the net numbers is ours make it 0 - if incoming is 1 - if the net number is 0 make it ours - */ - -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) -{ - unsigned long pnetwork_number; - pnetwork_number = (unsigned long) ((sendpacket[6] << 24) + - (sendpacket[7] << 16) + (sendpacket[8] << 8) + - sendpacket[9]); - if (!incoming) { - /* If the destination network number is ours, make it 0 */ - if (pnetwork_number == network_number) { - sendpacket[6] = sendpacket[7] = sendpacket[8] = - sendpacket[9] = 0x00; - } - } else { - /* If the incoming network is 0, make it ours */ - if (pnetwork_number == 0) { - sendpacket[6] = (unsigned char) (network_number >> 24); - sendpacket[7] = (unsigned char) ((network_number & - 0x00FF0000) >> 16); - sendpacket[8] = (unsigned char) ((network_number & - 0x0000FF00) >> 8); - sendpacket[9] = (unsigned char) (network_number & - 0x000000FF); - } - } - pnetwork_number = (unsigned long) ((sendpacket[18] << 24) + - (sendpacket[19] << 16) + (sendpacket[20] << 8) + - sendpacket[21]); - if (!incoming) { - /* If the source network is ours, make it 0 */ - if (pnetwork_number == network_number) { - sendpacket[18] = sendpacket[19] = sendpacket[20] = - sendpacket[21] = 0x00; - } - } else { - /* If the source network is 0, make it ours */ - if (pnetwork_number == 0) { - sendpacket[18] = (unsigned char) (network_number >> 24); - sendpacket[19] = (unsigned char) ((network_number & - 0x00FF0000) >> 16); - sendpacket[20] = (unsigned char) ((network_number & - 0x0000FF00) >> 8); - sendpacket[21] = (unsigned char) (network_number & - 0x000000FF); - } - } -} /* switch_net_numbers */ - -/*============================================================================ - * Get Ethernet-style interface statistics. - * Return a pointer to struct enet_statistics. - */ - -static struct enet_statistics *if_stats(struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card; - - /* - * Device is down:No statistics - */ - - if(ppp_priv_area==NULL) - return NULL; - - card = ppp_priv_area->card; - return &card->wandev.stats; -} - -/****** PPP Firmware Interface Functions ************************************/ - -/*============================================================================ - * Read firmware code version. - * Put code version as ASCII string in str. - */ - -static int ppp_read_version(sdla_t * card, char *str) -{ - ppp_mbox_t *mb = card->mbox; - int err; - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.command = PPP_READ_CODE_VERSION; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) - ppp_error(card, err, mb); - else if (str) { - int len = mb->cmd.length; - memcpy(str, mb->data, len); - str[len] = '\0'; - } - return err; -} - -/*============================================================================ - * Configure PPP firmware. - */ - -static int ppp_configure(sdla_t * card, void *data) -{ - ppp_mbox_t *mb = card->mbox; - int data_len = (card->hw.fwid == SFID_PPP502) ? - sizeof(ppp502_conf_t) : sizeof(ppp508_conf_t); - int err; - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - memcpy(mb->data, data, data_len); - mb->cmd.length = data_len; - mb->cmd.command = PPP_SET_CONFIG; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) - ppp_error(card, err, mb); - return err; -} - -/*============================================================================ - * Set interrupt mode. - */ - -static int ppp_set_intr_mode(sdla_t * card, unsigned mode) -{ - ppp_mbox_t *mb = card->mbox; - int err; - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->data[0] = mode; - switch (card->hw.fwid) { - case SFID_PPP502: - mb->cmd.length = 1; - break; - case SFID_PPP508: - default: - mb->data[1] = card->hw.irq; - mb->cmd.length = 2; - } - mb->cmd.command = PPP_SET_INTR_FLAGS; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) - ppp_error(card, err, mb); - return err; -} - -/*============================================================================ - * Enable communications. - */ - -static int ppp_comm_enable(sdla_t * card) -{ - ppp_mbox_t *mb = card->mbox; - int err; - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.command = PPP_COMM_ENABLE; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) - ppp_error(card, err, mb); - return err; -} - -/*============================================================================ - * Disable communications. - */ - -static int ppp_comm_disable(sdla_t * card) -{ - ppp_mbox_t *mb = card->mbox; - int err; - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.command = PPP_COMM_DISABLE; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) - ppp_error(card, err, mb); - return err; -} - -/*============================================================================ - * Get communications error statistics. - */ - -static int ppp_get_err_stats(sdla_t * card) -{ - ppp_mbox_t *mb = card->mbox; - int err; - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.command = PPP_READ_ERROR_STATS; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err == CMD_OK) { - ppp_err_stats_t *stats = (void *) mb->data; - card->wandev.stats.rx_over_errors = stats->rx_overrun; - card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; - card->wandev.stats.rx_missed_errors = stats->rx_abort; - card->wandev.stats.rx_length_errors = stats->rx_lost; - card->wandev.stats.tx_aborted_errors = stats->tx_abort; - } else - ppp_error(card, err, mb); - return err; -} - -/*============================================================================ - * Send packet. - * Return: 0 - o.k. - * 1 - no transmit buffers available - */ - -static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto) -{ - ppp_buf_ctl_t *txbuf = card->u.p.txbuf; - unsigned long addr; - if (txbuf->flag) - return 1 - ; - if (card->hw.fwid == SFID_PPP502) - addr = (txbuf->buf.o_p[1] << 8) + txbuf->buf.o_p[0]; - else - addr = txbuf->buf.ptr; - sdla_poke(&card->hw, addr, data, len); - txbuf->length = len; /* frame length */ - if (proto == ETH_P_IPX) - txbuf->proto = 0x01; /* protocol ID */ - txbuf->flag = 1; /* start transmission */ - /* Update transmit buffer control fields */ - card->u.p.txbuf = ++txbuf; - if ((void *) txbuf > card->u.p.txbuf_last) - card->u.p.txbuf = card->u.p.txbuf_base; - return 0; -} - -/****** Firmware Error Handler **********************************************/ - -/*============================================================================ - * Firmware error handler. - * This routine is called whenever firmware command returns non-zero - * return code. - * - * Return zero if previous command has to be cancelled. - */ - -static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb) -{ - unsigned cmd = mb->cmd.command; - switch (err) { - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd); - break; - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" - ,card->devname, cmd, err); - } - return 0; -} - -/****** Interrupt Handlers **************************************************/ - -/*============================================================================ - * PPP interrupt service routine. - */ - -STATIC void wpp_isr(sdla_t * card) -{ - ppp_flags_t *flags = card->flags; - char *ptr = &flags->iflag; - unsigned long host_cpu_flags; - struct net_device *dev = card->wandev.dev; - int i; - card->in_isr = 1; - ++card->statistics.isr_entry; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) { - ++card->statistics.isr_already_critical; - printk(KERN_INFO "%s: Critical while in ISR!\n", card->devname); - card->in_isr = 0; - return; - } - /* For all interrupts set the critical flag to CRITICAL_IN_ISR. - * If the if_send routine is called with this flag set it will set - * the enable transmit flag to 1. (for a delayed interrupt) - */ - card->wandev.critical = CRITICAL_IN_ISR; - card->buff_int_mode_unbusy = 0; - switch (flags->iflag) { - case 0x01: /* receive interrupt */ - ++card->statistics.isr_rx; - rx_intr(card); - break; - case 0x02: /* transmit interrupt */ - ++card->statistics.isr_tx; - flags->imask &= ~0x02; - dev->tbusy = 0; - card->buff_int_mode_unbusy = 1; - break; - case 0x08: - ++Intr_test_counter; - ++card->statistics.isr_intr_test; - break; - default: /* unexpected interrupt */ - ++card->statistics.isr_spurious; - printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", - card->devname, flags->iflag); - printk(KERN_INFO "%s: ID Bytes = ", card->devname); - for (i = 0; i < 8; i++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); - } - /* The critical flag is set to CRITICAL_INTR_HANDLED to let the - * if_send call know that the interrupt is handled so that - * transmit interrupts are not enabled again. - */ - card->wandev.critical = CRITICAL_INTR_HANDLED; - /* If the enable transmit interrupt flag is set then enable transmit - * interrupt on the board. This only goes through if if_send is called - * and the critical flag is set due to an Interrupt. - */ - if (card->wandev.enable_tx_int) { - flags->imask |= 0x02; - card->wandev.enable_tx_int = 0; - ++card->statistics.isr_enable_tx_int; - } - save_flags(host_cpu_flags); - cli(); - card->in_isr = 0; - flags->iflag = 0; - card->wandev.critical = 0; - restore_flags(host_cpu_flags); - if (card->buff_int_mode_unbusy) - mark_bh(NET_BH); -} - -/*============================================================================ - * Receive interrupt handler. - */ - -static void rx_intr(sdla_t * card) -{ - ppp_buf_ctl_t *rxbuf = card->rxmb; - struct net_device *dev = card->wandev.dev; - ppp_private_area_t *ppp_priv_area; - struct sk_buff *skb; - unsigned len; - void *buf; - int i, err; - ppp_flags_t *flags = card->flags; - char *ptr = &flags->iflag; - int udp_type; - if (rxbuf->flag != 0x01) { - printk(KERN_INFO - "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", - card->devname, (unsigned) rxbuf, rxbuf->flag); - printk(KERN_INFO "%s: ID Bytes = ", card->devname); - for (i = 0; i < 8; i++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); - ++card->statistics.rx_intr_corrupt_rx_bfr; - return; - } - if (dev && dev->start) { - len = rxbuf->length; - ppp_priv_area = dev->priv; - /* Allocate socket buffer */ - skb = dev_alloc_skb(len); - if (skb != NULL) { - /* Copy data to the socket buffer */ - if (card->hw.fwid == SFID_PPP502) { - unsigned addr = (rxbuf->buf.o_p[1] << 8) + - rxbuf->buf.o_p[0]; - buf = skb_put(skb, len); - sdla_peek(&card->hw, addr, buf, len); - } else { - unsigned addr = rxbuf->buf.ptr; - if ((addr + len) > card->u.p.rx_top + 1) { - unsigned tmp = card->u.p.rx_top - addr - + 1; - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, addr, buf, tmp); - addr = card->u.p.rx_base; - len -= tmp; - } - buf = skb_put(skb, len); - sdla_peek(&card->hw, addr, buf, len); - } - /* Decapsulate packet */ - switch (rxbuf->proto) { - case 0x00: - skb->protocol = htons(ETH_P_IP); - break; - case 0x01: - skb->protocol = htons(ETH_P_IPX); - break; - } - udp_type = udp_pkt_type(skb, card); - if (udp_type == UDP_DRVSTATS_TYPE) { - ++ppp_priv_area->rx_intr_DRVSTATS_request; - process_udp_driver_call( - UDP_PKT_FRM_NETWORK, card, skb, - dev, ppp_priv_area); - dev_kfree_skb(skb); - } else if (udp_type == UDP_PTPIPE_TYPE) { - ++ppp_priv_area->rx_intr_PTPIPE_request; - err = process_udp_mgmt_pkt( - UDP_PKT_FRM_NETWORK, card, - skb, dev, ppp_priv_area); - dev_kfree_skb(skb); - } else if (handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) { - if (card->wandev.enable_IPX) { - ppp_send(card, skb->data, skb->len, ETH_P_IPX); - dev_kfree_skb(skb); - } else { - ++card->wandev.stats.rx_dropped; - } - } else { - /* Pass it up the protocol stack */ - skb->dev = dev; - skb->mac.raw = skb->data; - netif_rx(skb); - ++card->wandev.stats.rx_packets; - card->wandev.stats.rx_bytes += skb->len; - ++ppp_priv_area->rx_intr_bfr_passed_to_stack; - } - } else { - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - ++card->wandev.stats.rx_dropped; - ++ppp_priv_area->rx_intr_no_socket; - } - } else - ++card->statistics.rx_intr_dev_not_started; - /* Release buffer element and calculate a pointer to the next one */ - rxbuf->flag = (card->hw.fwid == SFID_PPP502) ? 0xFF : 0x00; - card->rxmb = ++rxbuf; - if ((void *) rxbuf > card->u.p.rxbuf_last) - card->rxmb = card->u.p.rxbuf_base; -} - -/*============================================================================ - * Transmit interrupt handler. - */ - -static void tx_intr(sdla_t * card) -{ - struct net_device *dev = card->wandev.dev; - if (!dev || !dev->start) { - ++card->statistics.tx_intr_dev_not_started; - return; - } - dev->tbusy = 0; - mark_bh(NET_BH); -} - -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) -{ - int i; - if (proto == htons(ETH_P_IPX)) { - /* It's an IPX packet */ - if (!enable_IPX) { - /* Return 1 so we don't pass it up the stack. */ - return 1; - } - } else { - /* It's not IPX so pass it up the stack. */ - return 0; - } - if (sendpacket[16] == 0x90 && - sendpacket[17] == 0x04) { - /* It's IPXWAN */ - if (sendpacket[2] == 0x02 && - sendpacket[34] == 0x00) { - /* It's a timer request packet */ - printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", devname); - /* Go through the routing options and answer no to every */ - /* option except Unnumbered RIP/SAP */ - for (i = 41; sendpacket[i] == 0x00; i += 5) { - /* 0x02 is the option for Unnumbered RIP/SAP */ - if (sendpacket[i + 4] != 0x02) { - sendpacket[i + 1] = 0; - } - } - /* Skip over the extended Node ID option */ - if (sendpacket[i] == 0x04) { - i += 8; - } - /* We also want to turn off all header compression opt. */ - for (; sendpacket[i] == 0x80;) { - sendpacket[i + 1] = 0; - i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; - } - /* Set the packet type to timer response */ - sendpacket[34] = 0x01; - printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", devname); - } else if (sendpacket[34] == 0x02) { - /* This is an information request packet */ - printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n", devname); - /* Set the packet type to information response */ - sendpacket[34] = 0x03; - /* Set the router name */ - sendpacket[51] = 'P'; - sendpacket[52] = 'T'; - sendpacket[53] = 'P'; - sendpacket[54] = 'I'; - sendpacket[55] = 'P'; - sendpacket[56] = 'E'; - sendpacket[57] = '-'; - sendpacket[58] = CVHexToAscii(network_number >> 28); - sendpacket[59] = CVHexToAscii((network_number & 0x0F000000) >> 24); - sendpacket[60] = CVHexToAscii((network_number & 0x00F00000) >> 20); - sendpacket[61] = CVHexToAscii((network_number & 0x000F0000) >> 16); - sendpacket[62] = CVHexToAscii((network_number & 0x0000F000) >> 12); - sendpacket[63] = CVHexToAscii((network_number & 0x00000F00) >> 8); - sendpacket[64] = CVHexToAscii((network_number & 0x000000F0) >> 4); - sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); - for (i = 66; i < 99; i += 1) - sendpacket[i] = 0; - printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", devname); - } else { - printk(KERN_INFO "%s: Unknown IPXWAN packet!\n", devname); - return 0; - } - /* Set the WNodeID to our network address */ - sendpacket[35] = (unsigned char) (network_number >> 24); - sendpacket[36] = (unsigned char) ((network_number & 0x00FF0000) >> 16); - sendpacket[37] = (unsigned char) ((network_number & 0x0000FF00) >> 8); - sendpacket[38] = (unsigned char) (network_number & 0x000000FF); - return 1; - } else { - /* If we get here's its an IPX-data packet, so it'll get passed up the stack. */ - /* switch the network numbers */ - switch_net_numbers(sendpacket, network_number, 1); - return 0; - } -} - -/****** Background Polling Routines ****************************************/ - -/*============================================================================ - * Main polling routine. - * This routine is repeatedly called by the WANPIPE 'thread' to allow for - * time-dependent housekeeping work. - * - * Notes: - * 1. This routine may be called on interrupt context with all interrupts - * enabled. Beware! - */ - -static void wpp_poll(sdla_t * card) -{ - struct net_device *dev = card->wandev.dev; - ppp_flags_t *adptr_flags = card->flags; - unsigned long host_cpu_flags; - ++card->statistics.poll_entry; - /* The wpp_poll is called continously by the WANPIPE thread to allow - * for line state housekeeping. However if we are in a connected state - * then we do not need to go through all the checks everytime. When in - * connected state execute wpp_poll once every second. - */ - if (card->wandev.state == WAN_CONNECTED) { - if ((jiffies - card->state_tick) < HZ) - return; - } - disable_irq(card->hw.irq); - ++card->irq_dis_poll_count; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) { - ++card->statistics.poll_already_critical; - printk(KERN_INFO "%s: critical inside wpp_poll\n", - card->devname); - save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && - (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - return; - } - ++card->statistics.poll_processed; - if (dev && dev->tbusy && !(adptr_flags->imask & 0x02)) { - ++card->statistics.poll_tbusy_bad_status; - printk(KERN_INFO "%s: Wpp_Poll: tbusy = 0x01, imask = 0x%02X\n" - ,card->devname, adptr_flags->imask); - } - switch (card->wandev.state) { - case WAN_CONNECTED: - card->state_tick = jiffies; - poll_active(card); - break; - case WAN_CONNECTING: - poll_connecting(card); - break; - case WAN_DISCONNECTED: - poll_disconnected(card); - break; - default: - printk(KERN_INFO "%s: Unknown Poll State 0x%02X\n", - card->devname, card->wandev.state); - break; - } - card->wandev.critical = 0; - save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); -} - -/*============================================================================ - * Monitor active link phase. - */ - -static void poll_active(sdla_t * card) -{ - ppp_flags_t *flags = card->flags; - /* We check the lcp_state to see if we are in DISCONNECTED state. - * We are considered to be connected for lcp states 0x06, 0x07, 0x08 - * and 0x09. - */ - if ((flags->lcp_state <= 0x05) || (flags->disc_cause & 0x03)) { - wanpipe_set_state(card, WAN_DISCONNECTED); - show_disc_cause(card, flags->disc_cause); - } -} - -/*============================================================================ - * Monitor link establishment phase. - * o if connection timed out, disconnect the link. - */ - -static void poll_connecting(sdla_t * card) -{ - ppp_flags_t *flags = card->flags; - if (flags->lcp_state == 0x09) { - wanpipe_set_state(card, WAN_CONNECTED); - } else if (flags->disc_cause & 0x03) { - wanpipe_set_state(card, WAN_DISCONNECTED); - show_disc_cause(card, flags->disc_cause); - } -} - -/*============================================================================ - * Monitor physical link disconnected phase. - * o if interface is up and the hold-down timeout has expired, then retry - * connection. - */ - -static void poll_disconnected(sdla_t * card) -{ - struct net_device *dev = card->wandev.dev; - if (dev && dev->start && - ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) { - wanpipe_set_state(card, WAN_CONNECTING); - if (ppp_comm_enable(card) == CMD_OK) - init_ppp_tx_rx_buff(card); - } -} - -/****** Miscellaneous Functions *********************************************/ - -/*============================================================================ - * Configure S502 adapter. - */ - -static int config502(sdla_t * card) -{ - ppp502_conf_t cfg; - /* Prepare PPP configuration structure */ - memset(&cfg, 0, sizeof(ppp502_conf_t)); - if (card->wandev.clocking) - cfg.line_speed = bps_to_speed_code(card->wandev.bps); - cfg.txbuf_num = 4; - cfg.mtu_local = card->wandev.mtu; - cfg.mtu_remote = card->wandev.mtu; - cfg.restart_tmr = 30; - cfg.auth_rsrt_tmr = 30; - cfg.auth_wait_tmr = 300; - cfg.mdm_fail_tmr = 5; - cfg.dtr_drop_tmr = 1; - cfg.connect_tmout = 0; /* changed it from 900 */ - cfg.conf_retry = 10; - cfg.term_retry = 2; - cfg.fail_retry = 5; - cfg.auth_retry = 10; - cfg.ip_options = 0x80; - cfg.ipx_options = 0xA0; - cfg.conf_flags |= 0x0E; -/* - cfg.ip_local = dev->pa_addr; - cfg.ip_remote = dev->pa_dstaddr; - */ - return ppp_configure(card, &cfg); -} - -/*============================================================================ - * Configure S508 adapter. - */ - -static int config508(sdla_t * card) -{ - ppp508_conf_t cfg; - /* Prepare PPP configuration structure */ - memset(&cfg, 0, sizeof(ppp508_conf_t)); - if (card->wandev.clocking) - cfg.line_speed = card->wandev.bps; - if (card->wandev.interface == WANOPT_RS232) - cfg.conf_flags |= 0x0020; - cfg.conf_flags |= 0x300; /*send Configure-Request packets forever */ - cfg.txbuf_percent = 60; /* % of Tx bufs */ - cfg.mtu_local = card->wandev.mtu; - cfg.mtu_remote = card->wandev.mtu; - cfg.restart_tmr = 30; - cfg.auth_rsrt_tmr = 30; - cfg.auth_wait_tmr = 300; - cfg.mdm_fail_tmr = 100; - cfg.dtr_drop_tmr = 1; - cfg.connect_tmout = 0; /* changed it from 900 */ - cfg.conf_retry = 10; - cfg.term_retry = 2; - cfg.fail_retry = 5; - cfg.auth_retry = 10; - cfg.ip_options = 0x80; - cfg.ipx_options = 0xA0; -/* - cfg.ip_local = dev->pa_addr; - cfg.ip_remote = dev->pa_dstaddr; - */ - return ppp_configure(card, &cfg); -} - -/*============================================================================ - * Show disconnection cause. - */ - -static void show_disc_cause(sdla_t * card, unsigned cause) -{ - if (cause & 0x0002) - printk(KERN_INFO "%s: link terminated by peer\n", - card->devname); - else if (cause & 0x0004) - printk(KERN_INFO "%s: link terminated by user\n", - card->devname); - else if (cause & 0x0008) - printk(KERN_INFO "%s: authentication failed\n", card->devname); - else if (cause & 0x0010) - printk(KERN_INFO - "%s: authentication protocol negotiation failed\n", - card->devname); - else if (cause & 0x0020) - printk(KERN_INFO - "%s: peer's request for authentication rejected\n", - card->devname); - else if (cause & 0x0040) - printk(KERN_INFO "%s: MRU option rejected by peer\n", - card->devname); - else if (cause & 0x0080) - printk(KERN_INFO "%s: peer's MRU was too small\n", - card->devname); - else if (cause & 0x0100) - printk(KERN_INFO "%s: failed to negotiate peer's LCP options\n", - card->devname); - else if (cause & 0x0200) - printk(KERN_INFO "%s: failed to negotiate peer's IPCP options\n" - ,card->devname); - else if (cause & 0x0400) - printk(KERN_INFO - "%s: failed to negotiate peer's IPXCP options\n", - card->devname); -} - -/*============================================================================ - * Convert line speed in bps to a number used by S502 code. - */ - -static unsigned char bps_to_speed_code(unsigned long bps) -{ - unsigned char number; - if (bps <= 1200) - number = 0x01; - else if (bps <= 2400) - number = 0x02; - else if (bps <= 4800) - number = 0x03; - else if (bps <= 9600) - number = 0x04; - else if (bps <= 19200) - number = 0x05; - else if (bps <= 38400) - number = 0x06; - else if (bps <= 45000) - number = 0x07; - else if (bps <= 56000) - number = 0x08; - else if (bps <= 64000) - number = 0x09; - else if (bps <= 74000) - number = 0x0A; - else if (bps <= 112000) - number = 0x0B; - else if (bps <= 128000) - number = 0x0C; - else - number = 0x0D; - return number; -} - -/*============================================================================ - * Process UDP call of type DRVSTATS. - */ - -static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, ppp_private_area_t * ppp_priv_area) -{ - unsigned char *sendpacket; - unsigned char buf2[5]; - unsigned char *data; - unsigned char *buf; - unsigned int len; - ppp_mbox_t *mbox = card->mbox; - struct sk_buff *new_skb; - int err; - sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) { - printk(KERN_INFO - "%s: Error allocating memory for UDP DRIVER STATS cmnd0x%02X" - ,card->devname, data[45]); - ++ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err; - return 1; - } - memcpy(data, sendpacket, skb->len); - switch (data[45]) { - /* PPIPE_DRIVER_STATISTICS */ - case 0x26: - *(unsigned long *) &data[60] = - ppp_priv_area->if_send_entry; - *(unsigned long *) &data[64] = - ppp_priv_area->if_send_skb_null; - *(unsigned long *) &data[68] = - ppp_priv_area->if_send_broadcast; - *(unsigned long *) &data[72] = - ppp_priv_area->if_send_multicast; - *(unsigned long *) &data[76] = - ppp_priv_area->if_send_critical_ISR; - *(unsigned long *) &data[80] = - ppp_priv_area->if_send_critical_non_ISR; - *(unsigned long *) &data[84] = - ppp_priv_area->if_send_busy; - *(unsigned long *) &data[88] = - ppp_priv_area->if_send_busy_timeout; - *(unsigned long *) &data[92] = - ppp_priv_area->if_send_DRVSTATS_request; - *(unsigned long *) &data[96] = - ppp_priv_area->if_send_PTPIPE_request; - *(unsigned long *) &data[100] = - ppp_priv_area->if_send_wan_disconnected; - *(unsigned long *) &data[104] = - ppp_priv_area->if_send_adptr_bfrs_full; - *(unsigned long *) &data[108] = - ppp_priv_area->if_send_protocol_error; - *(unsigned long *) &data[112] = - ppp_priv_area->if_send_tx_int_enabled; - *(unsigned long *) &data[116] = - ppp_priv_area->if_send_bfr_passed_to_adptr; - *(unsigned long *) &data[118] = - card->irq_dis_if_send_count; - mbox->cmd.length = 62; - break; - case 0x27: - *(unsigned long *) &data[60] = card->statistics.isr_entry; - *(unsigned long *) &data[64] = - card->statistics.isr_already_critical; - *(unsigned long *) &data[68] = card->statistics.isr_rx; - *(unsigned long *) &data[72] = card->statistics.isr_tx; - *(unsigned long *) &data[76] = - card->statistics.isr_intr_test; - *(unsigned long *) &data[80] = - card->statistics.isr_spurious; - *(unsigned long *) &data[84] = - card->statistics.isr_enable_tx_int; - *(unsigned long *) &data[88] = - card->statistics.rx_intr_corrupt_rx_bfr; - *(unsigned long *) &data[92] = - ppp_priv_area->rx_intr_no_socket; - *(unsigned long *) &data[96] = - ppp_priv_area->rx_intr_DRVSTATS_request; - *(unsigned long *) &data[100] = - ppp_priv_area->rx_intr_PTPIPE_request; - *(unsigned long *) &data[104] = - ppp_priv_area->rx_intr_bfr_passed_to_stack; - *(unsigned long *) &data[108] = - card->statistics.rx_intr_dev_not_started; - *(unsigned long *) &data[112] = - card->statistics.tx_intr_dev_not_started; - mbox->cmd.length = 56; - break; - case 0x28: - *(unsigned long *) &data[60] = - ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err; - *(unsigned long *) &data[64] = - ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err; - *(unsigned long *) &data[68] = - ppp_priv_area->UDP_PTPIPE_mgmt_direction_err; - *(unsigned long *) &data[72] = - ppp_priv_area-> - UDP_PTPIPE_mgmt_adptr_cmnd_timeout; - *(unsigned long *) &data[76] = - ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK; - *(unsigned long *) &data[80] = - ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr; - *(unsigned long *) &data[84] = - ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack; - *(unsigned long *) &data[88] = - ppp_priv_area->UDP_PTPIPE_mgmt_no_socket; - *(unsigned long *) &data[92] = - ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err; - *(unsigned long *) &data[96] = - ppp_priv_area-> - UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; - *(unsigned long *) &data[100] = - ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; - *(unsigned long *) &data[104] = - ppp_priv_area-> - UDP_DRVSTATS_mgmt_passed_to_adptr; - *(unsigned long *) &data[108] = - ppp_priv_area-> - UDP_DRVSTATS_mgmt_passed_to_stack; - *(unsigned long *) &data[112] = - ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket; - *(unsigned long *) &data[116] = - card->statistics.poll_entry; - *(unsigned long *) &data[120] = - card->statistics.poll_already_critical; - *(unsigned long *) &data[124] = - card->statistics.poll_processed; - *(unsigned long *) &data[126] = - card->irq_dis_poll_count; - mbox->cmd.length = 70; - break; - default: - /* it's a board command */ - memcpy(&mbox->cmd, &sendpacket[45], sizeof(ppp_cmd_t)); - if (mbox->cmd.length) { - memcpy(&mbox->data, &sendpacket[60], - mbox->cmd.length); - } - /* run the command on the board */ - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) { - ppp_error(card, err, mbox); - ++ppp_priv_area-> - UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; - break; - } - ++ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; - /* copy the result back to our buffer */ - memcpy(data, sendpacket, skb->len); - memcpy(&data[45], &mbox->cmd, sizeof(ppp_cmd_t)); - if (mbox->cmd.length) { - memcpy(&data[60], &mbox->data, mbox->cmd.length); - } - } - /* Fill UDP TTL */ - data[8] = card->wandev.ttl; - len = reply_udp(data, mbox->cmd.length); - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { - ++ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_adptr; - ppp_send(card, data, len, skb->protocol); - } else { - /* Pass it up the stack - Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) { - /* copy data into new_skb */ - buf = skb_put(new_skb, len); - memcpy(buf, data, len); - ++ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack; - /* Decapsulate packet and pass it up the protocol - stack */ - new_skb->protocol = htons(ETH_P_IP); - new_skb->dev = dev; - new_skb->mac.raw = new_skb->data; - netif_rx(new_skb); - } else { - ++ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket; - printk(KERN_INFO "no socket buffers available!\n"); - } - } - kfree(data); - return 0; -} - -/*============================================================================= - * Process UDP call of type PTPIPEAB. - */ - -static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, - struct sk_buff *skb, struct net_device *dev, - ppp_private_area_t * ppp_priv_area) -{ - unsigned char *sendpacket; - unsigned char buf2[5]; - unsigned char *data; - unsigned char *buf; - unsigned int frames, len; - struct sk_buff *new_skb; - unsigned short buffer_length, real_len; - unsigned long data_ptr; - int udp_mgmt_req_valid = 1; - ppp_mbox_t *mbox = card->mbox; - struct timeval tv; - int err; - sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) { - printk(KERN_INFO - "%s: Error allocating memory for UDP management cmnd0x%02X" - ,card->devname, data[45]); - ++ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err; - return 1; - } - memcpy(data, sendpacket, skb->len); - switch (data[45]) { - /* FT1 MONITOR STATUS */ - case 0x80: - if (card->hw.fwid != SFID_PPP508) { - ++ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err; - udp_mgmt_req_valid = 0; - break; - } - /* PPIPE_ENABLE_TRACING */ - case 0x20: - /* PPIPE_DISABLE_TRACING */ - case 0x21: - /* PPIPE_GET_TRACE_INFO */ - case 0x22: - /* SET FT1 MODE */ - case 0x81: - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { - ++ppp_priv_area->UDP_PTPIPE_mgmt_direction_err; - udp_mgmt_req_valid = 0; - } - break; - default: - break; - } - if (!udp_mgmt_req_valid) { - /* set length to 0 */ - data[46] = data[47] = 0; - /* set return code */ - data[48] = 0xCD; - } else { - switch (data[45]) { - /* PPIPE_ENABLE_TRACING */ - case 0x20: - if (!TracingEnabled) { - /* OPERATE_DATALINE_MONITOR */ - mbox->cmd.command = 0x33; - mbox->cmd.length = 1; - mbox->data[0] = 0x03; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) { - ppp_error(card, err, mbox); - TracingEnabled = 0; - /* set the return code */ - data[48] = mbox->cmd.result; - mbox->cmd.length = 0; - break; - } - if (card->hw.fwid == SFID_PPP502) { - sdla_peek(&card->hw, 0x9000, &buf2, 2); - } else { - sdla_peek(&card->hw, 0xC000, &buf2, 2); - } - curr_trace_addr = 0; - memcpy(&curr_trace_addr, &buf2, 2); - start_trace_addr = curr_trace_addr; - /* MAX_SEND_BUFFER_SIZE -sizeof(UDP_MGMT_PACKET) - - 41 */ - available_buffer_space = 1926; - } - data[48] = 0; - mbox->cmd.length = 0; - TracingEnabled = 1; - break; - /* PPIPE_DISABLE_TRACING */ - case 0x21: - if (TracingEnabled) { - /* OPERATE_DATALINE_MONITOR */ - mbox->cmd.command = 0x3; - mbox->cmd.length = 1; - mbox->data[0] = 0x00; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - } - /*set return code */ - data[48] = 0; - mbox->cmd.length = 0; - TracingEnabled = 0; - break; - /* PPIPE_GET_TRACE_INFO */ - case 0x22: - if (TracingEnabled) { - buffer_length = 0; - /* frames < NUM_TRACE_FRAMES */ - for (frames = 0; frames < 62; frames += 1) { - sdla_peek(&card->hw, curr_trace_addr, - &buf2, 1); - /* no data on board so exit */ - if (buf2[0] == 0x00) - break; - /*1+sizeof(FRAME_DATA) = 9 */ - if ((available_buffer_space - - buffer_length) < 9) { - /*indicate we have more frames - on board and exit */ - data[60] |= 0x02; - break; - } - /* get frame status */ - sdla_peek(&card->hw, curr_trace_addr + - 0x01, &data[60 + buffer_length], 1); - /* get time stamp */ - sdla_peek(&card->hw, curr_trace_addr + - 0x06, &data[64 + buffer_length], 2); - /* get frame length */ - sdla_peek(&card->hw, curr_trace_addr + - 0x02, &data[62 + buffer_length], 2); - /* get pointer to real data */ - sdla_peek(&card->hw, curr_trace_addr + - 0x04, &buf2, 2); - data_ptr = 0; - memcpy(&data_ptr, &buf2, 2); - /* see if we can fit the frame into the - user buffer */ - memcpy(&real_len, - &data[62 + buffer_length], 2); - if ((data_ptr == 0) || - ((real_len + 8) > - available_buffer_space)) { - data[61 + buffer_length] = 0x00; - } else { - /* we can take it next time */ - if ((available_buffer_space - - buffer_length) < - (real_len + 8)) { - data[60] |= 0x02; - break; - } - /* ok, get the frame */ - data[61 + buffer_length] = 0x01; - /* get the data */ - sdla_peek(&card->hw, data_ptr, - &data[66 + buffer_length], - real_len); - /* zero the opp flag to - show we got the frame */ - buf2[0] = 0x00; - sdla_poke(&card->hw, - curr_trace_addr, &buf2, 1); - /* now move onto the next - frame */ - curr_trace_addr += 8; - /* check if we passed the last - address */ - if (curr_trace_addr >= - start_trace_addr + 0x1F0) { - curr_trace_addr = - start_trace_addr; - } - /* update buffer length and make sure its even */ - if (data[61 + buffer_length] - == 0x01) { - buffer_length += - real_len - 1; - } - /* for the header */ - buffer_length += 8; - if (buffer_length & 0x0001) - buffer_length += 1; - } - } - /* ok now set the total number of frames passed - in the high 5 bits */ - data[60] = (frames << 2) | data[60]; - /* set the data length */ - mbox->cmd.length = buffer_length; - memcpy(&data[46], &buffer_length, 2); - /* set return code */ - data[48] = 0; - } else { - /* set return code */ - data[48] = 1; - mbox->cmd.length = 0; - } - break; - /* PPIPE_GET_IBA_DATA */ - case 0x23: - mbox->cmd.length = 0x09; - if (card->hw.fwid == SFID_PPP502) { - sdla_peek(&card->hw, 0xA003, &data[60], - mbox->cmd.length); - } else { - sdla_peek(&card->hw, 0xF003, &data[60], - mbox->cmd.length); - } - /* set the length of the data */ - data[46] = 0x09; - /* set return code */ - data[48] = 0x00; - break; - /* PPIPE_KILL_BOARD */ - case 0x24: - break; - /* PPIPE_FT1_READ_STATUS */ - case 0x25: - sdla_peek(&card->hw, 0xF020, &data[60], 2); - data[46] = 2; - data[47] = 0; - data[48] = 0; - mbox->cmd.length = 2; - break; - case 0x29: - init_ppp_priv_struct(ppp_priv_area); - init_global_statistics(card); - mbox->cmd.length = 0; - break; - case 0x30: - do_gettimeofday(&tv); - ppp_priv_area->router_up_time = tv.tv_sec - - ppp_priv_area->router_start_time; - *(unsigned long *) &data[60] = - ppp_priv_area->router_up_time; - mbox->cmd.length = 4; - break; - /* FT1 MONITOR STATUS */ - case 0x80: - /* Enable FT1 MONITOR STATUS */ - if (data[60] == 1) { - if (rCount++ != 0) { - data[48] = 0; - mbox->cmd.length = 1; - break; - } - } - /* Disable FT1 MONITOR STATUS */ - if (data[60] == 0) { - if (--rCount != 0) { - data[48] = 0; - mbox->cmd.length = 1; - break; - } - } - default: - /* it's a board command */ - memcpy(&mbox->cmd, &sendpacket[45], sizeof(ppp_cmd_t)); - if (mbox->cmd.length) { - memcpy(&mbox->data, &sendpacket[60], - mbox->cmd.length); - } - /* run the command on the board */ - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) { - ppp_error(card, err, mbox); - ++ppp_priv_area-> - UDP_PTPIPE_mgmt_adptr_cmnd_timeout; - break; - } - ++ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK; - /* copy the result back to our buffer */ - memcpy(data, sendpacket, skb->len); - memcpy(&data[45], &mbox->cmd, sizeof(ppp_cmd_t)); - if (mbox->cmd.length) { - memcpy(&data[60], &mbox->data, mbox->cmd.length); - } - } /* end of switch */ - } /* end of else */ - /* Fill UDP TTL */ - data[8] = card->wandev.ttl; - len = reply_udp(data, mbox->cmd.length); - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { - ++ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr; - ppp_send(card, data, len, skb->protocol); - } else { - /* Pass it up the stack - Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) { - /* copy data into new_skb */ - buf = skb_put(new_skb, len); - memcpy(buf, data, len); - ++ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack; - /* Decapsulate packet and pass it up the protocol - stack */ - new_skb->protocol = htons(ETH_P_IP); - new_skb->dev = dev; - new_skb->mac.raw = new_skb->data; - netif_rx(new_skb); - } else { - ++ppp_priv_area->UDP_PTPIPE_mgmt_no_socket; - printk(KERN_INFO "no socket buffers available!\n"); - } - } - kfree(data); - return 0; -} - -/*============================================================================= - * Initial the ppp_private_area structure. - */ - -static void init_ppp_priv_struct(ppp_private_area_t * ppp_priv_area) -{ - ppp_priv_area->if_send_entry = 0; - ppp_priv_area->if_send_skb_null = 0; - ppp_priv_area->if_send_broadcast = 0; - ppp_priv_area->if_send_multicast = 0; - ppp_priv_area->if_send_critical_ISR = 0; - ppp_priv_area->if_send_critical_non_ISR = 0; - ppp_priv_area->if_send_busy = 0; - ppp_priv_area->if_send_busy_timeout = 0; - ppp_priv_area->if_send_DRVSTATS_request = 0; - ppp_priv_area->if_send_PTPIPE_request = 0; - ppp_priv_area->if_send_wan_disconnected = 0; - ppp_priv_area->if_send_adptr_bfrs_full = 0; - ppp_priv_area->if_send_bfr_passed_to_adptr = 0; - ppp_priv_area->rx_intr_no_socket = 0; - ppp_priv_area->rx_intr_DRVSTATS_request = 0; - ppp_priv_area->rx_intr_PTPIPE_request = 0; - ppp_priv_area->rx_intr_bfr_not_passed_to_stack = 0; - ppp_priv_area->rx_intr_bfr_passed_to_stack = 0; - ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err = 0; - ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err = 0; - ppp_priv_area->UDP_PTPIPE_mgmt_direction_err = 0; - ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_timeout = 0; - ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK = 0; - ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr = 0; - ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack = 0; - ppp_priv_area->UDP_PTPIPE_mgmt_no_socket = 0; - ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err = 0; - ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_type_err = 0; - ppp_priv_area->UDP_DRVSTATS_mgmt_direction_err = 0; - ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout = 0; - ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK = 0; - ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_adptr = 0; - ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack = 0; - ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket = 0; -} - -/*============================================================================ - * Initialize Global Statistics - */ - -static void init_global_statistics(sdla_t * card) -{ - card->statistics.isr_entry = 0; - card->statistics.isr_already_critical = 0; - card->statistics.isr_tx = 0; - card->statistics.isr_rx = 0; - card->statistics.isr_intr_test = 0; - card->statistics.isr_spurious = 0; - card->statistics.isr_enable_tx_int = 0; - card->statistics.rx_intr_corrupt_rx_bfr = 0; - card->statistics.rx_intr_dev_not_started = 0; - card->statistics.tx_intr_dev_not_started = 0; - card->statistics.poll_entry = 0; - card->statistics.poll_already_critical = 0; - card->statistics.poll_processed = 0; - card->statistics.poll_tbusy_bad_status = 0; -} - -/*============================================================================ - * Initialize Receive and Transmit Buffers. - */ - -static void init_ppp_tx_rx_buff(sdla_t * card) -{ - if (card->hw.fwid == SFID_PPP502) { - ppp502_buf_info_t *info = - (void *) (card->hw.dpmbase + PPP502_BUF_OFFS); - card->u.p.txbuf_base = - (void *) (card->hw.dpmbase + info->txb_offs); - card->u.p.txbuf_last = (ppp_buf_ctl_t *) card->u.p.txbuf_base + - (info->txb_num - 1); - card->u.p.rxbuf_base = - (void *) (card->hw.dpmbase + info->rxb_offs); - card->u.p.rxbuf_last = (ppp_buf_ctl_t *) card->u.p.rxbuf_base + - (info->rxb_num - 1); - } else { - ppp508_buf_info_t *info = - (void *) (card->hw.dpmbase + PPP508_BUF_OFFS); - card->u.p.txbuf_base = (void *) (card->hw.dpmbase + - (info->txb_ptr - PPP508_MB_VECT)); - card->u.p.txbuf_last = (ppp_buf_ctl_t *) card->u.p.txbuf_base + - (info->txb_num - 1); - card->u.p.rxbuf_base = (void *) (card->hw.dpmbase + - (info->rxb_ptr - PPP508_MB_VECT)); - card->u.p.rxbuf_last = (ppp_buf_ctl_t *) card->u.p.rxbuf_base + - (info->rxb_num - 1); - card->u.p.rx_base = info->rxb_base; - card->u.p.rx_top = info->rxb_end; - } - card->u.p.txbuf = card->u.p.txbuf_base; - card->rxmb = card->u.p.rxbuf_base; -} - -/*============================================================================= - * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR - * _TEST_COUNTER times. - */ - -static int intr_test(sdla_t * card) -{ - ppp_mbox_t *mb = card->mbox; - int err, i; - /* The critical flag is unset because during initialization (if_open) - * we want the interrupts to be enabled so that when the wpp_isr is - * called it does not exit due to critical flag set. - */ - card->wandev.critical = 0; - err = ppp_set_intr_mode(card, 0x08); - if (err == CMD_OK) { - for (i = 0; i < MAX_INTR_TEST_COUNTER; i++) { - /* Run command READ_CODE_VERSION */ - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.length = 0; - mb->cmd.command = 0x10; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) - ppp_error(card, err, mb); - } - } else - return err; - err = ppp_set_intr_mode(card, 0); - if (err != CMD_OK) - return err; - card->wandev.critical = 1; - return 0; -} - -/*============================================================================== - * Determine what type of UDP call it is. DRVSTATS or PTPIPEAB ? - */ - -static int udp_pkt_type(struct sk_buff *skb, sdla_t * card) -{ - unsigned char *sendpacket; - unsigned char buf2[5]; - sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - if (sendpacket[0] == 0x45 && /* IP packet */ - sendpacket[9] == 0x11 && /* UDP packet */ - sendpacket[22] == buf2[1] && /* UDP Port */ - sendpacket[23] == buf2[0] && - sendpacket[36] == 0x01) { - if (sendpacket[28] == 0x50 && /* PTPIPEAB: Signature */ - sendpacket[29] == 0x54 && - sendpacket[30] == 0x50 && - sendpacket[31] == 0x49 && - sendpacket[32] == 0x50 && - sendpacket[33] == 0x45 && - sendpacket[34] == 0x41 && - sendpacket[35] == 0x42) { - return UDP_PTPIPE_TYPE; - } else if (sendpacket[28] == 0x44 && /* DRVSTATS: Signature */ - sendpacket[29] == 0x52 && - sendpacket[30] == 0x56 && - sendpacket[31] == 0x53 && - sendpacket[32] == 0x54 && - sendpacket[33] == 0x41 && - sendpacket[34] == 0x54 && - sendpacket[35] == 0x53) { - return UDP_DRVSTATS_TYPE; - } else - return UDP_INVALID_TYPE; - } else - return UDP_INVALID_TYPE; -} - -/****** End *****************************************************************/ diff -u --recursive --new-file v2.3.20/linux/drivers/net/sdla_x25.c linux/drivers/net/sdla_x25.c --- v2.3.20/linux/drivers/net/sdla_x25.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/sdla_x25.c Wed Dec 31 16:00:00 1969 @@ -1,2435 +0,0 @@ -/***************************************************************************** -* sdla_x25.c WANPIPE(tm) Multiprotocol WAN Link Driver. X.25 module. -* -* Author: Gene Kozin -* -* 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 /* printk(), and other useful stuff */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include /* kmalloc(), kfree() */ -#include /* WAN router definitions */ -#include /* WANPIPE common user API definitions */ -#include /* htons(), etc. */ -#include - -#define _GNUC_ -#include /* X.25 firmware API definitions */ - -/****** Defines & Macros ****************************************************/ - -#define CMD_OK 0 /* normal firmware return code */ -#define CMD_TIMEOUT 0xFF /* firmware command timed out */ -#define MAX_CMD_RETRY 10 /* max number of firmware retries */ - -#define X25_CHAN_MTU 4096 /* unfragmented logical channel MTU */ -#define X25_HRDHDR_SZ 7 /* max encapsulation header size */ -#define X25_CONCT_TMOUT (90*HZ) /* link connection timeout */ -#define X25_RECON_TMOUT (10*HZ) /* link connection timeout */ -#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ -#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ - -/* For IPXWAN */ -#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) - -/****** Data Structures *****************************************************/ - -/* This is an extention of the 'struct net_device' we create for each network - * interface to keep the rest of X.25 channel-specific data. - */ -typedef struct x25_channel -{ - char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ - char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ - unsigned lcn; /* logical channel number */ - unsigned tx_pkt_size; - unsigned short protocol; /* ethertype, 0 - multiplexed */ - char svc; /* 0 - permanent, 1 - switched */ - char state; /* channel state */ - char drop_sequence; /* mark sequence for dropping */ - unsigned long state_tick; /* time of the last state change */ - unsigned idle_timeout; /* sec, before disconnecting */ - unsigned long i_timeout_sofar; /* # of sec's we've been idle */ - unsigned hold_timeout; /* sec, before re-connecting */ - unsigned long tick_counter; /* counter for transmit time out */ - char devtint; /* Weather we should dev_tint() */ - struct sk_buff* rx_skb; /* receive socket buffer */ - struct sk_buff* tx_skb; /* transmit socket buffer */ - sdla_t* card; /* -> owner */ - int ch_idx; - struct net_device_stats ifstats; /* interface statistics */ -} x25_channel_t; - -typedef struct x25_call_info -{ - char dest[17]; /* ASCIIZ destination address */ - char src[17]; /* ASCIIZ source address */ - char nuser; /* number of user data bytes */ - unsigned char user[127]; /* user data */ - char nfacil; /* number of facilities */ - struct - { - unsigned char code; - unsigned char parm; - } facil[64]; /* facilities */ -} x25_call_info_t; - -/****** Function Prototypes *************************************************/ - -/* WAN link driver entry points. These are called by the WAN router module. */ -static int update (wan_device_t* wandev); -static int new_if (wan_device_t* wandev, struct net_device* dev, - wanif_conf_t* conf); -static int del_if (wan_device_t* wandev, struct net_device* dev); - -/* WANPIPE-specific entry points */ -static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data); - -/* Network device interface */ -static int if_init (struct net_device* dev); -static int if_open (struct net_device* dev); -static int if_close (struct net_device* dev); -static int if_header (struct sk_buff* skb, struct net_device* dev, - unsigned short type, void* daddr, void* saddr, unsigned len); -static int if_rebuild_hdr (struct sk_buff* skb); -static int if_send (struct sk_buff* skb, struct net_device* dev); -static struct net_device_stats * if_stats (struct net_device* dev); - -/* Interrupt handlers */ -static void wpx_isr (sdla_t* card); -static void rx_intr (sdla_t* card); -static void tx_intr (sdla_t* card); -static void status_intr (sdla_t* card); -static void event_intr (sdla_t* card); -static void spur_intr (sdla_t* card); - -/* Background polling routines */ -static void wpx_poll (sdla_t* card); -static void poll_disconnected (sdla_t* card); -static void poll_connecting (sdla_t* card); -static void poll_active (sdla_t* card); - -/* X.25 firmware interface functions */ -static int x25_get_version (sdla_t* card, char* str); -static int x25_configure (sdla_t* card, TX25Config* conf); -static int x25_get_err_stats (sdla_t* card); -static int x25_get_stats (sdla_t* card); -static int x25_set_intr_mode (sdla_t* card, int mode); -static int x25_close_hdlc (sdla_t* card); -static int x25_open_hdlc (sdla_t* card); -static int x25_setup_hdlc (sdla_t* card); -static int x25_set_dtr (sdla_t* card, int dtr); -static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan); -static int x25_place_call (sdla_t* card, x25_channel_t* chan); -static int x25_accept_call (sdla_t* card, int lcn, int qdm); -static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn); -static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf); -static int x25_fetch_events (sdla_t* card); -static int x25_error (sdla_t* card, int err, int cmd, int lcn); - -/* X.25 asynchronous event handlers */ -static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); -static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); -static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); -static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); -static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); - -/* Miscellaneous functions */ -static int connect (sdla_t* card); -static int disconnect (sdla_t* card); -static struct net_device* get_dev_by_lcn(wan_device_t* wandev, unsigned lcn); -static int chan_connect (struct net_device* dev); -static int chan_disc (struct net_device* dev); -static void set_chan_state (struct net_device* dev, int state); -static int chan_send (struct net_device* dev, struct sk_buff* skb); -static unsigned char bps_to_speed_code (unsigned long bps); -static unsigned int dec_to_uint (unsigned char* str, int len); -static unsigned int hex_to_uint (unsigned char* str, int len); -static void parse_call_info (unsigned char* str, x25_call_info_t* info); - -/* IPX functions */ -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto); - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -/****** Global Data ********************************************************** - * Note: All data must be explicitly initialized!!! - */ - -/****** Public Functions ****************************************************/ - -/*============================================================================ - * X.25 Protocol Initialization routine. - * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and X.25 firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. - * - * Return: 0 o.k. - * < 0 failure. - */ -int wpx_init (sdla_t* card, wandev_conf_t* conf) -{ - union - { - char str[80]; - TX25Config cfg; - } u; - - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_X25) - { - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id) - ; - return -EINVAL; - } - - /* Initialize protocol-specific fields */ - card->mbox = (void*)(card->hw.dpmbase + X25_MBOX_OFFS); - card->rxmb = (void*)(card->hw.dpmbase + X25_RXMBOX_OFFS); - card->flags = (void*)(card->hw.dpmbase + X25_STATUS_OFFS); - - /* Read firmware version. Note that when adapter initializes, it - * clears the mailbox, so it may appear that the first command was - * executed successfully when in fact it was merely erased. To work - * around this, we execute the first command twice. - */ - if (x25_get_version(card, NULL) || x25_get_version(card, u.str)) - return -EIO - ; - printk(KERN_INFO "%s: running X.25 firmware v%s\n", - card->devname, u.str) - ; - - /* Configure adapter. Here we set resonable defaults, then parse - * device configuration structure and set configuration options. - * Most configuration options are verified and corrected (if - * necessary) since we can't rely on the adapter to do so and don't - * want it to fail either. - */ - memset(&u.cfg, 0, sizeof(u.cfg)); - u.cfg.t1 = 3; - u.cfg.n2 = 10; - u.cfg.autoHdlc = 1; /* automatic HDLC connection */ - u.cfg.hdlcWindow = 7; - u.cfg.pktWindow = 2; - u.cfg.station = 1; /* DTE */ - u.cfg.options = 0x00B0; /* disable D-bit pragmatics */ - u.cfg.ccittCompat = 1988; - u.cfg.t10t20 = 30; - u.cfg.t11t21 = 30; - u.cfg.t12t22 = 30; - u.cfg.t13t23 = 30; - u.cfg.t16t26 = 30; - u.cfg.t28 = 30; - u.cfg.r10r20 = 5; - u.cfg.r12r22 = 5; - u.cfg.r13r23 = 5; - u.cfg.responseOpt = 1; /* RR's after every packet */ - - if (conf->clocking != WANOPT_EXTERNAL) - u.cfg.baudRate = bps_to_speed_code(conf->bps) - ; - if (conf->station != WANOPT_DTE) - { - u.cfg.station = 0; /* DCE mode */ - } - if (conf->interface != WANOPT_RS232 ) { - u.cfg.hdlcOptions |= 0x80; /* V35 mode */ - } - /* adjust MTU */ - if (!conf->mtu || (conf->mtu >= 1024)) - card->wandev.mtu = 1024 - ; - else if (conf->mtu >= 512) - card->wandev.mtu = 512 - ; - else if (conf->mtu >= 256) - card->wandev.mtu = 256 - ; - else if (conf->mtu >= 128) - card->wandev.mtu = 128 - ; - else card->wandev.mtu = 64; - u.cfg.defPktSize = u.cfg.pktMTU = card->wandev.mtu; - - if (conf->u.x25.hi_pvc) - { - card->u.x.hi_pvc = min(conf->u.x25.hi_pvc, 4095); - card->u.x.lo_pvc = min(conf->u.x25.lo_pvc, card->u.x.hi_pvc); - } - if (conf->u.x25.hi_svc) - { - card->u.x.hi_svc = min(conf->u.x25.hi_svc, 4095); - card->u.x.lo_svc = min(conf->u.x25.lo_svc, card->u.x.hi_svc); - } - u.cfg.loPVC = card->u.x.lo_pvc; - u.cfg.hiPVC = card->u.x.hi_pvc; - u.cfg.loTwoWaySVC = card->u.x.lo_svc; - u.cfg.hiTwoWaySVC = card->u.x.hi_svc; - - if (conf->u.x25.hdlc_window) - u.cfg.hdlcWindow = min(conf->u.x25.hdlc_window, 7) - ; - if (conf->u.x25.pkt_window) - u.cfg.pktWindow = min(conf->u.x25.pkt_window, 7) - ; - if (conf->u.x25.t1) - u.cfg.t1 = min(conf->u.x25.t1, 30) - ; - u.cfg.t2 = min(conf->u.x25.t2, 29); - u.cfg.t4 = min(conf->u.x25.t4, 240); - if (conf->u.x25.n2) - u.cfg.n2 = min(conf->u.x25.n2, 30) - ; - if (conf->u.x25.ccitt_compat) - u.cfg.ccittCompat = conf->u.x25.ccitt_compat - ; - - /* initialize adapter */ - if ((x25_configure(card, &u.cfg) != CMD_OK) || - (x25_close_hdlc(card) != CMD_OK) || /* close HDLC link */ - (x25_set_dtr(card, 0) != CMD_OK)) /* drop DTR */ - return -EIO - ; - - /* Initialize protocol-specific fields of adapter data space */ - card->wandev.bps = conf->bps; - card->wandev.interface = conf->interface; - card->wandev.clocking = conf->clocking; - card->wandev.station = conf->station; - card->isr = &wpx_isr; - card->poll = &wpx_poll; - card->exec = &wpx_exec; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.state = WAN_DISCONNECTED; - card->wandev.enable_tx_int = 0; - card->irq_dis_if_send_count = 0; - card->irq_dis_poll_count = 0; - card->wandev.enable_IPX = conf->enable_IPX; - - if (conf->network_number) - card->wandev.network_number = conf->network_number; - else - card->wandev.network_number = 0xDEADBEEF; - return 0; -} - -/******* WAN Device Driver Entry Points *************************************/ - -/*============================================================================ - * Update device status & statistics. - */ -static int update (wan_device_t* wandev) -{ - sdla_t* card; - - /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - if (wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - if (test_and_set_bit(0, (void*)&wandev->critical)) - return -EAGAIN; - card = wandev->private; - - x25_get_err_stats(card); - x25_get_stats(card); - wandev->critical = 0; - return 0; -} - -/*============================================================================ - * Create new logical channel. - * This routine is called by the router when ROUTER_IFNEW IOCTL is being - * handled. - * o parse media- and hardware-specific configuration - * o make sure that a new channel can be created - * o allocate resources, if necessary - * o prepare network device structure for registaration. - * - * Return: 0 o.k. - * < 0 failure (channel will not be created) - */ -static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf) -{ - sdla_t* card = wandev->private; - x25_channel_t* chan; - int err = 0; - - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) - { - printk(KERN_INFO "%s: invalid interface name!\n", - card->devname) - ; - return -EINVAL; - } - - /* allocate and initialize private data */ - chan = kmalloc(sizeof(x25_channel_t), GFP_KERNEL); - if (chan == NULL) - return -ENOMEM - ; - memset(chan, 0, sizeof(x25_channel_t)); - strcpy(chan->name, conf->name); - chan->card = card; - chan->protocol = ETH_P_IP; - chan->tx_skb = chan->rx_skb = NULL; - - /* verify media address */ - if (conf->addr[0] == '@') /* SVC */ - { - chan->svc = 1; - strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ); - - /* Set channel timeouts (default if not specified) */ - chan->idle_timeout = (conf->idle_timeout) ? conf->idle_timeout : 90; - chan->hold_timeout = (conf->hold_timeout) ? conf->hold_timeout : 10; - } - else if (is_digit(conf->addr[0])) /* PVC */ - { - int lcn = dec_to_uint(conf->addr, 0); - - if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc)) - { - chan->lcn = lcn; - } - else - { - printk(KERN_ERR - "%s: PVC %u is out of range on interface %s!\n", - wandev->name, lcn, chan->name) - ; - err = -EINVAL; - } - } - else - { - printk(KERN_ERR - "%s: invalid media address on interface %s!\n", - wandev->name, chan->name) - ; - err = -EINVAL; - } - if (err) - { - kfree(chan); - return err; - } - - /* prepare network device data space for registration */ - dev->name = chan->name; - dev->init = &if_init; - dev->priv = chan; - return 0; -} - -/*============================================================================ - * Delete logical channel. - */ -static int del_if (wan_device_t* wandev, struct net_device* dev) -{ - if (dev->priv) - { - kfree(dev->priv); - dev->priv = NULL; - } - return 0; -} - -/****** WANPIPE-specific entry points ***************************************/ - -/*============================================================================ - * Execute adapter interface command. - */ - -static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err, len; - TX25Cmd cmd; - - if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) - return -EFAULT; - - /* execute command */ - - do - { - memcpy(&mbox->cmd, &cmd, sizeof(cmd)); - if (cmd.length) - { - if(copy_from_user((void*)&mbox->data, u_data, cmd.length)) - return-EFAULT; - } - if (sdla_exec(mbox)) - err = mbox->cmd.result - ; - else return -EIO; - } - while (err && retry-- && x25_error(card, err, cmd.command, cmd.lcn)); - - /* return result */ - if(copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(TX25Cmd))) - return -EFAULT; - len = mbox->cmd.length; - if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)) - return -EFAULT; - return 0; -} - -/****** Network Device Interface ********************************************/ - -/*============================================================================ - * Initialize Linux network interface. - * - * This routine is called only once for each interface, during Linux network - * interface registration. Returning anything but zero will fail interface - * registration. - */ -static int if_init (struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - wan_device_t* wandev = &card->wandev; - - /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = &if_header; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; - - /* Initialize media-specific parameters */ - dev->type = 30; /* ARP h/w type */ - dev->mtu = X25_CHAN_MTU; - dev->hard_header_len = X25_HRDHDR_SZ; /* media header length */ - dev->addr_len = 2; /* hardware address length */ - if (!chan->svc) - *(unsigned short*)dev->dev_addr = htons(chan->lcn); - - /* Initialize hardware parameters (just for reference) */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = (unsigned long)wandev->maddr; - dev->mem_end = dev->mem_end + wandev->msize - 1; - - /* Set transmit buffer queue length */ - dev->tx_queue_len = 10; - - /* Initialize socket buffers */ - - dev_init_buffers(dev); - set_chan_state(dev, WAN_DISCONNECTED); - return 0; -} - -/*============================================================================ - * Open network interface. - * o prevent module from unloading by incrementing use count - * o if link is disconnected then initiate connection - * - * Return 0 if O.k. or errno. - */ -static int if_open (struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - - if (dev->start) - return -EBUSY; /* only one open is allowed */ - - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - return -EAGAIN; - - dev->interrupt = 0; - dev->tbusy = 0; - dev->start = 1; - wanpipe_open(card); - - /* If this is the first open, initiate physical connection */ - if (card->open_cnt == 1) - connect(card); - card->wandev.critical = 0; - return 0; -} - -/*============================================================================ - * Close network interface. - * o reset flags. - * o if there's no more open channels then disconnect physical link. - */ -static int if_close (struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - return -EAGAIN; - - dev->start = 0; - if ((chan->state == WAN_CONNECTED) || (chan->state == WAN_CONNECTING)) - chan_disc(dev); - - wanpipe_close(card); - - /* If this is the last close, disconnect physical link */ - if (!card->open_cnt) - disconnect(card); - - card->wandev.critical = 0; - return 0; -} - -/*============================================================================ - * Build media header. - * o encapsulate packet according to encapsulation type. - * - * The trick here is to put packet type (Ethertype) into 'protocol' field of - * the socket buffer, so that we don't forget it. If encapsulation fails, - * set skb->protocol to 0 and discard packet later. - * - * Return: media header length. - */ -static int if_header (struct sk_buff* skb, struct net_device* dev, - unsigned short type, void* daddr, void* saddr, unsigned len) -{ - x25_channel_t* chan = dev->priv; - int hdr_len = dev->hard_header_len; - - skb->protocol = type; - if (!chan->protocol) - { - hdr_len = wanrouter_encapsulate(skb, dev); - if (hdr_len < 0) - { - hdr_len = 0; - skb->protocol = 0; - } - } - return hdr_len; -} - -/*============================================================================ - * Re-build media header. - * - * Return: 1 physical address resolved. - * 0 physical address not resolved - */ - -static int if_rebuild_hdr (struct sk_buff* skb) -{ - struct net_device *dev=skb->dev; - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - - printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name); - return 1; -} - -/*============================================================================ - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission). - * o check link state. If link is not up, then drop the packet. - * o check channel status. If it's down then initiate a call. - * o pass a packet to corresponding WAN device. - * o free socket buffer - * - * Return: 0 complete (socket buffer must be freed) - * non-0 packet may be re-transmitted (tbusy must be set) - * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. - */ - -static int if_send (struct sk_buff* skb, struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - struct net_device *dev2; - TX25Status* status = card->flags; - unsigned long host_cpu_flags; - - if (dev->tbusy) - { - ++chan->ifstats.rx_dropped; - if ((jiffies - chan->tick_counter) < (5*HZ)) - { - return dev->tbusy; - } - printk(KERN_INFO "%s: Transmit time out %s!\n", - card->devname, dev->name) - ; - for( dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) - { - dev2->tbusy = 0; - } - } - chan->tick_counter = jiffies; - - disable_irq(card->hw.irq); - ++card->irq_dis_if_send_count; - - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - { - printk(KERN_INFO "Hit critical in if_send()!\n"); - if (card->wandev.critical == CRITICAL_IN_ISR) - { - card->wandev.enable_tx_int = 1; - dev->tbusy = 1; - - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - - return dev->tbusy; - } - dev_kfree_skb(skb); - - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - - return dev->tbusy; - } - - /* Below is only until we have per-channel IPX going.... */ - if(!(chan->svc)) - chan->protocol = skb->protocol; - - if (card->wandev.state != WAN_CONNECTED) - ++chan->ifstats.tx_dropped; - - /* Below is only until we have per-channel IPX going.... */ - else if ( (chan->svc) && (chan->protocol && (chan->protocol != skb->protocol))) - { - printk(KERN_INFO - "%s: unsupported Ethertype 0x%04X on interface %s!\n", - card->devname, skb->protocol, dev->name); - ++chan->ifstats.tx_errors; - } - else switch (chan->state) - { - case WAN_DISCONNECTED: - /* Try to establish connection. If succeded, then start - * transmission, else drop a packet. - */ - if (chan_connect(dev) != 0) - { - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - break; - } - /* fall through */ - - case WAN_CONNECTED: - if( skb->protocol == ETH_P_IPX ) - { - if(card->wandev.enable_IPX) - { - switch_net_numbers( skb->data, - card->wandev.network_number, 0); - } - else - { - ++card->wandev.stats.tx_dropped; - ++chan->ifstats.tx_dropped; - goto tx_done; - } - } - dev->trans_start = jiffies; - if(chan_send(dev, skb)) - { - dev->tbusy = 1; - status->imask |= 0x2; - } - break; - - default: - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - } -tx_done: - if (!dev->tbusy) - dev_kfree_skb(skb); - - card->wandev.critical = 0; - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - return dev->tbusy; -} - -/*============================================================================ - * Get Ethernet-style interface statistics. - * Return a pointer to struct net_device_stats - */ - -static struct net_device_stats* if_stats (struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - if(chan==NULL) - return NULL; - return &chan->ifstats; -} - -/****** Interrupt Handlers **************************************************/ - -/*============================================================================ - * X.25 Interrupt Service Routine. - */ - -static void wpx_isr (sdla_t* card) -{ - TX25Status* status = card->flags; - struct net_device *dev; - unsigned long host_cpu_flags; - - card->in_isr = 1; - card->buff_int_mode_unbusy = 0; - - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - { - - printk(KERN_INFO "wpx_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, status->iflags); - card->in_isr = 0; - return; - } - - /* For all interrupts set the critical flag to CRITICAL_RX_INTR. - * If the if_send routine is called with this flag set it will set - * the enable transmit flag to 1. (for a delayed interrupt) - */ - card->wandev.critical = CRITICAL_IN_ISR; - - switch (status->iflags) - { - case 0x01: /* receive interrupt */ - rx_intr(card); - break; - - case 0x02: /* transmit interrupt */ - tx_intr(card); - card->buff_int_mode_unbusy = 1; - status->imask &= ~0x2; - break; - - case 0x04: /* modem status interrupt */ - status_intr(card); - break; - - case 0x10: /* network event interrupt */ - event_intr(card); - break; - - default: /* unwanted interrupt */ - spur_intr(card); - } - card->wandev.critical = CRITICAL_INTR_HANDLED; - if( card->wandev.enable_tx_int) - { - card->wandev.enable_tx_int = 0; - status->imask |= 0x2; - } - save_flags(host_cpu_flags); - cli(); - card->in_isr = 0; - status->iflags = 0; /* clear interrupt condition */ - card->wandev.critical = 0; - restore_flags(host_cpu_flags); - - if(card->buff_int_mode_unbusy) - { - for(dev = card->wandev.dev; dev; dev = dev->slave) - { - if(((x25_channel_t*)dev->priv)->devtint) - { - mark_bh(NET_BH); - return; - } - } - } -} - -/*============================================================================ - * Receive interrupt handler. - * This routine handles fragmented IP packets using M-bit according to the - * RFC1356. - * o map ligical channel number to network interface. - * o allocate socket buffer or append received packet to the existing one. - * o if M-bit is reset (i.e. it's the last packet in a sequence) then - * decapsulate packet and pass socket buffer to the protocol stack. - * - * Notes: - * 1. When allocating a socket buffer, if M-bit is set then more data is - * comming and we have to allocate buffer for the maximum IP packet size - * expected on this channel. - * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no - * socket buffers available) the whole packet sequence must be discarded. - */ - -static void rx_intr (sdla_t* card) -{ - TX25Mbox* rxmb = card->rxmb; - unsigned lcn = rxmb->cmd.lcn; /* logical channel number */ - unsigned len = rxmb->cmd.length; /* packet length */ - unsigned qdm = rxmb->cmd.qdm; /* Q,D and M bits */ - wan_device_t* wandev = &card->wandev; - struct net_device* dev = get_dev_by_lcn(wandev, lcn); - x25_channel_t* chan; - struct sk_buff* skb; - void* bufptr; - - if (dev == NULL) - { - /* Invalid channel, discard packet */ - printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n", - card->devname, lcn); - return; - } - - chan = dev->priv; - chan->i_timeout_sofar = jiffies; - if (chan->drop_sequence) - { - if (!(qdm & 0x01)) chan->drop_sequence = 0; - return; - } - - skb = chan->rx_skb; - if (skb == NULL) - { - /* Allocate new socket buffer */ - int bufsize = (qdm & 0x01) ? dev->mtu : len; - - skb = dev_alloc_skb(bufsize + dev->hard_header_len); - if (skb == NULL) - { - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - chan->drop_sequence = 1; /* set flag */ - ++chan->ifstats.rx_dropped; - return; - } - skb->dev = dev; - skb->protocol = htons(chan->protocol); - chan->rx_skb = skb; - } - - if (skb_tailroom(skb) < len) - { - /* No room for the packet. Call off the whole thing! */ - dev_kfree_skb(skb); - chan->rx_skb = NULL; - if (qdm & 0x01) chan->drop_sequence = 1; - - printk(KERN_INFO "%s: unexpectedly long packet sequence " - "on interface %s!\n", card->devname, dev->name); - ++chan->ifstats.rx_length_errors; - return; - } - - /* Append packet to the socket buffer */ - bufptr = skb_put(skb, len); - memcpy(bufptr, rxmb->data, len); - - if (qdm & 0x01) - return; /* more data is comming */ - - dev->last_rx = jiffies; /* timestamp */ - chan->rx_skb = NULL; /* dequeue packet */ - - /* Decapsulate packet, if necessary */ - if (!skb->protocol && !wanrouter_type_trans(skb, dev)) - { - /* can't decapsulate packet */ - dev_kfree_skb(skb); - ++chan->ifstats.rx_errors; - } - else - { - if( handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) - { - if( card->wandev.enable_IPX ) - { - if(chan_send(dev, skb)) - { - chan->tx_skb = skb; - } - else - { - dev_kfree_skb(skb); - } - } - else - { - /* FIXME: increment IPX packet dropped statistic */ - } - } - else - { - netif_rx(skb); - ++chan->ifstats.rx_packets; - chan->ifstats.rx_bytes += skb->len; - } - } -} - -/*============================================================================ - * Transmit interrupt handler. - * o Release socket buffer - * o Clear 'tbusy' flag - */ - -static void tx_intr (sdla_t* card) -{ - struct net_device *dev; - - /* unbusy all devices and then dev_tint(); */ - for(dev = card->wandev.dev; dev; dev = dev->slave) - { - ((x25_channel_t*)dev->priv)->devtint = dev->tbusy; - dev->tbusy = 0; - } - -} - -/*============================================================================ - * Modem status interrupt handler. - */ -static void status_intr (sdla_t* card) -{ -} - -/*============================================================================ - * Network event interrupt handler. - */ -static void event_intr (sdla_t* card) -{ -} - -/*============================================================================ - * Spurious interrupt handler. - * o print a warning - * o - * If number of spurious interrupts exceeded some limit, then ??? - */ -static void spur_intr (sdla_t* card) -{ - printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); -} - -/****** Background Polling Routines ****************************************/ - -/*============================================================================ - * Main polling routine. - * This routine is repeatedly called by the WANPIPE 'thread' to allow for - * time-dependent housekeeping work. - * - * Notes: - * 1. This routine may be called on interrupt context with all interrupts - * enabled. Beware! - */ - -static void wpx_poll (sdla_t* card) -{ - unsigned long host_cpu_flags; - - disable_irq(card->hw.irq); - ++card->irq_dis_poll_count; - - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - { - printk(KERN_INFO "%s: critical in polling!\n",card->devname); - save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && - (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - return; - } - - switch(card->wandev.state) - { - case WAN_CONNECTED: - poll_active(card); - break; - - case WAN_CONNECTING: - poll_connecting(card); - break; - - case WAN_DISCONNECTED: - poll_disconnected(card); - } - card->wandev.critical = 0; - save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); -} - -/*============================================================================ - * Handle physical link establishment phase. - * o if connection timed out, disconnect the link. - */ -static void poll_connecting (sdla_t* card) -{ - TX25Status* status = card->flags; - - if (status->gflags & X25_HDLC_ABM) - { - wanpipe_set_state(card, WAN_CONNECTED); - x25_set_intr_mode(card, 0x83); /* enable Rx interrupts */ - status->imask &= ~0x2; /* mask Tx interupts */ - } - else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT) - disconnect(card); -} - -/*============================================================================ - * Handle physical link disconnected phase. - * o if hold-down timeout has expired and there are open interfaces, connect - * link. - */ -static void poll_disconnected (sdla_t* card) -{ - if (card->open_cnt && ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) - connect(card); -} - -/*============================================================================ - * Handle active link phase. - * o fetch X.25 asynchronous events. - * o kick off transmission on all interfaces. - */ -static void poll_active (sdla_t* card) -{ - struct net_device* dev; - - /* Fetch X.25 asynchronous events */ - x25_fetch_events(card); - - for (dev = card->wandev.dev; dev; dev = dev->slave) - { - x25_channel_t* chan = dev->priv; - struct sk_buff* skb = chan->tx_skb; - - /* If there is a packet queued for transmission then kick - * the channel's send routine. When transmission is complete - * or if error has occurred, release socket buffer and reset - * 'tbusy' flag. - */ - if (skb && (chan_send(dev, skb) == 0)) - { - chan->tx_skb = NULL; - dev->tbusy = 0; - dev_kfree_skb(skb); - } - - /* If SVC has been idle long enough, close virtual circuit */ - - if(( chan->svc )&&( chan->state == WAN_CONNECTED )) - { - if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout ) - { - /* Close svc */ - printk(KERN_INFO "%s: Closing down Idle link %s on LCN %d\n",card->devname,chan->name,chan->lcn); - chan->i_timeout_sofar = jiffies; - chan_disc(dev); - } - } - } -} - -/****** SDLA Firmware-Specific Functions ************************************* - * Almost all X.25 commands can unexpetedly fail due to so called 'X.25 - * asynchronous events' such as restart, interrupt, incoming call request, - * call clear request, etc. They can't be ignored and have to be dealt with - * immediately. To tackle with this problem we execute each interface command - * in a loop until good return code is received or maximum number of retries - * is reached. Each interface command returns non-zero return code, an - * asynchronous event/error handler x25_error() is called. - */ - -/*============================================================================ - * Read X.25 firmware version. - * Put code version as ASCII string in str. - */ -static int x25_get_version (sdla_t* card, char* str) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_READ_CODE_VERSION; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && - x25_error(card, err, X25_READ_CODE_VERSION, 0)); - - if (!err && str) - { - int len = mbox->cmd.length; - memcpy(str, mbox->data, len); - str[len] = '\0'; - } - return err; -} - -/*============================================================================ - * Configure adapter. - */ - -static int x25_configure (sdla_t* card, TX25Config* conf) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - memcpy(mbox->data, (void*)conf, sizeof(TX25Config)); - mbox->cmd.length = sizeof(TX25Config); - mbox->cmd.command = X25_SET_CONFIGURATION; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0)); - return err; -} - -/*============================================================================ - * Get communications error statistics. - */ -static int x25_get_err_stats (sdla_t* card) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_HDLC_READ_COMM_ERR; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0)); - - if (!err) - { - THdlcCommErr* stats = (void*)mbox->data; - - card->wandev.stats.rx_over_errors = stats->rxOverrun; - card->wandev.stats.rx_crc_errors = stats->rxBadCrc; - card->wandev.stats.rx_missed_errors = stats->rxAborted; - card->wandev.stats.tx_aborted_errors = stats->txAborted; - } - return err; -} - -/*============================================================================ - * Get protocol statistics. - */ -static int x25_get_stats (sdla_t* card) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_READ_STATISTICS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0)); - - if (!err) - { - TX25Stats* stats = (void*)mbox->data; - - card->wandev.stats.rx_packets = stats->rxData; - card->wandev.stats.tx_packets = stats->rxData; - } - return err; -} - -/*============================================================================ - * Close HDLC link. - */ -static int x25_close_hdlc (sdla_t* card) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_HDLC_LINK_CLOSE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_CLOSE, 0)); - - return err; -} - -/*============================================================================ - * Open HDLC link. - */ -static int x25_open_hdlc (sdla_t* card) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_HDLC_LINK_OPEN; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_OPEN, 0)); - - return err; -} - -/*============================================================================ - * Setup HDLC link. - */ -static int x25_setup_hdlc (sdla_t* card) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_HDLC_LINK_SETUP; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_SETUP, 0)); - - return err; -} - -/*============================================================================ - * Set (raise/drop) DTR. - */ -static int x25_set_dtr (sdla_t* card, int dtr) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->data[0] = 0; - mbox->data[2] = 0; - mbox->data[1] = dtr ? 0x02 : 0x01; - mbox->cmd.length = 3; - mbox->cmd.command = X25_SET_GLOBAL_VARS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_SET_GLOBAL_VARS, 0)); - - return err; -} - -/*============================================================================ - * Set interrupt mode. - */ -static int x25_set_intr_mode (sdla_t* card, int mode) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->data[0] = mode; - if (card->hw.fwid == SFID_X25_508) - { - mbox->data[1] = card->hw.irq; - mbox->cmd.length = 2; - } - else mbox->cmd.length = 1; - mbox->cmd.command = X25_SET_INTERRUPT_MODE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)) ; - return err; -} - -/*============================================================================ - * Read X.25 channel configuration. - */ -static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int lcn = chan->lcn; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.lcn = lcn; - mbox->cmd.command = X25_READ_CHANNEL_CONFIG; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_READ_CHANNEL_CONFIG, lcn)); - - if (!err) - { - TX25Status* status = card->flags; - - /* calculate an offset into the array of status bytes */ - if (card->u.x.hi_svc <= 255) - chan->ch_idx = lcn - 1; - else - { - int offset; - - switch (mbox->data[0] && 0x1F) - { - case 0x01: - offset = status->pvc_map; break; - case 0x03: - offset = status->icc_map; break; - case 0x07: - offset = status->twc_map; break; - case 0x0B: - offset = status->ogc_map; break; - default: - offset = 0; - } - chan->ch_idx = lcn - 1 - offset; - } - - /* get actual transmit packet size on this channel */ - switch(mbox->data[1] & 0x38) - { - case 0x00: - chan->tx_pkt_size = 16; - break; - case 0x08: - chan->tx_pkt_size = 32; - break; - case 0x10: - chan->tx_pkt_size = 64; - break; - case 0x18: - chan->tx_pkt_size = 128; - break; - case 0x20: - chan->tx_pkt_size = 256; - break; - case 0x28: - chan->tx_pkt_size = 512; - break; - case 0x30: - chan->tx_pkt_size = 1024; - break; - } - printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n", - card->devname, lcn, chan->tx_pkt_size); - } - return err; -} - -/*============================================================================ - * Place X.25 call. - */ - -static int x25_place_call (sdla_t* card, x25_channel_t* chan) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - char str[64]; - - sprintf(str, "-d%s -uCC", chan->addr); - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - strcpy(mbox->data, str); - mbox->cmd.length = strlen(str); - mbox->cmd.command = X25_PLACE_CALL; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_PLACE_CALL, 0)); - - if (!err) - { - chan->lcn = mbox->cmd.lcn; - chan->protocol = ETH_P_IP; - } - return err; -} - -/*============================================================================ - * Accept X.25 call. - */ - -static int x25_accept_call (sdla_t* card, int lcn, int qdm) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.lcn = lcn; - mbox->cmd.qdm = qdm; - mbox->cmd.command = X25_ACCEPT_CALL; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_ACCEPT_CALL, lcn)); - - return err; -} - -/*============================================================================ - * Clear X.25 call. - */ -static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.lcn = lcn; - mbox->cmd.cause = cause; - mbox->cmd.diagn = diagn; - mbox->cmd.command = X25_CLEAR_CALL; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_CLEAR_CALL, lcn)); - - return err; -} - -/*============================================================================ - * Send X.25 data packet. - */ -static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - memcpy(mbox->data, buf, len); - mbox->cmd.length = len; - mbox->cmd.lcn = lcn; - mbox->cmd.qdm = qdm; - mbox->cmd.command = X25_WRITE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_WRITE, lcn)); - return err; -} - -/*============================================================================ - * Fetch X.25 asynchronous events. - */ -static int x25_fetch_events (sdla_t* card) -{ - TX25Status* status = card->flags; - TX25Mbox* mbox = card->mbox; - int err = 0; - - if (status->gflags & 0x20) - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_IS_DATA_AVAILABLE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) - x25_error(card, err, X25_IS_DATA_AVAILABLE, 0); - } - return err; -} - -/*============================================================================ - * X.25 asynchronous event/error handler. - * This routine is called each time interface command returns non-zero - * return code to handle X.25 asynchronous events and common errors. - * Return non-zero to repeat command or zero to cancel it. - * - * Notes: - * 1. This function may be called recursively, as handling some of the - * asynchronous events (e.g. call request) requires execution of the - * interface command(s) that, in turn, may also return asynchronous - * events. To avoid re-entrancy problems we copy mailbox to dynamically - * allocated memory before processing events. - */ -static int x25_error (sdla_t* card, int err, int cmd, int lcn) -{ - int retry = 1; - unsigned dlen = ((TX25Mbox*)card->mbox)->cmd.length; - TX25Mbox* mb; - - mb = kmalloc(sizeof(TX25Mbox) + dlen, GFP_ATOMIC); - if (mb == NULL) - { - printk(KERN_ERR "%s: x25_error() out of memory!\n", - card->devname); - return 0; - } - memcpy(mb, card->mbox, sizeof(TX25Mbox) + dlen); - switch (err) - { - case 0x40: /* X.25 asynchronous packet was received */ - mb->data[dlen] = '\0'; - switch (mb->cmd.pktType & 0x7F) - { - case 0x30: /* incoming call */ - retry = incoming_call(card, cmd, lcn, mb); - break; - - case 0x31: /* connected */ - retry = call_accepted(card, cmd, lcn, mb); - break; - - case 0x02: /* call clear request */ - retry = call_cleared(card, cmd, lcn, mb); - break; - - case 0x04: /* reset request */ - printk(KERN_INFO "%s: X.25 reset request on LCN %d! " - "Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.lcn, mb->cmd.cause, - mb->cmd.diagn); - break; - - case 0x08: /* restart request */ - retry = restart_event(card, cmd, lcn, mb); - break; - - default: - printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! " - "Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.pktType, - mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn); - } - break; - - case 0x41: /* X.25 protocol violation indication */ - printk(KERN_INFO - "%s: X.25 protocol violation on LCN %d! " - "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.lcn, - mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn); - break; - - case 0x42: /* X.25 timeout */ - retry = timeout_event(card, cmd, lcn, mb); - break; - - case 0x43: /* X.25 retry limit exceeded */ - printk(KERN_INFO - "%s: exceeded X.25 retry limit on LCN %d! " - "Packet:0x%02X Diagn:0x%02X\n", card->devname, - mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn); - break; - - case 0x08: /* modem failure */ - printk(KERN_INFO "%s: modem failure!\n", card->devname); - break; - - case 0x09: /* N2 retry limit */ - printk(KERN_INFO "%s: exceeded HDLC retry limit!\n", - card->devname); - break; - - case 0x06: /* unnumbered frame was received while in ABM */ - printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n", - card->devname, mb->data[0]); - break; - - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd); - retry = 0; /* abort command */ - break; - - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", - card->devname, cmd, err); - retry = 0; /* abort command */ - } - kfree(mb); - return retry; -} - -/****** X.25 Asynchronous Event Handlers ************************************* - * These functions are called by the x25_error() and should return 0, if - * the command resulting in the asynchronous event must be aborted. - */ - -/*============================================================================ - * Handle X.25 incoming call request. - * RFC 1356 establishes the following rules: - * 1. The first octet in the Call User Data (CUD) field of the call - * request packet contains NLPID identifying protocol encapsulation. - * 2. Calls MUST NOT be accepted unless router supports requested - * protocol encapsulation. - * 3. A diagnostic code 249 defined by ISO/IEC 8208 may be used when - * clearing a call because protocol encapsulation is not supported. - * 4. If an incoming call is received while a call request is pending - * (i.e. call collision has occurred), the incoming call shall be - * rejected and call request shall be retried. - */ - -static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) -{ - wan_device_t* wandev = &card->wandev; - int new_lcn = mb->cmd.lcn; - struct net_device* dev = get_dev_by_lcn(wandev, new_lcn); - x25_channel_t* chan = NULL; - int accept = 0; /* set to '1' if o.k. to accept call */ - x25_call_info_t* info; - - /* Make sure there is no call collision */ - if (dev != NULL) - { - printk(KERN_INFO - "%s: X.25 incoming call collision on LCN %d!\n", - card->devname, new_lcn); - x25_clear_call(card, new_lcn, 0, 0); - return 1; - } - - /* Make sure D bit is not set in call request */ - if (mb->cmd.qdm & 0x02) - { - printk(KERN_INFO - "%s: X.25 incoming call on LCN %d with D-bit set!\n", - card->devname, new_lcn); - x25_clear_call(card, new_lcn, 0, 0); - return 1; - } - - /* Parse call request data */ - info = kmalloc(sizeof(x25_call_info_t), GFP_ATOMIC); - if (info == NULL) - { - printk(KERN_ERR - "%s: not enough memory to parse X.25 incoming call " - "on LCN %d!\n", card->devname, new_lcn); - x25_clear_call(card, new_lcn, 0, 0); - return 1; - } - parse_call_info(mb->data, info); - printk(KERN_INFO "%s: X.25 incoming call on LCN %d! Call data: %s\n", - card->devname, new_lcn, mb->data); - - /* Find available channel */ - for (dev = wandev->dev; dev; dev = dev->slave) - { - chan = dev->priv; - - if (!chan->svc || (chan->state != WAN_DISCONNECTED)) - continue; - if (strcmp(info->src, chan->addr) == 0) - break; - /* If just an '@' is specified, accept all incoming calls */ - if (strcmp(chan->addr, "") == 0) - break; - } - - if (dev == NULL) - { - printk(KERN_INFO "%s: no channels available!\n", - card->devname); - x25_clear_call(card, new_lcn, 0, 0); - } - - /* Check requested protocol encapsulation */ - else if (info->nuser == 0) - { - printk(KERN_INFO - "%s: no user data in incoming call on LCN %d!\n", - card->devname, new_lcn); - x25_clear_call(card, new_lcn, 0, 0); - } - else switch (info->user[0]) - { - case 0: /* multiplexed */ - chan->protocol = 0; - accept = 1; - break; - - case NLPID_IP: /* IP datagrams */ - chan->protocol = ETH_P_IP; - accept = 1; - break; - - case NLPID_SNAP: /* IPX datagrams */ - chan->protocol = ETH_P_IPX; - accept = 1; - break; - default: - printk(KERN_INFO - "%s: unsupported NLPID 0x%02X in incoming call " - "on LCN %d!\n", card->devname, info->user[0], new_lcn); - x25_clear_call(card, new_lcn, 0, 249); - } - - if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK)) - { - chan->lcn = new_lcn; - if (x25_get_chan_conf(card, chan) == CMD_OK) - set_chan_state(dev, WAN_CONNECTED); - else - x25_clear_call(card, new_lcn, 0, 0); - } - kfree(info); - return 1; -} - -/*============================================================================ - * Handle accepted call. - */ - -static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) -{ - unsigned new_lcn = mb->cmd.lcn; - struct net_device* dev = get_dev_by_lcn(&card->wandev, new_lcn); - x25_channel_t* chan; - - printk(KERN_INFO "%s: X.25 call accepted on LCN %d!\n", - card->devname, new_lcn); - if (dev == NULL) - { - printk(KERN_INFO - "%s: clearing orphaned connection on LCN %d!\n", - card->devname, new_lcn); - x25_clear_call(card, new_lcn, 0, 0); - return 1; - } - - /* Get channel configuration and notify router */ - chan = dev->priv; - if (x25_get_chan_conf(card, chan) != CMD_OK) - { - x25_clear_call(card, new_lcn, 0, 0); - return 1; - } - set_chan_state(dev, WAN_CONNECTED); - return 1; -} - -/*============================================================================ - * Handle cleared call. - */ - -static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) -{ - unsigned new_lcn = mb->cmd.lcn; - struct net_device* dev = get_dev_by_lcn(&card->wandev, new_lcn); - - printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X " - "Diagn:0x%02X\n", - card->devname, new_lcn, mb->cmd.cause, mb->cmd.diagn); - if (dev == NULL) - return 1; - set_chan_state(dev, WAN_DISCONNECTED); - return ((cmd == X25_WRITE) && (lcn == new_lcn)) ? 0 : 1; -} - -/*============================================================================ - * Handle X.25 restart event. - */ - -static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) -{ - wan_device_t* wandev = &card->wandev; - struct net_device* dev; - - printk(KERN_INFO - "%s: X.25 restart request! Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.cause, mb->cmd.diagn); - - /* down all logical channels */ - for (dev = wandev->dev; dev; dev = dev->slave) - set_chan_state(dev, WAN_DISCONNECTED); - return (cmd == X25_WRITE) ? 0 : 1; -} - -/*============================================================================ - * Handle timeout event. - */ -static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) -{ - unsigned new_lcn = mb->cmd.lcn; - - if (mb->cmd.pktType == 0x05) /* call request time out */ - { - struct net_device* dev = get_dev_by_lcn(&card->wandev, new_lcn); - - printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n", - card->devname, new_lcn); - if (dev) - set_chan_state(dev, WAN_DISCONNECTED); - } - else printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n", - card->devname, mb->cmd.pktType, new_lcn); - return 1; -} - -/******* Miscellaneous ******************************************************/ - -/*============================================================================ - * Establish physical connection. - * o open HDLC and raise DTR - * - * Return: 0 connection established - * 1 connection is in progress - * <0 error - */ -static int connect (sdla_t* card) -{ - if (x25_open_hdlc(card) || x25_setup_hdlc(card)) - return -EIO; - wanpipe_set_state(card, WAN_CONNECTING); - return 1; -} - -/*============================================================================ - * Tear down physical connection. - * o close HDLC link - * o drop DTR - * - * Return: 0 - * <0 error - */ -static int disconnect (sdla_t* card) -{ - wanpipe_set_state(card, WAN_DISCONNECTED); - x25_set_intr_mode(card, 0); /* disable interrupt generation */ - x25_close_hdlc(card); /* close HDLC link */ - x25_set_dtr(card, 0); /* drop DTR */ - return 0; -} - -/*============================================================================ - * Find network device by its channel number. - */ -static struct net_device* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn) -{ - struct net_device* dev; - - for (dev = wandev->dev; dev; dev = dev->slave) - if (((x25_channel_t*)dev->priv)->lcn == lcn) - break; - return dev; -} - -/*============================================================================ - * Initiate connection on the logical channel. - * o for PVC we just get channel configuration - * o for SVCs place an X.25 call - * - * Return: 0 connected - * >0 connection in progress - * <0 failure - */ -static int chan_connect (struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - - if (chan->svc) - { - if (!chan->addr[0]) - return -EINVAL; /* no destination address */ - printk(KERN_INFO "%s: placing X.25 call to %s ...\n", - card->devname, chan->addr); - if (x25_place_call(card, chan) != CMD_OK) - return -EIO; - set_chan_state(dev, WAN_CONNECTING); - return 1; - } - else - { - if (x25_get_chan_conf(card, chan) != CMD_OK) - return -EIO; - set_chan_state(dev, WAN_CONNECTED); - } - return 0; -} - -/*============================================================================ - * Disconnect logical channel. - * o if SVC then clear X.25 call - */ -static int chan_disc (struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - - if (chan->svc) - x25_clear_call(chan->card, chan->lcn, 0, 0); - set_chan_state(dev, WAN_DISCONNECTED); - return 0; -} - -/*============================================================================ - * Set logical channel state. - */ -static void set_chan_state (struct net_device* dev, int state) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - unsigned long flags; - - save_flags(flags); - cli(); - if (chan->state != state) - { - switch (state) - { - case WAN_CONNECTED: - printk (KERN_INFO "%s: interface %s connected!\n", - card->devname, dev->name); - *(unsigned short*)dev->dev_addr = htons(chan->lcn); - chan->i_timeout_sofar = jiffies; - break; - - case WAN_CONNECTING: - printk (KERN_INFO "%s: interface %s connecting...\n", - card->devname, dev->name); - break; - - case WAN_DISCONNECTED: - printk (KERN_INFO "%s: interface %s disconnected!\n", - card->devname, dev->name); - if (chan->svc) - { - *(unsigned short*)dev->dev_addr = 0; - chan->lcn = 0; - } - break; - } - chan->state = state; - } - chan->state_tick = jiffies; - restore_flags(flags); -} - -/*============================================================================ - * Send packet on a logical channel. - * When this function is called, tx_skb field of the channel data space - * points to the transmit socket buffer. When transmission is complete, - * release socket buffer and reset 'tbusy' flag. - * - * Return: 0 - transmission complete - * 1 - busy - * - * Notes: - * 1. If packet length is greater than MTU for this channel, we'll fragment - * the packet into 'complete sequence' using M-bit. - * 2. When transmission is complete, an event notification should be issued - * to the router. - */ -static int chan_send (struct net_device* dev, struct sk_buff* skb) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - TX25Status* status = card->flags; - unsigned len, qdm; - - /* Check to see if channel is ready */ - if (!(status->cflags[chan->ch_idx] & 0x40)) - return 1; - - if (skb->len > chan->tx_pkt_size) - { - len = chan->tx_pkt_size; - qdm = 0x01; /* set M-bit (more data) */ - } - else /* final packet */ - { - len = skb->len; - qdm = 0; - } - switch(x25_send(card, chan->lcn, qdm, len, skb->data)) - { - case 0x00: /* success */ - chan->i_timeout_sofar = jiffies; - if (qdm) - { - skb_pull(skb, len); - return 1; - } - ++chan->ifstats.tx_packets; - chan->ifstats.tx_bytes += skb->len; - break; - - case 0x33: /* Tx busy */ - return 1; - - default: /* failure */ - ++chan->ifstats.tx_errors; -/* return 1; */ - } - return 0; -} - -/*============================================================================ - * Parse X.25 call request data and fill x25_call_info_t structure. - */ - -static void parse_call_info (unsigned char* str, x25_call_info_t* info) -{ - memset(info, 0, sizeof(x25_call_info_t)); - for (; *str; ++str) - { - int i; - unsigned ch; - - if (*str == '-') switch (str[1]) - { - case 'd': /* destination address */ - for (i = 0; i < 16; ++i) - { - ch = str[2+i]; - if (!is_digit(ch)) - break; - info->dest[i] = ch; - } - break; - - case 's': /* source address */ - for (i = 0; i < 16; ++i) - { - ch = str[2+i]; - if (!is_digit(ch)) - break; - info->src[i] = ch; - } - break; - - case 'u': /* user data */ - for (i = 0; i < 127; ++i) - { - ch = str[2+2*i]; - if (!is_hex_digit(ch)) - break; - info->user[i] = hex_to_uint(&str[2+2*i], 2); - } - info->nuser = i; - break; - - case 'f': /* facilities */ - for (i = 0; i < 64; ++i) - { - ch = str[2+4*i]; - if (!is_hex_digit(ch)) - break; - info->facil[i].code = - hex_to_uint(&str[2+4*i], 2); - ch = str[4+4*i]; - if (!is_hex_digit(ch)) - break; - info->facil[i].parm = - hex_to_uint(&str[4+4*i], 2); - } - info->nfacil = i; - break; - } - } -} - -/*============================================================================ - * Convert line speed in bps to a number used by S502 code. - */ -static unsigned char bps_to_speed_code (unsigned long bps) -{ - unsigned char number; - - if (bps <= 1200) number = 0x01 ; - else if (bps <= 2400) number = 0x02; - else if (bps <= 4800) number = 0x03; - else if (bps <= 9600) number = 0x04; - else if (bps <= 19200) number = 0x05; - else if (bps <= 38400) number = 0x06; - else if (bps <= 45000) number = 0x07; - else if (bps <= 56000) number = 0x08; - else if (bps <= 64000) number = 0x09; - else if (bps <= 74000) number = 0x0A; - else if (bps <= 112000) number = 0x0B; - else if (bps <= 128000) number = 0x0C; - else number = 0x0D; - - return number; -} - -/*============================================================================ - * Convert decimal string to unsigned integer. - * If len != 0 then only 'len' characters of the string are converted. - */ -static unsigned int dec_to_uint (unsigned char* str, int len) -{ - unsigned val; - - if (!len) len = strlen(str); - for (val = 0; len && is_digit(*str); ++str, --len) - val = (val * 10) + (*str - (unsigned)'0'); - return val; -} - -/*============================================================================ - * Convert hex string to unsigned integer. - * If len != 0 then only 'len' characters of the string are conferted. - */ -static unsigned int hex_to_uint (unsigned char* str, int len) -{ - unsigned val, ch; - - if (!len) len = strlen(str); - for (val = 0; len; ++str, --len) - { - ch = *str; - if (is_digit(ch)) - val = (val << 4) + (ch - (unsigned)'0'); - else if (is_hex_digit(ch)) - val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10); - else - break; - } - return val; -} - - -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) -{ - int i; - - if( proto == htons(ETH_P_IPX) ) { - /* It's an IPX packet */ - if(!enable_IPX) { - /* Return 1 so we don't pass it up the stack. */ - return 1; - } - } else { - /* It's not IPX so pass it up the stack. */ - return 0; - } - - if( sendpacket[16] == 0x90 && - sendpacket[17] == 0x04) - { - /* It's IPXWAN */ - - if( sendpacket[2] == 0x02 && - sendpacket[34] == 0x00) - { - /* It's a timer request packet */ - printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); - - /* Go through the routing options and answer no to every - * option except Unnumbered RIP/SAP */ - for(i = 41; sendpacket[i] == 0x00; i += 5) - { - /* 0x02 is the option for Unnumbered RIP/SAP */ - if( sendpacket[i + 4] != 0x02) - sendpacket[i + 1] = 0; - } - - /* Skip over the extended Node ID option */ - if( sendpacket[i] == 0x04 ) - i += 8; - - /* We also want to turn off all header compression opt. */ - for(; sendpacket[i] == 0x80 ;) - { - sendpacket[i + 1] = 0; - i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; - } - - /* Set the packet type to timer response */ - sendpacket[34] = 0x01; - - printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); - } - else if( sendpacket[34] == 0x02 ) - { - /* This is an information request packet */ - printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); - - /* Set the packet type to information response */ - sendpacket[34] = 0x03; - - /* Set the router name */ - sendpacket[51] = 'X'; - sendpacket[52] = 'T'; - sendpacket[53] = 'P'; - sendpacket[54] = 'I'; - sendpacket[55] = 'P'; - sendpacket[56] = 'E'; - sendpacket[57] = '-'; - sendpacket[58] = CVHexToAscii(network_number >> 28); - sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24); - sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20); - sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16); - sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12); - sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8); - sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); - sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); - for(i = 66; i < 99; i+= 1) - sendpacket[i] = 0; - - printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); - } - else - { - printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); - return 0; - } - - /* Set the WNodeID to our network address */ - sendpacket[35] = (unsigned char)(network_number >> 24); - sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16); - sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8); - sendpacket[38] = (unsigned char)(network_number & 0x000000FF); - - return 1; - } else { - /* If we get here its an IPX-data packet, so it'll get passed up the stack. - switch the network numbers */ - switch_net_numbers(sendpacket, network_number, 1); - return 0; - } -} - -/* - If incoming is 0 (outgoing)- if the net numbers is ours make it 0 - if incoming is 1 - if the net number is 0 make it ours - -*/ - -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) -{ - unsigned long pnetwork_number; - - pnetwork_number = (unsigned long)((sendpacket[6] << 24) + - (sendpacket[7] << 16) + (sendpacket[8] << 8) + - sendpacket[9]); - - if (!incoming) - { - /* If the destination network number is ours, make it 0 */ - if( pnetwork_number == network_number) - { - sendpacket[6] = sendpacket[7] = sendpacket[8] = - sendpacket[9] = 0x00; - } - } - else - { - /* If the incoming network is 0, make it ours */ - if( pnetwork_number == 0) - { - sendpacket[6] = (unsigned char)(network_number >> 24); - sendpacket[7] = (unsigned char)((network_number & - 0x00FF0000) >> 16); - sendpacket[8] = (unsigned char)((network_number & - 0x0000FF00) >> 8); - sendpacket[9] = (unsigned char)(network_number & - 0x000000FF); - } - } - - - pnetwork_number = (unsigned long)((sendpacket[18] << 24) + - (sendpacket[19] << 16) + (sendpacket[20] << 8) + - sendpacket[21]); - - if( !incoming ) - { - /* If the source network is ours, make it 0 */ - if( pnetwork_number == network_number) - { - sendpacket[18] = sendpacket[19] = sendpacket[20] = - sendpacket[21] = 0x00; - } - } - else - { - /* If the source network is 0, make it ours */ - if( pnetwork_number == 0 ) - { - sendpacket[18] = (unsigned char)(network_number >> 24); - sendpacket[19] = (unsigned char)((network_number & - 0x00FF0000) >> 16); - sendpacket[20] = (unsigned char)((network_number & - 0x0000FF00) >> 8); - sendpacket[21] = (unsigned char)(network_number & - 0x000000FF); - } - } -} /* switch_net_numbers */ - - -/****** End *****************************************************************/ diff -u --recursive --new-file v2.3.20/linux/drivers/net/sdladrv.c linux/drivers/net/sdladrv.c --- v2.3.20/linux/drivers/net/sdladrv.c Wed Jun 2 14:40:22 1999 +++ linux/drivers/net/sdladrv.c Wed Dec 31 16:00:00 1969 @@ -1,1856 +0,0 @@ -/***************************************************************************** -* sdladrv.c SDLA Support Module. Main module. -* -* This module is a library of common hardware-specific functions -* used by all Sangoma drivers. -* -* Author: Gene Kozin -* -* 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 /* printk(), and other useful stuff */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include /* support for loadable modules */ -#include /* for jiffies, HZ, etc. */ -#include /* API definitions */ -#include /* SDLA firmware module definitions */ -#include /* 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 /* API definitions */ -#include /* SDLA firmware module definitions */ -#include /* for inb(), outb(), etc. */ -#define _INB(port) (inb(port)) -#define _OUTB(port, byte) (outb((port),(byte))) -#define SYSTEM_TICK lbolt - -#else -#error Unknown system type! -#endif - -#define MOD_VERSION 3 -#define MOD_RELEASE 0 - -#define SDLA_IODELAY 100 /* I/O Rd/Wr delay, 10 works for 486DX2-66 */ -#define EXEC_DELAY 20 /* shared memory access delay, mks */ -#define EXEC_TIMEOUT (HZ*2) /* command timeout, in ticks */ - -/* I/O port address range */ -#define S502A_IORANGE 3 -#define S502E_IORANGE 4 -#define S503_IORANGE 3 -#define S507_IORANGE 4 -#define S508_IORANGE 4 - -/* Maximum amount of memory */ -#define S502_MAXMEM 0x10000L -#define S503_MAXMEM 0x10000L -#define S507_MAXMEM 0x40000L -#define S508_MAXMEM 0x40000L - -/* Minimum amount of memory */ -#define S502_MINMEM 0x8000L -#define S503_MINMEM 0x8000L -#define S507_MINMEM 0x20000L -#define S508_MINMEM 0x20000L - -/****** Function Prototypes *************************************************/ - -/* Module entry points. These are called by the OS and must be public. */ -int init_module (void); -void cleanup_module (void); - -/* Hardware-specific functions */ -static int sdla_detect (sdlahw_t* hw); -static int sdla_autodpm (sdlahw_t* hw); -static int sdla_setdpm (sdlahw_t* hw); -static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len); -static int sdla_init (sdlahw_t* hw); -static unsigned long sdla_memtest (sdlahw_t* hw); -static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo); -static unsigned char make_config_byte (sdlahw_t* hw); -static int sdla_start (sdlahw_t* hw, unsigned addr); - -static int init_s502a (sdlahw_t* hw); -static int init_s502e (sdlahw_t* hw); -static int init_s503 (sdlahw_t* hw); -static int init_s507 (sdlahw_t* hw); -static int init_s508 (sdlahw_t* hw); - -static int detect_s502a (int port); -static int detect_s502e (int port); -static int detect_s503 (int port); -static int detect_s507 (int port); -static int detect_s508 (int port); - -/* Miscellaneous functions */ -static int calibrate_delay (int mks); -static int get_option_index (unsigned* optlist, unsigned optval); -static unsigned check_memregion (void* ptr, unsigned len); -static unsigned test_memregion (void* ptr, unsigned len); -static unsigned short checksum (unsigned char* buf, unsigned len); - -/****** Global Data ********************************************************** - * Note: All data must be explicitly initialized!!! - */ - -/* private data */ -static char modname[] = "sdladrv"; -static char fullname[] = "SDLA Support Module"; -static char copyright[] = "(c) 1995-1996 Sangoma Technologies Inc."; -static unsigned exec_idle; - -/* Hardware configuration options. - * These are arrays of configuration options used by verification routines. - * The first element of each array is its size (i.e. number of options). - */ -static unsigned s502_port_options[] = - { 4, 0x250, 0x300, 0x350, 0x360 } -; -static unsigned s503_port_options[] = - { 8, 0x250, 0x254, 0x300, 0x304, 0x350, 0x354, 0x360, 0x364 } -; -static unsigned s508_port_options[] = - { 8, 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390 } -; - -static unsigned s502a_irq_options[] = { 0 }; -static unsigned s502e_irq_options[] = { 4, 2, 3, 5, 7 }; -static unsigned s503_irq_options[] = { 5, 2, 3, 4, 5, 7 }; -static unsigned s508_irq_options[] = { 8, 3, 4, 5, 7, 10, 11, 12, 15 }; - -static unsigned s502a_dpmbase_options[] = -{ - 28, - 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, - 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, - 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, - 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, -}; -static unsigned s507_dpmbase_options[] = -{ - 32, - 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, - 0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000, - 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000, - 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000, -}; -static unsigned s508_dpmbase_options[] = /* incl. S502E and S503 */ -{ - 32, - 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, - 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000, - 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, 0xDE000, - 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000, -}; - -/* -static unsigned s502_dpmsize_options[] = { 2, 0x2000, 0x10000 }; -static unsigned s507_dpmsize_options[] = { 2, 0x2000, 0x4000 }; -static unsigned s508_dpmsize_options[] = { 1, 0x2000 }; -*/ - -static unsigned s502a_pclk_options[] = { 2, 3600, 7200 }; -static unsigned s502e_pclk_options[] = { 5, 3600, 5000, 7200, 8000, 10000 }; -static unsigned s503_pclk_options[] = { 3, 7200, 8000, 10000 }; -static unsigned s507_pclk_options[] = { 1, 12288 }; -static unsigned s508_pclk_options[] = { 1, 16000 }; - -/* Host memory control register masks */ -static unsigned char s502a_hmcr[] = -{ - 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, /* A0000 - AC000 */ - 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, /* C0000 - CC000 */ - 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, /* D0000 - DC000 */ - 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, /* E0000 - EC000 */ -}; -static unsigned char s502e_hmcr[] = -{ - 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, /* A0000 - AE000 */ - 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E, /* C0000 - CE000 */ - 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* D0000 - DE000 */ - 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E, /* E0000 - EE000 */ -}; -static unsigned char s507_hmcr[] = -{ - 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* A0000 - AE000 */ - 0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, /* B0000 - BE000 */ - 0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E, /* C0000 - CE000 */ - 0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, /* E0000 - EE000 */ -}; -static unsigned char s508_hmcr[] = -{ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* A0000 - AE000 */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* C0000 - CE000 */ - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* D0000 - DE000 */ - 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* E0000 - EE000 */ -}; - -static unsigned char s507_irqmask[] = -{ - 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0 -}; - -/******* Kernel Loadable Module Entry Points ********************************/ - -/*============================================================================ - * Module 'insert' entry point. - * o print announcement - * o initialize static data - * o calibrate SDLA shared memory access delay. - * - * Return: 0 Ok - * < 0 error. - * Context: process - */ - -#ifdef MODULE -int init_module (void) -{ - printk(KERN_INFO "%s v%u.%u %s\n", - fullname, MOD_VERSION, MOD_RELEASE, copyright); - exec_idle = calibrate_delay(EXEC_DELAY); -#ifdef WANDEBUG - printk(KERN_DEBUG "%s: exec_idle = %d\n", modname, exec_idle); -#endif - return 0; -} - -/*============================================================================ - * Module 'remove' entry point. - * o release all remaining system resources - */ -void cleanup_module (void) -{ -} -#endif - -/******* Kernel APIs ********************************************************/ - -/*============================================================================ - * Set up adapter. - * o detect adapter type - * o verify hardware configuration options - * o check for hardware conflicts - * o set up adapter shared memory - * o test adapter memory - * o load firmware - * Return: 0 ok. - * < 0 error - */ - -EXPORT_SYMBOL(sdla_setup); - -int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len) -{ - unsigned* irq_opt = NULL; /* IRQ options */ - unsigned* dpmbase_opt = NULL; /* DPM window base options */ - unsigned* pclk_opt = NULL; /* CPU clock rate options */ - int err; - - if (sdla_detect(hw)) - { - printk(KERN_ERR "%s: adapter S%04u not found at port 0x%X!\n", - modname, hw->type, hw->port) - ; - return -EINVAL; - } - printk(KERN_INFO "%s: found S%04u card at port 0x%X.\n", - modname, hw->type, hw->port) - ; - - hw->dpmsize = SDLA_WINDOWSIZE; - switch (hw->type) - { - case SDLA_S502A: - hw->io_range = S502A_IORANGE; - irq_opt = s502a_irq_options; - dpmbase_opt = s502a_dpmbase_options; - pclk_opt = s502a_pclk_options; - break; - - case SDLA_S502E: - hw->io_range = S502E_IORANGE; - irq_opt = s502e_irq_options; - dpmbase_opt = s508_dpmbase_options; - pclk_opt = s502e_pclk_options; - break; - - case SDLA_S503: - hw->io_range = S503_IORANGE; - irq_opt = s503_irq_options; - dpmbase_opt = s508_dpmbase_options; - pclk_opt = s503_pclk_options; - break; - - case SDLA_S507: - hw->io_range = S507_IORANGE; - irq_opt = s508_irq_options; - dpmbase_opt = s507_dpmbase_options; - pclk_opt = s507_pclk_options; - break; - - case SDLA_S508: - hw->io_range = S508_IORANGE; - irq_opt = s508_irq_options; - dpmbase_opt = s508_dpmbase_options; - pclk_opt = s508_pclk_options; - break; - } - - /* Verify IRQ configuration options */ - if (!get_option_index(irq_opt, hw->irq)) - { - printk(KERN_ERR "%s: IRQ %d is illegal!\n", - modname, hw->irq) - ; - return -EINVAL; - } - - /* Verify CPU clock rate configuration options */ - if (hw->pclk == 0) - hw->pclk = pclk_opt[1] /* use default */ - ; - else if (!get_option_index(pclk_opt, hw->pclk)) - { - printk(KERN_ERR "%s: CPU clock %u is illegal!\n", - modname, hw->pclk) - ; - return -EINVAL; - } - printk(KERN_INFO "%s: assuming CPU clock rate of %u kHz.\n", - modname, hw->pclk) - ; - - /* Setup adapter dual-port memory window and test memory */ - if (hw->dpmbase == 0) - { - err = sdla_autodpm(hw); - if (err) - { - printk(KERN_ERR - "%s: can't find available memory region!\n", - modname) - ; - return err; - } - } - else if (!get_option_index(dpmbase_opt, virt_to_phys(hw->dpmbase))) - { - printk(KERN_ERR "%s: memory address 0x%lX is illegal!\n", - modname, virt_to_phys(hw->dpmbase)) - ; - return -EINVAL; - } - else if (sdla_setdpm(hw)) - { - printk(KERN_ERR - "%s: 8K memory region at 0x%lX is not available!\n", - modname, virt_to_phys(hw->dpmbase)); - return -EINVAL; - } - printk(KERN_INFO "%s: dual-port memory window is set at 0x%lX.\n", - modname, virt_to_phys(hw->dpmbase)); - - printk(KERN_INFO "%s: found %luK bytes of on-board memory.\n", - modname, hw->memory / 1024); - - /* Load firmware. If loader fails then shut down adapter */ - err = sdla_load(hw, sfm, len); - if (err) sdla_down(hw); /* shutdown adapter */ - return err; -} - -/*============================================================================ - * Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc. - */ - -EXPORT_SYMBOL(sdla_down); - -int sdla_down (sdlahw_t* hw) -{ - unsigned port = hw->port; - int i; - - if (!port) return -EFAULT; - - switch (hw->type) - { - case SDLA_S502A: - _OUTB(port, 0x08); /* halt CPU */ - _OUTB(port, 0x08); - _OUTB(port, 0x08); - hw->regs[0] = 0x08; - _OUTB(port + 1, 0xFF); /* close memory window */ - hw->regs[1] = 0xFF; - break; - - case SDLA_S502E: - _OUTB(port + 3, 0); /* stop CPU */ - _OUTB(port, 0); /* reset board */ - for (i = 0; i < S502E_IORANGE; ++i) - hw->regs[i] = 0 - ; - break; - - case SDLA_S503: - case SDLA_S507: - case SDLA_S508: - _OUTB(port, 0); /* reset board logic */ - hw->regs[0] = 0; - break; - - default: - return -EINVAL; - } - return 0; -} - -/*============================================================================ - * Map shared memory window into SDLA address space. - */ - -EXPORT_SYMBOL(sdla_mapmem); - -int sdla_mapmem (sdlahw_t* hw, unsigned long addr) -{ - unsigned port = hw->port; - register int tmp; - - switch (hw->type) - { - case SDLA_S502A: - case SDLA_S502E: - if (addr < S502_MAXMEM) /* verify parameter */ - { - tmp = addr >> 13; /* convert to register mask */ - _OUTB(port + 2, tmp); - hw->regs[2] = tmp; - } - else return -EINVAL; - break; - - case SDLA_S503: - if (addr < S503_MAXMEM) /* verify parameter */ - { - tmp = (hw->regs[0] & 0x8F) | ((addr >> 9) & 0x70); - _OUTB(port, tmp); - hw->regs[0] = tmp; - } - else return -EINVAL; - break; - - case SDLA_S507: - if (addr < S507_MAXMEM) - { - if (!(_INB(port) & 0x02)) - return -EIO - ; - tmp = addr >> 13; /* convert to register mask */ - _OUTB(port + 2, tmp); - hw->regs[2] = tmp; - } - else return -EINVAL; - break; - - case SDLA_S508: - if (addr < S508_MAXMEM) - { - tmp = addr >> 13; /* convert to register mask */ - _OUTB(port + 2, tmp); - hw->regs[2] = tmp; - } - else return -EINVAL; - break; - - default: - return -EINVAL; - } - hw->vector = addr & 0xFFFFE000L; - return 0; -} - -/*============================================================================ - * Enable interrupt generation. - */ - -EXPORT_SYMBOL(sdla_inten); - -int sdla_inten (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - switch (hw->type) - { - case SDLA_S502E: - /* Note thar interrupt control operations on S502E are allowed - * only if CPU is enabled (bit 0 of status register is set). - */ - if (_INB(port) & 0x01) - { - _OUTB(port, 0x02); /* bit1 = 1, bit2 = 0 */ - _OUTB(port, 0x06); /* bit1 = 1, bit2 = 1 */ - hw->regs[0] = 0x06; - } - else return -EIO; - break; - - case SDLA_S503: - tmp = hw->regs[0] | 0x04; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (!(_INB(port) & 0x02)) /* verify */ - return -EIO - ; - break; - - case SDLA_S508: - tmp = hw->regs[0] | 0x10; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (!(_INB(port + 1) & 0x10)) /* verify */ - return -EIO - ; - break; - - case SDLA_S502A: - case SDLA_S507: - break; - - default: - return -EINVAL; - - } - return 0; -} - -/*============================================================================ - * Disable interrupt generation. - */ - -EXPORT_SYMBOL(sdla_intde); - -int sdla_intde (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - switch (hw->type) - { - case SDLA_S502E: - /* Notes: - * 1) interrupt control operations are allowed only if CPU is - * enabled (bit 0 of status register is set). - * 2) disabling interrupts using bit 1 of control register - * causes IRQ line go high, therefore we are going to use - * 0x04 instead: lower it to inhibit interrupts to PC. - */ - if (_INB(port) & 0x01) - { - _OUTB(port, hw->regs[0] & ~0x04); - hw->regs[0] &= ~0x04; - } - else return -EIO; - break; - - case SDLA_S503: - tmp = hw->regs[0] & ~0x04; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) & 0x02) /* verify */ - return -EIO - ; - break; - - case SDLA_S508: - tmp = hw->regs[0] & ~0x10; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) & 0x10) /* verify */ - return -EIO - ; - break; - - case SDLA_S502A: - case SDLA_S507: - break; - - default: - return -EINVAL; - } - return 0; -} - -/*============================================================================ - * Acknowledge SDLA hardware interrupt. - */ - -EXPORT_SYMBOL(sdla_intack); - -int sdla_intack (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp; - - switch (hw->type) - { - case SDLA_S502E: - /* To acknoledge hardware interrupt we have to toggle bit 3 of - * control register: \_/ - * Note that interrupt control operations on S502E are allowed - * only if CPU is enabled (bit 1 of status register is set). - */ - if (_INB(port) & 0x01) - { - tmp = hw->regs[0] & ~0x04; - _OUTB(port, tmp); - tmp |= 0x04; - _OUTB(port, tmp); - hw->regs[0] = tmp; - } - else return -EIO; - break; - - case SDLA_S503: - if (_INB(port) & 0x04) - { - tmp = hw->regs[0] & ~0x08; - _OUTB(port, tmp); - tmp |= 0x08; - _OUTB(port, tmp); - hw->regs[0] = tmp; - } - break; - - case SDLA_S502A: - case SDLA_S507: - case SDLA_S508: - break; - - default: - return -EINVAL; - } - return 0; -} - -/*============================================================================ - * Generate an interrupt to adapter's CPU. - */ - -EXPORT_SYMBOL(sdla_intr); - -int sdla_intr (sdlahw_t* hw) -{ - unsigned port = hw->port; - - switch (hw->type) - { - case SDLA_S502A: - if (!(_INB(port) & 0x40)) - { - _OUTB(port, 0x10); /* issue NMI to CPU */ - hw->regs[0] = 0x10; - } - else return -EIO; - break; - - case SDLA_S507: - if ((_INB(port) & 0x06) == 0x06) - { - _OUTB(port + 3, 0); - } - else return -EIO; - break; - - case SDLA_S508: - if (_INB(port + 1) & 0x02) - { - _OUTB(port, 0x08); - } - else return -EIO; - break; - - case SDLA_S502E: - case SDLA_S503: - default: - return -EINVAL; - } - return 0; -} - -/*============================================================================ - * Execute Adapter Command. - * o Set exec flag. - * o Busy-wait until flag is reset. - * o Return number of loops made, or 0 if command timed out. - */ - -EXPORT_SYMBOL(sdla_exec); - -int sdla_exec (void* opflag) -{ - volatile unsigned char* flag = opflag; - unsigned long tstop; - int nloops; - - if (*flag) return 0; /* ???? */ - - *flag = 1; - tstop = SYSTEM_TICK + EXEC_TIMEOUT; - for (nloops = 1; *flag; ++nloops) - { - unsigned delay = exec_idle; - while (--delay); /* delay */ - if (SYSTEM_TICK > tstop) return 0; /* time is up! */ - } - return nloops; -} - -/*============================================================================ - * Read absolute adapter memory. - * Transfer data from adapter's memory to data buffer. - * - * Note: - * Care should be taken when crossing dual-port memory window boundary. - * This function is not atomic, so caller must disable interrupt if - * interrupt routines are accessing adapter shared memory. - */ - -EXPORT_SYMBOL(sdla_peek); - -int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) -{ - unsigned long oldvec = hw->vector; - unsigned winsize = hw->dpmsize; - unsigned curpos, curlen; /* current offset and block size */ - unsigned long curvec; /* current DPM window vector */ - int err = 0; - - if (addr + len > hw->memory) /* verify arguments */ - return -EINVAL - ; - while (len && !err) - { - curpos = addr % winsize; /* current window offset */ - curvec = addr - curpos; /* current window vector */ - curlen = (len > (winsize - curpos)) ? (winsize - curpos) : len; - - /* Relocate window and copy block of data */ - err = sdla_mapmem(hw, curvec); - memcpy(buf, (void *)((u8 *)hw->dpmbase + curpos), curlen); - addr += curlen; - (char*)buf += curlen; - len -= curlen; - } - - /* Restore DPM window position */ - sdla_mapmem(hw, oldvec); - return err; -} - -/*============================================================================ - * Write Absolute Adapter Memory. - * Transfer data from data buffer to adapter's memory. - * - * Note: - * Care should be taken when crossing dual-port memory window boundary. - * This function is not atomic, so caller must disable interrupt if - * interrupt routines are accessing adapter shared memory. - */ - -EXPORT_SYMBOL(sdla_poke); - -int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) -{ - unsigned long oldvec = hw->vector; - unsigned winsize = hw->dpmsize; - unsigned curpos, curlen; /* current offset and block size */ - unsigned long curvec; /* current DPM window vector */ - int err = 0; - - if (addr + len > hw->memory) /* verify arguments */ - return -EINVAL - ; - while (len && !err) - { - curpos = addr % winsize; /* current window offset */ - curvec = addr - curpos; /* current window vector */ - curlen = (len > (winsize - curpos)) ? (winsize - curpos) : len; - - /* Relocate window and copy block of data */ - sdla_mapmem(hw, curvec); - memcpy((void*)((u8 *)hw->dpmbase + curpos), buf, curlen); - addr += curlen; - (char*)buf += curlen; - len -= curlen; - } - - /* Restore DPM window position */ - sdla_mapmem(hw, oldvec); - return err; -} - -#ifdef DONT_COMPIPLE_THIS -#endif /* DONT_COMPIPLE_THIS */ - -/****** Hardware-Specific Functions *****************************************/ - -/*============================================================================ - * Detect adapter type. - * o if adapter type is specified then call detection routine for that adapter - * type. Otherwise call detection routines for every adapter types until - * adapter is detected. - * - * Notes: - * 1) Detection tests are destructive! Adapter will be left in shutdown state - * after the test. - */ -static int sdla_detect (sdlahw_t* hw) -{ - unsigned port = hw->port; - int err = 0; - - if (!port) - return -EFAULT - ; - switch (hw->type) - { - case SDLA_S502A: - if (!detect_s502a(port)) err = -ENODEV; - break; - - case SDLA_S502E: - if (!detect_s502e(port)) err = -ENODEV; - break; - - case SDLA_S503: - if (!detect_s503(port)) err = -ENODEV; - break; - - case SDLA_S507: - if (!detect_s507(port)) err = -ENODEV; - break; - - case SDLA_S508: - if (!detect_s508(port)) err = -ENODEV; - break; - - default: - if (detect_s502a(port)) - hw->type = SDLA_S502A - ; - else if (detect_s502e(port)) - hw->type = SDLA_S502E - ; - else if (detect_s503(port)) - hw->type = SDLA_S503 - ; - else if (detect_s507(port)) - hw->type = SDLA_S507 - ; - else if (detect_s508(port)) - hw->type = SDLA_S508 - ; - else err = -ENODEV; - } - return err; -} - -/*============================================================================ - * Autoselect memory region. - * o try all available DMP address options from the top down until success. - */ -static int sdla_autodpm (sdlahw_t* hw) -{ - int i, err = -EINVAL; - unsigned* opt; - - switch (hw->type) - { - case SDLA_S502A: - opt = s502a_dpmbase_options; - break; - - case SDLA_S502E: - case SDLA_S503: - case SDLA_S508: - opt = s508_dpmbase_options; - break; - - case SDLA_S507: - opt = s507_dpmbase_options; - break; - - default: - return -EINVAL; - } - - for (i = opt[0]; i && err; --i) - { - hw->dpmbase = phys_to_virt(opt[i]); - err = sdla_setdpm(hw); - } - return err; -} - -/*============================================================================ - * Set up adapter dual-port memory window. - * o shut down adapter - * o make sure that no physical memory exists in this region, i.e entire - * region reads 0xFF and is not writable when adapter is shut down. - * o initialize adapter hardware - * o make sure that region is usable with SDLA card, i.e. we can write to it - * when adapter is configured. - */ -static int sdla_setdpm (sdlahw_t* hw) -{ - int err; - - /* Shut down card and verify memory region */ - sdla_down(hw); - if (check_memregion(hw->dpmbase, hw->dpmsize)) - return -EINVAL - ; - - /* Initialize adapter and test on-board memory segment by segment. - * If memory size appears to be less than shared memory window size, - * assume that memory region is unusable. - */ - err = sdla_init(hw); - if (err) return err; - - if (sdla_memtest(hw) < hw->dpmsize) /* less than window size */ - { - sdla_down(hw); - return -EIO; - } - sdla_mapmem(hw, 0L); /* set window vector at bottom */ - return 0; -} - -/*============================================================================ - * Load adapter from the memory image of the SDLA firmware module. - * o verify firmware integrity and compatibility - * o start adapter up - */ -static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len) -{ - int i; - - /* Verify firmware signature */ - if (strcmp(sfm->signature, SFM_SIGNATURE)) - { - printk(KERN_ERR "%s: not SDLA firmware!\n", - modname) - ; - return -EINVAL; - } - - /* Verify firmware module format version */ - if (sfm->version != SFM_VERSION) - { - printk(KERN_ERR - "%s: firmware format %u rejected! Expecting %u.\n", - modname, sfm->version, SFM_VERSION) - ; - return -EINVAL; - } - - /* Verify firmware module length and checksum */ - if ((len - offsetof(sfm_t, image) != sfm->info.codesize) || - (checksum((void*)&sfm->info, - sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum)) - { - printk(KERN_ERR "%s: firmware corrupted!\n", modname); - return -EINVAL; - } - - /* Announce */ - printk(KERN_INFO "%s: loading %s (ID=%u)...\n", modname, - (sfm->descr[0] != '\0') ? sfm->descr : "unknown firmware", - sfm->info.codeid) - ; - - /* Scan through the list of compatible adapters and make sure our - * adapter type is listed. - */ - for (i = 0; - (i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hw->type); - ++i) - ; - if (i == SFM_MAX_SDLA) - { - printk(KERN_ERR "%s: firmware is not compatible with S%u!\n", - modname, hw->type) - ; - return -EINVAL; - } - - /* Make sure there is enough on-board memory */ - if (hw->memory < sfm->info.memsize) - { - printk(KERN_ERR - "%s: firmware needs %lu bytes of on-board memory!\n", - modname, sfm->info.memsize) - ; - return -EINVAL; - } - - /* Move code onto adapter */ - if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize)) - { - printk(KERN_ERR "%s: failed to load code segment!\n", - modname) - ; - return -EIO; - } - - /* Prepare boot-time configuration data and kick-off CPU */ - sdla_bootcfg(hw, &sfm->info); - if (sdla_start(hw, sfm->info.startoffs)) - { - printk(KERN_ERR "%s: Damn... Adapter won't start!\n", - modname) - ; - return -EIO; - } - - /* position DPM window over the mailbox and enable interrupts */ - if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw)) - { - printk(KERN_ERR "%s: adapter hardware failure!\n", - modname) - ; - return -EIO; - } - hw->fwid = sfm->info.codeid; /* set firmware ID */ - return 0; -} - -/*============================================================================ - * Initialize SDLA hardware: setup memory window, IRQ, etc. - */ -static int sdla_init (sdlahw_t* hw) -{ - int i; - - for (i = 0; i < SDLA_MAXIORANGE; ++i) - hw->regs[i] = 0 - ; - switch (hw->type) - { - case SDLA_S502A: return init_s502a(hw); - case SDLA_S502E: return init_s502e(hw); - case SDLA_S503: return init_s503(hw); - case SDLA_S507: return init_s507(hw); - case SDLA_S508: return init_s508(hw); - } - return -EINVAL; -} - -/*============================================================================ - * Test adapter on-board memory. - * o slide DPM window from the bottom up and test adapter memory segment by - * segment. - * Return adapter memory size. - */ -static unsigned long sdla_memtest (sdlahw_t* hw) -{ - unsigned long memsize; - unsigned winsize; - - for (memsize = 0, winsize = hw->dpmsize; - !sdla_mapmem(hw, memsize) && - (test_memregion(hw->dpmbase, winsize) == winsize) - ; - memsize += winsize) - ; - hw->memory = memsize; - return memsize; -} - -/*============================================================================ - * Prepare boot-time firmware configuration data. - * o position DPM window - * o initialize configuration data area - */ -static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo) -{ - unsigned char* data; - - if (!sfminfo->datasize) return 0; /* nothing to do */ - - if (sdla_mapmem(hw, sfminfo->dataoffs) != 0) - return -EIO - ; - data = (void*)((u8 *)hw->dpmbase + (sfminfo->dataoffs - hw->vector)); - memset(data, 0, sfminfo->datasize); - - data[0x00] = make_config_byte(hw); - switch (sfminfo->codeid) - { - case SFID_X25_502: - case SFID_X25_508: - data[0x01] = 3; /* T1 timer */ - data[0x03] = 10; /* N2 */ - data[0x06] = 7; /* HDLC window size */ - data[0x0B] = 1; /* DTE */ - data[0x0C] = 2; /* X.25 packet window size */ - *(short*)&data[0x0D] = 128; /* default X.25 data size */ - *(short*)&data[0x0F] = 128; /* maximum X.25 data size */ - break; - } - return 0; -} - -/*============================================================================ - * Prepare configuration byte identifying adapter type and CPU clock rate. - */ -static unsigned char make_config_byte (sdlahw_t* hw) -{ - unsigned char byte = 0; - - switch (hw->pclk) - { - case 5000: byte = 0x01; break; - case 7200: byte = 0x02; break; - case 8000: byte = 0x03; break; - case 10000: byte = 0x04; break; - case 16000: byte = 0x05; break; - } - switch (hw->type) - { - case SDLA_S502E: byte |= 0x80; break; - case SDLA_S503: byte |= 0x40; break; - } - return byte; -} - -/*============================================================================ - * Start adapter's CPU. - * o calculate a pointer to adapter's cold boot entry point - * o position DPM window - * o place boot instruction (jp addr) at cold boot entry point - * o start CPU - */ -static int sdla_start (sdlahw_t* hw, unsigned addr) -{ - unsigned port = hw->port; - unsigned char *bootp; - int err, tmp, i; - - if (!port) return -EFAULT; - - switch (hw->type) - { - case SDLA_S502A: - bootp = hw->dpmbase; - bootp += 0x66; - break; - - case SDLA_S502E: - case SDLA_S503: - case SDLA_S507: - case SDLA_S508: - bootp = hw->dpmbase; - break; - - default: - return -EINVAL; - } - - err = sdla_mapmem(hw, 0); - if (err) return err; - - *bootp = 0xC3; /* Z80: 'jp' opcode */ - bootp++; - *((unsigned short*)(bootp)) = addr; - - switch (hw->type) - { - case SDLA_S502A: - _OUTB(port, 0x10); /* issue NMI to CPU */ - hw->regs[0] = 0x10; - break; - - case SDLA_S502E: - _OUTB(port + 3, 0x01); /* start CPU */ - hw->regs[3] = 0x01; - for (i = 0; i < SDLA_IODELAY; ++i); - if (_INB(port) & 0x01) /* verify */ - { - /* - * Enabling CPU changes functionality of the - * control register, so we have to reset its - * mirror. - */ - _OUTB(port, 0); /* disable interrupts */ - hw->regs[0] = 0; - } - else return -EIO; - break; - - case SDLA_S503: - tmp = hw->regs[0] | 0x09; /* set bits 0 and 3 */ - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); - if (!(_INB(port) & 0x01)) /* verify */ - return -EIO - ; - break; - - case SDLA_S507: - tmp = hw->regs[0] | 0x02; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); - if (!(_INB(port) & 0x04)) /* verify */ - return -EIO - ; - break; - - case SDLA_S508: - tmp = hw->regs[0] | 0x02; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); - if (!(_INB(port + 1) & 0x02)) /* verify */ - return -EIO - ; - break; - - default: - return -EINVAL; - } - return 0; -} - -/*============================================================================ - * Initialize S502A adapter. - */ -static int init_s502a (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - if (!detect_s502a(port)) - return -ENODEV - ; - hw->regs[0] = 0x08; - hw->regs[1] = 0xFF; - - /* Verify configuration options */ - i = get_option_index(s502a_dpmbase_options, virt_to_phys(hw->dpmbase)); - if (i == 0) - return -EINVAL - ; - - tmp = s502a_hmcr[i - 1]; - switch (hw->dpmsize) - { - case 0x2000: - tmp |= 0x01; - break; - - case 0x10000L: - break; - - default: - return -EINVAL; - } - - /* Setup dual-port memory window (this also enables memory access) */ - _OUTB(port + 1, tmp); - hw->regs[1] = tmp; - hw->regs[0] = 0x08; - return 0; -} - -/*============================================================================ - * Initialize S502E adapter. - */ -static int init_s502e (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - if (!detect_s502e(port)) - return -ENODEV - ; - - /* Verify configuration options */ - i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); - if (i == 0) - return -EINVAL - ; - - tmp = s502e_hmcr[i - 1]; - switch (hw->dpmsize) - { - case 0x2000: - tmp |= 0x01; - break; - - case 0x10000L: - break; - - default: - return -EINVAL; - } - - /* Setup dual-port memory window */ - _OUTB(port + 1, tmp); - hw->regs[1] = tmp; - - /* Enable memory access */ - _OUTB(port, 0x02); - hw->regs[0] = 0x02; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - return (_INB(port) & 0x02) ? 0 : -EIO; -} - -/*============================================================================ - * Initialize S503 adapter. - * --------------------------------------------------------------------------- - */ -static int init_s503 (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - if (!detect_s503(port)) - return -ENODEV - ; - - /* Verify configuration options */ - i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); - if (i == 0) - return -EINVAL - ; - - tmp = s502e_hmcr[i - 1]; - switch (hw->dpmsize) - { - case 0x2000: - tmp |= 0x01; - break; - - case 0x10000L: - break; - - default: - return -EINVAL; - } - - /* Setup dual-port memory window */ - _OUTB(port + 1, tmp); - hw->regs[1] = tmp; - - /* Enable memory access */ - _OUTB(port, 0x02); - hw->regs[0] = 0x02; /* update mirror */ - return 0; -} - -/*============================================================================ - * Initialize S507 adapter. - */ -static int init_s507 (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - if (!detect_s507(port)) - return -ENODEV - ; - - /* Verify configuration options */ - i = get_option_index(s507_dpmbase_options, virt_to_phys(hw->dpmbase)); - if (i == 0) - return -EINVAL - ; - - tmp = s507_hmcr[i - 1]; - switch (hw->dpmsize) - { - case 0x2000: - tmp |= 0x01; - break; - - case 0x10000L: - break; - - default: - return -EINVAL; - } - - /* Enable adapter's logic */ - _OUTB(port, 0x01); - hw->regs[0] = 0x01; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (!(_INB(port) & 0x20)) - return -EIO - ; - - /* Setup dual-port memory window */ - _OUTB(port + 1, tmp); - hw->regs[1] = tmp; - - /* Enable memory access */ - tmp = hw->regs[0] | 0x04; - if (hw->irq) - { - i = get_option_index(s508_irq_options, hw->irq); - if (i) tmp |= s507_irqmask[i - 1]; - } - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - return (_INB(port) & 0x08) ? 0 : -EIO; -} - -/*============================================================================ - * Initialize S508 adapter. - */ -static int init_s508 (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - if (!detect_s508(port)) - return -ENODEV - ; - - /* Verify configuration options */ - i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); - if (i == 0) - return -EINVAL - ; - - /* Setup memory configuration */ - tmp = s508_hmcr[i - 1]; - _OUTB(port + 1, tmp); - hw->regs[1] = tmp; - - /* Enable memory access */ - _OUTB(port, 0x04); - hw->regs[0] = 0x04; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - return (_INB(port + 1) & 0x04) ? 0 : -EIO; -} - -/*============================================================================ - * Detect S502A adapter. - * Following tests are used to detect S502A adapter: - * 1. All registers other than status (BASE) should read 0xFF - * 2. After writing 00001000b to control register, status register should - * read 01000000b. - * 3. After writing 0 to control register, status register should still - * read 01000000b. - * 4. After writing 00000100b to control register, status register should - * read 01000100b. - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s502a (int port) -{ - int i, j; - - if (!get_option_index(s502_port_options, port)) - return 0 - ; - for (j = 1; j < SDLA_MAXIORANGE; ++j) - { - if (_INB(port + j) != 0xFF) - return 0 - ; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - } - - _OUTB(port, 0x08); /* halt CPU */ - _OUTB(port, 0x08); - _OUTB(port, 0x08); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0x40) - return 0 - ; - _OUTB(port, 0x00); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0x40) - return 0 - ; - _OUTB(port, 0x04); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0x44) - return 0 - ; - - /* Reset adapter */ - _OUTB(port, 0x08); - _OUTB(port, 0x08); - _OUTB(port, 0x08); - _OUTB(port + 1, 0xFF); - return 1; -} - -/*============================================================================ - * Detect S502E adapter. - * Following tests are used to verify adapter presence: - * 1. All registers other than status (BASE) should read 0xFF. - * 2. After writing 0 to CPU control register (BASE+3), status register - * (BASE) should read 11111000b. - * 3. After writing 00000100b to port BASE (set bit 2), status register - * (BASE) should read 11111100b. - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s502e (int port) -{ - int i, j; - - if (!get_option_index(s502_port_options, port)) - return 0 - ; - for (j = 1; j < SDLA_MAXIORANGE; ++j) - { - if (_INB(port + j) != 0xFF) - return 0 - ; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - } - - _OUTB(port + 3, 0); /* CPU control reg. */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0xF8) /* read status */ - return 0 - ; - _OUTB(port, 0x04); /* set bit 2 */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0xFC) /* verify */ - return 0 - ; - - /* Reset adapter */ - _OUTB(port, 0); - return 1; -} - -/*============================================================================ - * Detect s503 adapter. - * Following tests are used to verify adapter presence: - * 1. All registers other than status (BASE) should read 0xFF. - * 2. After writing 0 to control register (BASE), status register (BASE) - * should read 11110000b. - * 3. After writing 00000100b (set bit 2) to control register (BASE), - * status register should read 11110010b. - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s503 (int port) -{ - int i, j; - - if (!get_option_index(s503_port_options, port)) - return 0 - ; - for (j = 1; j < SDLA_MAXIORANGE; ++j) - { - if (_INB(port + j) != 0xFF) - return 0 - ; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - } - - _OUTB(port, 0); /* reset control reg.*/ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0xF0) /* read status */ - return 0 - ; - _OUTB(port, 0x04); /* set bit 2 */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0xF2) /* verify */ - return 0 - ; - - /* Reset adapter */ - _OUTB(port, 0); - return 1; -} - -/*============================================================================ - * Detect s507 adapter. - * Following tests are used to detect s507 adapter: - * 1. All ports should read the same value. - * 2. After writing 0x00 to control register, status register should read - * ?011000?b. - * 3. After writing 0x01 to control register, status register should read - * ?011001?b. - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s507 (int port) -{ - int tmp, i, j; - - if (!get_option_index(s508_port_options, port)) - return 0 - ; - tmp = _INB(port); - for (j = 1; j < S507_IORANGE; ++j) - { - if (_INB(port + j) != tmp) - return 0 - ; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - } - - _OUTB(port, 0x00); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if ((_INB(port) & 0x7E) != 0x30) - return 0 - ; - _OUTB(port, 0x01); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if ((_INB(port) & 0x7E) != 0x32) - return 0 - ; - - /* Reset adapter */ - _OUTB(port, 0x00); - return 1; -} - -/*============================================================================ - * Detect s508 adapter. - * Following tests are used to detect s508 adapter: - * 1. After writing 0x00 to control register, status register should read - * ??000000b. - * 2. After writing 0x10 to control register, status register should read - * ??010000b - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s508 (int port) -{ - int i; - - if (!get_option_index(s508_port_options, port)) - return 0 - ; - _OUTB(port, 0x00); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if ((_INB(port + 1) & 0x3F) != 0x00) - return 0 - ; - _OUTB(port, 0x10); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if ((_INB(port + 1) & 0x3F) != 0x10) - return 0 - ; - - /* Reset adapter */ - _OUTB(port, 0x00); - return 1; -} - -/******* Miscellaneous ******************************************************/ - -/*============================================================================ - * Calibrate SDLA memory access delay. - * Count number of idle loops made within 1 second and then calculate the - * number of loops that should be made to achive desired delay. - */ -static int calibrate_delay (int mks) -{ - unsigned int delay; - unsigned long stop; - - for (delay = 0, stop = SYSTEM_TICK + HZ; SYSTEM_TICK < stop; ++delay); - return (delay/(1000000L/mks) + 1); -} - -/*============================================================================ - * Get option's index into the options list. - * Return option's index (1 .. N) or zero if option is invalid. - */ -static int get_option_index (unsigned* optlist, unsigned optval) -{ - int i; - - for (i = 1; i <= optlist[0]; ++i) - if ( optlist[i] == optval) return i - ; - return 0; -} - -/*============================================================================ - * Check memory region to see if it's available. - * Return: 0 ok. - */ -static unsigned check_memregion (void* ptr, unsigned len) -{ - volatile unsigned char* p = ptr; - - for (; len && (*p == 0xFF); --len, ++p) - { - *p = 0; /* attempt to write 0 */ - if (*p != 0xFF) /* still has to read 0xFF */ - { - *p = 0xFF; /* restore original value */ - break; /* not good */ - } - } - return len; -} - -/*============================================================================ - * Test memory region. - * Return: size of the region that passed the test. - * Note: Region size must be multiple of 2 ! - */ -static unsigned test_memregion (void* ptr, unsigned len) -{ - volatile unsigned short* w_ptr; - unsigned len_w = len >> 1; /* region len in words */ - unsigned i; - - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - *w_ptr = 0xAA55 - ; - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - if (*w_ptr != 0xAA55) - { - len_w = i; - break; - } - ; - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - *w_ptr = 0x55AA - ; - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - if (*w_ptr != 0x55AA) - { - len_w = i; - break; - } - ; - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) *w_ptr = 0; - return len_w << 1; -} - -/*============================================================================ - * Calculate 16-bit CRC using CCITT polynomial. - */ -static unsigned short checksum (unsigned char* buf, unsigned len) -{ - unsigned short crc = 0; - unsigned mask, flag; - - for (; len; --len, ++buf) - { - for (mask = 0x80; mask; mask >>= 1) - { - flag = (crc & 0x8000); - crc <<= 1; - crc |= ((*buf & mask) ? 1 : 0); - if (flag) crc ^= 0x1021; - } - } - return crc; -} - - -/****** End *****************************************************************/ diff -u --recursive --new-file v2.3.20/linux/drivers/net/sdlamain.c linux/drivers/net/sdlamain.c --- v2.3.20/linux/drivers/net/sdlamain.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/net/sdlamain.c Wed Dec 31 16:00:00 1969 @@ -1,627 +0,0 @@ -/***************************************************************************** -* sdlamain.c WANPIPE(tm) Multiprotocol WAN Link Driver. Main module. -* -* Author: Gene Kozin -* Jaspreet Singh -* -* 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 /* OS configuration options */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include /* kmalloc(), kfree() */ -#include /* printk(), and other useful stuff */ -#include /* support for loadable modules */ -#include /* request_region(), release_region() */ -#include /* for kernel task queues */ -#include /* WAN router definitions */ -#include /* WANPIPE common user API definitions */ -#include /* kernel <-> user copy */ -#include /* phys_to_virt() */ -#include /* __init (when not using as a module) */ - - -/****** Defines & Macros ****************************************************/ - -#ifdef _DEBUG_ -#define STATIC -#else -#define STATIC static -#endif - -#define DRV_VERSION 4 /* version number */ -#define DRV_RELEASE 1 /* release (minor version) number */ -#define MAX_CARDS 8 /* max number of adapters */ - -#ifndef CONFIG_WANPIPE_CARDS /* configurable option */ -#define CONFIG_WANPIPE_CARDS 1 -#endif - -#define CMD_OK 0 /* normal firmware return code */ -#define CMD_TIMEOUT 0xFF /* firmware command timed out */ -#define MAX_CMD_RETRY 10 /* max number of firmware retries */ - -/****** Function Prototypes *************************************************/ - -/* Module entry points */ -int init_module (void); -void cleanup_module (void); - -/* WAN link driver entry points */ -static int setup (wan_device_t* wandev, wandev_conf_t* conf); -static int shutdown (wan_device_t* wandev); -static int ioctl (wan_device_t* wandev, unsigned cmd, unsigned long arg); - -/* IOCTL hanlers */ -static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump); -static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec); - -/* Miscellaneous functions */ -STATIC void sdla_isr (int irq, void* dev_id, struct pt_regs *regs); -STATIC void sdla_poll (void* data); - -/****** Global Data ********************************************************** - * Note: All data must be explicitly initialized!!! - */ - -/* private data */ -static char drvname[] = "wanpipe"; -static char fullname[] = "WANPIPE(tm) Multiprotocol Driver"; -static char copyright[] = "(c) 1995-1996 Sangoma Technologies Inc."; -static int ncards = CONFIG_WANPIPE_CARDS; -static int active = 0; /* number of active cards */ -static sdla_t* card_array = NULL; /* adapter data space */ - -/* Task queue element for creating a 'thread' */ -static struct tq_struct sdla_tq = -{ - NULL, /* .next */ - 0, /* .sync */ - &sdla_poll, /* .routine */ - NULL /* .data */ -}; - -/******* Kernel Loadable Module Entry Points ********************************/ - -/*============================================================================ - * Module 'insert' entry point. - * o print announcement - * o allocate adapter data space - * o initialize static data - * o register all cards with WAN router - * o calibrate SDLA shared memory access delay. - * - * Return: 0 Ok - * < 0 error. - * Context: process - */ - -#ifdef MODULE -int init_module (void) -#else -int __init wanpipe_init(void) -#endif -{ - int cnt, err = 0; - - printk(KERN_INFO "%s v%u.%u %s\n", - fullname, DRV_VERSION, DRV_RELEASE, copyright) - ; - - /* Verify number of cards and allocate adapter data space */ - ncards = min(ncards, MAX_CARDS); - ncards = max(ncards, 1); - card_array = kmalloc(sizeof(sdla_t) * ncards, GFP_KERNEL); - if (card_array == NULL) - return -ENOMEM - ; - memset(card_array, 0, sizeof(sdla_t) * ncards); - - /* Register adapters with WAN router */ - for (cnt = 0; cnt < ncards; ++cnt) - { - sdla_t* card = &card_array[cnt]; - wan_device_t* wandev = &card->wandev; - - sprintf(card->devname, "%s%d", drvname, cnt + 1); - wandev->magic = ROUTER_MAGIC; - wandev->name = card->devname; - wandev->private = card; - wandev->enable_tx_int = 0; - wandev->setup = &setup; - wandev->shutdown = &shutdown; - wandev->ioctl = &ioctl; - err = register_wan_device(wandev); - if (err) - { - printk(KERN_ERR - "%s: %s registration failed with error %d!\n", - drvname, card->devname, err) - ; - break; - } - } - if (cnt) - ncards = cnt; /* adjust actual number of cards */ - else - { - kfree(card_array); - err = -ENODEV; - } - return err; -} - -#ifdef MODULE -/*============================================================================ - * Module 'remove' entry point. - * o unregister all adapters from the WAN router - * o release all remaining system resources - */ -void cleanup_module (void) -{ - int i; - - for (i = 0; i < ncards; ++i) - { - sdla_t* card = &card_array[i]; - unregister_wan_device(card->devname); - } - kfree(card_array); -} - -#endif - -/******* WAN Device Driver Entry Points *************************************/ - -/*============================================================================ - * Setup/confugure WAN link driver. - * o check adapter state - * o make sure firmware is present in configuration - * o make sure I/O port and IRQ are specified - * o make sure I/O region is available - * o allocate interrupt vector - * o setup SDLA hardware - * o call appropriate routine to perform protocol-specific initialization - * o mark I/O region as used - * o if this is the first active card, then schedule background task - * - * This function is called when router handles ROUTER_SETUP IOCTL. The - * configuration structure is in kernel memory (including extended data, if - * any). - */ - -static int setup (wan_device_t* wandev, wandev_conf_t* conf) -{ - sdla_t* card; - int err = 0; - int irq; - - /* Sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL)) - return -EFAULT; - - card = wandev->private; - if (wandev->state != WAN_UNCONFIGURED) - return -EBUSY; /* already configured */ - - if (!conf->data_size || (conf->data == NULL)) - { - printk(KERN_ERR - "%s: firmware not found in configuration data!\n", - wandev->name); - return -EINVAL; - } - if (conf->ioport <= 0) - { - printk(KERN_ERR - "%s: can't configure without I/O port address!\n", - wandev->name); - return -EINVAL; - } - - if (conf->irq <= 0) - { - printk(KERN_ERR "%s: can't configure without IRQ!\n", - wandev->name); - return -EINVAL; - } - - /* Make sure I/O port region is available */ - if (check_region(conf->ioport, SDLA_MAXIORANGE)) - { - printk(KERN_ERR "%s: I/O region 0x%X - 0x%X is in use!\n", - wandev->name, conf->ioport, - conf->ioport + SDLA_MAXIORANGE); - return -EINVAL; - } - - /* Allocate IRQ */ - irq = (conf->irq == 2) ? 9 : conf->irq; /* IRQ2 -> IRQ9 */ - if (request_irq(irq, sdla_isr, 0, wandev->name, card)) - { - printk(KERN_ERR "%s: can't reserve IRQ %d!\n", - wandev->name, irq); - return -EINVAL; - } - - /* Configure hardware, load firmware, etc. */ - memset(&card->hw, 0, sizeof(sdlahw_t)); - card->hw.port = conf->ioport; - card->hw.irq = (conf->irq == 9) ? 2 : conf->irq; - /* Compute the virtual address of the card in kernel space */ - if(conf->maddr) - card->hw.dpmbase = phys_to_virt(conf->maddr); - else /* But 0 means NULL */ - card->hw.dpmbase = (void *)conf->maddr; - - card->hw.dpmsize = SDLA_WINDOWSIZE; - card->hw.type = conf->hw_opt[0]; - card->hw.pclk = conf->hw_opt[1]; - err = sdla_setup(&card->hw, conf->data, conf->data_size); - if (err) - { - free_irq(irq, card); - return err; - } - - /* Intialize WAN device data space */ - wandev->irq = irq; - wandev->dma = 0; - wandev->ioport = card->hw.port; - wandev->maddr = card->hw.dpmbase; - wandev->msize = card->hw.dpmsize; - wandev->hw_opt[0] = card->hw.type; - wandev->hw_opt[1] = card->hw.pclk; - wandev->hw_opt[2] = card->hw.memory; - wandev->hw_opt[3] = card->hw.fwid; - - /* Protocol-specific initialization */ - switch (card->hw.fwid) - { -#ifdef CONFIG_WANPIPE_X25 - case SFID_X25_502: - case SFID_X25_508: - err = wpx_init(card, conf); - break; -#endif - -#ifdef CONFIG_WANPIPE_FR - case SFID_FR502: - case SFID_FR508: - err = wpf_init(card, conf); - break; -#endif - -#ifdef CONFIG_WANPIPE_PPP - case SFID_PPP502: - case SFID_PPP508: - err = wpp_init(card, conf); - break; -#endif - - default: - printk(KERN_ERR "%s: this firmware is not supported!\n", - wandev->name) - ; - err = -EINVAL; - } - if (err) - { - sdla_down(&card->hw); - free_irq(irq, card); - return err; - } - /* Reserve I/O region and schedule background task */ -/* printk(KERN_INFO "about to request\n");*/ - request_region(card->hw.port, card->hw.io_range, wandev->name); -/* printk(KERN_INFO "request done\n");*/ - if (++active == 1) - queue_task(&sdla_tq, &tq_scheduler); - - wandev->critical = 0; - return 0; -} - -/*============================================================================ - * Shut down WAN link driver. - * o shut down adapter hardware - * o release system resources. - * - * This function is called by the router when device is being unregistered or - * when it handles ROUTER_DOWN IOCTL. - */ -static int shutdown (wan_device_t* wandev) -{ - sdla_t* card; - - /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - - if (wandev->state == WAN_UNCONFIGURED) - return 0; - - /* If wee are in a critical section we lose */ - if (test_and_set_bit(0, (void*)&wandev->critical)) - return -EAGAIN; - - card = wandev->private; - wandev->state = WAN_UNCONFIGURED; - - if (--active == 0) - schedule(); /* stop background thread */ - -/* printk(KERN_INFO "active now %d\n", active); - - printk(KERN_INFO "About to call sdla_down\n");*/ - sdla_down(&card->hw); -/* printk(KERN_INFO "sdla_down done\n"); - printk(KERN_INFO "About to call free_irq\n");*/ - free_irq(wandev->irq, card); -/* printk(KERN_INFO "free_irq done\n"); - printk(KERN_INFO "About to call release_region\n");*/ - release_region(card->hw.port, card->hw.io_range); -/* printk(KERN_INFO "release_region done\n");*/ - wandev->critical = 0; - return 0; -} - -/*============================================================================ - * Driver I/O control. - * o verify arguments - * o perform requested action - * - * This function is called when router handles one of the reserved user - * IOCTLs. Note that 'arg' stil points to user address space. - */ -static int ioctl (wan_device_t* wandev, unsigned cmd, unsigned long arg) -{ - int err; - - /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT - ; - if (wandev->state == WAN_UNCONFIGURED) - return -ENODEV - ; - if (test_and_set_bit(0, (void*)&wandev->critical)) - return -EAGAIN - ; - switch (cmd) - { - case WANPIPE_DUMP: - err = ioctl_dump(wandev->private, (void*)arg); - break; - - case WANPIPE_EXEC: - err = ioctl_exec(wandev->private, (void*)arg); - break; - - default: - err = -EINVAL; - } - wandev->critical = 0; - return err; -} - -/****** Driver IOCTL Hanlers ************************************************/ - -/*============================================================================ - * Dump adapter memory to user buffer. - * o verify request structure - * o copy request structure to kernel data space - * o verify length/offset - * o verify user buffer - * o copy adapter memory image to user buffer - * - * Note: when dumping memory, this routine switches curent dual-port memory - * vector, so care must be taken to avoid racing conditions. - */ -static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump) -{ - sdla_dump_t dump; - unsigned winsize; - unsigned long oldvec; /* DPM window vector */ - unsigned long flags; - int err = 0; - - if(copy_from_user((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t))) - return -EFAULT; - - if ((dump.magic != WANPIPE_MAGIC) || - (dump.offset + dump.length > card->hw.memory)) - return -EINVAL; - - winsize = card->hw.dpmsize; - save_flags(flags); - cli(); /* >>> critical section start <<< */ - oldvec = card->hw.vector; - while (dump.length) - { - unsigned pos = dump.offset % winsize; /* current offset */ - unsigned long vec = dump.offset - pos; /* current vector */ - unsigned len = (dump.length > (winsize - pos)) ? - (winsize - pos) : dump.length - ; - if (sdla_mapmem(&card->hw, vec) != 0) /* relocate window */ - { - err = -EIO; - break; - } - /* FIXME::: COPY TO KERNEL BUFFER FIRST ?? */ - sti(); /* Not ideal but tough we have to do this */ - if(copy_to_user((void *)dump.ptr, - (u8 *)card->hw.dpmbase + pos, len)) - return -EFAULT; - cli(); - dump.length -= len; - dump.offset += len; - (char*)dump.ptr += len; - } - sdla_mapmem(&card->hw, oldvec); /* restore DPM window position */ - restore_flags(flags); /* >>> critical section end <<< */ - return err; -} - -/*============================================================================ - * Execute adapter firmware command. - * o verify request structure - * o copy request structure to kernel data space - * o call protocol-specific 'exec' function - */ -static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec) -{ - sdla_exec_t exec; - - if (card->exec == NULL) - return -ENODEV; - - if(copy_from_user((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t))) - return -EFAULT; - if ((exec.magic != WANPIPE_MAGIC) || (exec.cmd == NULL)) - return -EINVAL; - return card->exec(card, exec.cmd, exec.data); -} - -/******* Miscellaneous ******************************************************/ - -/*============================================================================ - * SDLA Interrupt Service Routine. - * o acknowledge SDLA hardware interrupt. - * o call protocol-specific interrupt service routine, if any. - */ -STATIC void sdla_isr (int irq, void* dev_id, struct pt_regs *regs) -{ -#define card ((sdla_t*)dev_id) - - if (!card || (card->wandev.state == WAN_UNCONFIGURED)) - return - ; - if (card->in_isr) - { - printk(KERN_WARNING "%s: interrupt re-entrancy on IRQ %d!\n", - card->devname, card->wandev.irq) - ; - return; - } - - sdla_intack(&card->hw); - if (card->isr) - card->isr(card); - -#undef card -} - -/*============================================================================ - * SDLA polling routine. - * This routine simulates kernel thread to perform various housekeeping job. - * - * o for each configured device call its poll() routine - * o if there is at least one active card, then reschedule itself once again - */ -STATIC void sdla_poll (void* data) -{ - int i; - - for (i = 0; i < ncards; ++i) - { - sdla_t* card = &card_array[i]; - - if ((card->wandev.state != WAN_UNCONFIGURED) && card->poll && - !card->wandev.critical) - { - card->poll(card); - } - } - if (active) - queue_task(&sdla_tq, &tq_scheduler); -} - -/*============================================================================ - * This routine is called by the protocol-specific modules when network - * interface is being open. The only reason we need this, is because we - * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's - * defined more than once into the same kernel module. - */ -void wanpipe_open (sdla_t* card) -{ - ++card->open_cnt; - MOD_INC_USE_COUNT; -} - -/*============================================================================ - * This routine is called by the protocol-specific modules when network - * interface is being closed. The only reason we need this, is because we - * have to call MOD_DEC_USE_COUNT, but cannot include 'module.h' where it's - * defined more than once into the same kernel module. - */ -void wanpipe_close (sdla_t* card) -{ - --card->open_cnt; - MOD_DEC_USE_COUNT; -} - -/*============================================================================ - * Set WAN device state. - */ -void wanpipe_set_state (sdla_t* card, int state) -{ - unsigned long flags; - - save_flags(flags); - cli(); - if (card->wandev.state != state) - { - switch (state) - { - case WAN_CONNECTED: - printk (KERN_INFO "%s: link connected!\n", - card->devname) - ; - break; - - case WAN_CONNECTING: - printk (KERN_INFO "%s: link connecting...\n", - card->devname) - ; - break; - - case WAN_DISCONNECTED: - printk (KERN_INFO "%s: link disconnected!\n", - card->devname) - ; - break; - } - card->wandev.state = state; - } - card->state_tick = jiffies; - restore_flags(flags); -} - -/****** End *****************************************************************/ diff -u --recursive --new-file v2.3.20/linux/drivers/net/sealevel.c linux/drivers/net/sealevel.c --- v2.3.20/linux/drivers/net/sealevel.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/sealevel.c Wed Dec 31 16:00:00 1969 @@ -1,471 +0,0 @@ -#define LINUX_21 - -/* - * Sealevel Systems 4021 driver. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * (c) Copyright 1999 Building Number Three Ltd - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "syncppp.h" -#include "z85230.h" - - -struct slvl_device -{ - struct z8530_channel *chan; - struct ppp_device netdev; - char name[16]; - int channel; -}; - - -struct slvl_board -{ - struct slvl_device dev[2]; - struct z8530_dev board; - int iobase; -}; - -/* - * Network driver support routines - */ - -/* - * Frame receive. Simple for our card as we do sync ppp and there - * is no funny garbage involved - */ - -static void sealevel_input(struct z8530_channel *c, struct sk_buff *skb) -{ - /* Drop the CRC - its not a good idea to try and negotiate it ;) */ - skb_trim(skb, skb->len-2); - skb->protocol=htons(ETH_P_WAN_PPP); - skb->mac.raw=skb->data; - skb->dev=c->netdevice; - /* - * Send it to the PPP layer. We dont have time to process - * it right now. - */ - netif_rx(skb); -} - -/* - * We've been placed in the UP state - */ - -static int sealevel_open(struct net_device *d) -{ - struct slvl_device *slvl=d->priv; - int err = -1; - int unit = slvl->channel; - - /* - * Link layer up. - */ - - switch(unit) - { - case 0: - err=z8530_sync_dma_open(d, slvl->chan); - break; - case 1: - err=z8530_sync_open(d, slvl->chan); - break; - } - - if(err) - return err; - /* - * Begin PPP - */ - err=sppp_open(d); - if(err) - { - switch(unit) - { - case 0: - z8530_sync_dma_close(d, slvl->chan); - break; - case 1: - z8530_sync_close(d, slvl->chan); - break; - } - return err; - } - - slvl->chan->rx_function=sealevel_input; - - /* - * Go go go - */ - d->tbusy=0; - MOD_INC_USE_COUNT; - return 0; -} - -static int sealevel_close(struct net_device *d) -{ - struct slvl_device *slvl=d->priv; - int unit = slvl->channel; - - /* - * Discard new frames - */ - - slvl->chan->rx_function=z8530_null_rx; - - /* - * PPP off - */ - sppp_close(d); - /* - * Link layer down - */ - d->tbusy=1; - - switch(unit) - { - case 0: - z8530_sync_dma_close(d, slvl->chan); - break; - case 1: - z8530_sync_close(d, slvl->chan); - break; - } - MOD_DEC_USE_COUNT; - return 0; -} - -static int sealevel_ioctl(struct net_device *d, struct ifreq *ifr, int cmd) -{ - /* struct slvl_device *slvl=d->priv; - z8530_ioctl(d,&slvl->sync.chanA,ifr,cmd) */ - return sppp_do_ioctl(d, ifr,cmd); -} - -static struct enet_statistics *sealevel_get_stats(struct net_device *d) -{ - struct slvl_device *slvl=d->priv; - if(slvl) - return z8530_get_stats(slvl->chan); - else - return NULL; -} - -/* - * Passed PPP frames, fire them downwind. - */ - -static int sealevel_queue_xmit(struct sk_buff *skb, struct net_device *d) -{ - struct slvl_device *slvl=d->priv; - return z8530_queue_xmit(slvl->chan, skb); -} - -#ifdef LINUX_21 -static int sealevel_neigh_setup(struct neighbour *n) -{ - if (n->nud_state == NUD_NONE) { - n->ops = &arp_broken_ops; - n->output = n->ops->output; - } - return 0; -} - -static int sealevel_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) -{ - if (p->tbl->family == AF_INET) { - p->neigh_setup = sealevel_neigh_setup; - p->ucast_probes = 0; - p->mcast_probes = 0; - } - return 0; -} - -#else - -static int return_0(struct net_device *d) -{ - return 0; -} - -#endif - -/* - * Description block for a Comtrol Hostess SV11 card - */ - -static struct slvl_board *slvl_init(int iobase, int irq, int txdma, int rxdma, int slow) -{ - struct z8530_dev *dev; - struct slvl_device *sv; - struct slvl_board *b; - - int i; - unsigned long flags; - int u; - - /* - * Get the needed I/O space - */ - - if(check_region(iobase, 8)) - { - printk(KERN_WARNING "sealevel: I/O 0x%X already in use.\n", iobase); - return NULL; - } - request_region(iobase, 8, "Sealevel 4021"); - - b=(struct slvl_board *)kmalloc(sizeof(struct slvl_board), GFP_KERNEL); - if(!b) - goto fail3; - - memset(b, 0, sizeof(*sv)); - - b->dev[0].chan = &b->board.chanA; - b->dev[1].chan = &b->board.chanB; - - dev=&b->board; - - /* - * Stuff in the I/O addressing - */ - - dev->active = 0; - - b->iobase = iobase; - - /* - * Select 8530 delays for the old board - */ - - if(slow) - iobase |= Z8530_PORT_SLEEP; - - dev->chanA.ctrlio=iobase+1; - dev->chanA.dataio=iobase; - dev->chanB.ctrlio=iobase+3; - dev->chanB.dataio=iobase+2; - - dev->chanA.irqs=&z8530_nop; - dev->chanB.irqs=&z8530_nop; - - /* - * Assert DTR enable DMA - */ - - outb(3|(1<<7), b->iobase+4); - - - /* We want a fast IRQ for this device. Actually we'd like an even faster - IRQ ;) - This is one driver RtLinux is made for */ - - if(request_irq(irq, &z8530_interrupt, SA_INTERRUPT, "SeaLevel", dev)<0) - { - printk(KERN_WARNING "sealevel: IRQ %d already in use.\n", irq); - goto fail2; - } - - dev->irq=irq; - dev->chanA.private=&b->dev[0]; - dev->chanB.private=&b->dev[1]; - dev->chanA.netdevice=&b->dev[0].netdev.dev; - dev->chanB.netdevice=&b->dev[1].netdev.dev; - dev->chanA.dev=dev; - dev->chanB.dev=dev; - dev->name=b->dev[0].name; - - dev->chanA.txdma=3; - dev->chanA.rxdma=1; - if(request_dma(dev->chanA.txdma, "SeaLevel (TX)")!=0) - goto fail; - - if(request_dma(dev->chanA.rxdma, "SeaLevel (RX)")!=0) - goto dmafail; - - save_flags(flags); - cli(); - - /* - * Begin normal initialise - */ - - if(z8530_init(dev)!=0) - { - printk(KERN_ERR "Z8530 series device not found.\n"); - goto dmafail2; - } - if(dev->type==Z85C30) - { - z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream); - z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream); - } - else - { - z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream_85230); - z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream_85230); - } - - /* - * Now we can take the IRQ - */ - - restore_flags(flags); - - for(u=0; u<2; u++) - { - sv=&b->dev[u]; - sv->channel = u; - - for(i=0;i<999;i++) - { - sprintf(sv->name,"hdlc%d", i); - if(dev_get(sv->name)==NULL) - { - struct net_device *d=sv->chan->netdevice; - - /* - * Initialise the PPP components - */ - sppp_attach(&sv->netdev); - - /* - * Local fields - */ - sprintf(sv->name,"hdlc%d", i); - - d->name = sv->name; - d->base_addr = iobase; - d->irq = irq; - d->priv = sv; - d->init = NULL; - - d->open = sealevel_open; - d->stop = sealevel_close; - d->hard_start_xmit = sealevel_queue_xmit; - d->get_stats = sealevel_get_stats; - d->set_multicast_list = NULL; - d->do_ioctl = sealevel_ioctl; -#ifdef LINUX_21 - d->neigh_setup = sealevel_neigh_setup_dev; - dev_init_buffers(d); -#else - d->init = return_0; -#endif - d->set_mac_address = NULL; - - if(register_netdev(d)==-1) - { - printk(KERN_ERR "%s: unable to register device.\n", - sv->name); - goto fail_unit; - } - - break; - } - } - } - z8530_describe(dev, "I/O", iobase); - dev->active=1; - return b; - -fail_unit: - if(u==1) - unregister_netdev(b->dev[0].chan->netdevice); - -dmafail2: - free_dma(dev->chanA.rxdma); -dmafail: - free_dma(dev->chanA.txdma); -fail: - free_irq(irq, dev); -fail2: - kfree(b); -fail3: - release_region(iobase,8); - return NULL; -} - -static void slvl_shutdown(struct slvl_board *b) -{ - int u; - - z8530_shutdown(&b->board); - - for(u=0; u<2; u++) - { - sppp_detach(&b->dev[u].netdev.dev); - unregister_netdev(&b->dev[u].netdev.dev); - } - - free_irq(b->board.irq, &b->board); - free_dma(b->board.chanA.rxdma); - free_dma(b->board.chanA.txdma); - /* DMA off on the card, drop DTR */ - outb(0, b->iobase); - release_region(b->iobase, 8); -} - -#ifdef MODULE - -static int io=0x238; -static int txdma=1; -static int rxdma=3; -static int irq=5; -static int slow=0; - -#ifdef LINUX_21 -MODULE_PARM(io,"i"); -MODULE_PARM_DESC(io, "The I/O base of the Sealevel card"); -MODULE_PARM(txdma,"i"); -MODULE_PARM_DESC(txdma, "Transmit DMA channel"); -MODULE_PARM(rxdma,"i"); -MODULE_PARM_DESC(rxdma, "Receive DMA channel"); -MODULE_PARM(irq,"i"); -MODULE_PARM_DESC(irq, "The interrupt line setting for the SeaLevel card"); -MODULE_PARM(slow,"i"); -MODULE_PARM_DESC(slow, "Set this for an older Sealevel card such as the 4012"); - -MODULE_AUTHOR("Bulding Number Three Ltd"); -MODULE_DESCRIPTION("Modular driver for the SeaLevel 4021"); -#endif - -static struct slvl_board *slvl_unit; - -int init_module(void) -{ - printk(KERN_INFO "SeaLevel Z85230 Synchronous Driver v 0.01.\n"); - printk(KERN_INFO "(c) Copyright 1998, Building Number Three Ltd.\n"); - if((slvl_unit=slvl_init(io,irq, txdma, rxdma, slow))==NULL) - return -ENODEV; - return 0; -} - -void cleanup_module(void) -{ - if(slvl_unit) - slvl_shutdown(slvl_unit); -} - -#endif - diff -u --recursive --new-file v2.3.20/linux/drivers/net/sgiseeq.h linux/drivers/net/sgiseeq.h --- v2.3.20/linux/drivers/net/sgiseeq.h Thu Jun 26 12:33:39 1997 +++ linux/drivers/net/sgiseeq.h Mon Oct 11 10:13:24 1999 @@ -1,4 +1,4 @@ -/* $Id: sgiseeq.h,v 1.1 1997/06/09 08:34:32 ralf Exp $ +/* $Id: sgiseeq.h,v 1.3 1998/08/25 09:17:45 ralf Exp $ * sgiseeq.h: Defines for the Seeq8003 ethernet controller. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) diff -u --recursive --new-file v2.3.20/linux/drivers/net/sk_mca.c linux/drivers/net/sk_mca.c --- v2.3.20/linux/drivers/net/sk_mca.c Thu Aug 26 13:05:38 1999 +++ linux/drivers/net/sk_mca.c Mon Oct 11 10:13:24 1999 @@ -71,6 +71,7 @@ #include #include +#include #include #include #include diff -u --recursive --new-file v2.3.20/linux/drivers/net/sktr.c linux/drivers/net/sktr.c --- v2.3.20/linux/drivers/net/sktr.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/sktr.c Wed Dec 31 16:00:00 1969 @@ -1,2703 +0,0 @@ -/* - * sktr.c: A network driver for the SysKonnect Token Ring ISA/PCI Adapters. - * - * Written 1997 by Christoph Goos - * - * A fine result of the Linux Systems Network Architecture Project. - * http://samba.anu.edu.au/linux-sna/ - * - * This software may be used and distributed according to the terms - * of the GNU Public License, incorporated herein by reference. - * - * This device driver works with the following SysKonnect adapters: - * - SysKonnect TR4/16(+) ISA (SK-4190) - * - SysKonnect TR4/16(+) PCI (SK-4590) - * - SysKonnect TR4/16 PCI (SK-4591) - * - * Sources: - * - The hardware related parts of this driver are take from - * the SysKonnect Token Ring driver for Windows NT. - * - I used the IBM Token Ring driver 'ibmtr.c' as a base for this - * driver, as well as the 'skeleton.c' driver by Donald Becker. - * - Also various other drivers in the linux source tree were taken - * as samples for some tasks. - * - * Maintainer(s): - * JS Jay Schulist jschlst@samba.anu.edu.au - * CG Christoph Goos cgoos@syskonnect.de - * - * Modification History: - * 29-Aug-97 CG Created - * 04-Apr-98 CG Fixed problems caused by tok_timer_check - * 10-Apr-98 CG Fixed lockups at cable disconnection - * 27-May-98 JS Formated to Linux Kernel Format - * 31-May-98 JS Hacked in PCI support - * 16-Jun-98 JS Modulized for multiple cards with one driver - * - * To do: - * 1. Selectable 16 Mbps or 4Mbps - * 2. Multi/Broadcast packet handling - * - */ - -static const char *version = "sktr.c: v1.01 08/29/97 by Christoph Goos\n"; - -#ifdef MODULE -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#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; iVam->ocpl.NodeAddr[i] = mac->CurrentAddress[i]; - */ - - tp->ocpl.GroupAddr = 0; - tp->ocpl.FunctAddr = 0; - tp->ocpl.RxListSize = SWAPB(RplSize); - tp->ocpl.TxListSize = SWAPB(TplSize); - tp->ocpl.BufSize = SWAPB(BufferSize); - tp->ocpl.Reserved = 0; - tp->ocpl.TXBufMin = TX_BUF_MIN; - tp->ocpl.TXBufMax = TX_BUF_MAX; - - Addr = htonl(virt_to_bus(tp->ProductID)); - - tp->ocpl.ProdIDAddr[0] = LOWORD(Addr); - tp->ocpl.ProdIDAddr[1] = HIWORD(Addr); - - return; -} - -/* - * Send OPEN command to adapter - */ -static void sktr_open_adapter(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - - if(tp->OpenCommandIssued) - return; - - tp->OpenCommandIssued = 1; - sktr_exec_cmd(dev, OC_OPEN); - - return; -} - -/* - * Clear the adapter's interrupt flag. Clear system interrupt enable - * (SINTEN): disable adapter to system interrupts. - */ -static void sktr_disable_interrupts(struct net_device *dev) -{ - outb(0, dev->base_addr + SIFACL); - - return; -} - -/* - * Set the adapter's interrupt flag. Set system interrupt enable - * (SINTEN): enable adapter to system interrupts. - */ -static void sktr_enable_interrupts(struct net_device *dev) -{ - outb(ACL_SINTEN, dev->base_addr + SIFACL); - - return; -} - -/* - * Put command in command queue, try to execute it. - */ -static void sktr_exec_cmd(struct net_device *dev, unsigned short Command) -{ - struct net_local *tp = (struct net_local *)dev->priv; - - tp->CMDqueue |= Command; - sktr_chk_outstanding_cmds(dev); - - return; -} - -/* - * Linux always gives 18 byte of source routing information in the frame header. - * But the length field can indicate shorter length. Then cut header - * appropriate. - */ -static unsigned char *sktr_fix_srouting(unsigned char *buf, short *FrameLen) -{ - struct trh_hdr *trh = (struct trh_hdr *)buf; - int len; - - if(buf[8] & TR_RII) - { - trh->rcf &= ~SWAPB((unsigned short) TR_RCF_LONGEST_FRAME_MASK); - trh->rcf |= SWAPB((unsigned short) TR_RCF_FRAME4K); - len = (SWAPB(trh->rcf) & TR_RCF_LEN_MASK) >> 8; - if(len < 18) - { - memcpy(&buf[18-len],buf,sizeof(struct trh_hdr)-18+len); - *FrameLen -= (18 - len); - } - return (&buf[18-len]); - } - - return (buf); -} - -/* - * Gets skb from system, queues it and checks if it can be sent - */ -static int sktr_send_packet(struct sk_buff *skb, struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - - if(dev->tbusy) - { - /* - * If we get here, some higher level has decided we are broken. - * There should really be a "kick me" function call instead. - * - * Resetting the token ring adapter takes a long time so just - * fake transmission time and go on trying. Our own timeout - * routine is in sktr_timer_chk() - */ - dev->tbusy = 0; - dev->trans_start = jiffies; - return (1); - } - - /* - * If some higher layer thinks we've missed an tx-done interrupt we - * are passed NULL. - */ - if(skb == NULL) - return (0); - - /* - * Block a timer-based transmit from overlapping. This could better be - * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. - */ - if(test_and_set_bit(0, (void*)&dev->tbusy) != 0) - { - printk("%s: Transmitter access conflict.\n", dev->name); - return (1); - } - - if(tp->QueueSkb == 0) - return (1); /* Return with tbusy set: queue full */ - - tp->QueueSkb--; - skb_queue_tail(&tp->SendSkbQueue, skb); - sktr_hardware_send_packet(dev, tp); - if(tp->QueueSkb > 0) - dev->tbusy = 0; - - return (0); -} - -/* - * Move frames from internal skb queue into adapter tx queue - */ -static void sktr_hardware_send_packet(struct net_device *dev, struct net_local* tp) -{ - TPL *tpl; - short length; - unsigned char *buf, *newbuf; - struct sk_buff *skb; - int i; - - for(;;) - { - /* Try to get a free TPL from the chain. - * - * NOTE: We *must* always leave one unused TPL in the chain, - * because otherwise the adapter might send frames twice. - */ - if(tp->TplFree->NextTPLPtr->BusyFlag) /* No free TPL */ - { - printk(KERN_INFO "%s: No free TPL\n", dev->name); - return; - } - - /* Send first buffer from queue */ - skb = skb_dequeue(&tp->SendSkbQueue); - if(skb == NULL) - return; - - tp->QueueSkb++; - /* Is buffer reachable for Busmaster-DMA? */ - if(virt_to_bus((void*)(((long) skb->data) + skb->len)) - > ISA_MAX_ADDRESS) - { - /* Copy frame to local buffer */ - i = tp->TplFree->TPLIndex; - length = skb->len; - buf = tp->LocalTxBuffers[i]; - memcpy(buf, skb->data, length); - newbuf = sktr_fix_srouting(buf, &length); - } - else - { - /* Send direct from skb->data */ - length = skb->len; - newbuf = sktr_fix_srouting(skb->data, &length); - } - - /* Source address in packet? */ - sktr_chk_src_addr(newbuf, dev->dev_addr); - - tp->LastSendTime = jiffies; - tpl = tp->TplFree; /* Get the "free" TPL */ - tpl->BusyFlag = 1; /* Mark TPL as busy */ - tp->TplFree = tpl->NextTPLPtr; - - /* Save the skb for delayed return of skb to system */ - tpl->Skb = skb; - tpl->FragList[0].DataCount = (unsigned short) SWAPB(length); - tpl->FragList[0].DataAddr = htonl(virt_to_bus(newbuf)); - - /* Write the data length in the transmit list. */ - tpl->FrameSize = (unsigned short) SWAPB(length); - tpl->MData = newbuf; - - /* Transmit the frame and set the status values. */ - sktr_write_tpl_status(tpl, TX_VALID | TX_START_FRAME - | TX_END_FRAME | TX_PASS_SRC_ADDR - | TX_FRAME_IRQ); - - /* Let adapter send the frame. */ - sktr_exec_sifcmd(dev, CMD_TX_VALID); - } - - return; -} - -/* - * Write the given value to the 'Status' field of the specified TPL. - * NOTE: This function should be used whenever the status of any TPL must be - * modified by the driver, because the compiler may otherwise change the - * order of instructions such that writing the TPL status may be executed at - * an undesireable time. When this function is used, the status is always - * written when the function is called. - */ -static void sktr_write_tpl_status(TPL *tpl, unsigned int Status) -{ - tpl->Status = Status; -} - -static void sktr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr) -{ - unsigned char SRBit; - - if((((unsigned long)frame[8]) & ~0x80) != 0) /* Compare 4 bytes */ - return; - if((unsigned short)frame[12] != 0) /* Compare 2 bytes */ - return; - - SRBit = frame[8] & 0x80; - memcpy(&frame[8], hw_addr, 6); - frame[8] |= SRBit; - - return; -} - -/* - * The timer routine: Check if adapter still open and working, reopen if not. - */ -static void sktr_timer_chk(unsigned long data) -{ - struct net_device *dev = (struct net_device*)data; - struct net_local *tp = (struct net_local*)dev->priv; - - if(tp->HaltInProgress) - return; - - sktr_chk_outstanding_cmds(dev); - if(time_before(tp->LastSendTime + SEND_TIMEOUT, jiffies) - && (tp->QueueSkb < MAX_TX_QUEUE || tp->TplFree != tp->TplBusy)) - { - /* Anything to send, but stalled to long */ - tp->LastSendTime = jiffies; - sktr_exec_cmd(dev, OC_CLOSE); /* Does reopen automatically */ - } - - tp->timer.expires = jiffies + 2*HZ; - add_timer(&tp->timer); - - if(tp->AdapterOpenFlag || tp->ReOpenInProgress) - return; - tp->ReOpenInProgress = 1; - sktr_open_adapter(dev); - - return; -} - -/* - * The typical workload of the driver: Handle the network interface interrupts. - */ -static void sktr_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = dev_id; - struct net_local *tp; - int ioaddr; - unsigned short irq_type; - - if(dev == NULL) - { - printk("%s: irq %d for unknown device.\n", dev->name, irq); - return; - } - - dev->interrupt = 1; - - ioaddr = dev->base_addr; - tp = (struct net_local *)dev->priv; - - irq_type = inw(ioaddr + SIFSTS); - - while(irq_type & STS_SYSTEM_IRQ) - { - irq_type &= STS_IRQ_MASK; - - if(!sktr_chk_ssb(tp, irq_type)) - { - printk(KERN_INFO "%s: DATA LATE occurred\n", dev->name); - break; - } - - switch(irq_type) - { - case STS_IRQ_RECEIVE_STATUS: - sktr_reset_interrupt(dev); - sktr_rcv_status_irq(dev); - break; - - case STS_IRQ_TRANSMIT_STATUS: - /* Check if TRANSMIT.HALT command is complete */ - if(tp->ssb.Parm[0] & COMMAND_COMPLETE) - { - tp->TransmitCommandActive = 0; - tp->TransmitHaltScheduled = 0; - - /* Issue a new transmit command. */ - sktr_exec_cmd(dev, OC_TRANSMIT); - } - - sktr_reset_interrupt(dev); - sktr_tx_status_irq(dev); - break; - - case STS_IRQ_COMMAND_STATUS: - /* The SSB contains status of last command - * other than receive/transmit. - */ - sktr_cmd_status_irq(dev); - break; - - case STS_IRQ_SCB_CLEAR: - /* The SCB is free for another command. */ - tp->ScbInUse = 0; - sktr_chk_outstanding_cmds(dev); - break; - - case STS_IRQ_RING_STATUS: - sktr_ring_status_irq(dev); - break; - - case STS_IRQ_ADAPTER_CHECK: - sktr_chk_irq(dev); - break; - - default: - printk(KERN_INFO "Unknown Token Ring IRQ\n"); - break; - } - - /* Reset system interrupt if not already done. */ - if(irq_type != STS_IRQ_TRANSMIT_STATUS - && irq_type != STS_IRQ_RECEIVE_STATUS) - { - sktr_reset_interrupt(dev); - } - - irq_type = inw(ioaddr + SIFSTS); - } - - dev->interrupt = 0; - - return; -} - -/* - * Reset the INTERRUPT SYSTEM bit and issue SSB CLEAR command. - */ -static void sktr_reset_interrupt(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - SSB *ssb = &tp->ssb; - - /* - * [Workaround for "Data Late"] - * Set all fields of the SSB to well-defined values so we can - * check if the adapter has written the SSB. - */ - - ssb->STS = (unsigned short) -1; - ssb->Parm[0] = (unsigned short) -1; - ssb->Parm[1] = (unsigned short) -1; - ssb->Parm[2] = (unsigned short) -1; - - /* Free SSB by issuing SSB_CLEAR command after reading IRQ code - * and clear STS_SYSTEM_IRQ bit: enable adapter for further interrupts. - */ - sktr_exec_sifcmd(dev, CMD_SSB_CLEAR | CMD_CLEAR_SYSTEM_IRQ); - - return; -} - -/* - * Check if the SSB has actually been written by the adapter. - */ -static unsigned char sktr_chk_ssb(struct net_local *tp, unsigned short IrqType) -{ - SSB *ssb = &tp->ssb; /* The address of the SSB. */ - - /* C 0 1 2 INTERRUPT CODE - * - - - - -------------- - * 1 1 1 1 TRANSMIT STATUS - * 1 1 1 1 RECEIVE STATUS - * 1 ? ? 0 COMMAND STATUS - * 0 0 0 0 SCB CLEAR - * 1 1 0 0 RING STATUS - * 0 0 0 0 ADAPTER CHECK - * - * 0 = SSB field not affected by interrupt - * 1 = SSB field is affected by interrupt - * - * C = SSB ADDRESS +0: COMMAND - * 0 = SSB ADDRESS +2: STATUS 0 - * 1 = SSB ADDRESS +4: STATUS 1 - * 2 = SSB ADDRESS +6: STATUS 2 - */ - - /* Check if this interrupt does use the SSB. */ - - if(IrqType != STS_IRQ_TRANSMIT_STATUS - && IrqType != STS_IRQ_RECEIVE_STATUS - && IrqType != STS_IRQ_COMMAND_STATUS - && IrqType != STS_IRQ_RING_STATUS) - { - return (1); /* SSB not involved. */ - } - - /* Note: All fields of the SSB have been set to all ones (-1) after it - * has last been used by the software (see DriverIsr()). - * - * Check if the affected SSB fields are still unchanged. - */ - - if(ssb->STS == (unsigned short) -1) - return (0); /* Command field not yet available. */ - if(IrqType == STS_IRQ_COMMAND_STATUS) - return (1); /* Status fields not always affected. */ - if(ssb->Parm[0] == (unsigned short) -1) - return (0); /* Status 1 field not yet available. */ - if(IrqType == STS_IRQ_RING_STATUS) - return (1); /* Status 2 & 3 fields not affected. */ - - /* Note: At this point, the interrupt is either TRANSMIT or RECEIVE. */ - if(ssb->Parm[1] == (unsigned short) -1) - return (0); /* Status 2 field not yet available. */ - if(ssb->Parm[2] == (unsigned short) -1) - return (0); /* Status 3 field not yet available. */ - - return (1); /* All SSB fields have been written by the adapter. */ -} - -/* - * Evaluates the command results status in the SSB status field. - */ -static void sktr_cmd_status_irq(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - unsigned short ssb_cmd, ssb_parm_0; - unsigned short ssb_parm_1; - char *open_err = "Open error -"; - char *code_err = "Open code -"; - - /* Copy the ssb values to local variables */ - ssb_cmd = tp->ssb.STS; - ssb_parm_0 = tp->ssb.Parm[0]; - ssb_parm_1 = tp->ssb.Parm[1]; - - if(ssb_cmd == OPEN) - { - tp->Sleeping = 0; - if(!tp->ReOpenInProgress) - wake_up_interruptible(&tp->wait_for_tok_int); - - tp->OpenCommandIssued = 0; - tp->ScbInUse = 0; - - if((ssb_parm_0 & 0x00FF) == GOOD_COMPLETION) - { - /* Success, the adapter is open. */ - tp->LobeWireFaultLogged = 0; - tp->AdapterOpenFlag = 1; - tp->AdapterVirtOpenFlag = 1; - tp->TransmitCommandActive = 0; - sktr_exec_cmd(dev, OC_TRANSMIT); - sktr_exec_cmd(dev, OC_RECEIVE); - - if(tp->ReOpenInProgress) - tp->ReOpenInProgress = 0; - - return; - } - else /* The adapter did not open. */ - { - if(ssb_parm_0 & NODE_ADDR_ERROR) - printk(KERN_INFO "%s: Node address error\n", - dev->name); - if(ssb_parm_0 & LIST_SIZE_ERROR) - printk(KERN_INFO "%s: List size error\n", - dev->name); - if(ssb_parm_0 & BUF_SIZE_ERROR) - printk(KERN_INFO "%s: Buffer size error\n", - dev->name); - if(ssb_parm_0 & TX_BUF_COUNT_ERROR) - printk(KERN_INFO "%s: Tx buffer count error\n", - dev->name); - if(ssb_parm_0 & INVALID_OPEN_OPTION) - printk(KERN_INFO "%s: Invalid open option\n", - dev->name); - if(ssb_parm_0 & OPEN_ERROR) - { - /* Show the open phase. */ - switch(ssb_parm_0 & OPEN_PHASES_MASK) - { - case LOBE_MEDIA_TEST: - if(!tp->LobeWireFaultLogged) - { - tp->LobeWireFaultLogged = 1; - printk(KERN_INFO "%s: %s Lobe wire fault (check cable !).\n", dev->name, open_err); - } - tp->ReOpenInProgress = 1; - tp->AdapterOpenFlag = 0; - tp->AdapterVirtOpenFlag = 1; - sktr_open_adapter(dev); - return; - - case PHYSICAL_INSERTION: - printk(KERN_INFO "%s: %s Physical insertion.\n", dev->name, open_err); - break; - - case ADDRESS_VERIFICATION: - printk(KERN_INFO "%s: %s Address verification.\n", dev->name, open_err); - break; - - case PARTICIPATION_IN_RING_POLL: - printk(KERN_INFO "%s: %s Participation in ring poll.\n", dev->name, open_err); - break; - - case REQUEST_INITIALISATION: - printk(KERN_INFO "%s: %s Request initialisation.\n", dev->name, open_err); - break; - - case FULLDUPLEX_CHECK: - printk(KERN_INFO "%s: %s Full duplex check.\n", dev->name, open_err); - break; - - default: - printk(KERN_INFO "%s: %s Unknown open phase\n", dev->name, open_err); - break; - } - - /* Show the open errors. */ - switch(ssb_parm_0 & OPEN_ERROR_CODES_MASK) - { - case OPEN_FUNCTION_FAILURE: - printk(KERN_INFO "%s: %s OPEN_FUNCTION_FAILURE", dev->name, code_err); - tp->LastOpenStatus = - OPEN_FUNCTION_FAILURE; - break; - - case OPEN_SIGNAL_LOSS: - printk(KERN_INFO "%s: %s OPEN_SIGNAL_LOSS\n", dev->name, code_err); - tp->LastOpenStatus = - OPEN_SIGNAL_LOSS; - break; - - case OPEN_TIMEOUT: - printk(KERN_INFO "%s: %s OPEN_TIMEOUT\n", dev->name, code_err); - tp->LastOpenStatus = - OPEN_TIMEOUT; - break; - - case OPEN_RING_FAILURE: - printk(KERN_INFO "%s: %s OPEN_RING_FAILURE\n", dev->name, code_err); - tp->LastOpenStatus = - OPEN_RING_FAILURE; - break; - - case OPEN_RING_BEACONING: - printk(KERN_INFO "%s: %s OPEN_RING_BEACONING\n", dev->name, code_err); - tp->LastOpenStatus = - OPEN_RING_BEACONING; - break; - - case OPEN_DUPLICATE_NODEADDR: - printk(KERN_INFO "%s: %s OPEN_DUPLICATE_NODEADDR\n", dev->name, code_err); - tp->LastOpenStatus = - OPEN_DUPLICATE_NODEADDR; - break; - - case OPEN_REQUEST_INIT: - printk(KERN_INFO "%s: %s OPEN_REQUEST_INIT\n", dev->name, code_err); - tp->LastOpenStatus = - OPEN_REQUEST_INIT; - break; - - case OPEN_REMOVE_RECEIVED: - printk(KERN_INFO "%s: %s OPEN_REMOVE_RECEIVED", dev->name, code_err); - tp->LastOpenStatus = - OPEN_REMOVE_RECEIVED; - break; - - case OPEN_FULLDUPLEX_SET: - printk(KERN_INFO "%s: %s OPEN_FULLDUPLEX_SET\n", dev->name, code_err); - tp->LastOpenStatus = - OPEN_FULLDUPLEX_SET; - break; - - default: - printk(KERN_INFO "%s: %s Unknown open err code", dev->name, code_err); - tp->LastOpenStatus = - OPEN_FUNCTION_FAILURE; - break; - } - } - - tp->AdapterOpenFlag = 0; - tp->AdapterVirtOpenFlag = 0; - - return; - } - } - else - { - if(ssb_cmd != READ_ERROR_LOG) - return; - - /* Add values from the error log table to the MAC - * statistics counters and update the errorlogtable - * memory. - */ - tp->MacStat.line_errors += tp->errorlogtable.Line_Error; - tp->MacStat.burst_errors += tp->errorlogtable.Burst_Error; - tp->MacStat.A_C_errors += tp->errorlogtable.ARI_FCI_Error; - tp->MacStat.lost_frames += tp->errorlogtable.Lost_Frame_Error; - tp->MacStat.recv_congest_count += tp->errorlogtable.Rx_Congest_Error; - tp->MacStat.rx_errors += tp->errorlogtable.Rx_Congest_Error; - tp->MacStat.frame_copied_errors += tp->errorlogtable.Frame_Copied_Error; - tp->MacStat.token_errors += tp->errorlogtable.Token_Error; - tp->MacStat.dummy1 += tp->errorlogtable.DMA_Bus_Error; - tp->MacStat.dummy1 += tp->errorlogtable.DMA_Parity_Error; - tp->MacStat.abort_delimiters += tp->errorlogtable.AbortDelimeters; - tp->MacStat.frequency_errors += tp->errorlogtable.Frequency_Error; - tp->MacStat.internal_errors += tp->errorlogtable.Internal_Error; - } - - return; -} - -/* - * The inverse routine to sktr_open(). - */ -static int sktr_close(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - - dev->tbusy = 1; - dev->start = 0; - - del_timer(&tp->timer); - - /* Flush the Tx and disable Rx here. */ - - tp->HaltInProgress = 1; - sktr_exec_cmd(dev, OC_CLOSE); - tp->timer.expires = jiffies + 1*HZ; - tp->timer.function = sktr_timer_end_wait; - tp->timer.data = (unsigned long)dev; - add_timer(&tp->timer); - - sktr_enable_interrupts(dev); - - tp->Sleeping = 1; - interruptible_sleep_on(&tp->wait_for_tok_int); - tp->TransmitCommandActive = 0; - - del_timer(&tp->timer); - sktr_disable_interrupts(dev); - - if(dev->dma > 0) - { - unsigned long flags=claim_dma_lock(); - disable_dma(dev->dma); - release_dma_lock(flags); - } - - outw(0xFF00, dev->base_addr + SIFCMD); - if(dev->dma > 0) - outb(0xff, dev->base_addr + POSREG); - -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif - - sktr_cancel_tx_queue(tp); - - return (0); -} - -/* - * Get the current statistics. This may be called with the card open - * or closed. - */ -static struct enet_statistics *sktr_get_stats(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - - return ((struct enet_statistics *)&tp->MacStat); -} - -/* - * Set or clear the multicast filter for this adapter. - */ -static void sktr_set_multicast_list(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - unsigned int OpenOptions; - - OpenOptions = tp->ocpl.OPENOptions & - ~(PASS_ADAPTER_MAC_FRAMES - | PASS_ATTENTION_FRAMES - | PASS_BEACON_MAC_FRAMES - | COPY_ALL_MAC_FRAMES - | COPY_ALL_NON_MAC_FRAMES); - - if(dev->flags & IFF_PROMISC) - /* Enable promiscuous mode */ - OpenOptions |= COPY_ALL_NON_MAC_FRAMES | COPY_ALL_MAC_FRAMES; - else - { - if(dev->flags & IFF_ALLMULTI) - /* || dev->mc_count > HW_MAX_ADDRS) */ - { - /* Disable promiscuous mode, use normal mode. */ - } - else - { - if(dev->mc_count) - { - /* Walk the address list, and load the filter */ - } - } - } - - tp->ocpl.OPENOptions = OpenOptions; - sktr_exec_cmd(dev, OC_MODIFY_OPEN_PARMS); - - return; -} - -/* - * Wait for some time (microseconds) - */ -static void sktr_wait(unsigned long time) -{ - long tmp; - - tmp = jiffies + time/(1000000/HZ); - do { - current->state = TASK_INTERRUPTIBLE; - tmp = schedule_timeout(tmp); - } while(time_after(tmp, jiffies)); - - return; -} - -/* - * Write a command value to the SIFCMD register - */ -static void sktr_exec_sifcmd(struct net_device *dev, unsigned int WriteValue) -{ - int ioaddr = dev->base_addr; - unsigned short cmd; - unsigned short SifStsValue; - unsigned long loop_counter; - - WriteValue = ((WriteValue ^ CMD_SYSTEM_IRQ) | CMD_INTERRUPT_ADAPTER); - cmd = (unsigned short)WriteValue; - loop_counter = 0,5 * 800000; - do { - SifStsValue = inw(ioaddr + SIFSTS); - } while((SifStsValue & CMD_INTERRUPT_ADAPTER) && loop_counter--); - outw(cmd, ioaddr + SIFCMD); - - return; -} - -/* - * Processes adapter hardware reset, halts adapter and downloads firmware, - * clears the halt bit. - */ -static int sktr_reset_adapter(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - unsigned short *fw_ptr = (unsigned short *)&sktr_code; - unsigned short count, c; - int ioaddr = dev->base_addr; - - /* Hardware adapter reset */ - outw(ACL_ARESET, ioaddr + SIFACL); - sktr_wait(40); - - c = inw(ioaddr + SIFACL); - sktr_wait(20); - - if(dev->dma == 0) /* For PCI adapters */ - { - c &= ~(ACL_SPEED4 | ACL_SPEED16); /* Clear bits */ - if(tp->DataRate == SPEED_4) - c |= ACL_SPEED4; /* Set 4Mbps */ - else - c |= ACL_SPEED16; /* Set 16Mbps */ - } - - /* In case a command is pending - forget it */ - tp->ScbInUse = 0; - - c &= ~ACL_ARESET; /* Clear adapter reset bit */ - c |= ACL_CPHALT; /* Halt adapter CPU, allow download */ - c &= ~ACL_PSDMAEN; /* Clear pseudo dma bit */ - outw(c, ioaddr + SIFACL); - sktr_wait(40); - - /* Download firmware via DIO interface: */ - do { - /* Download first address part */ - outw(*fw_ptr, ioaddr + SIFADX); - fw_ptr++; - - /* Download second address part */ - outw(*fw_ptr, ioaddr + SIFADD); - fw_ptr++; - - if((count = *fw_ptr) != 0) /* Load loop counter */ - { - fw_ptr++; /* Download block data */ - for(; count > 0; count--) - { - outw(*fw_ptr, ioaddr + SIFINC); - fw_ptr++; - } - } - else /* Stop, if last block downloaded */ - { - c = inw(ioaddr + SIFACL); - c &= (~ACL_CPHALT | ACL_SINTEN); - - /* Clear CPHALT and start BUD */ - outw(c, ioaddr + SIFACL); - return (1); - } - } while(count == 0); - - return (-1); -} - -/* - * Starts bring up diagnostics of token ring adapter and evaluates - * diagnostic results. - */ -static int sktr_bringup_diags(struct net_device *dev) -{ - int loop_cnt, retry_cnt; - unsigned short Status; - int ioaddr = dev->base_addr; - - sktr_wait(HALF_SECOND); - sktr_exec_sifcmd(dev, EXEC_SOFT_RESET); - sktr_wait(HALF_SECOND); - - retry_cnt = BUD_MAX_RETRIES; /* maximal number of retrys */ - - do { - retry_cnt--; - if(sktr_debug > 3) - printk(KERN_INFO "BUD-Status: \n"); - loop_cnt = BUD_MAX_LOOPCNT; /* maximum: three seconds*/ - do { /* Inspect BUD results */ - loop_cnt--; - sktr_wait(HALF_SECOND); - Status = inw(ioaddr + SIFSTS); - Status &= STS_MASK; - - if(sktr_debug > 3) - printk(KERN_INFO " %04X \n", Status); - /* BUD successfully completed */ - if(Status == STS_INITIALIZE) - return (1); - /* Unrecoverable hardware error, BUD not completed? */ - } while((loop_cnt > 0) && ((Status & (STS_ERROR | STS_TEST)) - != (STS_ERROR | STS_TEST))); - - /* Error preventing completion of BUD */ - if(retry_cnt > 0) - { - printk(KERN_INFO "%s: Adapter Software Reset.\n", - dev->name); - sktr_exec_sifcmd(dev, EXEC_SOFT_RESET); - sktr_wait(HALF_SECOND); - } - } while(retry_cnt > 0); - - Status = inw(ioaddr + SIFSTS); - Status &= STS_ERROR_MASK; /* Hardware error occurred! */ - - printk(KERN_INFO "%s: Bring Up Diagnostics Error (%04X) occurred\n", - dev->name, Status); - - return (-1); -} - -/* - * Copy initialisation data to adapter memory, beginning at address - * 1:0A00; Starting DMA test and evaluating result bits. - */ -static int sktr_init_adapter(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - - const unsigned char SCB_Test[6] = {0x00, 0x00, 0xC1, 0xE2, 0xD4, 0x8B}; - const unsigned char SSB_Test[8] = {0xFF, 0xFF, 0xD1, 0xD7, - 0xC5, 0xD9, 0xC3, 0xD4}; - void *ptr = (void *)&tp->ipb; - unsigned short *ipb_ptr = (unsigned short *)ptr; - unsigned char *cb_ptr = (unsigned char *) &tp->scb; - unsigned char *sb_ptr = (unsigned char *) &tp->ssb; - unsigned short Status; - int i, loop_cnt, retry_cnt; - int ioaddr = dev->base_addr; - - /* Normalize: byte order low/high, word order high/low! (only IPB!) */ - tp->ipb.SCB_Addr = SWAPW(virt_to_bus(&tp->scb)); - tp->ipb.SSB_Addr = SWAPW(virt_to_bus(&tp->ssb)); - - /* Maximum: three initialization retries */ - retry_cnt = INIT_MAX_RETRIES; - - do { - retry_cnt--; - - /* Transfer initialization block */ - outw(0x0001, ioaddr + SIFADX); - - /* To address 0001:0A00 of adapter RAM */ - outw(0x0A00, ioaddr + SIFADD); - - /* Write 11 words to adapter RAM */ - for(i = 0; i < 11; i++) - outw(ipb_ptr[i], ioaddr + SIFINC); - - /* Execute SCB adapter command */ - sktr_exec_sifcmd(dev, CMD_EXECUTE); - - loop_cnt = INIT_MAX_LOOPCNT; /* Maximum: 11 seconds */ - - /* While remaining retries, no error and not completed */ - do { - Status = 0; - loop_cnt--; - sktr_wait(HALF_SECOND); - - /* Mask interesting status bits */ - Status = inw(ioaddr + SIFSTS); - Status &= STS_MASK; - } while(((Status &(STS_INITIALIZE | STS_ERROR | STS_TEST)) != 0) - && ((Status & STS_ERROR) == 0) && (loop_cnt != 0)); - - if((Status & (STS_INITIALIZE | STS_ERROR | STS_TEST)) == 0) - { - /* Initialization completed without error */ - i = 0; - do { /* Test if contents of SCB is valid */ - if(SCB_Test[i] != *(cb_ptr + i)) - /* DMA data error: wrong data in SCB */ - return (-1); - i++; - } while(i < 6); - - i = 0; - do { /* Test if contents of SSB is valid */ - if(SSB_Test[i] != *(sb_ptr + i)) - /* DMA data error: wrong data in SSB */ - return (-1); - i++; - } while (i < 8); - - return (1); /* Adapter successfully initialized */ - } - else - { - if((Status & STS_ERROR) != 0) - { - /* Initialization error occurred */ - Status = inw(ioaddr + SIFSTS); - Status &= STS_ERROR_MASK; - /* ShowInitialisationErrorCode(Status); */ - return (-1); /* Unrecoverable error */ - } - else - { - if(retry_cnt > 0) - { - /* Reset adapter and try init again */ - sktr_exec_sifcmd(dev, EXEC_SOFT_RESET); - sktr_wait(HALF_SECOND); - } - } - } - } while(retry_cnt > 0); - - return (-1); -} - -/* - * Check for outstanding commands in command queue and tries to execute - * command immediately. Corresponding command flag in command queue is cleared. - */ -static void sktr_chk_outstanding_cmds(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - unsigned long Addr = 0; - unsigned char i = 0; - - if(tp->CMDqueue == 0) - return; /* No command execution */ - - /* If SCB in use: no command */ - if(tp->ScbInUse == 1) - return; - - /* Check if adapter is opened, avoiding COMMAND_REJECT - * interrupt by the adapter! - */ - if(tp->AdapterOpenFlag == 0) - { - if(tp->CMDqueue & OC_OPEN) - { - /* Execute OPEN command */ - tp->CMDqueue ^= OC_OPEN; - - /* Copy the 18 bytes of the product ID */ - while((AdapterName[i] != '\0') && (i < PROD_ID_SIZE)) - { - tp->ProductID[i] = AdapterName[i]; - i++; - } - - Addr = htonl(virt_to_bus(&tp->ocpl)); - tp->scb.Parm[0] = LOWORD(Addr); - tp->scb.Parm[1] = HIWORD(Addr); - tp->scb.CMD = OPEN; - } - else - /* No OPEN command queued, but adapter closed. Note: - * We'll try to re-open the adapter in DriverPoll() - */ - return; /* No adapter command issued */ - } - else - { - /* Adapter is open; evaluate command queue: try to execute - * outstanding commands (depending on priority!) CLOSE - * command queued - */ - if(tp->CMDqueue & OC_CLOSE) - { - tp->CMDqueue ^= OC_CLOSE; - tp->AdapterOpenFlag = 0; - tp->scb.Parm[0] = 0; /* Parm[0], Parm[1] are ignored */ - tp->scb.Parm[1] = 0; /* but should be set to zero! */ - tp->scb.CMD = CLOSE; - if(!tp->HaltInProgress) - tp->CMDqueue |= OC_OPEN; /* re-open adapter */ - else - tp->CMDqueue = 0; /* no more commands */ - } - else - { - if(tp->CMDqueue & OC_RECEIVE) - { - tp->CMDqueue ^= OC_RECEIVE; - Addr = htonl(virt_to_bus(tp->RplHead)); - tp->scb.Parm[0] = LOWORD(Addr); - tp->scb.Parm[1] = HIWORD(Addr); - tp->scb.CMD = RECEIVE; - } - else - { - if(tp->CMDqueue & OC_TRANSMIT_HALT) - { - /* NOTE: TRANSMIT.HALT must be checked - * before TRANSMIT. - */ - tp->CMDqueue ^= OC_TRANSMIT_HALT; - tp->scb.CMD = TRANSMIT_HALT; - - /* Parm[0] and Parm[1] are ignored - * but should be set to zero! - */ - tp->scb.Parm[0] = 0; - tp->scb.Parm[1] = 0; - } - else - { - if(tp->CMDqueue & OC_TRANSMIT) - { - /* NOTE: TRANSMIT must be - * checked after TRANSMIT.HALT - */ - if(tp->TransmitCommandActive) - { - if(!tp->TransmitHaltScheduled) - { - tp->TransmitHaltScheduled = 1; - sktr_exec_cmd(dev, OC_TRANSMIT_HALT) ; - } - tp->TransmitCommandActive = 0; - return; - } - - tp->CMDqueue ^= OC_TRANSMIT; - sktr_cancel_tx_queue(tp); - Addr = htonl(virt_to_bus(tp->TplBusy)); - tp->scb.Parm[0] = LOWORD(Addr); - tp->scb.Parm[1] = HIWORD(Addr); - tp->scb.CMD = TRANSMIT; - tp->TransmitCommandActive = 1; - } - else - { - if(tp->CMDqueue & OC_MODIFY_OPEN_PARMS) - { - tp->CMDqueue ^= OC_MODIFY_OPEN_PARMS; - tp->scb.Parm[0] = tp->ocpl.OPENOptions; /* new OPEN options*/ - tp->scb.Parm[0] |= ENABLE_FULL_DUPLEX_SELECTION; - tp->scb.Parm[1] = 0; /* is ignored but should be zero */ - tp->scb.CMD = MODIFY_OPEN_PARMS; - } - else - { - if(tp->CMDqueue & OC_SET_FUNCT_ADDR) - { - tp->CMDqueue ^= OC_SET_FUNCT_ADDR; - tp->scb.Parm[0] = LOWORD(tp->ocpl.FunctAddr); - tp->scb.Parm[1] = HIWORD(tp->ocpl.FunctAddr); - tp->scb.CMD = SET_FUNCT_ADDR; - } - else - { - if(tp->CMDqueue & OC_SET_GROUP_ADDR) - { - tp->CMDqueue ^= OC_SET_GROUP_ADDR; - tp->scb.Parm[0] = LOWORD(tp->ocpl.GroupAddr); - tp->scb.Parm[1] = HIWORD(tp->ocpl.GroupAddr); - tp->scb.CMD = SET_GROUP_ADDR; - } - else - { - if(tp->CMDqueue & OC_READ_ERROR_LOG) - { - tp->CMDqueue ^= OC_READ_ERROR_LOG; - Addr = htonl(virt_to_bus(&tp->errorlogtable)); - tp->scb.Parm[0] = LOWORD(Addr); - tp->scb.Parm[1] = HIWORD(Addr); - tp->scb.CMD = READ_ERROR_LOG; - } - else - { - printk(KERN_WARNING "CheckForOutstandingCommand: unknown Command\n"); - tp->CMDqueue = 0; - return; - } - } - } - } - } - } - } - } - } - - tp->ScbInUse = 1; /* Set semaphore: SCB in use. */ - - /* Execute SCB and generate IRQ when done. */ - sktr_exec_sifcmd(dev, CMD_EXECUTE | CMD_SCB_REQUEST); - - return; -} - -/* - * IRQ conditions: signal loss on the ring, transmit or receive of beacon - * frames (disabled if bit 1 of OPEN option is set); report error MAC - * frame transmit (disabled if bit 2 of OPEN option is set); open or short - * cirquit fault on the lobe is detected; remove MAC frame received; - * error counter overflow (255); opened adapter is the only station in ring. - * After some of the IRQs the adapter is closed! - */ -static void sktr_ring_status_irq(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - - tp->CurrentRingStatus = SWAPB(tp->ssb.Parm[0]); - - /* First: fill up statistics */ - if(tp->ssb.Parm[0] & SIGNAL_LOSS) - { - printk(KERN_INFO "%s: Signal Loss\n", dev->name); - tp->MacStat.line_errors++; - } - - /* Adapter is closed, but initialized */ - if(tp->ssb.Parm[0] & LOBE_WIRE_FAULT) - { - printk(KERN_INFO "%s: Lobe Wire Fault, Reopen Adapter\n", - dev->name); - tp->MacStat.line_errors++; - } - - if(tp->ssb.Parm[0] & RING_RECOVERY) - printk(KERN_INFO "%s: Ring Recovery\n", dev->name); - - /* Counter overflow: read error log */ - if(tp->ssb.Parm[0] & COUNTER_OVERFLOW) - { - printk(KERN_INFO "%s: Counter Overflow\n", dev->name); - sktr_exec_cmd(dev, OC_READ_ERROR_LOG); - } - - /* Adapter is closed, but initialized */ - if(tp->ssb.Parm[0] & REMOVE_RECEIVED) - printk(KERN_INFO "%s: Remove Received, Reopen Adapter\n", - dev->name); - - /* Adapter is closed, but initialized */ - if(tp->ssb.Parm[0] & AUTO_REMOVAL_ERROR) - printk(KERN_INFO "%s: Auto Removal Error, Reopen Adapter\n", - dev->name); - - if(tp->ssb.Parm[0] & HARD_ERROR) - printk(KERN_INFO "%s: Hard Error\n", dev->name); - - if(tp->ssb.Parm[0] & SOFT_ERROR) - printk(KERN_INFO "%s: Soft Error\n", dev->name); - - if(tp->ssb.Parm[0] & TRANSMIT_BEACON) - printk(KERN_INFO "%s: Transmit Beacon\n", dev->name); - - if(tp->ssb.Parm[0] & SINGLE_STATION) - printk(KERN_INFO "%s: Single Station\n", dev->name); - - /* Check if adapter has been closed */ - if(tp->ssb.Parm[0] & ADAPTER_CLOSED) - { - printk(KERN_INFO "%s: Adapter closed (Reopening)," - "QueueSkb %d, CurrentRingStat %x\n", - dev->name, tp->QueueSkb, tp->CurrentRingStatus); - tp->AdapterOpenFlag = 0; - sktr_open_adapter(dev); - } - - return; -} - -/* - * Issued if adapter has encountered an unrecoverable hardware - * or software error. - */ -static void sktr_chk_irq(struct net_device *dev) -{ - int i; - unsigned short AdapterCheckBlock[4]; - unsigned short ioaddr = dev->base_addr; - struct net_local *tp = (struct net_local *)dev->priv; - - tp->AdapterOpenFlag = 0; /* Adapter closed now */ - - /* Page number of adapter memory */ - outw(0x0001, ioaddr + SIFADX); - /* Address offset */ - outw(CHECKADDR, ioaddr + SIFADR); - - /* Reading 8 byte adapter check block. */ - for(i = 0; i < 4; i++) - AdapterCheckBlock[i] = inw(ioaddr + SIFINC); - - if(sktr_debug > 3) - { - printk("%s: AdapterCheckBlock: ", dev->name); - for (i = 0; i < 4; i++) - printk("%04X", AdapterCheckBlock[i]); - printk("\n"); - } - - switch(AdapterCheckBlock[0]) - { - case DIO_PARITY: - printk(KERN_INFO "%s: DIO parity error\n", dev->name); - break; - - case DMA_READ_ABORT: - printk(KERN_INFO "%s DMA read operation aborted:\n", - dev->name); - switch (AdapterCheckBlock[1]) - { - case 0: - printk(KERN_INFO "Timeout\n"); - printk(KERN_INFO "Address: %04X %04X\n", - AdapterCheckBlock[2], - AdapterCheckBlock[3]); - break; - - case 1: - printk(KERN_INFO "Parity error\n"); - printk(KERN_INFO "Address: %04X %04X\n", - AdapterCheckBlock[2], - AdapterCheckBlock[3]); - break; - - case 2: - printk(KERN_INFO "Bus error\n"); - printk(KERN_INFO "Address: %04X %04X\n", - AdapterCheckBlock[2], - AdapterCheckBlock[3]); - break; - - default: - printk(KERN_INFO "Unknown error.\n"); - break; - } - break; - - case DMA_WRITE_ABORT: - printk(KERN_INFO "%s: DMA write operation aborted: \n", - dev->name); - switch (AdapterCheckBlock[1]) - { - case 0: - printk(KERN_INFO "Timeout\n"); - printk(KERN_INFO "Address: %04X %04X\n", - AdapterCheckBlock[2], - AdapterCheckBlock[3]); - break; - - case 1: - printk(KERN_INFO "Parity error\n"); - printk(KERN_INFO "Address: %04X %04X\n", - AdapterCheckBlock[2], - AdapterCheckBlock[3]); - break; - - case 2: - printk(KERN_INFO "Bus error\n"); - printk(KERN_INFO "Address: %04X %04X\n", - AdapterCheckBlock[2], - AdapterCheckBlock[3]); - break; - - default: - printk(KERN_INFO "Unknown error.\n"); - break; - } - break; - - case ILLEGAL_OP_CODE: - printk("%s: Illegal operation code in firmware\n", - dev->name); - /* Parm[0-3]: adapter internal register R13-R15 */ - break; - - case PARITY_ERRORS: - printk("%s: Adapter internal bus parity error\n", - dev->name); - /* Parm[0-3]: adapter internal register R13-R15 */ - break; - - case RAM_DATA_ERROR: - printk("%s: RAM data error\n", dev->name); - /* Parm[0-1]: MSW/LSW address of RAM location. */ - break; - - case RAM_PARITY_ERROR: - printk("%s: RAM parity error\n", dev->name); - /* Parm[0-1]: MSW/LSW address of RAM location. */ - break; - - case RING_UNDERRUN: - printk("%s: Internal DMA underrun detected\n", - dev->name); - break; - - case INVALID_IRQ: - printk("%s: Unrecognized interrupt detected\n", - dev->name); - /* Parm[0-3]: adapter internal register R13-R15 */ - break; - - case INVALID_ERROR_IRQ: - printk("%s: Unrecognized error interrupt detected\n", - dev->name); - /* Parm[0-3]: adapter internal register R13-R15 */ - break; - - case INVALID_XOP: - printk("%s: Unrecognized XOP request detected\n", - dev->name); - /* Parm[0-3]: adapter internal register R13-R15 */ - break; - - default: - printk("%s: Unknown status", dev->name); - break; - } - - if(sktr_chipset_init(dev) == 1) - { - /* Restart of firmware successful */ - tp->AdapterOpenFlag = 1; - } - - return; -} - -/* - * Internal adapter pointer to RAM data are copied from adapter into - * host system. - */ -static void sktr_read_ptr(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - unsigned short adapterram; - - sktr_read_ram(dev, (unsigned char *)&tp->intptrs.BurnedInAddrPtr, - ADAPTER_INT_PTRS, 16); - sktr_read_ram(dev, (unsigned char *)&adapterram, - (unsigned short)SWAPB(tp->intptrs.AdapterRAMPtr), 2); - - printk(KERN_INFO "%s: Adapter RAM size: %d K\n", - dev->name, SWAPB(adapterram)); - - return; -} - -/* - * Reads a number of bytes from adapter to system memory. - */ -static void sktr_read_ram(struct net_device *dev, unsigned char *Data, - unsigned short Address, int Length) -{ - int i; - unsigned short old_sifadx, old_sifadr, InWord; - unsigned short ioaddr = dev->base_addr; - - /* Save the current values */ - old_sifadx = inw(ioaddr + SIFADX); - old_sifadr = inw(ioaddr + SIFADR); - - /* Page number of adapter memory */ - outw(0x0001, ioaddr + SIFADX); - /* Address offset in adapter RAM */ - outw(Address, ioaddr + SIFADR); - - /* Copy len byte from adapter memory to system data area. */ - i = 0; - for(;;) - { - InWord = inw(ioaddr + SIFINC); - - *(Data + i) = HIBYTE(InWord); /* Write first byte */ - if(++i == Length) /* All is done break */ - break; - - *(Data + i) = LOBYTE(InWord); /* Write second byte */ - if (++i == Length) /* All is done break */ - break; - } - - /* Restore original values */ - outw(old_sifadx, ioaddr + SIFADX); - outw(old_sifadr, ioaddr + SIFADR); - - return; -} - -/* - * Reads MAC address from adapter ROM. - */ -static void sktr_read_addr(struct net_device *dev, unsigned char *Address) -{ - int i, In; - unsigned short ioaddr = dev->base_addr; - - /* Address: 0000:0000 */ - outw(0, ioaddr + SIFADX); - outw(0, ioaddr + SIFADR); - - /* Read six byte MAC address data */ - for(i = 0; i < 6; i++) - { - In = inw(ioaddr + SIFINC); - *(Address + i) = (unsigned char)(In >> 8); - } - - return; -} - -/* - * Cancel all queued packets in the transmission queue. - */ -static void sktr_cancel_tx_queue(struct net_local* tp) -{ - TPL *tpl; - struct sk_buff *skb; - - /* - * NOTE: There must not be an active TRANSMIT command pending, when - * this function is called. - */ - if(tp->TransmitCommandActive) - return; - - for(;;) - { - tpl = tp->TplBusy; - if(!tpl->BusyFlag) - break; - /* "Remove" TPL from busy list. */ - tp->TplBusy = tpl->NextTPLPtr; - sktr_write_tpl_status(tpl, 0); /* Clear VALID bit */ - tpl->BusyFlag = 0; /* "free" TPL */ - - printk(KERN_INFO "Cancel tx (%08lXh).\n", (unsigned long)tpl); - - dev_kfree_skb(tpl->Skb); - } - - for(;;) - { - skb = skb_dequeue(&tp->SendSkbQueue); - if(skb == NULL) - break; - tp->QueueSkb++; - dev_kfree_skb(skb); - } - - return; -} - -/* - * This function is called whenever a transmit interrupt is generated by the - * adapter. For a command complete interrupt, it is checked if we have to - * issue a new transmit command or not. - */ -static void sktr_tx_status_irq(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - unsigned char HighByte, HighAc, LowAc; - TPL *tpl; - - /* NOTE: At this point the SSB from TRANSMIT STATUS is no longer - * available, because the CLEAR SSB command has already been issued. - * - * Process all complete transmissions. - */ - - for(;;) - { - tpl = tp->TplBusy; - if(!tpl->BusyFlag || (tpl->Status - & (TX_VALID | TX_FRAME_COMPLETE)) - != TX_FRAME_COMPLETE) - { - break; - } - - /* "Remove" TPL from busy list. */ - tp->TplBusy = tpl->NextTPLPtr ; - - if(sktr_debug > 3) - sktr_dump(tpl->MData, SWAPB(tpl->FrameSize)); - - /* Check the transmit status field only for directed frames*/ - if(DIRECTED_FRAME(tpl) && (tpl->Status & TX_ERROR) == 0) - { - HighByte = GET_TRANSMIT_STATUS_HIGH_BYTE(tpl->Status); - HighAc = GET_FRAME_STATUS_HIGH_AC(HighByte); - LowAc = GET_FRAME_STATUS_LOW_AC(HighByte); - - if((HighAc != LowAc) || (HighAc == AC_NOT_RECOGNIZED)) - { - printk(KERN_INFO "%s: (DA=%08lX not recognized)", - dev->name, - *(unsigned long *)&tpl->MData[2+2]); - } - else - { - if(sktr_debug > 3) - printk("%s: Directed frame tx'd\n", - dev->name); - } - } - else - { - if(!DIRECTED_FRAME(tpl)) - { - if(sktr_debug > 3) - printk("%s: Broadcast frame tx'd\n", - dev->name); - } - } - - tp->MacStat.tx_packets++; - dev_kfree_skb(tpl->Skb); - tpl->BusyFlag = 0; /* "free" TPL */ - } - - dev->tbusy = 0; - if(tp->QueueSkb < MAX_TX_QUEUE) - sktr_hardware_send_packet(dev, tp); - - return; -} - -/* - * Called if a frame receive interrupt is generated by the adapter. - * Check if the frame is valid and indicate it to system. - */ -static void sktr_rcv_status_irq(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - unsigned char *ReceiveDataPtr; - struct sk_buff *skb; - unsigned int Length, Length2; - RPL *rpl; - RPL *SaveHead; - - /* NOTE: At this point the SSB from RECEIVE STATUS is no longer - * available, because the CLEAR SSB command has already been issued. - * - * Process all complete receives. - */ - - for(;;) - { - rpl = tp->RplHead; - if(rpl->Status & RX_VALID) - break; /* RPL still in use by adapter */ - - /* Forward RPLHead pointer to next list. */ - SaveHead = tp->RplHead; - tp->RplHead = rpl->NextRPLPtr; - - /* Get the frame size (Byte swap for Intel). - * Do this early (see workaround comment below) - */ - Length = (unsigned short)SWAPB(rpl->FrameSize); - - /* Check if the Frame_Start, Frame_End and - * Frame_Complete bits are set. - */ - if((rpl->Status & VALID_SINGLE_BUFFER_FRAME) - == VALID_SINGLE_BUFFER_FRAME) - { - ReceiveDataPtr = rpl->MData; - - /* Workaround for delayed write of FrameSize on ISA - * (FrameSize is false but valid-bit is reset) - * Frame size is set to zero when the RPL is freed. - * Length2 is there because there have also been - * cases where the FrameSize was partially written - */ - Length2 = (unsigned short)SWAPB(rpl->FrameSize); - - if(Length == 0 || Length != Length2) - { - tp->RplHead = SaveHead; - break; /* Return to sktr_interrupt */ - } - - /* Drop frames sent by myself */ - if(sktr_chk_frame(dev, rpl->MData)) - { - printk(KERN_INFO "%s: Received my own frame\n", - dev->name); - if(rpl->Skb != NULL) - dev_kfree_skb(rpl->Skb); - } - else - { - sktr_update_rcv_stats(tp,ReceiveDataPtr,Length); - - if(sktr_debug > 3) - printk("%s: Packet Length %04X (%d)\n", - dev->name, Length, Length); - - /* Indicate the received frame to system the - * adapter does the Source-Routing padding for - * us. See: OpenOptions in sktr_init_opb() - */ - skb = rpl->Skb; - if(rpl->SkbStat == SKB_UNAVAILABLE) - { - /* Try again to allocate skb */ - skb = dev_alloc_skb(tp->MaxPacketSize); - if(skb == NULL) - { - /* Update Stats ?? */ - } - else - { - skb->dev = dev; - skb_put(skb, tp->MaxPacketSize); - rpl->SkbStat = SKB_DATA_COPY; - ReceiveDataPtr = rpl->MData; - } - } - - if(rpl->SkbStat == SKB_DATA_COPY - || rpl->SkbStat == SKB_DMA_DIRECT) - { - if(rpl->SkbStat == SKB_DATA_COPY) - { - memmove(skb->data, ReceiveDataPtr, Length); - } - - /* Deliver frame to system */ - rpl->Skb = NULL; - skb_trim(skb,Length); - skb->protocol = tr_type_trans(skb,dev); - netif_rx(skb); - } - } - } - else /* Invalid frame */ - { - if(rpl->Skb != NULL) - dev_kfree_skb(rpl->Skb); - - /* Skip list. */ - if(rpl->Status & RX_START_FRAME) - /* Frame start bit is set -> overflow. */ - tp->MacStat.rx_errors++; - } - - /* Allocate new skb for rpl */ - rpl->Skb = dev_alloc_skb(tp->MaxPacketSize); - - /* skb == NULL ? then use local buffer */ - if(rpl->Skb == NULL) - { - rpl->SkbStat = SKB_UNAVAILABLE; - rpl->FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[rpl->RPLIndex])); - rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex]; - } - else /* skb != NULL */ - { - rpl->Skb->dev = dev; - skb_put(rpl->Skb, tp->MaxPacketSize); - - /* Data unreachable for DMA ? then use local buffer */ - if(virt_to_bus(rpl->Skb->data) + tp->MaxPacketSize - > ISA_MAX_ADDRESS) - { - rpl->SkbStat = SKB_DATA_COPY; - rpl->FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[rpl->RPLIndex])); - rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex]; - } - else - { - /* DMA directly in skb->data */ - rpl->SkbStat = SKB_DMA_DIRECT; - rpl->FragList[0].DataAddr = htonl(virt_to_bus(rpl->Skb->data)); - rpl->MData = rpl->Skb->data; - } - } - - rpl->FragList[0].DataCount = SWAPB(tp->MaxPacketSize); - rpl->FrameSize = 0; - - /* Pass the last RPL back to the adapter */ - tp->RplTail->FrameSize = 0; - - /* Reset the CSTAT field in the list. */ - sktr_write_rpl_status(tp->RplTail, RX_VALID | RX_FRAME_IRQ); - - /* Current RPL becomes last one in list. */ - tp->RplTail = tp->RplTail->NextRPLPtr; - - /* Inform adapter about RPL valid. */ - sktr_exec_sifcmd(dev, CMD_RX_VALID); - } - - return; -} - -/* - * This function should be used whenever the status of any RPL must be - * modified by the driver, because the compiler may otherwise change the - * order of instructions such that writing the RPL status may be executed - * at an undesireable time. When this function is used, the status is - * always written when the function is called. - */ -static void sktr_write_rpl_status(RPL *rpl, unsigned int Status) -{ - rpl->Status = Status; - - return; -} - -/* - * The function updates the statistic counters in mac->MacStat. - * It differtiates between directed and broadcast/multicast ( ==functional) - * frames. - */ -static void sktr_update_rcv_stats(struct net_local *tp, unsigned char DataPtr[], - unsigned int Length) -{ - tp->MacStat.rx_packets++; - - /* Test functional bit */ - if(DataPtr[2] & GROUP_BIT) - tp->MacStat.multicast++; - - return; -} - -/* - * Check if it is a frame of myself. Compare source address with my current - * address in reverse direction, and mask out the TR_RII. - */ -static unsigned char sktr_chk_frame(struct net_device *dev, unsigned char *Addr) -{ - int i; - - for(i = 5; i > 0; i--) - { - if(Addr[8 + i] != dev->dev_addr[i]) - return (0); - } - - /* Mask out RIF bit. */ - if((Addr[8] & ~TR_RII) != (unsigned char)(dev->dev_addr[0])) - return (0); - - return (1); /* It is my frame. */ -} - -/* - * Dump Packet (data) - */ -static void sktr_dump(unsigned char *Data, int length) -{ - int i, j; - - for (i = 0, j = 0; i < length / 8; i++, j += 8) - { - printk(KERN_DEBUG "%02x %02x %02x %02x %02x %02x %02x %02x\n", - Data[j+0],Data[j+1],Data[j+2],Data[j+3], - Data[j+4],Data[j+5],Data[j+6],Data[j+7]); - } - - return; -} - -#ifdef MODULE - -static struct net_device* dev_sktr[SKTR_MAX_ADAPTERS]; -static int io[SKTR_MAX_ADAPTERS] = { 0, 0 }; -static int irq[SKTR_MAX_ADAPTERS] = { 0, 0 }; -static int mem[SKTR_MAX_ADAPTERS] = { 0, 0 }; - -MODULE_PARM(io, "1-" __MODULE_STRING(SKTR_MAX_ADAPTERS) "i"); -MODULE_PARM(irq, "1-" __MODULE_STRING(SKTR_MAX_ADAPTERS) "i"); -MODULE_PARM(mem, "1-" __MODULE_STRING(SKTR_MAX_ADAPTERS) "i"); - -int init_module(void) -{ - int i; - - for(i = 0; i < SKTR_MAX_ADAPTERS; i++) - { - irq[i] = 0; - mem[i] = 0; - dev_sktr[i] = NULL; - dev_sktr[i] = init_trdev(dev_sktr[i], 0); - if(dev_sktr[i] == NULL) - return (-ENOMEM); - - dev_sktr[i]->base_addr = io[i]; - dev_sktr[i]->irq = irq[i]; - dev_sktr[i]->mem_start = mem[i]; - dev_sktr[i]->init = &sktr_probe; - - if(register_trdev(dev_sktr[i]) != 0) - { - kfree_s(dev_sktr[i], sizeof(struct net_device)); - dev_sktr[i] = NULL; - if(i == 0) - { - printk("sktr: register_trdev() returned non-zero.\n"); - return (-EIO); - } - else - return (0); - } - } - - return (0); -} - -void cleanup_module(void) -{ - int i; - - for(i = 0; i < SKTR_MAX_ADAPTERS; i++) - { - if(dev_sktr[i]) - { - unregister_trdev(dev_sktr[i]); - release_region(dev_sktr[i]->base_addr, SKTR_IO_EXTENT); - if(dev_sktr[i]->irq) - free_irq(dev_sktr[i]->irq, dev_sktr[i]); - if(dev_sktr[i]->dma > 0) - free_dma(dev_sktr[i]->dma); - if(dev_sktr[i]->priv) - kfree_s(dev_sktr[i]->priv, sizeof(struct net_local)); - kfree_s(dev_sktr[i], sizeof(struct net_device)); - dev_sktr[i] = NULL; - } - } -} -#endif /* MODULE */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/sktr.h linux/drivers/net/sktr.h --- v2.3.20/linux/drivers/net/sktr.h Wed May 12 13:27:37 1999 +++ linux/drivers/net/sktr.h Wed Dec 31 16:00:00 1969 @@ -1,1098 +0,0 @@ -/* sktr.h: SysKonnect TokenRing driver for Linux - * - * Authors: - * - Christoph Goos - */ - -#ifndef __LINUX_SKTR_H -#define __LINUX_SKTR_H - -#ifdef __KERNEL__ - -#define SKTR_MAX_ADAPTERS 7 - -#define SEND_TIMEOUT 10*HZ - -#define TR_RCF_LONGEST_FRAME_MASK 0x0070 -#define TR_RCF_FRAME4K 0x0030 - -/*------------------------------------------------------------------*/ -/* Bit order for adapter communication with DMA */ -/* -------------------------------------------------------------- */ -/* Bit 8 | 9| 10| 11|| 12| 13| 14| 15|| 0| 1| 2| 3|| 4| 5| 6| 7| */ -/* -------------------------------------------------------------- */ -/* The bytes in a word must be byte swapped. Also, if a double */ -/* word is used for storage, then the words, as well as the bytes, */ -/* must be swapped. */ -/* Bit order for adapter communication with DIO */ -/* -------------------------------------------------------------- */ -/* Bit 0 | 1| 2| 3|| 4| 5| 6| 7|| 8| 9| 10| 11|| 12| 13| 14| 15| */ -/* -------------------------------------------------------------- */ -/*------------------------------------------------------------------*/ - -/* Swap bytes of a word. */ -#define SWAPB(x) (((unsigned short)((x) << 8)) | ((unsigned short)((x) >> 8))) - -/* Swap words of a long. */ -#define SWAPW(x) (((x) << 16) | ((x) >> 16)) - -/* Get the low byte of a word. */ -#define LOBYTE(w) ((unsigned char)(w)) - -/* Get the high byte of a word. */ -#define HIBYTE(w) ((unsigned char)((unsigned short)(w) >> 8)) - -/* Get the low word of a long. */ -#define LOWORD(l) ((unsigned short)(l)) - -/* Get the high word of a long. */ -#define HIWORD(l) ((unsigned short)((unsigned long)(l) >> 16)) - - - -/* Token ring adapter I/O addresses for normal mode. */ -#define SIFDAT 0L /* SIF/DMA data. */ -#define SIFINC 2L /* IO Word data with auto increment. */ -#define SIFINH 3L /* IO Byte data with auto increment. */ -#define SIFADR 4L /* SIF/DMA Address. */ -#define SIFCMD 6L /* SIF Command. */ -#define SIFSTS 6L /* SIF Status. */ -#define SIFACL 8L /* SIF Adapter Control Register. */ -#define SIFADD 10L /* SIF/DMA Address. */ -#define SIFADX 12L -#define DMALEN 14L /* SIF DMA length. */ -#define POSREG 16L /* Adapter Program Option Select (POS) - * Register: base IO address + 16 byte. - */ -#define POSREG_2 24L /* only for TR4/16+ adapter - * base IO address + 24 byte. - */ - - -/* SIFCMD command codes (high-low) */ -#define CMD_INTERRUPT_ADAPTER 0x8000 /* Cause internal adapter interrupt */ -#define CMD_ADAPTER_RESET 0x4000 /* Hardware reset of adapter */ -#define CMD_SSB_CLEAR 0x2000 /* Acknowledge to adapter to - * system interrupts. - */ -#define CMD_EXECUTE 0x1000 /* Execute SCB command */ -#define CMD_SCB_REQUEST 0x0800 /* Request adapter to interrupt - * system when SCB is available for - * another command. - */ -#define CMD_RX_CONTINUE 0x0400 /* Continue receive after odd pointer - * stop. (odd pointer receive method) - */ -#define CMD_RX_VALID 0x0200 /* Now actual RPL is valid. */ -#define CMD_TX_VALID 0x0100 /* Now actual TPL is valid. (valid - * bit receive/transmit method) - */ -#define CMD_SYSTEM_IRQ 0x0080 /* Adapter-to-attached-system - * interrupt is reset. - */ -#define CMD_CLEAR_SYSTEM_IRQ 0x0080 /* Clear SYSTEM_INTERRUPT bit. - * (write: 1=ignore, 0=reset) - */ -#define EXEC_SOFT_RESET 0xFF00 /* adapter soft reset. (restart - * adapter after hardware reset) - */ - - -/* ACL commands (high-low) */ -#define ACL_SWHLDA 0x0800 /* Software hold acknowledge. */ -#define ACL_SWDDIR 0x0400 /* Data transfer direction. */ -#define ACL_SWHRQ 0x0200 /* Pseudo DMA operation. */ -#define ACL_PSDMAEN 0x0100 /* Enable pseudo system DMA. */ -#define ACL_ARESET 0x0080 /* Adapter hardware reset command. - * (held in reset condition as - * long as bit is set) - */ -#define ACL_CPHALT 0x0040 /* Communication processor halt. - * (can only be set while ACL_ARESET - * bit is set; prevents adapter - * processor from executing code while - * downloading firmware) - */ -#define ACL_BOOT 0x0020 -#define ACL_SINTEN 0x0008 /* System interrupt enable/disable - * (1/0): can be written if ACL_ARESET - * is zero. - */ -#define ACL_SPEED4 0x0003 -#define ACL_SPEED16 0x0001 -#define PS_DMA_MASK (ACL_SWHRQ | ACL_PSDMAEN) - - -/* SIFSTS register return codes (high-low) */ -#define STS_SYSTEM_IRQ 0x0080 /* Adapter-to-attached-system - * interrupt is valid. - */ -#define STS_INITIALIZE 0x0040 /* INITIALIZE status. (ready to - * initialize) - */ -#define STS_TEST 0x0020 /* TEST status. (BUD not completed) */ -#define STS_ERROR 0x0010 /* ERROR status. (unrecoverable - * HW error occurred) - */ -#define STS_MASK 0x00F0 /* Mask interesting status bits. */ -#define STS_ERROR_MASK 0x000F /* Get Error Code by masking the - * interrupt code bits. - */ -#define ADAPTER_INT_PTRS 0x0A00 /* Address offset of adapter internal - * pointers 01:0a00 (high-low) have to - * be read after init and before open. - */ - - -/* Interrupt Codes (only MAC IRQs) */ -#define STS_IRQ_ADAPTER_CHECK 0x0000 /* unrecoverable hardware or - * software error. - */ -#define STS_IRQ_RING_STATUS 0x0004 /* SSB is updated with ring status. */ -#define STS_IRQ_SCB_CLEAR 0x0006 /* SCB clear, following an - * SCB_REQUEST IRQ. - */ -#define STS_IRQ_COMMAND_STATUS 0x0008 /* SSB is updated with command - * status. - */ -#define STS_IRQ_RECEIVE_STATUS 0x000A /* SSB is updated with receive - * status. - */ -#define STS_IRQ_TRANSMIT_STATUS 0x000C /* SSB is updated with transmit - * status - */ -#define STS_IRQ_MASK 0x000F /* = STS_ERROR_MASK. */ - - -/* TRANSMIT_STATUS completion code: (SSB.Parm[0]) */ -#define COMMAND_COMPLETE 0x0080 /* TRANSMIT command completed - * (avoid this!) issue another transmit - * to send additional frames. - */ -#define FRAME_COMPLETE 0x0040 /* Frame has been transmitted; - * INTERRUPT_FRAME bit was set in the - * CSTAT request; indication of possibly - * more than one frame transmissions! - * SSB.Parm[0-1]: 32 bit pointer to - * TPL of last frame. - */ -#define LIST_ERROR 0x0020 /* Error in one of the TPLs that - * compose the frame; TRANSMIT - * terminated; Parm[1-2]: 32 bit pointer - * to TPL which starts the error - * frame; error details in bits 8-13. - * (14?) - */ -#define FRAME_SIZE_ERROR 0x8000 /* FRAME_SIZE does not equal the sum of - * the valid DATA_COUNT fields; - * FRAME_SIZE less than header plus - * information field. (15 bytes + - * routing field) Or if FRAME_SIZE - * was specified as zero in one list. - */ -#define TX_THRESHOLD 0x4000 /* FRAME_SIZE greater than (BUFFER_SIZE - * - 9) * TX_BUF_MAX. - */ -#define ODD_ADDRESS 0x2000 /* Odd forward pointer value is - * read on a list without END_FRAME - * indication. - */ -#define FRAME_ERROR 0x1000 /* START_FRAME bit is (not) anticipated, - * but (not) set. - */ -#define ACCESS_PRIORITY_ERROR 0x0800 /* Access priority requested has not - * been allowed. - */ -#define UNENABLED_MAC_FRAME 0x0400 /* MAC frame has source class of zero - * or MAC frame PCF ATTN field is - * greater than one. - */ -#define ILLEGAL_FRAME_FORMAT 0x0200 /* Bit 0 or FC field was set to one. */ - - -/* - * Since we need to support some functions even if the adapter is in a - * CLOSED state, we have a (pseudo-) command queue which holds commands - * that are outstandig to be executed. - * - * Each time a command completes, an interrupt occurs and the next - * command is executed. The command queue is actually a simple word with - * a bit for each outstandig command. Therefore the commands will not be - * executed in the order they have been queued. - * - * The following defines the command code bits and the command queue: - */ -#define OC_OPEN 0x0001 /* OPEN command */ -#define OC_TRANSMIT 0x0002 /* TRANSMIT command */ -#define OC_TRANSMIT_HALT 0x0004 /* TRANSMIT_HALT command */ -#define OC_RECEIVE 0x0008 /* RECEIVE command */ -#define OC_CLOSE 0x0010 /* CLOSE command */ -#define OC_SET_GROUP_ADDR 0x0020 /* SET_GROUP_ADDR command */ -#define OC_SET_FUNCT_ADDR 0x0040 /* SET_FUNCT_ADDR command */ -#define OC_READ_ERROR_LOG 0x0080 /* READ_ERROR_LOG command */ -#define OC_READ_ADAPTER 0x0100 /* READ_ADAPTER command */ -#define OC_MODIFY_OPEN_PARMS 0x0400 /* MODIFY_OPEN_PARMS command */ -#define OC_RESTORE_OPEN_PARMS 0x0800 /* RESTORE_OPEN_PARMS command */ -#define OC_SET_FIRST_16_GROUP 0x1000 /* SET_FIRST_16_GROUP command */ -#define OC_SET_BRIDGE_PARMS 0x2000 /* SET_BRIDGE_PARMS command */ -#define OC_CONFIG_BRIDGE_PARMS 0x4000 /* CONFIG_BRIDGE_PARMS command */ - -#define OPEN 0x0300 /* C: open command. S: completion. */ -#define TRANSMIT 0x0400 /* C: transmit command. S: completion - * status. (reject: COMMAND_REJECT if - * adapter not opened, TRANSMIT already - * issued or address passed in the SCB - * not word aligned) - */ -#define TRANSMIT_HALT 0x0500 /* C: interrupt TX TPL chain; if no - * TRANSMIT command issued, the command - * is ignored. (completion with TRANSMIT - * status (0x0400)!) - */ -#define RECEIVE 0x0600 /* C: receive command. S: completion - * status. (reject: COMMAND_REJECT if - * adapter not opened, RECEIVE already - * issued or address passed in the SCB - * not word aligned) - */ -#define CLOSE 0x0700 /* C: close adapter. S: completion. - * (COMMAND_REJECT if adapter not open) - */ -#define SET_GROUP_ADDR 0x0800 /* C: alter adapter group address after - * OPEN. S: completion. (COMMAND_REJECT - * if adapter not open) - */ -#define SET_FUNCT_ADDR 0x0900 /* C: alter adapter functional address - * after OPEN. S: completion. - * (COMMAND_REJECT if adapter not open) - */ -#define READ_ERROR_LOG 0x0A00 /* C: read adapter error counters. - * S: completion. (command ignored - * if adapter not open!) - */ -#define READ_ADAPTER 0x0B00 /* C: read data from adapter memory. - * (important: after init and before - * open!) S: completion. (ADAPTER_CHECK - * interrupt if undefined storage area - * read) - */ -#define MODIFY_OPEN_PARMS 0x0D00 /* C: modify some adapter operational - * parameters. (bit correspondend to - * WRAP_INTERFACE is ignored) - * S: completion. (reject: - * COMMAND_REJECT) - */ -#define RESTORE_OPEN_PARMS 0x0E00 /* C: modify some adapter operational - * parameters. (bit correspondend - * to WRAP_INTERFACE is ignored) - * S: completion. (reject: - * COMMAND_REJECT) - */ -#define SET_FIRST_16_GROUP 0x0F00 /* C: alter the first two bytes in - * adapter group address. - * S: completion. (reject: - * COMMAND_REJECT) - */ -#define SET_BRIDGE_PARMS 0x1000 /* C: values and conditions for the - * adapter hardware to use when frames - * are copied for forwarding. - * S: completion. (reject: - * COMMAND_REJECT) - */ -#define CONFIG_BRIDGE_PARMS 0x1100 /* C: .. - * S: completion. (reject: - * COMMAND_REJECT) - */ - -#define SPEED_4 4 -#define SPEED_16 16 /* Default transmission speed */ - - -/* Initialization Parameter Block (IPB); word alignment necessary! */ -#define BURST_SIZE 0x0018 /* Default burst size */ -#define BURST_MODE 0x9F00 /* Burst mode enable */ -#define DMA_RETRIES 0x0505 /* Magic DMA retry number... */ - -#define CYCLE_TIME 3 /* Default AT-bus cycle time: 500 ns - * (later adapter version: fix cycle time!) - */ -#define LINE_SPEED_BIT 0x80 - -/* Macro definition for the wait function. */ -#define ONE_SECOND_TICKS 1000000 -#define HALF_SECOND (ONE_SECOND_TICKS / 2) -#define ONE_SECOND (ONE_SECOND_TICKS) -#define TWO_SECONDS (ONE_SECOND_TICKS * 2) -#define THREE_SECONDS (ONE_SECOND_TICKS * 3) -#define FOUR_SECONDS (ONE_SECOND_TICKS * 4) -#define FIVE_SECONDS (ONE_SECOND_TICKS * 5) - -#define BUFFER_SIZE 2048 /* Buffers on Adapter */ - -#pragma pack(1) -typedef struct { - unsigned short Init_Options; /* Initialize with burst mode; - * LLC disabled. (MAC only) - */ - - /* Interrupt vectors the adapter places on attached system bus. */ - unsigned char CMD_Status_IV; /* Interrupt vector: command status. */ - unsigned char TX_IV; /* Interrupt vector: transmit. */ - unsigned char RX_IV; /* Interrupt vector: receive. */ - unsigned char Ring_Status_IV; /* Interrupt vector: ring status. */ - unsigned char SCB_Clear_IV; /* Interrupt vector: SCB clear. */ - unsigned char Adapter_CHK_IV; /* Interrupt vector: adapter check. */ - - unsigned short RX_Burst_Size; /* Max. number of transfer cycles. */ - unsigned short TX_Burst_Size; /* During DMA burst; even value! */ - unsigned short DMA_Abort_Thrhld; /* Number of DMA retries. */ - - unsigned long SCB_Addr; /* SCB address: even, word aligned, high-low. */ - unsigned long SSB_Addr; /* SSB address: even, word aligned, high-low. */ -} IPB, *IPB_Ptr; -#pragma pack() - -/* - * OPEN Command Parameter List (OCPL) (can be reused, if the adapter has to - * be reopened) - */ -#define BUFFER_SIZE 2048 /* Buffers on Adapter. */ -#define TPL_SIZE 8+6*TX_FRAG_NUM /* Depending on fragments per TPL. */ -#define RPL_SIZE 14 /* (with TI firmware v2.26 handling - * up to nine fragments possible) - */ -#define TX_BUF_MIN 20 /* ??? (Stephan: calculation with */ -#define TX_BUF_MAX 40 /* BUFFER_SIZE and MAX_FRAME_SIZE) ??? - */ -#define DISABLE_EARLY_TOKEN_RELEASE 0x1000 - -/* OPEN Options (high-low) */ -#define WRAP_INTERFACE 0x0080 /* Inserting omitted for test - * purposes; transmit data appears - * as receive data. (usefull for - * testing; change: CLOSE necessary) - */ -#define DISABLE_HARD_ERROR 0x0040 /* On HARD_ERROR & TRANSMIT_BEACON - * no RING.STATUS interrupt. - */ -#define DISABLE_SOFT_ERROR 0x0020 /* On SOFT_ERROR, no RING.STATUS - * interrupt. - */ -#define PASS_ADAPTER_MAC_FRAMES 0x0010 /* Passing unsupported MAC frames - * to system. - */ -#define PASS_ATTENTION_FRAMES 0x0008 /* All changed attention MAC frames are - * passed to the system. - */ -#define PAD_ROUTING_FIELD 0x0004 /* Routing field is padded to 18 - * bytes. - */ -#define FRAME_HOLD 0x0002 /* Adapter waits for entire frame before - * initiating DMA transfer; otherwise: - * DMA transfer initiation if internal - * buffer filled. - */ -#define CONTENDER 0x0001 /* Adapter participates in the monitor - * contention process. - */ -#define PASS_BEACON_MAC_FRAMES 0x8000 /* Adapter passes beacon MAC frames - * to the system. - */ -#define EARLY_TOKEN_RELEASE 0x1000 /* Only valid in 16 Mbps operation; - * 0 = ETR. (no effect in 4 Mbps - * operation) - */ -#define COPY_ALL_MAC_FRAMES 0x0400 /* All MAC frames are copied to - * the system. (after OPEN: duplicate - * address test (DAT) MAC frame is - * first received frame copied to the - * system) - */ -#define COPY_ALL_NON_MAC_FRAMES 0x0200 /* All non MAC frames are copied to - * the system. - */ -#define PASS_FIRST_BUF_ONLY 0x0100 /* Passes only first internal buffer - * of each received frame; FrameSize - * of RPLs must contain internal - * BUFFER_SIZE bits for promiscous mode. - */ -#define ENABLE_FULL_DUPLEX_SELECTION 0x2000 /* Enable the use of full-duplex - * settings with bits in byte 22 in - * ocpl. (new feature in firmware - * version 3.09) - */ - -/* Full-duplex settings */ -#define OPEN_FULL_DUPLEX_OFF 0x0000 -#define OPEN_FULL_DUPLEX_ON 0x00c0 -#define OPEN_FULL_DUPLEX_AUTO 0x0080 - -#define PROD_ID_SIZE 18 /* Length of product ID. */ - -#define TX_FRAG_NUM 3 /* Number of fragments used in one TPL. */ -#define TX_MORE_FRAGMENTS 0x8000 /* Bit set in DataCount to indicate more - * fragments following. - */ - -#define ISA_MAX_ADDRESS 0x00ffffff - -#pragma pack(1) -typedef struct { - unsigned short OPENOptions; - unsigned char NodeAddr[6]; /* Adapter node address; use ROM - * address - */ - unsigned long GroupAddr; /* Multicast: high order - * bytes = 0xC000 - */ - unsigned long FunctAddr; /* High order bytes = 0xC000 */ - unsigned short RxListSize; /* RPL size: 0 (=26), 14, 20 or - * 26 bytes read by the adapter. - * (Depending on the number of - * fragments/list) - */ - unsigned short TxListSize; /* TPL size */ - unsigned short BufSize; /* Is automatically rounded up to the - * nearest nK boundary. - */ - unsigned short FullDuplex; - unsigned short Reserved; - unsigned char TXBufMin; /* Number of adapter buffers reserved - * for transmission a minimum of 2 - * buffers must be allocated. - */ - unsigned char TXBufMax; /* Maximum number of adapter buffers - * for transmit; a minimum of 2 buffers - * must be available for receive. - * Default: 6 - */ - unsigned short ProdIDAddr[2]; /* Pointer to product ID. */ -} OPB, *OPB_Ptr; -#pragma pack() - -/* - * SCB: adapter commands enabled by the host system started by writing - * CMD_INTERRUPT_ADAPTER | CMD_EXECUTE (|SCB_REQUEST) to the SIFCMD IO - * register. (special case: | CMD_SYSTEM_IRQ for initialization) - */ -#pragma pack(1) -typedef struct { - unsigned short CMD; /* Command code */ - unsigned short Parm[2]; /* Pointer to Command Parameter Block */ -} SCB; /* System Command Block (32 bit physical address; big endian)*/ -#pragma pack() - -/* - * SSB: adapter command return status can be evaluated after COMMAND_STATUS - * adapter to system interrupt after reading SSB, the availability of the SSB - * has to be told the adapter by writing CMD_INTERRUPT_ADAPTER | CMD_SSB_CLEAR - * in the SIFCMD IO register. - */ -#pragma pack(1) -typedef struct { - unsigned short STS; /* Status code */ - unsigned short Parm[3]; /* Parameter or pointer to Status Parameter - * Block. - */ -} SSB; /* System Status Block (big endian - physical address) */ -#pragma pack() - -typedef struct { - unsigned short BurnedInAddrPtr; /* Pointer to adapter burned in - * address. (BIA) - */ - unsigned short SoftwareLevelPtr;/* Pointer to software level data. */ - unsigned short AdapterAddrPtr; /* Pointer to adapter addresses. */ - unsigned short AdapterParmsPtr; /* Pointer to adapter parameters. */ - unsigned short MACBufferPtr; /* Pointer to MAC buffer. (internal) */ - unsigned short LLCCountersPtr; /* Pointer to LLC counters. */ - unsigned short SpeedFlagPtr; /* Pointer to data rate flag. - * (4/16 Mbps) - */ - unsigned short AdapterRAMPtr; /* Pointer to adapter RAM found. (KB) */ -} INTPTRS; /* Adapter internal pointers */ - -#pragma pack(1) -typedef struct { - unsigned char Line_Error; /* Line error: code violation in - * frame or in a token, or FCS error. - */ - unsigned char Internal_Error; /* IBM specific. (Reserved_1) */ - unsigned char Burst_Error; - unsigned char ARI_FCI_Error; /* ARI/FCI bit zero in AMP or - * SMP MAC frame. - */ - unsigned char AbortDelimeters; /* IBM specific. (Reserved_2) */ - unsigned char Reserved_3; - unsigned char Lost_Frame_Error; /* Receive of end of transmitted - * frame failed. - */ - unsigned char Rx_Congest_Error; /* Adapter in repeat mode has not - * enough buffer space to copy incoming - * frame. - */ - unsigned char Frame_Copied_Error;/* ARI bit not zero in frame - * addressed to adapter. - */ - unsigned char Frequency_Error; /* IBM specific. (Reserved_4) */ - unsigned char Token_Error; /* (active only in monitor station) */ - unsigned char Reserved_5; - unsigned char DMA_Bus_Error; /* DMA bus errors not exceeding the - * abort thresholds. - */ - unsigned char DMA_Parity_Error; /* DMA parity errors not exceeding - * the abort thresholds. - */ -} ERRORTAB; /* Adapter error counters */ -#pragma pack() - - -/*--------------------- Send and Receive definitions -------------------*/ -#pragma pack(1) -typedef struct { - unsigned short DataCount; /* Value 0, even and odd values are - * permitted; value is unaltered most - * significant bit set: following - * fragments last fragment: most - * significant bit is not evaluated. - * (???) - */ - unsigned long DataAddr; /* Pointer to frame data fragment; - * even or odd. - */ -} Fragment; -#pragma pack() - -#define MAX_FRAG_NUMBERS 9 /* Maximal number of fragments possible to use - * in one RPL/TPL. (depending on TI firmware - * version) - */ -#define MAX_TX_QUEUE 10 /* Maximal number of skb's queued in driver. */ - -/* - * AC (1), FC (1), Dst (6), Src (6), RIF (18), Data (4472) = 4504 - * The packet size can be one of the follows: 548, 1502, 2084, 4504, 8176, - * 11439, 17832. Refer to TMS380 Second Generation Token Ring User's Guide - * Page 2-27. - */ -#define HEADER_SIZE (1 + 1 + 6 + 6) -#define SRC_SIZE 18 -#define MIN_DATA_SIZE 516 -#define DEFAULT_DATA_SIZE 4472 -#define MAX_DATA_SIZE 17800 - -#define DEFAULT_PACKET_SIZE (HEADER_SIZE + SRC_SIZE + DEFAULT_DATA_SIZE) -#define MIN_PACKET_SIZE (HEADER_SIZE + SRC_SIZE + MIN_DATA_SIZE) -#define MAX_PACKET_SIZE (HEADER_SIZE + SRC_SIZE + MAX_DATA_SIZE) - -/* - * Macros to deal with the frame status field. - */ -#define AC_NOT_RECOGNIZED 0x00 -#define GROUP_BIT 0x80 -#define GET_TRANSMIT_STATUS_HIGH_BYTE(Ts) ((unsigned char)((Ts) >> 8)) -#define GET_FRAME_STATUS_HIGH_AC(Fs) ((unsigned char)(((Fs) & 0xC0) >> 6)) -#define GET_FRAME_STATUS_LOW_AC(Fs) ((unsigned char)(((Fs) & 0x0C) >> 2)) -#define DIRECTED_FRAME(Context) (!((Context)->MData[2] & GROUP_BIT)) - - -/*--------------------- Send Functions ---------------------------------*/ -/* define TX_CSTAT _REQUEST (R) and _COMPLETE (C) values (high-low) */ - -#define TX_VALID 0x0080 /* R: set via TRANSMIT.VALID interrupt. - * C: always reset to zero! - */ -#define TX_FRAME_COMPLETE 0x0040 /* R: must be reset to zero. - * C: set to one. - */ -#define TX_START_FRAME 0x0020 /* R: start of a frame: 1 - * C: unchanged. - */ -#define TX_END_FRAME 0x0010 /* R: end of a frame: 1 - * C: unchanged. - */ -#define TX_FRAME_IRQ 0x0008 /* R: request interrupt generation - * after transmission. - * C: unchanged. - */ -#define TX_ERROR 0x0004 /* R: reserved. - * C: set to one if Error occurred. - */ -#define TX_INTERFRAME_WAIT 0x0004 -#define TX_PASS_CRC 0x0002 /* R: set if CRC value is already - * calculated. (valid only in - * FRAME_START TPL) - * C: unchanged. - */ -#define TX_PASS_SRC_ADDR 0x0001 /* R: adapter uses explicit frame - * source address and does not overwrite - * with the adapter node address. - * (valid only in FRAME_START TPL) - * - * C: unchanged. - */ -#define TX_STRIP_FS 0xFF00 /* R: reserved. - * C: if no Transmission Error, - * field contains copy of FS byte after - * stripping of frame. - */ - -/* - * Structure of Transmit Parameter Lists (TPLs) (only one frame every TPL, - * but possibly multiple TPLs for one frame) the length of the TPLs has to be - * initialized in the OPL. (OPEN parameter list) - */ -#define TPL_NUM 3 /* Number of Transmit Parameter Lists. - * !! MUST BE >= 3 !! - */ - -#pragma pack(1) -typedef struct s_TPL TPL; - -struct s_TPL { /* Transmit Parameter List (align on even word boundaries) */ - unsigned long NextTPLAddr; /* Pointer to next TPL in chain; if - * pointer is odd: this is the last - * TPL. Pointing to itself can cause - * problems! - */ - volatile unsigned short Status; /* Initialized by the adapter: - * CSTAT_REQUEST important: update least - * significant bit first! Set by the - * adapter: CSTAT_COMPLETE status. - */ - unsigned short FrameSize; /* Number of bytes to be transmitted - * as a frame including AC/FC, - * Destination, Source, Routing field - * not including CRC, FS, End Delimiter - * (valid only if START_FRAME bit in - * CSTAT nonzero) must not be zero in - * any list; maximum value: (BUFFER_SIZE - * - 8) * TX_BUF_MAX sum of DataCount - * values in FragmentList must equal - * Frame_Size value in START_FRAME TPL! - * frame data fragment list. - */ - - /* TPL/RPL size in OPEN parameter list depending on maximal - * numbers of fragments used in one parameter list. - */ - Fragment FragList[TX_FRAG_NUM]; /* Maximum: nine frame fragments in one - * TPL actual version of firmware: 9 - * fragments possible. - */ -#pragma pack() - - /* Special proprietary data and precalculations */ - - TPL *NextTPLPtr; /* Pointer to next TPL in chain. */ - unsigned char *MData; - struct sk_buff *Skb; - unsigned char TPLIndex; - volatile unsigned char BusyFlag;/* Flag: TPL busy? */ -}; - -/* ---------------------Receive Functions-------------------------------* - * define RECEIVE_CSTAT_REQUEST (R) and RECEIVE_CSTAT_COMPLETE (C) values. - * (high-low) - */ -#define RX_VALID 0x0080 /* R: set; tell adapter with - * RECEIVE.VALID interrupt. - * C: reset to zero. - */ -#define RX_FRAME_COMPLETE 0x0040 /* R: must be reset to zero, - * C: set to one. - */ -#define RX_START_FRAME 0x0020 /* R: must be reset to zero. - * C: set to one on the list. - */ -#define RX_END_FRAME 0x0010 /* R: must be reset to zero. - * C: set to one on the list - * that ends the frame. - */ -#define RX_FRAME_IRQ 0x0008 /* R: request interrupt generation - * after receive. - * C: unchanged. - */ -#define RX_INTERFRAME_WAIT 0x0004 /* R: after receiving a frame: - * interrupt and wait for a - * RECEIVE.CONTINUE. - * C: unchanged. - */ -#define RX_PASS_CRC 0x0002 /* R: if set, the adapter includes - * the CRC in data passed. (last four - * bytes; valid only if FRAME_START is - * set) - * C: set, if CRC is included in - * received data. - */ -#define RX_PASS_SRC_ADDR 0x0001 /* R: adapter uses explicit frame - * source address and does not - * overwrite with the adapter node - * address. (valid only if FRAME_START - * is set) - * C: unchanged. - */ -#define RX_RECEIVE_FS 0xFC00 /* R: reserved; must be reset to zero. - * C: on lists with START_FRAME, field - * contains frame status field from - * received frame; otherwise cleared. - */ -#define RX_ADDR_MATCH 0x0300 /* R: reserved; must be reset to zero. - * C: address match code mask. - */ -#define RX_STATUS_MASK 0x00FF /* Mask for receive status bits. */ - -#define RX_INTERN_ADDR_MATCH 0x0100 /* C: internally address match. */ -#define RX_EXTERN_ADDR_MATCH 0x0200 /* C: externally matched via - * XMATCH/XFAIL interface. - */ -#define RX_INTEXT_ADDR_MATCH 0x0300 /* C: internally and externally - * matched. - */ -#define RX_READY (RX_VALID | RX_FRAME_IRQ) /* Ready for receive. */ - -/* Constants for Command Status Interrupt. - * COMMAND_REJECT status field bit functions (SSB.Parm[0]) - */ -#define ILLEGAL_COMMAND 0x0080 /* Set if an unknown command - * is issued to the adapter - */ -#define ADDRESS_ERROR 0x0040 /* Set if any address field in - * the SCB is odd. (not word aligned) - */ -#define ADAPTER_OPEN 0x0020 /* Command issued illegal with - * open adapter. - */ -#define ADAPTER_CLOSE 0x0010 /* Command issued illegal with - * closed adapter. - */ -#define SAME_COMMAND 0x0008 /* Command issued with same command - * already executing. - */ - -/* OPEN_COMPLETION values (SSB.Parm[0], MSB) */ -#define NODE_ADDR_ERROR 0x0040 /* Wrong address or BIA read - * zero address. - */ -#define LIST_SIZE_ERROR 0x0020 /* If List_Size value not in 0, - * 14, 20, 26. - */ -#define BUF_SIZE_ERROR 0x0010 /* Not enough available memory for - * two buffers. - */ -#define TX_BUF_COUNT_ERROR 0x0004 /* Remaining receive buffers less than - * two. - */ -#define OPEN_ERROR 0x0002 /* Error during ring insertion; more - * information in bits 8-15. - */ - -/* Standard return codes */ -#define GOOD_COMPLETION 0x0080 /* =OPEN_SUCCESSFULL */ -#define INVALID_OPEN_OPTION 0x0001 /* OPEN options are not supported by - * the adapter. - */ - -/* OPEN phases; details of OPEN_ERROR (SSB.Parm[0], LSB) */ -#define OPEN_PHASES_MASK 0xF000 /* Check only the bits 8-11. */ -#define LOBE_MEDIA_TEST 0x1000 -#define PHYSICAL_INSERTION 0x2000 -#define ADDRESS_VERIFICATION 0x3000 -#define PARTICIPATION_IN_RING_POLL 0x4000 -#define REQUEST_INITIALISATION 0x5000 -#define FULLDUPLEX_CHECK 0x6000 - -/* OPEN error codes; details of OPEN_ERROR (SSB.Parm[0], LSB) */ -#define OPEN_ERROR_CODES_MASK 0x0F00 /* Check only the bits 12-15. */ -#define OPEN_FUNCTION_FAILURE 0x0100 /* Unable to transmit to itself or - * frames received before insertion. - */ -#define OPEN_SIGNAL_LOSS 0x0200 /* Signal loss condition detected at - * receiver. - */ -#define OPEN_TIMEOUT 0x0500 /* Insertion timer expired before - * logical insertion. - */ -#define OPEN_RING_FAILURE 0x0600 /* Unable to receive own ring purge - * MAC frames. - */ -#define OPEN_RING_BEACONING 0x0700 /* Beacon MAC frame received after - * ring insertion. - */ -#define OPEN_DUPLICATE_NODEADDR 0x0800 /* Other station in ring found - * with the same address. - */ -#define OPEN_REQUEST_INIT 0x0900 /* RPS present but does not respond. */ -#define OPEN_REMOVE_RECEIVED 0x0A00 /* Adapter received a remove adapter - * MAC frame. - */ -#define OPEN_FULLDUPLEX_SET 0x0D00 /* Got this with full duplex on when - * trying to connect to a normal ring. - */ - -/* SET_BRIDGE_PARMS return codes: */ -#define BRIDGE_INVALID_MAX_LEN 0x4000 /* MAX_ROUTING_FIELD_LENGTH odd, - * less than 6 or > 30. - */ -#define BRIDGE_INVALID_SRC_RING 0x2000 /* SOURCE_RING number zero, too large - * or = TARGET_RING. - */ -#define BRIDGE_INVALID_TRG_RING 0x1000 /* TARGET_RING number zero, too large - * or = SOURCE_RING. - */ -#define BRIDGE_INVALID_BRDGE_NO 0x0800 /* BRIDGE_NUMBER too large. */ -#define BRIDGE_INVALID_OPTIONS 0x0400 /* Invalid bridge options. */ -#define BRIDGE_DIAGS_FAILED 0x0200 /* Diagnostics of TMS380SRA failed. */ -#define BRIDGE_NO_SRA 0x0100 /* The TMS380SRA does not exist in HW - * configuration. - */ - -/* - * Bring Up Diagnostics error codes. - */ -#define BUD_INITIAL_ERROR 0x0 -#define BUD_CHECKSUM_ERROR 0x1 -#define BUD_ADAPTER_RAM_ERROR 0x2 -#define BUD_INSTRUCTION_ERROR 0x3 -#define BUD_CONTEXT_ERROR 0x4 -#define BUD_PROTOCOL_ERROR 0x5 -#define BUD_INTERFACE_ERROR 0x6 - -/* BUD constants */ -#define BUD_MAX_RETRIES 3 -#define BUD_MAX_LOOPCNT 6 -#define BUD_TIMEOUT 3000 - -/* Initialization constants */ -#define INIT_MAX_RETRIES 3 /* Maximum three retries. */ -#define INIT_MAX_LOOPCNT 22 /* Maximum loop counts. */ - -/* RING STATUS field values (high/low) */ -#define SIGNAL_LOSS 0x0080 /* Loss of signal on the ring - * detected. - */ -#define HARD_ERROR 0x0040 /* Transmitting or receiving beacon - * frames. - */ -#define SOFT_ERROR 0x0020 /* Report error MAC frame - * transmitted. - */ -#define TRANSMIT_BEACON 0x0010 /* Transmitting beacon frames on the - * ring. - */ -#define LOBE_WIRE_FAULT 0x0008 /* Open or short circuit in the - * cable to concentrator; adapter - * closed. - */ -#define AUTO_REMOVAL_ERROR 0x0004 /* Lobe wrap test failed, deinserted; - * adapter closed. - */ -#define REMOVE_RECEIVED 0x0001 /* Received a remove ring station MAC - * MAC frame request; adapter closed. - */ -#define COUNTER_OVERFLOW 0x8000 /* Overflow of one of the adapters - * error counters; READ.ERROR.LOG. - */ -#define SINGLE_STATION 0x4000 /* Adapter is the only station on the - * ring. - */ -#define RING_RECOVERY 0x2000 /* Claim token MAC frames on the ring; - * reset after ring purge frame. - */ - -#define ADAPTER_CLOSED (LOBE_WIRE_FAULT | AUTO_REMOVAL_ERROR |\ - REMOVE_RECEIVED) - -/* Adapter_check_block.Status field bit assignments: */ -#define DIO_PARITY 0x8000 /* Adapter detects bad parity - * through direct I/O access. - */ -#define DMA_READ_ABORT 0x4000 /* Aborting DMA read operation - * from system Parm[0]: 0=timeout, - * 1=parity error, 2=bus error; - * Parm[1]: 32 bit pointer to host - * system address at failure. - */ -#define DMA_WRITE_ABORT 0x2000 /* Aborting DMA write operation - * to system. (parameters analogous to - * DMA_READ_ABORT) - */ -#define ILLEGAL_OP_CODE 0x1000 /* Illegal operation code in the - * the adapters firmware Parm[0]-2: - * communications processor registers - * R13-R15. - */ -#define PARITY_ERRORS 0x0800 /* Adapter detects internal bus - * parity error. - */ -#define RAM_DATA_ERROR 0x0080 /* Valid only during RAM testing; - * RAM data error Parm[0-1]: 32 bit - * pointer to RAM location. - */ -#define RAM_PARITY_ERROR 0x0040 /* Valid only during RAM testing; - * RAM parity error Parm[0-1]: 32 bit - * pointer to RAM location. - */ -#define RING_UNDERRUN 0x0020 /* Internal DMA underrun when - * transmitting onto ring. - */ -#define INVALID_IRQ 0x0008 /* Unrecognized interrupt generated - * internal to adapter Parm[0-2]: - * adapter register R13-R15. - */ -#define INVALID_ERROR_IRQ 0x0004 /* Unrecognized error interrupt - * generated Parm[0-2]: adapter register - * R13-R15. - */ -#define INVALID_XOP 0x0002 /* Unrecognized XOP request in - * communication processor Parm[0-2]: - * adapter register R13-R15. - */ -#define CHECKADDR 0x05E0 /* Adapter check status information - * address offset. - */ -#define ROM_PAGE_0 0x0000 /* Adapter ROM page 0. */ - -/* - * RECEIVE.STATUS interrupt result SSB values: (high-low) - * (RECEIVE_COMPLETE field bit definitions in SSB.Parm[0]) - */ -#define RX_COMPLETE 0x0080 /* SSB.Parm[0]; SSB.Parm[1]: 32 - * bit pointer to last RPL. - */ -#define RX_SUSPENDED 0x0040 /* SSB.Parm[0]; SSB.Parm[1]: 32 - * bit pointer to RPL with odd - * forward pointer. - */ - -/* Valid receive CSTAT: */ -#define RX_FRAME_CONTROL_BITS (RX_VALID | RX_START_FRAME | RX_END_FRAME | \ - RX_FRAME_COMPLETE) -#define VALID_SINGLE_BUFFER_FRAME (RX_START_FRAME | RX_END_FRAME | \ - RX_FRAME_COMPLETE) - -typedef enum SKB_STAT SKB_STAT; -enum SKB_STAT { - SKB_UNAVAILABLE, - SKB_DMA_DIRECT, - SKB_DATA_COPY -}; - -/* Receive Parameter List (RPL) The length of the RPLs has to be initialized - * in the OPL. (OPEN parameter list) - */ -#define RPL_NUM 3 - -#define RX_FRAG_NUM 1 /* Maximal number of used fragments in one RPL. - * (up to firmware v2.24: 3, now: up to 9) - */ - -#pragma pack(1) -typedef struct s_RPL RPL; -struct s_RPL { /* Receive Parameter List */ - unsigned long NextRPLAddr; /* Pointer to next RPL in chain - * (normalized = physical 32 bit - * address) if pointer is odd: this - * is last RPL. Pointing to itself can - * cause problems! - */ - volatile unsigned short Status; /* Set by creation of Receive Parameter - * List RECEIVE_CSTAT_COMPLETE set by - * adapter in lists that start or end - * a frame. - */ - volatile unsigned short FrameSize; /* Number of bytes received as a - * frame including AC/FC, Destination, - * Source, Routing field not including - * CRC, FS (Frame Status), End Delimiter - * (valid only if START_FRAME bit in - * CSTAT nonzero) must not be zero in - * any list; maximum value: (BUFFER_SIZE - * - 8) * TX_BUF_MAX sum of DataCount - * values in FragmentList must equal - * Frame_Size value in START_FRAME TPL! - * frame data fragment list - */ - - /* TPL/RPL size in OPEN parameter list depending on maximal numbers - * of fragments used in one parameter list. - */ - Fragment FragList[RX_FRAG_NUM]; /* Maximum: nine frame fragments in - * one TPL. Actual version of firmware: - * 9 fragments possible. - */ -#pragma pack() - - /* Special proprietary data and precalculations. */ - RPL *NextRPLPtr; /* Logical pointer to next RPL in chain. */ - unsigned char *MData; - struct sk_buff *Skb; - SKB_STAT SkbStat; - int RPLIndex; -}; - -/* Information that need to be kept for each board. */ -typedef struct net_local { -#pragma pack(1) - IPB ipb; /* Initialization Parameter Block. */ - SCB scb; /* System Command Block: system to adapter - * communication. - */ - SSB ssb; /* System Status Block: adapter to system - * communication. - */ - OPB ocpl; /* Open Options Parameter Block. */ - - ERRORTAB errorlogtable; /* Adapter statistic error counters. - * (read from adapter memory) - */ - unsigned char ProductID[PROD_ID_SIZE + 1]; /* Product ID */ -#pragma pack() - - TPL Tpl[TPL_NUM]; - TPL *TplFree; - TPL *TplBusy; - unsigned char LocalTxBuffers[TPL_NUM][DEFAULT_PACKET_SIZE]; - - RPL Rpl[RPL_NUM]; - RPL *RplHead; - RPL *RplTail; - unsigned char LocalRxBuffers[RPL_NUM][DEFAULT_PACKET_SIZE]; - - int DataRate; - unsigned char ScbInUse; - unsigned short CMDqueue; - - unsigned long AdapterOpenFlag:1; - unsigned long AdapterVirtOpenFlag:1; - unsigned long OpenCommandIssued:1; - unsigned long TransmitCommandActive:1; - unsigned long TransmitHaltScheduled:1; - unsigned long HaltInProgress:1; - unsigned long LobeWireFaultLogged:1; - unsigned long ReOpenInProgress:1; - unsigned long Sleeping:1; - - unsigned long LastOpenStatus; - unsigned short CurrentRingStatus; - unsigned long MaxPacketSize; - - unsigned long StartTime; - unsigned long LastSendTime; - - struct sk_buff_head SendSkbQueue; - unsigned short QueueSkb; - - struct tr_statistics MacStat; /* MAC statistics structure */ - - struct timer_list timer; - - wait_queue_head_t wait_for_tok_int; - - INTPTRS intptrs; /* Internal adapter pointer. Must be read - * before OPEN command. - */ -} NET_LOCAL; - -#endif /* __KERNEL__ */ -#endif /* __LINUX_SKTR_H */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/sktr_firmware.h linux/drivers/net/sktr_firmware.h --- v2.3.20/linux/drivers/net/sktr_firmware.h Thu Jan 7 08:46:59 1999 +++ linux/drivers/net/sktr_firmware.h Wed Dec 31 16:00:00 1969 @@ -1,3616 +0,0 @@ -/* - * The firmware this driver downloads into the tokenring card is a - * separate program and is not GPL'd source code, even though the Linux - * side driver and the routine that loads this data into the card are. - * - * This firmware is licensed to you strictly for use in conjunction - * with the use of SysKonnect TokenRing adapters. There is no - * waranty expressed or implied about its fitness for any purpose. - */ - -/* sktr_firmware.h: SysKonnect TokenRing driver firmware dump for Linux. - * - * Notes: - * - Loaded from sktr_reset_adapter upon adapter reset. - * - * Authors: - * - Christoph Goos - */ - -#include - -#if defined(CONFIG_SKTR) || defined(CONFIG_SKTR_MODULE) - -unsigned char sktr_code[] = { - 0x00, 0x00, 0x00, 0xA0, 0x00, 0x20, 0x68, 0x54, - 0x73, 0x69, 0x63, 0x20, 0x64, 0x6F, 0x20, 0x65, - 0x73, 0x69, 0x72, 0x20, 0x6C, 0x65, 0x61, 0x65, - 0x65, 0x73, 0x20, 0x64, 0x6E, 0x75, 0x65, 0x64, - 0x20, 0x72, 0x69, 0x6C, 0x65, 0x63, 0x63, 0x6E, - 0x20, 0x65, 0x6E, 0x4F, 0x79, 0x6C, 0x20, 0x2C, - 0x6C, 0x41, 0x20, 0x6C, 0x69, 0x72, 0x68, 0x67, - 0x73, 0x74, 0x72, 0x20, 0x73, 0x65, 0x72, 0x65, - 0x65, 0x76, 0x2E, 0x64, 0x60, 0x01, 0x42, 0x01, - 0x00, 0x08, 0x08, 0x16, 0xB0, 0x03, 0xE0, 0x04, - 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0xFF, 0xFF, - 0xFC, 0x13, 0x80, 0x03, 0xA0, 0x07, 0x42, 0x01, - 0x00, 0x08, 0x20, 0x07, 0x00, 0x00, 0xE0, 0x04, - 0x00, 0x01, 0x8B, 0x07, 0x00, 0x3D, 0x60, 0x01, - 0x42, 0x01, 0x80, 0x00, 0x09, 0x13, 0x8B, 0x07, - 0x00, 0x2D, 0x20, 0xC0, 0x4E, 0x01, 0x80, 0x02, - 0x41, 0x0F, 0x02, 0x11, 0x8B, 0x07, 0x00, 0x3D, - 0x0B, 0xC8, 0x4A, 0x01, 0x00, 0x02, 0x00, 0x90, - 0xA0, 0x09, 0x00, 0xC8, 0x66, 0x01, 0xE0, 0x02, - 0xA0, 0x00, 0xA0, 0x07, 0x04, 0x01, 0x20, 0x00, - 0xA0, 0x01, 0x40, 0x01, 0x00, 0xFE, 0x20, 0x48, - 0x2A, 0xE0, 0x42, 0x01, 0xE0, 0x04, 0x02, 0x01, - 0xE0, 0x04, 0x60, 0x09, 0xE0, 0x04, 0x82, 0x01, - 0x60, 0x01, 0x1C, 0x01, 0x04, 0x00, 0x03, 0x16, - 0xE0, 0x01, 0x40, 0x01, 0x00, 0x0C, 0xA0, 0x06, - 0xBC, 0xA1, 0xA0, 0x07, 0x04, 0x01, 0x2D, 0x00, - 0x20, 0xC2, 0x00, 0xE0, 0x88, 0x02, 0x11, 0xE3, - 0x14, 0x16, 0xA0, 0x07, 0x04, 0x01, 0x2E, 0x00, - 0x60, 0x01, 0x42, 0x01, 0x00, 0x03, 0x0D, 0x16, - 0xA0, 0x07, 0x04, 0x01, 0x21, 0x00, 0x88, 0x07, - 0x00, 0xA0, 0x89, 0x07, 0xFE, 0xFF, 0xA8, 0x09, - 0xA9, 0x09, 0x8A, 0x07, 0x02, 0xE0, 0xA0, 0x06, - 0x84, 0xEC, 0x56, 0x10, 0x88, 0x07, 0x00, 0x90, - 0x89, 0x07, 0xFE, 0x9F, 0xA8, 0x09, 0xA9, 0x09, - 0x8A, 0x07, 0x78, 0xE0, 0xA0, 0x06, 0x84, 0xEC, - 0x4B, 0x10, 0xA0, 0x05, 0x04, 0x01, 0x88, 0x07, - 0x08, 0x00, 0x89, 0x07, 0x7A, 0x00, 0x00, 0x03, - 0x01, 0x00, 0xA0, 0x06, 0xD2, 0xAC, 0x40, 0x10, - 0xA0, 0x06, 0xBC, 0xA1, 0xE0, 0x02, 0xF4, 0x03, - 0x88, 0x07, 0xA0, 0x00, 0x89, 0x07, 0xFE, 0x00, - 0xA0, 0x06, 0xD2, 0xAC, 0x35, 0x10, 0xE0, 0x02, - 0xA0, 0x00, 0xE0, 0x04, 0x7E, 0x01, 0xC8, 0x04, - 0x09, 0x02, 0xF2, 0x03, 0x48, 0x62, 0xE0, 0xC1, - 0x40, 0x01, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x04, - 0x18, 0xCE, 0x09, 0x06, 0xFD, 0x16, 0xA0, 0x01, - 0x40, 0x01, 0x00, 0x40, 0x07, 0xC8, 0x40, 0x01, - 0x88, 0x07, 0xF4, 0x03, 0x89, 0x07, 0xFE, 0x3F, - 0xA0, 0x06, 0xD2, 0xAC, 0x19, 0x10, 0xE0, 0x02, - 0xA0, 0x00, 0xA0, 0x06, 0xFA, 0xAD, 0x14, 0x10, - 0x08, 0xC8, 0x44, 0x04, 0x09, 0xC8, 0x46, 0x04, - 0xA0, 0x06, 0x28, 0xAD, 0x0D, 0x10, 0x81, 0x07, - 0x7C, 0xE0, 0xB1, 0xC0, 0x26, 0x13, 0x01, 0xC8, - 0xE0, 0x00, 0xA0, 0x05, 0x04, 0x01, 0x92, 0x06, - 0x03, 0x10, 0x60, 0xC0, 0xE0, 0x00, 0xF5, 0x10, - 0xE0, 0x01, 0x04, 0x01, 0x10, 0x00, 0xB0, 0x03, - 0xFF, 0x10, 0xA0, 0x01, 0x04, 0x01, 0x00, 0x80, - 0x80, 0x03, 0x80, 0x07, 0xA0, 0x00, 0xC2, 0x04, - 0x80, 0xCC, 0x81, 0x07, 0xAA, 0xA1, 0x82, 0x02, - 0x1E, 0x00, 0x02, 0x16, 0x81, 0x07, 0xB4, 0xA1, - 0x81, 0xC4, 0x81, 0x8C, 0xE9, 0x16, 0x82, 0x02, - 0x7C, 0x00, 0xF2, 0x16, 0x00, 0x03, 0x0F, 0x00, - 0x5B, 0x04, 0x81, 0x07, 0x08, 0xE1, 0x82, 0x07, - 0x04, 0x00, 0xE0, 0x04, 0x80, 0x01, 0xE0, 0x04, - 0x82, 0x01, 0x91, 0xC4, 0xB1, 0x8C, 0xD8, 0x16, - 0x82, 0x02, 0x7C, 0x00, 0xFA, 0x16, 0x20, 0xC8, - 0x04, 0xE0, 0x82, 0x01, 0x20, 0xE8, 0x0C, 0xE0, - 0x82, 0x01, 0x20, 0xC8, 0x10, 0xE0, 0x80, 0x01, - 0x81, 0x07, 0x86, 0xE0, 0xB1, 0xC0, 0x07, 0x13, - 0xB1, 0xC4, 0xFC, 0x10, 0xA0, 0x07, 0x04, 0x01, - 0x2E, 0x00, 0x60, 0x04, 0xAA, 0xA1, 0x81, 0x07, - 0x34, 0xE0, 0x82, 0x07, 0xFC, 0x05, 0x83, 0x07, - 0x0A, 0x00, 0xB1, 0xCC, 0x43, 0x06, 0xFD, 0x16, - 0x02, 0x02, 0x00, 0x06, 0x60, 0xD0, 0x4E, 0x01, - 0xED, 0x13, 0x21, 0x02, 0x00, 0xF7, 0x21, 0x02, - 0x00, 0xC0, 0x81, 0xDC, 0x60, 0xD0, 0x4F, 0x01, - 0xC1, 0xC0, 0x41, 0x09, 0x21, 0x02, 0x00, 0xF0, - 0x81, 0xDC, 0x43, 0x02, 0x00, 0x0F, 0x23, 0x02, - 0x00, 0xF0, 0x83, 0xDC, 0x01, 0x02, 0x32, 0x0C, - 0xA0, 0xC0, 0x44, 0x04, 0xE0, 0xC0, 0x46, 0x04, - 0x03, 0xC1, 0x02, 0x61, 0x84, 0x05, 0x04, 0xC8, - 0x48, 0x04, 0x03, 0xC1, 0x84, 0x05, 0x04, 0xA1, - 0x01, 0xA1, 0x04, 0xC8, 0x30, 0x0C, 0x03, 0xC1, - 0x84, 0x05, 0xF1, 0x04, 0x04, 0x06, 0xFD, 0x16, - 0x08, 0x02, 0x00, 0xA0, 0xA8, 0x09, 0x60, 0xC2, - 0x30, 0x0C, 0x29, 0x02, 0xFF, 0x03, 0xA9, 0x09, - 0x29, 0x02, 0x40, 0x00, 0x80, 0x07, 0x00, 0x90, - 0xA0, 0x09, 0x8A, 0x07, 0xFE, 0x9F, 0x2A, 0x02, - 0xFF, 0x03, 0xAA, 0x09, 0x01, 0x02, 0x32, 0x0C, - 0x05, 0x02, 0x00, 0x00, 0x03, 0xC1, 0x84, 0x05, - 0x11, 0x07, 0xC1, 0x05, 0x85, 0x05, 0x04, 0x06, - 0x0B, 0x13, 0x85, 0x80, 0xF9, 0x1A, 0x05, 0x80, - 0xF8, 0x1A, 0x85, 0x82, 0xF5, 0x1A, 0x05, 0x82, - 0xF4, 0x1A, 0x45, 0x82, 0xF1, 0x1A, 0xF1, 0x10, - 0x20, 0x2D, 0x02, 0x00, 0x60, 0x01, 0x40, 0x01, - 0x00, 0x40, 0x06, 0x16, 0x8A, 0x07, 0x00, 0x08, - 0xA0, 0x01, 0x40, 0x01, 0x00, 0x40, 0x48, 0x10, - 0x60, 0x01, 0x42, 0x01, 0x00, 0x80, 0x06, 0x16, - 0x8A, 0x07, 0x00, 0x10, 0xA0, 0x01, 0x42, 0x01, - 0x00, 0x80, 0x3E, 0x10, 0x60, 0x01, 0x02, 0x01, - 0x00, 0x10, 0x0A, 0x16, 0x60, 0x01, 0x00, 0x01, - 0x00, 0x04, 0x06, 0x16, 0x8A, 0x07, 0x00, 0x80, - 0xA0, 0x01, 0x02, 0x01, 0x00, 0x10, 0x30, 0x10, - 0x60, 0x01, 0x02, 0x01, 0x00, 0x08, 0x0A, 0x16, - 0x60, 0x01, 0x00, 0x01, 0x00, 0x04, 0x06, 0x16, - 0xA0, 0x01, 0x02, 0x01, 0x00, 0x08, 0x0D, 0x02, - 0x01, 0x00, 0x0D, 0x10, 0x60, 0x01, 0x02, 0x01, - 0x00, 0x04, 0x16, 0x16, 0x60, 0x01, 0x00, 0x01, - 0x00, 0x08, 0x12, 0x16, 0xA0, 0x01, 0x02, 0x01, - 0x00, 0x04, 0x0D, 0x02, 0x02, 0x00, 0xA0, 0xC3, - 0x0E, 0x01, 0xE0, 0xC3, 0x10, 0x01, 0x8A, 0x07, - 0x00, 0x20, 0x60, 0x01, 0x00, 0x01, 0x00, 0x80, - 0x0B, 0x13, 0x8A, 0x07, 0x00, 0x40, 0x08, 0x10, - 0x8A, 0x07, 0x04, 0x00, 0x05, 0x10, 0x8A, 0x07, - 0x02, 0x00, 0x02, 0x10, 0x8A, 0x07, 0x08, 0x00, - 0x00, 0x03, 0x00, 0x00, 0xE0, 0x04, 0x82, 0x01, - 0x8B, 0x07, 0xE0, 0x05, 0xCA, 0xCE, 0xCD, 0xCE, - 0xCE, 0xCE, 0xCF, 0xC6, 0x20, 0xC3, 0x58, 0x07, - 0x20, 0x23, 0x04, 0xE0, 0x12, 0x13, 0x8B, 0x07, - 0x18, 0xFF, 0x8A, 0x02, 0x00, 0x80, 0x0A, 0x13, - 0x8B, 0x05, 0xCD, 0xA2, 0x8A, 0x02, 0x00, 0x40, - 0x05, 0x13, 0x8A, 0x02, 0x00, 0x20, 0x02, 0x13, - 0x8B, 0x07, 0x1D, 0xFF, 0x0B, 0xC8, 0x04, 0x01, - 0x0D, 0x10, 0x20, 0xD3, 0x05, 0x01, 0xFD, 0x11, - 0x20, 0xD8, 0xDF, 0x07, 0x17, 0x01, 0x8B, 0x07, - 0x80, 0xFF, 0x0B, 0xC8, 0x04, 0x01, 0x20, 0xE8, - 0x0A, 0xE0, 0x00, 0x01, 0xE0, 0xC2, 0x04, 0x01, - 0xE0, 0x22, 0x86, 0xE1, 0xFB, 0x16, 0xE0, 0x02, - 0xA0, 0x00, 0xE0, 0x04, 0x82, 0x01, 0x20, 0xE8, - 0x0A, 0xE0, 0x00, 0x01, 0xE0, 0xC2, 0x00, 0x01, - 0xE0, 0x22, 0x06, 0xE0, 0xF8, 0x13, 0xA0, 0x01, - 0x40, 0x01, 0x00, 0xF6, 0x60, 0x04, 0x90, 0xA0, - 0x00, 0x03, 0x02, 0x00, 0xA0, 0x07, 0x02, 0x01, - 0xFF, 0xDF, 0x90, 0x03, 0xFF, 0xFF, 0x80, 0x03, - 0x00, 0x03, 0x02, 0x00, 0x09, 0x07, 0xA0, 0xC2, - 0x04, 0x01, 0x8A, 0x01, 0x80, 0x00, 0x4A, 0x52, - 0x89, 0xD2, 0x0A, 0xC8, 0x04, 0x01, 0xA0, 0xD2, - 0x04, 0x01, 0xF9, 0x16, 0x49, 0x05, 0x89, 0x01, - 0x00, 0x80, 0x49, 0x01, 0x00, 0x40, 0x0E, 0x13, - 0x09, 0xF8, 0x3A, 0x07, 0x60, 0xC2, 0x36, 0x07, - 0x03, 0x16, 0x90, 0x03, 0xFF, 0xFF, 0x80, 0x03, - 0xE0, 0x04, 0x36, 0x07, 0x54, 0x04, 0x90, 0x03, - 0xFF, 0xFF, 0x80, 0x03, 0x60, 0x22, 0x86, 0xE1, - 0xC2, 0x13, 0xE0, 0x04, 0x82, 0x01, 0x60, 0x04, - 0xE0, 0xA3, 0x00, 0x03, 0x02, 0x00, 0xA0, 0x07, - 0x62, 0x09, 0xE8, 0x03, 0xC9, 0x04, 0xA0, 0xC1, - 0x34, 0x06, 0x04, 0x16, 0xA0, 0x06, 0x50, 0xB5, - 0xE0, 0x04, 0x20, 0x09, 0x86, 0x07, 0xE8, 0x05, - 0xA0, 0x01, 0x40, 0x01, 0x00, 0x80, 0x20, 0xC2, - 0x84, 0x01, 0x20, 0x48, 0x08, 0xE0, 0x84, 0x01, - 0x20, 0x22, 0x08, 0xE0, 0x08, 0x13, 0x60, 0x01, - 0xAE, 0x01, 0x01, 0x00, 0x04, 0x16, 0xE0, 0x01, - 0x34, 0x06, 0x00, 0x80, 0x06, 0x10, 0x20, 0xC2, - 0x32, 0x09, 0x06, 0x13, 0xE0, 0x01, 0x34, 0x06, - 0x00, 0x08, 0xE0, 0x04, 0x30, 0x06, 0x09, 0x07, - 0xA0, 0x05, 0xEE, 0x05, 0x20, 0x06, 0xEC, 0x05, - 0x02, 0x16, 0x16, 0xC2, 0x03, 0x16, 0x49, 0xC2, - 0x12, 0x16, 0x80, 0x03, 0x98, 0xC5, 0xE8, 0xC1, - 0x02, 0x00, 0xE0, 0xE9, 0x14, 0xE0, 0x04, 0x00, - 0xD7, 0x04, 0x27, 0x02, 0x08, 0x00, 0xA0, 0x06, - 0xE6, 0xB4, 0x16, 0xC2, 0x04, 0x13, 0x28, 0xC8, - 0x08, 0x00, 0xEC, 0x05, 0xEF, 0x13, 0x54, 0x04, - 0x00, 0x03, 0x02, 0x00, 0xE0, 0xC1, 0x86, 0x01, - 0x47, 0x02, 0x0E, 0x00, 0xA7, 0xC2, 0x90, 0xE1, - 0x5A, 0x04, 0x8A, 0x07, 0x00, 0xA0, 0x0A, 0xC8, - 0x86, 0x01, 0xC7, 0xA1, 0x27, 0x02, 0x98, 0xE1, - 0x37, 0xE8, 0x34, 0x06, 0x17, 0xE8, 0xD2, 0x06, - 0xE0, 0x04, 0x30, 0x06, 0x60, 0x04, 0xF2, 0xA9, - 0x0A, 0xE8, 0xD2, 0x06, 0xE0, 0x01, 0x34, 0x06, - 0x00, 0x08, 0xE0, 0x04, 0x30, 0x06, 0x20, 0xE0, - 0x18, 0xE0, 0x5B, 0x04, 0xA0, 0x05, 0x20, 0x09, - 0x20, 0x88, 0x20, 0x09, 0x16, 0xE0, 0xE5, 0x1A, - 0xE0, 0x04, 0x20, 0x09, 0xA0, 0x06, 0xD0, 0xD5, - 0x80, 0x03, 0xA0, 0x05, 0x32, 0x09, 0x80, 0x03, - 0x01, 0xC3, 0xFB, 0x13, 0x60, 0x01, 0x6A, 0x09, - 0x01, 0x00, 0x78, 0x13, 0xA0, 0x05, 0x32, 0x09, - 0x75, 0x10, 0x41, 0xC0, 0x06, 0x13, 0x01, 0xC8, - 0x6C, 0x01, 0xE0, 0xC2, 0x02, 0xFC, 0x01, 0x11, - 0x7B, 0x10, 0x60, 0x01, 0x9C, 0x01, 0x40, 0x00, - 0x79, 0x16, 0x20, 0xD8, 0x2F, 0x09, 0x83, 0x01, - 0x41, 0xC0, 0x04, 0x13, 0x01, 0xC8, 0x8A, 0x01, - 0x01, 0xC8, 0x18, 0x09, 0x86, 0x07, 0x43, 0x00, - 0x06, 0xC8, 0x6C, 0x01, 0x07, 0x02, 0x02, 0xFC, - 0x17, 0xC2, 0x60, 0x04, 0xFA, 0xA6, 0xE0, 0x04, - 0x18, 0x09, 0xC7, 0x61, 0x08, 0x07, 0x60, 0x01, - 0x06, 0xFC, 0x40, 0x00, 0x02, 0x13, 0x08, 0x02, - 0x01, 0x00, 0x09, 0x10, 0x4C, 0xC2, 0x20, 0xC3, - 0x00, 0xFC, 0x2A, 0x13, 0x0C, 0xC8, 0x6C, 0x01, - 0xE0, 0xC2, 0x02, 0xFC, 0x1B, 0x11, 0x4B, 0x01, - 0x00, 0x01, 0xF4, 0x16, 0xC8, 0x22, 0x12, 0x13, - 0xCB, 0x01, 0x00, 0x40, 0x0B, 0xC8, 0x02, 0xFC, - 0x0D, 0x10, 0xE0, 0xC1, 0x18, 0x09, 0x01, 0xC3, - 0x21, 0x13, 0x4C, 0xC2, 0x15, 0x13, 0x0C, 0xC8, - 0x6C, 0x01, 0xE0, 0xC2, 0x02, 0xFC, 0x06, 0x11, - 0xCC, 0x81, 0xD5, 0x13, 0x4C, 0xC2, 0x20, 0xC3, - 0x00, 0xFC, 0xF4, 0x10, 0x09, 0xC8, 0x6C, 0x01, - 0xE0, 0xC2, 0x02, 0xFC, 0x1E, 0x16, 0xA0, 0x07, - 0x02, 0xFC, 0x00, 0x80, 0x09, 0xC3, 0x19, 0x10, - 0x09, 0xC8, 0x6C, 0x01, 0xE0, 0xC2, 0x02, 0xFC, - 0x05, 0x16, 0xA0, 0x07, 0x02, 0xFC, 0x00, 0x80, - 0x09, 0xC3, 0x0F, 0x10, 0xE0, 0xC2, 0x02, 0x0C, - 0x01, 0x11, 0x1E, 0x10, 0x20, 0xD8, 0x00, 0xE2, - 0x83, 0x01, 0x8B, 0x09, 0x8B, 0x09, 0x8B, 0x09, - 0x8B, 0x09, 0xA0, 0x07, 0x8A, 0x01, 0x43, 0x00, - 0x13, 0x10, 0x0C, 0xC8, 0x8A, 0x01, 0x0C, 0xC8, - 0x18, 0x09, 0x0E, 0x10, 0x00, 0x03, 0x02, 0x00, - 0xE0, 0xC0, 0x6C, 0x01, 0x20, 0xC3, 0x8A, 0x01, - 0x20, 0x98, 0x83, 0x01, 0x00, 0xE2, 0x81, 0x13, - 0x60, 0x01, 0x9C, 0x01, 0x40, 0x00, 0xB9, 0x13, - 0x01, 0x83, 0x31, 0x16, 0x03, 0xC8, 0x6C, 0x01, - 0x40, 0x01, 0x10, 0x00, 0x14, 0x16, 0xE0, 0xC2, - 0x2E, 0x06, 0x11, 0x13, 0xE0, 0xC2, 0xF8, 0x05, - 0x0E, 0x13, 0xE0, 0x01, 0x3A, 0x07, 0x00, 0x80, - 0x80, 0x01, 0x10, 0x00, 0xE0, 0xC2, 0x36, 0x07, - 0x06, 0x13, 0xE0, 0x04, 0x36, 0x07, 0x80, 0x01, - 0x20, 0x00, 0x60, 0x04, 0xF2, 0xA9, 0x40, 0x01, - 0x20, 0x00, 0xF9, 0x13, 0x90, 0x03, 0xFF, 0x11, - 0x80, 0x03, 0x08, 0x01, 0x00, 0x04, 0x19, 0x16, - 0x60, 0x01, 0x6A, 0x09, 0x01, 0x00, 0x15, 0x16, - 0x88, 0x01, 0x00, 0x1A, 0xC8, 0x01, 0x00, 0x01, - 0xC8, 0xC5, 0x0F, 0x10, 0xE0, 0x04, 0x18, 0x09, - 0xC0, 0x01, 0x04, 0x00, 0x15, 0x10, 0x81, 0xC1, - 0x01, 0xC8, 0x6C, 0x01, 0x07, 0x02, 0x00, 0xFC, - 0x77, 0xC0, 0x17, 0xC2, 0x48, 0x01, 0x00, 0x18, - 0xE4, 0x13, 0x40, 0x01, 0x40, 0x00, 0x15, 0x16, - 0x80, 0x01, 0x45, 0x00, 0x46, 0xC1, 0x20, 0xD0, - 0x07, 0xFC, 0x60, 0x81, 0x18, 0x09, 0xE6, 0x13, - 0xE0, 0xC2, 0x08, 0xFC, 0x08, 0x11, 0xE0, 0xC2, - 0x0E, 0xFC, 0x07, 0x15, 0x06, 0x13, 0xE0, 0xC2, - 0x14, 0xFC, 0x03, 0x15, 0x02, 0x13, 0xC0, 0x01, - 0x01, 0x00, 0x48, 0x01, 0x00, 0x01, 0x11, 0x13, - 0x40, 0x01, 0x80, 0x40, 0x69, 0x13, 0x60, 0x04, - 0x66, 0xA6, 0x48, 0x01, 0x01, 0x00, 0x03, 0x16, - 0x40, 0x01, 0x00, 0x40, 0x0B, 0x16, 0xC8, 0x01, - 0x00, 0x40, 0xA0, 0x05, 0x32, 0x09, 0xC8, 0xC5, - 0x05, 0x10, 0xC0, 0x01, 0x40, 0x00, 0x40, 0x01, - 0x04, 0x00, 0xEF, 0x13, 0xB7, 0x01, 0x20, 0x00, - 0xD7, 0xC2, 0xC4, 0x62, 0x0B, 0x05, 0x2B, 0x02, - 0xFC, 0xFF, 0xCB, 0xC5, 0x02, 0x15, 0x46, 0x81, - 0x6A, 0x13, 0x08, 0x01, 0x00, 0x5E, 0x67, 0x16, - 0x08, 0x01, 0x88, 0x00, 0x13, 0x16, 0x86, 0x02, - 0x43, 0x00, 0x25, 0x16, 0x40, 0x01, 0x00, 0x40, - 0x0B, 0x13, 0x08, 0x01, 0x03, 0x00, 0x08, 0x13, - 0x84, 0xC2, 0x2A, 0x02, 0xD8, 0xFF, 0x06, 0xC8, - 0x6C, 0x01, 0x0A, 0x68, 0x04, 0xFC, 0x73, 0x10, - 0x60, 0x04, 0xD2, 0xA8, 0x40, 0x01, 0x01, 0x00, - 0xEA, 0x13, 0x08, 0x01, 0x02, 0x00, 0xE7, 0x16, - 0x48, 0x01, 0x01, 0x00, 0xE4, 0x16, 0x40, 0x01, - 0x00, 0x40, 0x04, 0x16, 0x60, 0x01, 0xA8, 0x09, - 0x80, 0x00, 0xDD, 0x13, 0x8A, 0x07, 0x80, 0x00, - 0xA0, 0x06, 0x32, 0xA5, 0xD8, 0x10, 0x00, 0xC0, - 0xE7, 0x11, 0x60, 0xC2, 0x6A, 0x09, 0x40, 0x01, - 0x00, 0x40, 0x0A, 0x13, 0x48, 0x01, 0x01, 0x00, - 0x34, 0x13, 0x48, 0x01, 0x02, 0x00, 0x0A, 0x13, - 0x49, 0x01, 0x04, 0x00, 0xD9, 0x16, 0x06, 0x10, - 0x49, 0x01, 0x02, 0x00, 0x03, 0x13, 0x08, 0x01, - 0x03, 0x00, 0x6E, 0x13, 0x49, 0x01, 0x01, 0x00, - 0x12, 0x13, 0x40, 0x01, 0x80, 0x40, 0x01, 0x16, - 0x46, 0xC1, 0xE0, 0x04, 0x00, 0xFC, 0x87, 0x07, - 0xF8, 0x05, 0x17, 0xC2, 0x14, 0x13, 0xC7, 0x05, - 0x17, 0xC8, 0x6C, 0x01, 0x05, 0xC8, 0x00, 0xFC, - 0xC6, 0xC5, 0x60, 0x04, 0x66, 0xA6, 0x07, 0x02, - 0x02, 0xFC, 0xE0, 0xA1, 0x2C, 0x09, 0xE0, 0xCD, - 0xEE, 0x05, 0xE0, 0xC5, 0x04, 0xFC, 0x20, 0xC8, - 0x2C, 0x09, 0x04, 0xFC, 0xE2, 0x10, 0xC5, 0xCD, - 0xC6, 0xC5, 0x60, 0x04, 0x66, 0xA6, 0x60, 0x04, - 0xB6, 0xA8, 0x06, 0xC8, 0x6C, 0x01, 0x85, 0x81, - 0x1A, 0x13, 0xE0, 0xC2, 0x04, 0xFC, 0x17, 0x15, - 0x86, 0xC2, 0x8A, 0xA2, 0xAA, 0xC1, 0x32, 0x0C, - 0x06, 0xC8, 0x6C, 0x01, 0x0B, 0xA8, 0x04, 0xFC, - 0x1A, 0x09, 0x0A, 0xC8, 0x6C, 0x01, 0xE0, 0xC2, - 0x02, 0xFC, 0xE0, 0x04, 0x00, 0xFC, 0x06, 0xC8, - 0x6C, 0x01, 0x0B, 0xC8, 0x02, 0xFC, 0xA0, 0x06, - 0x3E, 0xB4, 0x06, 0xC8, 0x6C, 0x01, 0xE0, 0x04, - 0x00, 0xFC, 0xA0, 0x01, 0x02, 0xFC, 0x02, 0x00, - 0x87, 0x07, 0x30, 0x06, 0xE7, 0x01, 0x04, 0x00, - 0x40, 0x00, 0xD7, 0x04, 0x27, 0x02, 0x0C, 0x00, - 0x05, 0xC2, 0x60, 0x01, 0x6A, 0x09, 0x04, 0x00, - 0x03, 0x16, 0xE0, 0x01, 0x02, 0xFC, 0x20, 0x00, - 0xA0, 0x06, 0xFC, 0xB4, 0xC0, 0x01, 0x20, 0x00, - 0x60, 0x04, 0x66, 0xA6, 0x48, 0x01, 0x00, 0x18, - 0x03, 0x13, 0x48, 0x01, 0x00, 0x10, 0x02, 0x16, - 0xA0, 0x05, 0x32, 0x09, 0x86, 0x02, 0x43, 0x00, - 0x03, 0x13, 0x40, 0x01, 0x80, 0x40, 0x98, 0x13, - 0x06, 0xC8, 0x6C, 0x01, 0xE0, 0x04, 0x00, 0xFC, - 0x85, 0xC2, 0xA0, 0x06, 0x3E, 0xB4, 0x20, 0x06, - 0x62, 0x09, 0xE6, 0x16, 0xA0, 0x06, 0xD0, 0xD5, - 0xE3, 0x10, 0xA0, 0xC2, 0xF6, 0x05, 0x56, 0x16, - 0x19, 0xC8, 0xF0, 0x05, 0xA9, 0xC2, 0x0A, 0x00, - 0x0D, 0x11, 0xA0, 0xF2, 0x2E, 0x09, 0x0A, 0xD8, - 0x80, 0x01, 0x29, 0xC8, 0x06, 0x00, 0x8C, 0x01, - 0xA0, 0x07, 0x16, 0x09, 0x04, 0x00, 0x09, 0xC8, - 0xF4, 0x05, 0x46, 0x10, 0x29, 0xC8, 0x06, 0x00, - 0x6C, 0x01, 0x20, 0xC8, 0x0E, 0xFC, 0xBC, 0x01, - 0x20, 0xC8, 0x10, 0xFC, 0xB0, 0x01, 0x20, 0xC8, - 0x12, 0xFC, 0xB2, 0x01, 0xA0, 0xF2, 0x2E, 0x09, - 0x8A, 0x01, 0x00, 0x10, 0xA0, 0x01, 0x80, 0x01, - 0x00, 0xC4, 0xE1, 0x10, 0x47, 0x01, 0x08, 0x00, - 0x06, 0x16, 0xA8, 0xC2, 0x06, 0x00, 0xA0, 0x06, - 0x3E, 0xB4, 0xE8, 0x04, 0x06, 0x00, 0x07, 0x01, - 0x20, 0x00, 0x31, 0x13, 0xE8, 0x04, 0x02, 0x00, - 0x3B, 0x10, 0xE0, 0x04, 0x00, 0xFC, 0xA0, 0x06, - 0x3E, 0xB4, 0x29, 0x10, 0x00, 0x03, 0x02, 0x00, - 0x20, 0xC2, 0x8C, 0x01, 0xE0, 0xC0, 0x6C, 0x01, - 0x20, 0xC2, 0xF4, 0x05, 0x28, 0xC8, 0x08, 0x00, - 0x6C, 0x01, 0xE8, 0xC1, 0x0A, 0x00, 0x20, 0xC3, - 0x02, 0xFC, 0x8C, 0x01, 0x20, 0x00, 0x0C, 0xC8, - 0x02, 0xFC, 0x0C, 0x01, 0x00, 0xFE, 0x3B, 0x16, - 0x47, 0x01, 0x40, 0x00, 0x50, 0x13, 0x60, 0xC2, - 0xF0, 0x05, 0xA7, 0x16, 0xE0, 0x04, 0xF4, 0x05, - 0x0C, 0xCA, 0x08, 0x00, 0x47, 0x01, 0x80, 0x00, - 0xC9, 0x16, 0x28, 0xC8, 0x06, 0x00, 0x6C, 0x01, - 0xA0, 0xC2, 0x00, 0xFC, 0xD2, 0x16, 0xE8, 0xC1, - 0x02, 0x00, 0xD7, 0xC2, 0x0F, 0x16, 0x27, 0x02, - 0x10, 0x00, 0xD8, 0x04, 0x57, 0xC2, 0x0E, 0x13, - 0xC7, 0x05, 0x57, 0xC2, 0x48, 0xC6, 0xC8, 0xC5, - 0x03, 0xC8, 0x6C, 0x01, 0x0D, 0x11, 0x90, 0x03, - 0xFF, 0x11, 0x80, 0x03, 0xD7, 0x04, 0xC3, 0x01, - 0x00, 0x80, 0xED, 0x10, 0xE7, 0x01, 0xF4, 0xFF, - 0x20, 0x00, 0xC8, 0xCD, 0xC8, 0xC5, 0xF0, 0x10, - 0x90, 0x03, 0xF8, 0x11, 0xE0, 0x02, 0xC0, 0x00, - 0x60, 0xC3, 0xFA, 0x00, 0xA0, 0xC3, 0xFC, 0x00, - 0xE0, 0xC3, 0xFE, 0x00, 0x54, 0x04, 0xE8, 0xC2, - 0x08, 0x00, 0xA8, 0xC2, 0x06, 0x00, 0x0C, 0xC3, - 0x33, 0x11, 0x20, 0x23, 0x0A, 0xE0, 0x45, 0x13, - 0x20, 0x23, 0x10, 0xE0, 0x46, 0x13, 0x20, 0x23, - 0x0E, 0xE0, 0x13, 0x13, 0xE0, 0x21, 0x16, 0xE0, - 0xB6, 0x16, 0x20, 0x23, 0x06, 0xE0, 0x03, 0x16, - 0x20, 0x27, 0xA8, 0xE4, 0x0A, 0x13, 0xE8, 0xC2, - 0x08, 0x00, 0xA8, 0xC2, 0x06, 0x00, 0x4C, 0x01, - 0x88, 0x00, 0xA9, 0x16, 0x0C, 0x01, 0x44, 0x00, - 0xA6, 0x16, 0x20, 0x06, 0x16, 0x09, 0xA3, 0x13, - 0x0A, 0xC8, 0x6C, 0x01, 0x20, 0xC8, 0x04, 0xE0, - 0x02, 0xFC, 0x0B, 0xC8, 0x6C, 0x01, 0xA0, 0x07, - 0x02, 0xFC, 0x00, 0x81, 0x20, 0xC3, 0x80, 0x01, - 0xA0, 0x01, 0x80, 0x01, 0x00, 0xC4, 0x0C, 0xC8, - 0x80, 0x01, 0x0A, 0xC8, 0x8C, 0x01, 0xAC, 0x10, - 0x0A, 0xC2, 0x0F, 0x13, 0x08, 0xC8, 0x6C, 0x01, - 0xA0, 0xC2, 0x00, 0xFC, 0x20, 0xC3, 0x02, 0xFC, - 0x20, 0x23, 0x12, 0xE0, 0xF5, 0x16, 0x0B, 0xC8, - 0x6C, 0x01, 0x0C, 0xC8, 0x02, 0xFC, 0x60, 0x04, - 0x72, 0xA9, 0x8A, 0x07, 0x00, 0x04, 0x60, 0x04, - 0x8A, 0xA3, 0x8A, 0x07, 0x20, 0x00, 0x60, 0x04, - 0x8A, 0xA3, 0x8A, 0x07, 0x00, 0x02, 0x20, 0x27, - 0x0E, 0xE0, 0x04, 0x16, 0xA0, 0x06, 0x32, 0xA5, - 0xC3, 0x01, 0x00, 0x80, 0xA8, 0xC2, 0x06, 0x00, - 0x60, 0x04, 0x98, 0xA9, 0x00, 0x03, 0x02, 0x00, - 0xC0, 0x01, 0x10, 0x00, 0xE0, 0xC2, 0x2E, 0x06, - 0x08, 0x13, 0xE0, 0xC2, 0xF8, 0x05, 0x05, 0x13, - 0xE0, 0x01, 0x3A, 0x07, 0x00, 0x80, 0x80, 0x01, - 0x10, 0x00, 0x90, 0x03, 0xFF, 0x7F, 0x80, 0x03, - 0x00, 0x03, 0x02, 0x00, 0x20, 0xC2, 0xF6, 0x05, - 0x20, 0xE2, 0xF4, 0x05, 0x0E, 0x16, 0x20, 0xD8, - 0x2E, 0x09, 0x80, 0x01, 0x2B, 0xC8, 0x06, 0x00, - 0x8C, 0x01, 0xA0, 0x07, 0x16, 0x09, 0x04, 0x00, - 0x0B, 0xC8, 0xF4, 0x05, 0x90, 0x03, 0xFF, 0xFF, - 0x80, 0x03, 0x87, 0x07, 0xF0, 0x05, 0xDB, 0x04, - 0x57, 0xC2, 0x05, 0x16, 0xCB, 0xCD, 0xCB, 0xC5, - 0x90, 0x03, 0xFF, 0xFF, 0x80, 0x03, 0xC7, 0x05, - 0x57, 0xC2, 0x4B, 0xC6, 0xCB, 0xC5, 0x90, 0x03, - 0xFF, 0xFF, 0x80, 0x03, 0x00, 0x03, 0x02, 0x00, - 0x0B, 0xC2, 0x20, 0xC3, 0xF4, 0x05, 0x0F, 0x13, - 0xA8, 0xC2, 0x0A, 0x00, 0x4A, 0x01, 0x10, 0x00, - 0x16, 0x16, 0xA0, 0x22, 0x04, 0xE0, 0x1A, 0x16, - 0x08, 0xC3, 0xA0, 0x06, 0x36, 0xAC, 0x0C, 0xC2, - 0x20, 0xC3, 0xF4, 0x05, 0x13, 0x16, 0x68, 0x01, - 0x0A, 0x00, 0x10, 0x00, 0x03, 0x13, 0xE0, 0xC2, - 0xF6, 0x05, 0x05, 0x16, 0xA0, 0x06, 0x78, 0xAC, - 0x90, 0x03, 0xFF, 0xFF, 0x80, 0x03, 0x87, 0x07, - 0xF0, 0x05, 0xA0, 0x06, 0xE6, 0xB4, 0x90, 0x03, - 0xFF, 0xFF, 0x80, 0x03, 0x87, 0x07, 0xF0, 0x05, - 0xA0, 0x06, 0x2C, 0xB5, 0x80, 0x03, 0x00, 0x03, - 0x02, 0x00, 0x87, 0x07, 0xF0, 0x05, 0xCB, 0xC2, - 0x08, 0x16, 0xA0, 0x06, 0x36, 0xAC, 0x20, 0x07, - 0xF6, 0x05, 0x60, 0xCB, 0xF4, 0x05, 0x02, 0x00, - 0x80, 0x03, 0xE0, 0x04, 0xF6, 0x05, 0x20, 0xC2, - 0xF4, 0x05, 0x05, 0x16, 0x17, 0xC2, 0x03, 0x13, - 0xD8, 0xC5, 0xA0, 0x06, 0x78, 0xAC, 0x80, 0x03, - 0x00, 0x03, 0x02, 0x00, 0x0B, 0xC3, 0xA0, 0x06, - 0x36, 0xAC, 0x8C, 0xC2, 0xCC, 0xC1, 0x27, 0x02, - 0x10, 0x00, 0x88, 0x07, 0xF0, 0x05, 0x88, 0xC1, - 0x18, 0xC2, 0x26, 0x13, 0xA8, 0x82, 0x02, 0x00, - 0xFA, 0x16, 0xE8, 0xC2, 0x0A, 0x00, 0xE0, 0x22, - 0x1E, 0xE0, 0xF5, 0x16, 0x98, 0xC5, 0xE0, 0x22, - 0x1C, 0xE0, 0x0B, 0x16, 0x28, 0xC8, 0x06, 0x00, - 0xF4, 0x00, 0xE0, 0x02, 0xE0, 0x00, 0xA0, 0x06, - 0x3E, 0xB4, 0xE0, 0x02, 0xC0, 0x00, 0xE8, 0x04, - 0x06, 0x00, 0xE0, 0x22, 0x18, 0xE0, 0xE4, 0x13, - 0x20, 0xEA, 0x22, 0xE0, 0x0A, 0x00, 0xA0, 0xEA, - 0x18, 0xE0, 0x04, 0x00, 0xDA, 0x04, 0xA0, 0x06, - 0xE6, 0xB4, 0x47, 0x06, 0x06, 0xC2, 0xD8, 0x10, - 0x06, 0xC8, 0xF2, 0x05, 0x60, 0xCB, 0xF4, 0x05, - 0x02, 0x00, 0x54, 0x04, 0x20, 0xC2, 0xF4, 0x05, - 0x13, 0x13, 0xE0, 0x01, 0x9C, 0x01, 0x00, 0x40, - 0x8B, 0x0B, 0x8B, 0x0B, 0x60, 0x01, 0x9C, 0x01, - 0x00, 0x40, 0x0A, 0x16, 0x60, 0xC2, 0x6C, 0x01, - 0x28, 0xC8, 0x06, 0x00, 0x6C, 0x01, 0xA0, 0xC2, - 0x02, 0xFC, 0x03, 0x11, 0x09, 0xC8, 0x6C, 0x01, - 0x5B, 0x04, 0x09, 0xC8, 0x6C, 0x01, 0x4B, 0xC2, - 0x87, 0x07, 0xF0, 0x05, 0xA0, 0x06, 0x2C, 0xB5, - 0xE0, 0x04, 0xF4, 0x05, 0x59, 0x04, 0xA8, 0xC2, - 0x0A, 0x00, 0x0D, 0x11, 0xA0, 0xF2, 0x2E, 0x09, - 0x0A, 0xD8, 0x80, 0x01, 0x28, 0xC8, 0x06, 0x00, - 0x8C, 0x01, 0xA0, 0x07, 0x16, 0x09, 0x04, 0x00, - 0x08, 0xC8, 0xF4, 0x05, 0x5B, 0x04, 0x20, 0xC3, - 0x6C, 0x01, 0x28, 0xC8, 0x06, 0x00, 0x6C, 0x01, - 0x20, 0xC8, 0x0E, 0xFC, 0xBC, 0x01, 0x20, 0xC8, - 0x10, 0xFC, 0xB0, 0x01, 0x20, 0xC8, 0x12, 0xFC, - 0xB2, 0x01, 0x0C, 0xC8, 0x6C, 0x01, 0xA0, 0xF2, - 0x2E, 0x09, 0x8A, 0x01, 0x00, 0x10, 0xA0, 0x01, - 0x80, 0x01, 0x00, 0xC4, 0xDD, 0x10, 0x48, 0xC0, - 0x89, 0xC0, 0x81, 0x60, 0xC2, 0x05, 0x5B, 0x04, - 0x0B, 0xC3, 0xA0, 0x06, 0xC8, 0xAC, 0x41, 0xCC, - 0x42, 0x06, 0xFD, 0x16, 0xA0, 0x06, 0xC8, 0xAC, - 0x01, 0xC1, 0x44, 0x8C, 0x12, 0x16, 0xC4, 0x05, - 0x42, 0x06, 0xFB, 0x16, 0x04, 0x02, 0x0E, 0xAD, - 0x03, 0x02, 0x01, 0x01, 0x94, 0x06, 0x03, 0x02, - 0x5A, 0x5A, 0x94, 0x06, 0x43, 0x05, 0x94, 0x06, - 0x03, 0x07, 0x94, 0x06, 0xC3, 0x04, 0x94, 0x06, - 0xCC, 0x05, 0x5C, 0x04, 0xCB, 0xC1, 0xA0, 0x06, - 0xC8, 0xAC, 0x43, 0xCC, 0x42, 0x06, 0xFD, 0x16, - 0xA0, 0x06, 0xC8, 0xAC, 0x43, 0x8C, 0xF5, 0x16, - 0x42, 0x06, 0xFC, 0x16, 0x57, 0x04, 0x8B, 0xC2, - 0x08, 0xC0, 0x49, 0xC1, 0x85, 0x05, 0x80, 0x02, - 0x40, 0x00, 0x03, 0x11, 0x80, 0x02, 0x4F, 0x00, - 0x45, 0x12, 0x01, 0x02, 0xC8, 0xAC, 0xA1, 0x09, - 0x01, 0x80, 0x40, 0x13, 0x01, 0x02, 0xF8, 0xAD, - 0xA1, 0x09, 0x01, 0x80, 0x3B, 0x13, 0x60, 0xC0, - 0x06, 0x00, 0xA1, 0x09, 0x01, 0x80, 0x36, 0x13, - 0x81, 0x05, 0x01, 0x80, 0x33, 0x13, 0x4A, 0xC0, - 0xA1, 0x09, 0x01, 0x80, 0x2F, 0x13, 0x00, 0xC8, - 0x6A, 0x01, 0x80, 0x02, 0x80, 0x00, 0x17, 0x14, - 0x01, 0x02, 0x00, 0xF8, 0xA0, 0xC1, 0x40, 0x01, - 0xA0, 0x01, 0x40, 0x01, 0x00, 0x04, 0x02, 0x02, - 0x00, 0x10, 0x03, 0x02, 0x00, 0x04, 0xB1, 0xCC, - 0x43, 0x06, 0xFD, 0x16, 0xA0, 0x01, 0x40, 0x01, - 0x00, 0x40, 0x08, 0x02, 0x10, 0xF8, 0x06, 0xC8, - 0x40, 0x01, 0x00, 0xC0, 0x02, 0x13, 0x08, 0x02, - 0x00, 0xF8, 0x09, 0x02, 0xFE, 0xFB, 0xA0, 0x06, - 0xD2, 0xAC, 0x25, 0x10, 0x80, 0x02, 0x80, 0x00, - 0x09, 0x14, 0x01, 0x02, 0x00, 0xF8, 0x02, 0x02, - 0x00, 0x10, 0x03, 0x02, 0x00, 0x04, 0x72, 0xCC, - 0x43, 0x06, 0xFD, 0x16, 0x80, 0x05, 0x80, 0x02, - 0x80, 0x00, 0x04, 0x12, 0x60, 0x01, 0x04, 0x01, - 0x20, 0x00, 0x05, 0x13, 0x40, 0x81, 0xAB, 0x16, - 0x80, 0x02, 0x80, 0x00, 0x0B, 0x14, 0xA0, 0x07, - 0x6A, 0x01, 0x7E, 0x00, 0x02, 0x02, 0x00, 0x10, - 0x03, 0x02, 0x00, 0x04, 0xC1, 0x04, 0x81, 0xCC, - 0x43, 0x06, 0xFD, 0x16, 0xCA, 0x05, 0x5A, 0x04, - 0x00, 0x02, 0xEA, 0xAD, 0x01, 0x02, 0x1A, 0xAF, - 0x40, 0x02, 0x00, 0xFC, 0x41, 0x02, 0x00, 0xFC, - 0x40, 0x80, 0x04, 0x13, 0xA0, 0x07, 0x04, 0x01, - 0x3C, 0x00, 0x5B, 0x04, 0xC0, 0x04, 0x01, 0x02, - 0x08, 0x00, 0x02, 0x02, 0x00, 0x12, 0xE0, 0xC1, - 0x40, 0x01, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x04, - 0x03, 0x02, 0x00, 0x01, 0x00, 0xC8, 0x6A, 0x01, - 0xA0, 0xCC, 0x10, 0xF8, 0x80, 0x05, 0x03, 0x06, - 0xF9, 0x16, 0x22, 0x02, 0x00, 0x02, 0x01, 0x06, - 0xF3, 0x16, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x40, - 0x07, 0xC8, 0x40, 0x01, 0x00, 0x02, 0x00, 0x08, - 0x40, 0xC0, 0x01, 0x06, 0x01, 0xC8, 0x6A, 0x01, - 0x61, 0x02, 0x00, 0x80, 0x01, 0xC8, 0x10, 0xF8, - 0x00, 0x06, 0xF6, 0x16, 0xC0, 0x04, 0xC8, 0x04, - 0xC9, 0x04, 0x03, 0x02, 0x00, 0x08, 0x00, 0xC8, - 0x6A, 0x01, 0x80, 0xC1, 0x66, 0x02, 0x00, 0x80, - 0x20, 0xC1, 0x10, 0xF8, 0x06, 0x81, 0x15, 0x16, - 0x08, 0xC2, 0x06, 0x13, 0x80, 0x05, 0x03, 0x06, - 0xF2, 0x16, 0x08, 0xC2, 0x0D, 0x13, 0x19, 0x10, - 0xA0, 0x07, 0x10, 0xF8, 0x55, 0x55, 0x20, 0xC1, - 0x10, 0xF8, 0x84, 0x02, 0x55, 0x55, 0x02, 0x16, - 0x06, 0xC2, 0xF0, 0x10, 0x06, 0x81, 0xEE, 0x13, - 0x5B, 0x04, 0xA0, 0x07, 0x10, 0xF8, 0x55, 0x55, - 0x60, 0xC1, 0x10, 0xF8, 0x05, 0x81, 0x03, 0x13, - 0x85, 0x02, 0x55, 0x55, 0xF5, 0x16, 0x08, 0xC2, - 0xE1, 0x13, 0x40, 0xC2, 0x09, 0x06, 0x48, 0x02, - 0xFF, 0x07, 0xC0, 0x04, 0x01, 0x02, 0x08, 0x00, - 0x02, 0x02, 0x00, 0x12, 0x03, 0x02, 0x00, 0x01, - 0x00, 0xC8, 0x6A, 0x01, 0x32, 0xC8, 0x10, 0xF8, - 0x80, 0x05, 0x03, 0x06, 0xF9, 0x16, 0x22, 0x02, - 0x00, 0x02, 0x01, 0x06, 0xF3, 0x16, 0x88, 0x02, - 0x40, 0x00, 0x13, 0x15, 0x89, 0x02, 0x4F, 0x00, - 0x10, 0x11, 0xC0, 0x04, 0x02, 0x02, 0x00, 0x12, - 0x01, 0x02, 0x08, 0x00, 0x03, 0x02, 0x00, 0x01, - 0x80, 0xCC, 0x03, 0x06, 0xFD, 0x16, 0x22, 0x02, - 0x00, 0x02, 0x01, 0x06, 0xF7, 0x16, 0xCB, 0x05, - 0x5B, 0x04, 0xA0, 0x07, 0x04, 0x01, 0x37, 0x00, - 0x5B, 0x04, 0x33, 0x07, 0x33, 0x07, 0x0C, 0x10, - 0x13, 0x07, 0x23, 0x07, 0x02, 0x00, 0xCB, 0xC8, - 0x06, 0x00, 0x23, 0x02, 0x18, 0x00, 0xE0, 0xCC, - 0x6C, 0x01, 0xCD, 0xCC, 0xCE, 0xCC, 0xCF, 0xCC, - 0x83, 0x07, 0x30, 0x06, 0xD3, 0xC1, 0x0A, 0x13, - 0x83, 0x07, 0x36, 0x07, 0xD3, 0xC1, 0x06, 0x13, - 0x83, 0x07, 0xA0, 0x00, 0x93, 0x00, 0x0C, 0xC8, - 0x6C, 0x01, 0x80, 0x03, 0x63, 0x07, 0x02, 0x00, - 0x2A, 0x15, 0x63, 0xC2, 0x04, 0x00, 0x63, 0x42, - 0x06, 0x00, 0xDB, 0x13, 0x63, 0xC3, 0x1A, 0x00, - 0x49, 0xD2, 0x0C, 0x13, 0xC9, 0x06, 0x49, 0x72, - 0x69, 0xD2, 0xC0, 0xE1, 0xC9, 0x06, 0x49, 0x72, - 0xE9, 0x48, 0x04, 0xE0, 0x04, 0x00, 0x49, 0xCB, - 0x02, 0x00, 0x52, 0x04, 0x69, 0xC2, 0xC0, 0xE1, - 0x49, 0x72, 0x29, 0x02, 0x10, 0x00, 0xC3, 0xC2, - 0xE9, 0xA2, 0xA8, 0xE1, 0x1B, 0xC3, 0x89, 0x02, - 0x12, 0x00, 0x0F, 0x13, 0xDC, 0xC6, 0x03, 0x16, - 0xE9, 0x48, 0x04, 0xE0, 0x04, 0x00, 0x49, 0xCB, - 0x02, 0x00, 0x4C, 0xCB, 0x04, 0x00, 0x90, 0x03, - 0xFF, 0x01, 0x93, 0x00, 0x0C, 0xC8, 0x6C, 0x01, - 0x80, 0x03, 0x0C, 0xC8, 0x6C, 0x01, 0xE0, 0xC6, - 0x00, 0xFC, 0xF1, 0x16, 0xE9, 0x48, 0x04, 0xE0, - 0x04, 0x00, 0x49, 0xCB, 0x02, 0x00, 0x4C, 0xCB, - 0x04, 0x00, 0xED, 0x10, 0x00, 0x03, 0x02, 0x00, - 0xDB, 0xC2, 0x63, 0xC2, 0x04, 0x00, 0x4B, 0x42, - 0x9F, 0x13, 0x49, 0xD2, 0x0E, 0x13, 0xC9, 0x06, - 0x49, 0x72, 0x69, 0xD2, 0xC0, 0xE1, 0xC9, 0x06, - 0x49, 0x72, 0xE9, 0x48, 0x04, 0xE0, 0x04, 0x00, - 0x49, 0xCB, 0x02, 0x00, 0x90, 0x03, 0xFF, 0xFF, - 0x80, 0x03, 0x69, 0xC2, 0xC0, 0xE1, 0x49, 0x72, - 0x29, 0x02, 0x10, 0x00, 0xC3, 0xC2, 0xE9, 0xA2, - 0xA8, 0xE1, 0x1B, 0xC3, 0x89, 0x02, 0x12, 0x00, - 0x0C, 0x13, 0xDC, 0xC6, 0x03, 0x16, 0xE9, 0x48, - 0x04, 0xE0, 0x04, 0x00, 0x49, 0xCB, 0x02, 0x00, - 0x4C, 0xCB, 0x04, 0x00, 0x90, 0x03, 0xFF, 0xFF, - 0x80, 0x03, 0x0C, 0xC8, 0x6C, 0x01, 0xE0, 0xC6, - 0x00, 0xFC, 0xF4, 0x16, 0xF0, 0x10, 0x00, 0x03, - 0x02, 0x00, 0xBB, 0xC2, 0xBB, 0xC1, 0x86, 0xD1, - 0x03, 0x13, 0x86, 0xEA, 0x04, 0x00, 0x13, 0x10, - 0xA6, 0xD1, 0xC0, 0xE1, 0xC6, 0x06, 0x86, 0x71, - 0xCA, 0xC1, 0xE6, 0xA1, 0xB8, 0xE1, 0xA6, 0xEA, - 0x14, 0xE0, 0x04, 0x00, 0x1B, 0xC2, 0x86, 0x02, - 0x02, 0x00, 0x03, 0x16, 0xA0, 0x06, 0x0C, 0xB5, - 0x02, 0x10, 0xA0, 0x06, 0xE6, 0xB4, 0xDA, 0x04, - 0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 0xAB, 0xC2, - 0x06, 0x00, 0x8C, 0x07, 0xE8, 0x05, 0x5C, 0xC2, - 0x16, 0x13, 0xA0, 0xC1, 0xEC, 0x05, 0x8A, 0x81, - 0x1A, 0x1A, 0xC6, 0xC1, 0x09, 0xC2, 0x59, 0xC2, - 0x20, 0x13, 0xE9, 0xA1, 0x08, 0x00, 0x87, 0x82, - 0xF9, 0x12, 0xA9, 0xA2, 0x08, 0x00, 0x87, 0x62, - 0xCA, 0xCA, 0x08, 0x00, 0x4A, 0x6A, 0x08, 0x00, - 0xC9, 0xC6, 0x0B, 0xC6, 0x80, 0x03, 0xCA, 0xCA, - 0x08, 0x00, 0x0A, 0xC8, 0xEC, 0x05, 0xDB, 0x04, - 0x0B, 0xCF, 0x0B, 0xC7, 0x80, 0x03, 0x8A, 0x61, - 0x46, 0xCA, 0x08, 0x00, 0xCA, 0xCA, 0x08, 0x00, - 0x0A, 0xC8, 0xEC, 0x05, 0xC9, 0xC6, 0x0B, 0xC7, - 0x80, 0x03, 0x87, 0x62, 0xCA, 0xCA, 0x08, 0x00, - 0xDB, 0x04, 0x0B, 0xC6, 0x0B, 0xCB, 0x02, 0x00, - 0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 0xBB, 0xC1, - 0xDB, 0xC2, 0x8C, 0x07, 0xE8, 0x05, 0x4C, 0xC2, - 0xED, 0x04, 0x02, 0x00, 0x09, 0xC2, 0x59, 0xC2, - 0x18, 0x13, 0xA9, 0x81, 0x02, 0x00, 0xFA, 0x16, - 0xE9, 0x82, 0x04, 0x00, 0xF7, 0x16, 0x49, 0xCB, - 0x04, 0x00, 0x99, 0xC2, 0x0A, 0xC6, 0x0A, 0x13, - 0x08, 0x83, 0x04, 0x13, 0xA9, 0xAA, 0x08, 0x00, - 0x08, 0x00, 0x80, 0x03, 0x2A, 0xA8, 0x08, 0x00, - 0xEC, 0x05, 0x80, 0x03, 0x08, 0xCB, 0x02, 0x00, - 0x80, 0x03, 0x2D, 0x07, 0x02, 0x00, 0x8C, 0x07, - 0x08, 0x00, 0x06, 0xA3, 0x4C, 0xC2, 0x09, 0xC2, - 0x59, 0xC2, 0x13, 0x13, 0xE9, 0x82, 0x04, 0x00, - 0xFA, 0x16, 0xAD, 0x07, 0x02, 0x00, 0x01, 0x00, - 0x49, 0xCB, 0x04, 0x00, 0x19, 0xC6, 0x01, 0x13, - 0x80, 0x03, 0x08, 0x83, 0x04, 0x16, 0xA0, 0x49, - 0x14, 0xE0, 0x04, 0x00, 0x80, 0x03, 0x08, 0xCB, - 0x02, 0x00, 0x80, 0x03, 0x00, 0x03, 0x02, 0x00, - 0x0B, 0x06, 0x1F, 0x11, 0x4D, 0x13, 0x8B, 0x07, - 0x00, 0x4E, 0x60, 0x01, 0x42, 0x01, 0x80, 0x00, - 0x09, 0x13, 0x8B, 0x07, 0x00, 0x3A, 0x20, 0xC1, - 0x4E, 0x01, 0x84, 0x02, 0x41, 0x0F, 0x02, 0x11, - 0x8B, 0x07, 0x00, 0x4E, 0x0B, 0xC8, 0x44, 0x01, - 0xA0, 0x07, 0x62, 0x09, 0xE8, 0x03, 0xE0, 0x01, - 0x40, 0x01, 0x00, 0x02, 0xE0, 0x01, 0x40, 0x01, - 0x00, 0x20, 0x84, 0x07, 0x34, 0xAF, 0x60, 0x04, - 0x42, 0xAF, 0x20, 0xC8, 0x16, 0xE0, 0xE0, 0x00, - 0xE0, 0xC2, 0x6A, 0x09, 0xE0, 0x22, 0x10, 0xE0, - 0x03, 0x13, 0x20, 0xE8, 0x14, 0xE0, 0xE0, 0x00, - 0x20, 0xC8, 0x04, 0xE0, 0x82, 0x01, 0x20, 0xC8, - 0xE2, 0x00, 0x8A, 0x01, 0xE0, 0x04, 0x18, 0x09, - 0xE0, 0x04, 0xF4, 0x05, 0xE0, 0x04, 0xF8, 0x05, - 0xE0, 0x04, 0xF0, 0x05, 0xE0, 0x04, 0x42, 0x07, - 0xA0, 0x07, 0x88, 0x01, 0x20, 0x00, 0xE0, 0xC2, - 0x30, 0x09, 0x09, 0x13, 0xA0, 0x07, 0x88, 0x01, - 0x80, 0x00, 0x20, 0xE8, 0x16, 0xE0, 0x80, 0x01, - 0xE0, 0x01, 0x82, 0x01, 0x00, 0x03, 0x8B, 0x07, - 0x00, 0xA0, 0x0B, 0xE8, 0x86, 0x01, 0x80, 0x03, - 0xE0, 0x04, 0x86, 0x01, 0xE0, 0x01, 0x9C, 0x01, - 0x40, 0x00, 0xE0, 0x01, 0x9C, 0x01, 0x00, 0x40, - 0xCB, 0x04, 0xB0, 0x03, 0x0B, 0x06, 0x04, 0x13, - 0x60, 0x01, 0x9C, 0x01, 0x00, 0x40, 0xF9, 0x16, - 0xE0, 0x04, 0x82, 0x01, 0x20, 0xE8, 0x08, 0xE0, - 0x6A, 0x09, 0x8B, 0x07, 0x00, 0x80, 0x0B, 0xC8, - 0x98, 0x07, 0x0B, 0xC8, 0x78, 0x07, 0x20, 0xC8, - 0x04, 0xE0, 0x82, 0x01, 0x8B, 0x07, 0x6F, 0x87, - 0x0B, 0x48, 0x3A, 0x07, 0xE0, 0xC2, 0x50, 0x07, - 0x8B, 0x02, 0x58, 0x07, 0x10, 0x13, 0x20, 0xE8, - 0x0A, 0xE0, 0x00, 0x01, 0xE0, 0xC2, 0x00, 0x01, - 0xE0, 0x22, 0x06, 0xE0, 0xF8, 0x13, 0x8B, 0x07, - 0x58, 0x07, 0x0B, 0xC8, 0x50, 0x07, 0x8B, 0x07, - 0x0C, 0xB8, 0x0B, 0xC8, 0x52, 0x07, 0x80, 0x03, - 0x00, 0x03, 0x02, 0x00, 0xE0, 0xC2, 0x1A, 0x09, - 0x0C, 0x13, 0x20, 0x06, 0x1C, 0x09, 0x0B, 0xC8, - 0x6C, 0x01, 0x20, 0xC8, 0x00, 0xFC, 0x1A, 0x09, - 0x4B, 0xCB, 0x02, 0x00, 0x90, 0x03, 0xFF, 0xFF, - 0x80, 0x03, 0x41, 0xC0, 0x0F, 0x13, 0x81, 0x80, - 0x0D, 0x13, 0x82, 0xA0, 0xE2, 0xC2, 0x32, 0x0C, - 0x12, 0x09, 0x0B, 0xC8, 0x6C, 0x01, 0xE0, 0x04, - 0x00, 0xFC, 0x20, 0xC3, 0x02, 0xFC, 0x07, 0x11, - 0x02, 0xC8, 0x00, 0xFC, 0xED, 0x04, 0x02, 0x00, - 0xE0, 0x04, 0x6C, 0x01, 0x80, 0x03, 0x42, 0xCB, - 0x02, 0x00, 0x02, 0xC8, 0x6C, 0x01, 0x8B, 0xC0, - 0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 0x83, 0x07, - 0x00, 0x80, 0x60, 0xC2, 0x7E, 0x09, 0x09, 0xC1, - 0x24, 0x02, 0xF8, 0xFF, 0xA9, 0x08, 0x01, 0x02, - 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x0B, 0x02, - 0x00, 0x00, 0x0C, 0x02, 0x00, 0x00, 0x07, 0x02, - 0x00, 0x00, 0x2C, 0xCB, 0x32, 0x0C, 0x32, 0x0C, - 0x06, 0x13, 0x8B, 0x05, 0xCC, 0x05, 0x0B, 0x88, - 0x46, 0x04, 0x27, 0x1B, 0xF6, 0x10, 0x09, 0xC2, - 0x8B, 0xC2, 0x08, 0x06, 0x0A, 0x13, 0x8B, 0x05, - 0xCC, 0x05, 0x0B, 0x88, 0x46, 0x04, 0x1D, 0x1B, - 0x2C, 0xCB, 0x32, 0x0C, 0x32, 0x0C, 0xED, 0x16, - 0xF4, 0x10, 0x82, 0xC0, 0x14, 0x13, 0x02, 0xC8, - 0x6C, 0x01, 0x0A, 0xC8, 0x00, 0xFC, 0x0A, 0xC8, - 0x6C, 0x01, 0xE0, 0x04, 0x00, 0xFC, 0xA0, 0x07, - 0x02, 0xFC, 0x00, 0x80, 0x04, 0xC8, 0x04, 0xFC, - 0x0A, 0xC2, 0x08, 0xA2, 0x02, 0xCA, 0x32, 0x0C, - 0x8A, 0xC0, 0x87, 0x05, 0xD6, 0x10, 0x4A, 0xC0, - 0xEE, 0x10, 0x47, 0xCB, 0x02, 0x00, 0xE0, 0x04, - 0x6C, 0x01, 0x8B, 0x07, 0x43, 0x00, 0xE0, 0x04, - 0x00, 0x0C, 0x00, 0x03, 0x02, 0x00, 0x0B, 0xC8, - 0x6C, 0x01, 0x8B, 0x02, 0x43, 0x00, 0x04, 0x13, - 0x60, 0x01, 0x02, 0xFC, 0x20, 0x00, 0x06, 0x13, - 0x8B, 0xC2, 0xA0, 0x06, 0x42, 0xB4, 0x90, 0x03, - 0x7F, 0x00, 0x80, 0x03, 0xA0, 0x01, 0x02, 0xFC, - 0x20, 0x00, 0x60, 0x01, 0x6A, 0x09, 0x01, 0x00, - 0x0B, 0x16, 0x0A, 0x02, 0x02, 0xFC, 0xA0, 0xA2, - 0x2C, 0x09, 0xA0, 0xCE, 0xEE, 0x05, 0xA0, 0xC6, - 0x04, 0xFC, 0x20, 0xC8, 0x2C, 0x09, 0x04, 0xFC, - 0x8A, 0x07, 0xF8, 0x05, 0x5A, 0xC2, 0x08, 0x13, - 0xCA, 0x05, 0x5A, 0xC2, 0x09, 0xC8, 0x6C, 0x01, - 0x0B, 0xC8, 0x00, 0xFC, 0x8B, 0xC6, 0x02, 0x10, - 0x8B, 0xCE, 0x8B, 0xC6, 0x20, 0x20, 0x1A, 0xE0, - 0x05, 0x16, 0x20, 0xE8, 0x04, 0xE0, 0x3A, 0x07, - 0xE0, 0x04, 0x36, 0x07, 0x90, 0x03, 0x7F, 0x00, - 0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 0x0B, 0xC8, - 0x6C, 0x01, 0xCC, 0x04, 0xE0, 0x04, 0x00, 0xFC, - 0x8B, 0xC2, 0xA0, 0x06, 0x50, 0xB4, 0x90, 0x03, - 0x7F, 0x00, 0x80, 0x03, 0xA0, 0x07, 0x02, 0xFC, - 0x00, 0x80, 0x20, 0xC8, 0x8C, 0xE1, 0x04, 0xFC, - 0x41, 0xC0, 0x0F, 0x16, 0x20, 0xD8, 0x00, 0xE2, - 0x83, 0x01, 0x8B, 0x0B, 0x8B, 0x0B, 0x8B, 0x0B, - 0x8B, 0x0B, 0x8B, 0x0B, 0x8B, 0x0B, 0x8B, 0x0B, - 0x8B, 0x0B, 0x8B, 0x0B, 0x8B, 0x0B, 0x0A, 0xC8, - 0x8A, 0x01, 0x5B, 0x04, 0x0A, 0xC8, 0x6C, 0x01, - 0x20, 0xC3, 0x00, 0xFC, 0xE0, 0x04, 0x00, 0xFC, - 0x8A, 0x02, 0x43, 0x00, 0xDF, 0x13, 0xA0, 0x07, - 0x02, 0xFC, 0x00, 0x80, 0x04, 0xC8, 0x04, 0xFC, - 0x20, 0x98, 0x84, 0x09, 0x1D, 0x09, 0x0A, 0x13, - 0x20, 0xC8, 0x1A, 0x09, 0x00, 0xFC, 0x0A, 0xC8, - 0x1A, 0x09, 0xA0, 0x05, 0x1C, 0x09, 0x8C, 0xC2, - 0xE5, 0x16, 0x5B, 0x04, 0x41, 0xC0, 0x10, 0x13, - 0x8A, 0xA2, 0x82, 0xCA, 0x32, 0x0C, 0x1A, 0x09, - 0x02, 0xC8, 0x6C, 0x01, 0x0A, 0xC8, 0x00, 0xFC, - 0x8A, 0xC0, 0x20, 0x98, 0x83, 0x01, 0x00, 0xE2, - 0x09, 0x13, 0x8C, 0xC2, 0xD3, 0x16, 0x5B, 0x04, - 0x4A, 0xC0, 0x8A, 0xC0, 0x20, 0x98, 0x83, 0x01, - 0x00, 0xE2, 0x1B, 0x16, 0xE0, 0x01, 0x9C, 0x01, - 0x40, 0x00, 0xA0, 0x07, 0x64, 0x09, 0x00, 0x70, - 0x60, 0x01, 0x9C, 0x01, 0x40, 0x00, 0x07, 0x13, - 0x20, 0x06, 0x64, 0x09, 0xF9, 0x16, 0x0A, 0x02, - 0x00, 0x01, 0x60, 0x04, 0x8A, 0xA3, 0x60, 0x01, - 0x02, 0x0C, 0x00, 0x01, 0xE2, 0x13, 0x20, 0xD8, - 0x2F, 0x09, 0x83, 0x01, 0xA0, 0x07, 0x02, 0x0C, - 0x00, 0x80, 0x0A, 0xC8, 0x8A, 0x01, 0x0A, 0xC8, - 0x18, 0x09, 0xD7, 0x10, 0xD8, 0x04, 0x57, 0xC2, - 0x03, 0x16, 0xC8, 0xCD, 0xC8, 0xC5, 0x5B, 0x04, - 0xC7, 0x05, 0x57, 0xC2, 0x48, 0xC6, 0xC8, 0xC5, - 0x5B, 0x04, 0x08, 0xC8, 0x6C, 0x01, 0x08, 0xA2, - 0x20, 0xCA, 0x00, 0xFC, 0x32, 0x0C, 0x18, 0x09, - 0x02, 0x10, 0x08, 0xC8, 0x6C, 0x01, 0xE0, 0x04, - 0x00, 0xFC, 0x57, 0xC2, 0x03, 0x16, 0xC8, 0xCD, - 0xC8, 0xC5, 0x5B, 0x04, 0xC7, 0x05, 0x17, 0xC8, - 0x6C, 0x01, 0x08, 0xC8, 0x00, 0xFC, 0xC8, 0xC5, - 0x5B, 0x04, 0x17, 0xC6, 0x02, 0x16, 0xC8, 0xC9, - 0x02, 0x00, 0xC8, 0xC5, 0x5B, 0x04, 0x17, 0xC2, - 0x08, 0xC8, 0x6C, 0x01, 0x07, 0x13, 0xE0, 0xC5, - 0x00, 0xFC, 0x08, 0xA2, 0x28, 0xC8, 0x32, 0x0C, - 0x00, 0xFC, 0x18, 0x09, 0x5B, 0x04, 0x60, 0x01, - 0x82, 0x01, 0x00, 0x20, 0x0A, 0x16, 0x60, 0xC2, - 0x84, 0x01, 0xA0, 0x01, 0x82, 0x01, 0x00, 0x20, - 0xE0, 0x01, 0x82, 0x01, 0x00, 0x20, 0x09, 0xC8, - 0x84, 0x01, 0xC9, 0x04, 0x5B, 0x04, 0xA0, 0x06, - 0xBE, 0xB7, 0xD3, 0x04, 0xE0, 0x04, 0x02, 0x01, - 0x20, 0xE8, 0x14, 0xE0, 0x00, 0x01, 0x20, 0xC8, - 0x16, 0xE0, 0x04, 0x01, 0x05, 0x2C, 0x20, 0x48, - 0x14, 0xE0, 0x00, 0x01, 0x8C, 0x07, 0x00, 0x0A, - 0x8D, 0x07, 0xD8, 0x07, 0x8E, 0x07, 0x18, 0x00, - 0x7C, 0xCF, 0x4E, 0x06, 0xFD, 0x16, 0xE0, 0x02, - 0xD8, 0x07, 0x8F, 0x07, 0x11, 0xFF, 0x8B, 0x02, - 0x3B, 0x59, 0x21, 0x16, 0x8A, 0x02, 0x3B, 0x59, - 0x1E, 0x13, 0x8F, 0x05, 0x20, 0x20, 0x16, 0xE0, - 0x01, 0x16, 0x19, 0x10, 0x20, 0x20, 0x04, 0xE0, - 0x16, 0x16, 0x00, 0x01, 0xBF, 0x00, 0x13, 0x16, - 0x8B, 0x07, 0xC0, 0x40, 0x00, 0x01, 0x00, 0x60, - 0x10, 0x13, 0x40, 0x01, 0x00, 0x60, 0x0B, 0x16, - 0x8B, 0x07, 0xC4, 0x44, 0xA0, 0xC3, 0x02, 0x01, - 0x0E, 0x48, 0x02, 0x01, 0x4E, 0x01, 0x00, 0x10, - 0x04, 0x16, 0x8F, 0x07, 0x18, 0xFF, 0x60, 0x04, - 0x94, 0xB7, 0x0B, 0xC3, 0x4B, 0xC3, 0x20, 0x20, - 0x0A, 0xE0, 0x02, 0x16, 0x6B, 0x02, 0x20, 0x20, - 0x20, 0x20, 0x0C, 0xE0, 0x02, 0x16, 0x6C, 0x02, - 0x00, 0x20, 0x20, 0x20, 0x0E, 0xE0, 0x02, 0x16, - 0x6C, 0x02, 0x20, 0x00, 0x8F, 0x05, 0x20, 0x20, - 0x10, 0xE0, 0x07, 0x16, 0x6D, 0x02, 0x20, 0x00, - 0x20, 0x21, 0x22, 0xE0, 0xE4, 0x13, 0x04, 0xC1, - 0x02, 0x16, 0x84, 0x07, 0xFE, 0x7F, 0x8F, 0x05, - 0x20, 0x20, 0x12, 0xE0, 0x02, 0x16, 0x6D, 0x02, - 0x00, 0x20, 0x60, 0x21, 0x22, 0xE0, 0xD7, 0x13, - 0x45, 0xC1, 0x02, 0x16, 0x85, 0x07, 0xFE, 0x7F, - 0x8F, 0x05, 0x86, 0xD1, 0x0B, 0x13, 0xA0, 0x25, - 0x26, 0xE0, 0x08, 0x13, 0x8F, 0x05, 0x20, 0x26, - 0x22, 0xE0, 0x04, 0x16, 0x8F, 0x05, 0xA0, 0x26, - 0x22, 0xE0, 0x02, 0x13, 0x60, 0x04, 0x94, 0xB7, - 0x01, 0xD8, 0xEC, 0x08, 0x20, 0xD8, 0xDB, 0x07, - 0x00, 0x09, 0x02, 0xD8, 0xF6, 0x08, 0x20, 0xD8, - 0xDD, 0x07, 0xE2, 0x08, 0xE0, 0x02, 0x58, 0x07, - 0x20, 0xD8, 0xEF, 0x07, 0xF4, 0x07, 0x20, 0xD8, - 0xF1, 0x07, 0xF6, 0x07, 0x20, 0xD8, 0xF3, 0x07, - 0xF8, 0x07, 0x09, 0x02, 0x06, 0x00, 0xCB, 0x04, - 0x0F, 0x02, 0xEE, 0x07, 0x8F, 0x05, 0xCB, 0xDF, - 0x09, 0x06, 0xFC, 0x16, 0xA0, 0x06, 0xBE, 0xB7, - 0x89, 0x07, 0x5C, 0xE3, 0xE0, 0x04, 0x1A, 0x01, - 0x20, 0xC8, 0xE4, 0x07, 0x18, 0x01, 0x19, 0xC8, - 0x0C, 0x01, 0x39, 0xC8, 0x0A, 0x01, 0x39, 0xC8, - 0x12, 0x01, 0x09, 0x16, 0x79, 0xC3, 0x0F, 0x02, - 0x00, 0xE0, 0x4F, 0x63, 0x2D, 0x02, 0x00, 0x90, - 0x0D, 0xC8, 0x14, 0x01, 0x02, 0x10, 0x39, 0xC8, - 0x14, 0x01, 0xF9, 0xC3, 0x3F, 0xC8, 0x0E, 0x01, - 0x1F, 0xC8, 0x10, 0x01, 0xE0, 0x04, 0x14, 0x09, - 0xB9, 0xC2, 0x1A, 0xC8, 0x00, 0x01, 0x96, 0x06, - 0x89, 0x02, 0x84, 0xE3, 0xE0, 0x16, 0x8F, 0x07, - 0x1C, 0xFF, 0x8C, 0x07, 0x00, 0x0A, 0x8D, 0x07, - 0x84, 0xE3, 0x8E, 0x07, 0x10, 0x00, 0x7C, 0x8F, - 0x44, 0x16, 0x4E, 0x06, 0xFC, 0x16, 0xA0, 0xC3, - 0xE2, 0x07, 0xE0, 0xC3, 0xE0, 0x07, 0xCE, 0x83, - 0x01, 0x14, 0xCE, 0xC3, 0x0F, 0xC8, 0x1A, 0x01, - 0x8C, 0x07, 0x94, 0xE3, 0x8D, 0x07, 0x00, 0x0A, - 0x8E, 0x07, 0xA4, 0xE3, 0x8C, 0x63, 0x7C, 0xCF, - 0x4E, 0x06, 0xFD, 0x16, 0xE0, 0x04, 0x30, 0x09, - 0x20, 0x01, 0x42, 0x01, 0x00, 0x04, 0x02, 0x16, - 0x20, 0x07, 0x30, 0x09, 0x60, 0xC2, 0x62, 0x01, - 0xE0, 0x04, 0x62, 0x01, 0x8E, 0x07, 0x00, 0x80, - 0x8C, 0x07, 0x34, 0x09, 0x8D, 0x07, 0x06, 0x00, - 0x3E, 0xDF, 0x8E, 0x05, 0x0D, 0x06, 0xFC, 0x16, - 0xFE, 0xD3, 0xCF, 0x06, 0x8E, 0x05, 0xFE, 0xD3, - 0xCF, 0x06, 0x8C, 0x07, 0x34, 0x09, 0x09, 0xC8, - 0x62, 0x01, 0xC9, 0x04, 0x5C, 0xA3, 0x7C, 0xE2, - 0x5C, 0xA3, 0x7C, 0xE2, 0x5C, 0xA3, 0x7C, 0xE2, - 0x02, 0x13, 0xCD, 0x83, 0x09, 0x13, 0x20, 0x07, - 0x34, 0x09, 0x06, 0x10, 0x8F, 0x07, 0x19, 0xFF, - 0xCD, 0xA3, 0x0F, 0xC8, 0x04, 0x01, 0xFF, 0x10, - 0xA0, 0x01, 0x02, 0x01, 0x00, 0x10, 0xE0, 0xC3, - 0xEE, 0x07, 0xE0, 0x43, 0x06, 0xE0, 0x0F, 0xC8, - 0x00, 0x01, 0x20, 0xC0, 0x04, 0xE0, 0xE0, 0x04, - 0xFE, 0x06, 0xD3, 0x04, 0xE0, 0x04, 0x04, 0x01, - 0x60, 0x04, 0x0C, 0xB8, 0x8C, 0x07, 0x00, 0x0A, - 0x8D, 0x07, 0x18, 0x00, 0x8E, 0x07, 0x3B, 0x59, - 0x0E, 0xCF, 0x4D, 0x06, 0xFD, 0x16, 0x5B, 0x04, - 0x93, 0x01, 0x00, 0x80, 0x20, 0x04, 0xC0, 0xE2, - 0x60, 0xD0, 0x98, 0x07, 0x1C, 0x13, 0x00, 0x03, - 0x02, 0x00, 0xA0, 0xC0, 0x46, 0x07, 0x12, 0xC8, - 0x46, 0x07, 0x02, 0x16, 0x93, 0x01, 0x20, 0x00, - 0x00, 0x03, 0x0F, 0x00, 0x20, 0x04, 0xE8, 0xE2, - 0x93, 0x01, 0x00, 0x20, 0x80, 0x01, 0x00, 0x40, - 0x00, 0x01, 0xFE, 0x00, 0x49, 0x16, 0xC4, 0xC3, - 0x25, 0x16, 0xD3, 0xC3, 0xC5, 0x43, 0x0C, 0x16, - 0xE0, 0xC3, 0x98, 0x07, 0x03, 0x11, 0xE0, 0x02, - 0x98, 0x07, 0x51, 0x04, 0xE0, 0xC3, 0x78, 0x07, - 0x0A, 0x11, 0xE0, 0x02, 0x78, 0x07, 0x51, 0x04, - 0xD3, 0x11, 0x4F, 0x01, 0x00, 0x20, 0xE4, 0x13, - 0x4F, 0x01, 0x20, 0x00, 0xD1, 0x13, 0x05, 0x2C, - 0x41, 0xA0, 0x21, 0x04, 0xC0, 0xE2, 0x8B, 0x07, - 0x0C, 0xB8, 0x00, 0x01, 0x00, 0x40, 0x0F, 0x13, - 0xDD, 0xC3, 0x4F, 0x02, 0x0F, 0x00, 0x2F, 0xE1, - 0x14, 0xE0, 0x5B, 0x04, 0xE4, 0xC3, 0xC0, 0xE1, - 0xCF, 0x73, 0x2F, 0x41, 0x14, 0xE0, 0x6F, 0xC3, - 0xEC, 0xEA, 0x8B, 0x07, 0x0C, 0xB8, 0x4B, 0xC2, - 0xA0, 0xC2, 0xF4, 0x07, 0x8C, 0x07, 0x08, 0x00, - 0xBD, 0xC0, 0xA0, 0xC3, 0xEA, 0x07, 0xE0, 0xC3, - 0xEC, 0x07, 0xA0, 0x06, 0x00, 0xBA, 0xC0, 0x01, - 0x00, 0x40, 0x02, 0xD8, 0x17, 0x01, 0x62, 0x02, - 0x80, 0xFF, 0xA0, 0x06, 0x54, 0xBA, 0x02, 0xC8, - 0x04, 0x01, 0x90, 0x03, 0x3F, 0x60, 0x59, 0x04, - 0xC0, 0xC3, 0xCF, 0x73, 0xEF, 0xC3, 0xC0, 0xE1, - 0xCF, 0x73, 0xAF, 0xC3, 0xDE, 0xEA, 0x9E, 0xC3, - 0x4E, 0x02, 0x0F, 0x00, 0x2E, 0x21, 0x14, 0xE0, - 0x08, 0x13, 0x2F, 0x40, 0x14, 0xE0, 0xCF, 0xA3, - 0x2F, 0x04, 0xF0, 0xE2, 0x40, 0x01, 0x00, 0x40, - 0xA4, 0x13, 0xC4, 0xC3, 0xC7, 0x16, 0x00, 0x01, - 0xFE, 0x00, 0xE6, 0x16, 0x9E, 0x10, 0x40, 0x01, - 0x00, 0x40, 0x05, 0x16, 0x20, 0xE0, 0x14, 0xE0, - 0x65, 0x02, 0x00, 0x58, 0x96, 0x10, 0x20, 0xD8, - 0xDE, 0x07, 0x17, 0x01, 0x8F, 0x07, 0x86, 0xFF, - 0x0F, 0xC8, 0x04, 0x01, 0xC0, 0x01, 0x00, 0x40, - 0x45, 0x02, 0xFF, 0xA7, 0x8A, 0x10, 0x20, 0xC3, - 0xFE, 0x06, 0x20, 0x27, 0x38, 0xE3, 0x07, 0x13, - 0x20, 0x23, 0x22, 0xE0, 0x1A, 0x13, 0x65, 0x02, - 0xFF, 0xDF, 0x20, 0x40, 0x14, 0xE0, 0x20, 0xE0, - 0x16, 0xE0, 0x0C, 0xC8, 0xE6, 0x08, 0x8D, 0x07, - 0xE2, 0x08, 0x58, 0x04, 0x20, 0x48, 0x08, 0xE0, - 0xFE, 0x06, 0x20, 0xC3, 0xE6, 0x08, 0x20, 0x27, - 0x38, 0xE3, 0x19, 0x16, 0x80, 0x03, 0x02, 0xC3, - 0x6C, 0xC2, 0x0A, 0x00, 0x99, 0x06, 0x60, 0x04, - 0x0C, 0xB8, 0xA0, 0xC2, 0xF4, 0x07, 0x8C, 0x07, - 0x01, 0x00, 0x8D, 0x07, 0x06, 0x06, 0xCE, 0x04, - 0xE0, 0xC3, 0x08, 0x06, 0x01, 0x13, 0x97, 0x06, - 0x20, 0xD8, 0x07, 0x06, 0x17, 0x01, 0x8B, 0x07, - 0x82, 0xFF, 0x0B, 0xC8, 0x04, 0x01, 0xA0, 0x06, - 0xB4, 0xBE, 0x60, 0x04, 0x0C, 0xB8, 0xA0, 0xC2, - 0xEE, 0x07, 0x8C, 0x07, 0x06, 0x00, 0x8D, 0x07, - 0xEE, 0x08, 0xA0, 0xC3, 0xE6, 0x07, 0xE0, 0xC3, - 0xE8, 0x07, 0x97, 0x06, 0xA0, 0xC2, 0xF4, 0x07, - 0x8D, 0x07, 0xF4, 0x08, 0xDD, 0x04, 0x8C, 0x07, - 0x02, 0x00, 0x97, 0x06, 0x8D, 0x07, 0x00, 0x80, - 0xA0, 0xC2, 0xEE, 0x08, 0x0A, 0x88, 0x0C, 0x06, - 0x14, 0x1B, 0x82, 0x07, 0xD0, 0xB9, 0xA0, 0xC3, - 0xF0, 0x08, 0xE0, 0xC3, 0xF2, 0x08, 0x8B, 0x07, - 0x0C, 0xE3, 0x8A, 0x02, 0x14, 0x00, 0x04, 0x1A, - 0x8B, 0x07, 0xBA, 0xEA, 0x2A, 0x02, 0xEC, 0xFF, - 0x8A, 0xA2, 0xCA, 0xA2, 0xDB, 0xC2, 0x01, 0x13, - 0x9B, 0x06, 0x20, 0xC8, 0xEE, 0x08, 0xF2, 0x08, - 0x20, 0xC8, 0x20, 0xE0, 0xEE, 0x08, 0x0D, 0xC8, - 0xF0, 0x08, 0x8D, 0x07, 0xEC, 0x08, 0x20, 0xE0, - 0x18, 0xE0, 0x65, 0x02, 0x00, 0x58, 0x58, 0x04, - 0x45, 0x02, 0xFF, 0xA7, 0x80, 0x03, 0x60, 0xC0, - 0xEE, 0x05, 0x21, 0x02, 0xE8, 0x03, 0x20, 0x01, - 0x02, 0x01, 0x06, 0x00, 0x07, 0x16, 0x01, 0x88, - 0xEE, 0x05, 0xF9, 0x16, 0x39, 0x10, 0x60, 0xD0, - 0x03, 0x01, 0xF1, 0x13, 0x01, 0x02, 0x0A, 0x01, - 0x4C, 0xCC, 0x4C, 0xCC, 0x4E, 0xCC, 0x4F, 0xCC, - 0xB1, 0x07, 0x40, 0x00, 0x4D, 0xCC, 0x0A, 0xC8, - 0x00, 0x01, 0x5B, 0x04, 0x60, 0xC0, 0xEE, 0x05, - 0x21, 0x02, 0xE8, 0x03, 0x20, 0x01, 0x02, 0x01, - 0x06, 0x00, 0x07, 0x16, 0x01, 0x88, 0xEE, 0x05, - 0xF9, 0x16, 0x1E, 0x10, 0x60, 0xD0, 0x03, 0x01, - 0xF1, 0x13, 0x01, 0x02, 0x0A, 0x01, 0x4C, 0xCC, - 0x4C, 0xCC, 0x4E, 0xCC, 0x4F, 0xCC, 0xB1, 0x07, - 0x40, 0x00, 0x4D, 0xCC, 0x0A, 0xC8, 0x00, 0x01, - 0xA0, 0x03, 0x60, 0xD0, 0x03, 0x01, 0x01, 0x13, - 0x5B, 0x04, 0x60, 0xC0, 0xEE, 0x05, 0x21, 0x02, - 0xE8, 0x03, 0x20, 0x01, 0x02, 0x01, 0x06, 0x00, - 0xF7, 0x16, 0x01, 0x88, 0xEE, 0x05, 0xF9, 0x16, - 0xCD, 0x04, 0x8A, 0x07, 0x00, 0x40, 0x20, 0xC3, - 0x00, 0x01, 0x0C, 0x01, 0x00, 0x80, 0x02, 0x13, - 0x8A, 0x07, 0x00, 0x20, 0xA0, 0xC3, 0x0E, 0x01, - 0xE0, 0xC3, 0x10, 0x01, 0xB0, 0x03, 0x20, 0xC3, - 0x58, 0x07, 0x20, 0x23, 0x04, 0xE0, 0x02, 0x13, - 0x60, 0x04, 0x8E, 0xB7, 0x60, 0x04, 0x8A, 0xA3, - 0x8D, 0x07, 0x00, 0x20, 0x20, 0x20, 0x0A, 0xE0, - 0x01, 0x16, 0x5B, 0x04, 0x0D, 0x02, 0x32, 0x0C, - 0x5D, 0xC2, 0x01, 0x11, 0xDD, 0x04, 0xCD, 0x05, - 0x0D, 0x88, 0x30, 0x0C, 0xF9, 0x16, 0x60, 0xC2, - 0x0A, 0x06, 0x8D, 0x07, 0x6A, 0x09, 0xA0, 0x06, - 0xF4, 0xBE, 0x09, 0x02, 0x48, 0x00, 0xE0, 0xC3, - 0x30, 0x09, 0x03, 0x16, 0xE0, 0x01, 0x6A, 0x09, - 0x10, 0x00, 0xE0, 0xC2, 0x6A, 0x09, 0x0F, 0x02, - 0x00, 0x01, 0xC9, 0x26, 0x02, 0x13, 0x60, 0x04, - 0x86, 0xBD, 0x09, 0x02, 0x00, 0x12, 0x4B, 0x01, - 0x10, 0x00, 0x02, 0x13, 0x09, 0x02, 0x00, 0x13, - 0x09, 0xD8, 0x2E, 0x09, 0x8F, 0x07, 0x00, 0x40, - 0x89, 0x07, 0x6C, 0x09, 0xCB, 0x04, 0xF9, 0xE2, - 0xF9, 0xE2, 0xF9, 0xE2, 0x07, 0x16, 0x8B, 0x07, - 0x34, 0x09, 0x8C, 0x07, 0x6C, 0x09, 0x3B, 0xCF, - 0x3B, 0xCF, 0x1B, 0xC7, 0x20, 0xC3, 0x6C, 0x09, - 0x19, 0x11, 0x8F, 0x07, 0x00, 0x20, 0x89, 0x07, - 0x7A, 0x09, 0xA0, 0x06, 0x3A, 0xBB, 0xA0, 0x06, - 0x3A, 0xBB, 0x12, 0x10, 0x4C, 0xCE, 0x5B, 0x04, - 0x19, 0xC3, 0x02, 0x16, 0x8C, 0x07, 0x1A, 0x00, - 0x4C, 0xC3, 0x2D, 0x02, 0xF8, 0xFF, 0x0A, 0x02, - 0x09, 0x00, 0x2D, 0x02, 0xFA, 0xFF, 0xF2, 0x13, - 0x0A, 0x06, 0xFB, 0x16, 0x60, 0x04, 0x86, 0xBD, - 0x8F, 0x07, 0x00, 0x10, 0xD9, 0xC2, 0xFA, 0x11, - 0x02, 0x16, 0x8B, 0x07, 0x00, 0x04, 0x4B, 0xC3, - 0x8D, 0x02, 0x20, 0x00, 0x02, 0x14, 0x0D, 0x02, - 0x20, 0x00, 0x8D, 0x02, 0x00, 0x04, 0x02, 0x12, - 0x0D, 0x02, 0x00, 0x04, 0x2D, 0x02, 0xF8, 0xFF, - 0x0D, 0xC8, 0x2C, 0x09, 0x2B, 0x02, 0xFF, 0x03, - 0x8B, 0x01, 0xFF, 0x03, 0x4B, 0xCE, 0x60, 0xC3, - 0x6A, 0x09, 0x60, 0x23, 0x18, 0xE0, 0x0C, 0x16, - 0x49, 0xC3, 0xDD, 0xC2, 0x0F, 0x02, 0x01, 0x01, - 0x8B, 0x01, 0x80, 0xC0, 0xD7, 0x16, 0x8F, 0x05, - 0xED, 0xC2, 0x02, 0x00, 0xD3, 0x16, 0x02, 0x10, - 0x8D, 0x07, 0xBA, 0xEA, 0x3D, 0xC8, 0xA8, 0x09, - 0x1D, 0xC8, 0xAA, 0x09, 0xCB, 0x04, 0xE0, 0x04, - 0xF8, 0x05, 0xE0, 0x04, 0x66, 0x09, 0x20, 0xC8, - 0x30, 0x0C, 0x80, 0x09, 0xA0, 0x07, 0x82, 0x09, - 0xFE, 0xDF, 0x8D, 0x07, 0xFE, 0xDF, 0xE0, 0xC3, - 0xD8, 0x07, 0xE0, 0x23, 0x16, 0xE0, 0x24, 0x16, - 0xE0, 0xC3, 0x30, 0x0C, 0x4F, 0x63, 0xFF, 0x04, - 0xFF, 0x04, 0x4D, 0x06, 0xFD, 0x16, 0x8D, 0x07, - 0xFE, 0xDF, 0x20, 0x04, 0xA2, 0xEA, 0xA0, 0xC3, - 0xA2, 0xEA, 0xEE, 0xC3, 0x12, 0x00, 0xAA, 0x16, - 0x6E, 0xC3, 0x18, 0x00, 0xAD, 0x09, 0x8C, 0x07, - 0x00, 0xE0, 0xAC, 0x09, 0x0D, 0x63, 0x0C, 0x13, - 0x6E, 0xC3, 0x18, 0x00, 0xAD, 0x09, 0x2D, 0x02, - 0x40, 0x00, 0x1D, 0x0A, 0x2D, 0x02, 0x32, 0x0C, - 0xBD, 0x07, 0xFF, 0x7F, 0x0C, 0x06, 0xFC, 0x16, - 0x20, 0xC3, 0x46, 0x04, 0x8C, 0x02, 0x80, 0x00, - 0x13, 0x1A, 0xAC, 0x02, 0x0C, 0xC8, 0x9A, 0x00, - 0xE0, 0x02, 0x80, 0x00, 0x88, 0x07, 0x80, 0x00, - 0x60, 0xC2, 0x46, 0x04, 0xA0, 0x06, 0x28, 0xAD, - 0x02, 0x10, 0x9D, 0x00, 0x05, 0x10, 0x9D, 0x00, - 0x8F, 0x07, 0x00, 0x08, 0x60, 0x04, 0x86, 0xBD, - 0x4B, 0x2D, 0x81, 0xC3, 0xC9, 0x05, 0x8F, 0x07, - 0x00, 0x10, 0x8E, 0x02, 0x02, 0x00, 0xF6, 0x11, - 0x8F, 0x07, 0x00, 0x04, 0xC9, 0x05, 0xD9, 0xC2, - 0xE0, 0x26, 0x26, 0xE0, 0x02, 0x16, 0x2B, 0x02, - 0x06, 0x00, 0x4B, 0xC6, 0x4B, 0xC3, 0xCB, 0x72, - 0x2E, 0x02, 0xFE, 0xFF, 0x8B, 0x83, 0xE6, 0x1B, - 0xCD, 0x06, 0x4D, 0x73, 0xCD, 0x82, 0xE2, 0x1B, - 0xE0, 0x04, 0x1A, 0x09, 0xE0, 0x04, 0x1C, 0x09, - 0x4D, 0xC3, 0x02, 0x13, 0x60, 0x66, 0x12, 0xE0, - 0xC9, 0x05, 0xCF, 0x04, 0x81, 0x2D, 0x01, 0xC8, - 0x6C, 0x01, 0xD4, 0x13, 0x0F, 0xC8, 0x00, 0xFC, - 0xC1, 0xC3, 0x0D, 0x06, 0xF7, 0x15, 0x0D, 0x02, - 0x36, 0x07, 0x0E, 0x02, 0x98, 0x08, 0x0C, 0x02, - 0x03, 0x00, 0x8D, 0xCB, 0x02, 0x00, 0x81, 0x2D, - 0x81, 0xCB, 0x06, 0x00, 0xC3, 0x13, 0xEE, 0x04, - 0x0C, 0x00, 0x2E, 0x02, 0x18, 0x00, 0x0C, 0x06, - 0xF4, 0x16, 0xE0, 0x04, 0x96, 0x08, 0x1F, 0x2E, - 0xB9, 0xC3, 0xD9, 0xC3, 0x89, 0x07, 0x12, 0x00, - 0x8D, 0x07, 0x3A, 0x09, 0xA0, 0x06, 0xF4, 0xBE, - 0x60, 0xC3, 0xD8, 0x07, 0x60, 0x23, 0x16, 0xE0, - 0x09, 0x16, 0x20, 0xE8, 0x10, 0xE0, 0x6A, 0x09, - 0x20, 0xE8, 0x18, 0xE0, 0x98, 0x07, 0x20, 0xE8, - 0x12, 0xE0, 0x78, 0x07, 0x60, 0xC3, 0x6A, 0x09, - 0x60, 0x23, 0x1E, 0xE0, 0x03, 0x16, 0x20, 0x48, - 0xA4, 0xE3, 0x6A, 0x09, 0x60, 0x23, 0x22, 0xE0, - 0x06, 0x13, 0x60, 0x27, 0xA6, 0xE3, 0x03, 0x13, - 0x20, 0xE8, 0x10, 0xE0, 0x6A, 0x09, 0x20, 0x2D, - 0x00, 0x00, 0x8E, 0x07, 0x00, 0x00, 0xA0, 0x06, - 0xD4, 0xBE, 0x4E, 0x05, 0x0E, 0x2C, 0xA0, 0xC0, - 0x04, 0x08, 0xEF, 0xC3, 0x06, 0x00, 0x1B, 0x16, - 0xA0, 0xC3, 0x72, 0x09, 0xE0, 0xC3, 0x74, 0x09, - 0xA0, 0x06, 0xC2, 0xBD, 0xA0, 0xC3, 0x76, 0x09, - 0xE0, 0xC3, 0x78, 0x09, 0xA0, 0x06, 0xE0, 0xBD, - 0x20, 0xE0, 0x0A, 0xE0, 0x60, 0xC3, 0xD8, 0x07, - 0x60, 0x23, 0x16, 0xE0, 0x05, 0x16, 0xE0, 0x04, - 0x2E, 0x06, 0x60, 0x41, 0x04, 0xE0, 0x4D, 0x2E, - 0x8D, 0x07, 0x00, 0x80, 0x52, 0x04, 0xCF, 0x73, - 0x2F, 0x02, 0x00, 0x02, 0x4F, 0xC3, 0x52, 0x04, - 0x20, 0x20, 0x0A, 0xE0, 0x03, 0x13, 0x8D, 0x07, - 0x00, 0x10, 0x5B, 0x04, 0x20, 0x40, 0x0A, 0xE0, - 0x40, 0x02, 0xFF, 0xF0, 0x8E, 0x07, 0x02, 0x00, - 0xA0, 0x06, 0xD4, 0xBE, 0x4E, 0x05, 0x0E, 0x2C, - 0xA0, 0xC0, 0x04, 0x08, 0xA0, 0x06, 0xB4, 0xBE, - 0x60, 0xC3, 0xD8, 0x07, 0x60, 0x23, 0x16, 0xE0, - 0x66, 0x16, 0x20, 0x04, 0xB6, 0xEA, 0x63, 0x10, - 0x6E, 0x02, 0x00, 0x80, 0x8D, 0x07, 0x00, 0xC0, - 0x0D, 0xC8, 0xA6, 0x01, 0x0E, 0xC8, 0x72, 0x09, - 0x0F, 0xC8, 0x74, 0x09, 0x0E, 0xC8, 0xA8, 0x01, - 0x0F, 0xC8, 0xAA, 0x01, 0x12, 0x10, 0x8F, 0x01, - 0x01, 0x00, 0x8A, 0x07, 0x76, 0x09, 0xA0, 0xE3, - 0x4E, 0x09, 0x8E, 0xCE, 0x9A, 0x01, 0xFE, 0xFF, - 0xE0, 0xE3, 0x50, 0x09, 0x8F, 0xE6, 0x8A, 0x07, - 0xAC, 0x01, 0x8E, 0xCE, 0x9A, 0x01, 0xFE, 0xFF, - 0x8F, 0xE6, 0x20, 0x20, 0x0A, 0xE0, 0x3F, 0x13, - 0x8D, 0x07, 0x00, 0x10, 0x5B, 0x04, 0x20, 0x20, - 0x0A, 0xE0, 0x03, 0x13, 0x0D, 0x02, 0x00, 0x10, - 0x5B, 0x04, 0x8E, 0xC3, 0x04, 0x13, 0xE0, 0x01, - 0x50, 0x09, 0x00, 0x01, 0x06, 0x10, 0xA0, 0x01, - 0x50, 0x09, 0x00, 0x01, 0xA0, 0x01, 0x78, 0x09, - 0x00, 0x01, 0xA0, 0xC3, 0x76, 0x09, 0xE0, 0xC3, - 0x78, 0x09, 0xA0, 0xE3, 0x4E, 0x09, 0xE0, 0xE3, - 0x50, 0x09, 0x0E, 0xC8, 0xAC, 0x01, 0x0F, 0xC8, - 0xAE, 0x01, 0x0E, 0xC8, 0x76, 0x09, 0x0F, 0xC8, - 0x78, 0x09, 0x19, 0x10, 0x6E, 0x02, 0x00, 0x80, - 0x0E, 0xC8, 0xA6, 0x01, 0x20, 0x20, 0x0A, 0xE0, - 0x12, 0x13, 0x0D, 0x02, 0x00, 0x10, 0x5B, 0x04, - 0x8D, 0x07, 0x28, 0x07, 0x89, 0x07, 0x0E, 0x00, - 0xA0, 0x06, 0xFA, 0xBE, 0x8D, 0x07, 0x28, 0x07, - 0xFD, 0x04, 0x8D, 0x02, 0x36, 0x07, 0xFC, 0x16, - 0x20, 0x48, 0x14, 0xE0, 0xFE, 0x06, 0x8D, 0x07, - 0x00, 0x80, 0x52, 0x04, 0xA0, 0xC2, 0xEE, 0x07, - 0x8C, 0x07, 0x04, 0x00, 0x8D, 0x07, 0xF0, 0x08, - 0x97, 0x06, 0x7D, 0xC2, 0x5D, 0xC3, 0x60, 0x43, - 0x22, 0xE0, 0xA0, 0x06, 0xFA, 0xBE, 0xEF, 0x10, - 0x0E, 0xC8, 0x06, 0x06, 0x0F, 0xC8, 0x08, 0x06, - 0xEA, 0x10, 0xB0, 0x03, 0xA0, 0x01, 0x60, 0x07, - 0x26, 0x00, 0x40, 0x02, 0x00, 0xC0, 0xE0, 0x04, - 0x06, 0x06, 0x8C, 0x07, 0x10, 0x40, 0xCC, 0x44, - 0xE0, 0x04, 0xFE, 0x06, 0x85, 0x07, 0x40, 0x80, - 0x5B, 0x04, 0x02, 0xC8, 0x04, 0x08, 0x8F, 0x07, - 0xFA, 0x07, 0xCE, 0xCB, 0x02, 0x00, 0x8E, 0x07, - 0x36, 0x07, 0xCE, 0xCB, 0x04, 0x00, 0x8D, 0x07, - 0x30, 0x06, 0x8E, 0x07, 0x10, 0x00, 0x4D, 0x2C, - 0x5B, 0x04, 0xA0, 0xC2, 0xF2, 0x07, 0x02, 0x10, - 0xA0, 0xC2, 0xF8, 0x07, 0x0B, 0xC8, 0xEA, 0x08, - 0x09, 0xC3, 0x0A, 0x13, 0xA0, 0x06, 0x36, 0xBA, - 0xA0, 0xC2, 0x00, 0x01, 0xA0, 0xE2, 0x06, 0xE0, - 0x4C, 0xA3, 0xCC, 0xA3, 0x01, 0x17, 0x8E, 0x05, - 0x4C, 0x62, 0xE0, 0xC2, 0xEA, 0x08, 0x5B, 0x04, - 0x8D, 0x07, 0x00, 0x10, 0x20, 0x20, 0x0A, 0xE0, - 0x01, 0x13, 0x5B, 0x04, 0x0D, 0x02, 0x48, 0x00, - 0xE0, 0xC3, 0x30, 0x09, 0x02, 0x16, 0xCE, 0x01, - 0x10, 0x00, 0x8D, 0x27, 0x03, 0x13, 0x0D, 0x02, - 0x00, 0x01, 0x52, 0x04, 0x00, 0x03, 0x02, 0x00, - 0x60, 0xC3, 0x6A, 0x09, 0x4D, 0x02, 0x08, 0x80, - 0x4E, 0x02, 0xF7, 0x7F, 0x8D, 0xE3, 0xE0, 0xC3, - 0xD8, 0x07, 0xE0, 0x23, 0x16, 0xE0, 0x04, 0x13, - 0x8D, 0x07, 0x06, 0x00, 0x8D, 0x27, 0x02, 0x13, - 0xA0, 0xE3, 0x10, 0xE0, 0x0E, 0xC8, 0x6A, 0x09, - 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, 0x09, 0x13, - 0x0D, 0x02, 0x00, 0x12, 0x4E, 0x01, 0x10, 0x00, - 0x02, 0x13, 0x0D, 0x02, 0x00, 0x13, 0x0D, 0xD8, - 0x2E, 0x09, 0x60, 0xC3, 0x80, 0x01, 0x4E, 0x02, - 0x01, 0x00, 0x4D, 0x02, 0xFE, 0xFF, 0x4E, 0xE3, - 0x0D, 0xC8, 0x80, 0x01, 0x20, 0xD8, 0x40, 0xE2, - 0x2F, 0x09, 0x20, 0x01, 0x6A, 0x09, 0x06, 0x00, - 0x03, 0x13, 0x20, 0xD8, 0xD0, 0xE1, 0x2F, 0x09, - 0x20, 0x98, 0x83, 0x01, 0x00, 0xE2, 0x03, 0x13, - 0x20, 0xD8, 0x2F, 0x09, 0x83, 0x01, 0x00, 0x03, - 0x0F, 0x00, 0x60, 0x04, 0x88, 0xBE, 0x20, 0x20, - 0x0A, 0xE0, 0x03, 0x13, 0x0D, 0x02, 0x00, 0x10, - 0x5B, 0x04, 0x09, 0x02, 0x08, 0x00, 0x0D, 0x02, - 0x58, 0x09, 0xA0, 0x06, 0xF4, 0xBE, 0xA0, 0x07, - 0x02, 0x02, 0x00, 0x00, 0x0D, 0x02, 0x00, 0x04, - 0xE0, 0xC3, 0x58, 0x09, 0x0F, 0x01, 0x00, 0x7C, - 0x01, 0x13, 0x52, 0x04, 0x8F, 0xC3, 0x4E, 0x02, - 0x0F, 0x00, 0xFB, 0x13, 0x8E, 0x02, 0x0F, 0x00, - 0xF8, 0x13, 0x0D, 0x02, 0x00, 0x40, 0x4F, 0xC2, - 0x49, 0x09, 0x49, 0x02, 0x3F, 0x00, 0x09, 0x01, - 0x01, 0x00, 0xEF, 0x16, 0x89, 0x02, 0x06, 0x00, - 0xEC, 0x1A, 0x89, 0x02, 0x20, 0x00, 0xE9, 0x14, - 0xC9, 0x06, 0x1F, 0x09, 0x4F, 0x02, 0x00, 0x40, - 0x4F, 0xE2, 0x69, 0x02, 0x00, 0x80, 0x09, 0xC8, - 0x58, 0x09, 0x0F, 0x02, 0xFF, 0xFF, 0x4E, 0xC2, - 0x1F, 0x09, 0x09, 0x06, 0xFD, 0x16, 0x4F, 0x05, - 0x0D, 0x02, 0x00, 0x20, 0x60, 0xC2, 0x5A, 0x09, - 0xD4, 0x13, 0x4F, 0x26, 0xD2, 0x16, 0x0D, 0x02, - 0x00, 0x10, 0x60, 0xC2, 0x5C, 0x09, 0xCD, 0x13, - 0x4F, 0x26, 0xCB, 0x16, 0x0D, 0x02, 0x00, 0x30, - 0x20, 0x88, 0x5A, 0x09, 0x5C, 0x09, 0xC5, 0x13, - 0xE0, 0xC3, 0x5A, 0x09, 0x4E, 0xC2, 0x1F, 0x0A, - 0x09, 0x06, 0xFD, 0x16, 0xE0, 0xE3, 0x5E, 0x09, - 0x0F, 0xC8, 0x5A, 0x09, 0xE0, 0xC3, 0x5C, 0x09, - 0x4E, 0xC2, 0x1F, 0x0A, 0x09, 0x06, 0xFD, 0x16, - 0xE0, 0xE3, 0x5E, 0x09, 0x0F, 0xC8, 0x5C, 0x09, - 0x0F, 0x02, 0xFF, 0xFF, 0x4E, 0xC2, 0x1F, 0x0A, - 0x09, 0x06, 0xFD, 0x16, 0x0D, 0x02, 0x00, 0x08, - 0x60, 0xC2, 0x5E, 0x09, 0x4F, 0x26, 0xA5, 0x16, - 0x4F, 0x05, 0x0F, 0xC8, 0x5E, 0x09, 0x0F, 0x02, - 0x02, 0x02, 0x0E, 0x02, 0x03, 0x00, 0x60, 0xC3, - 0x40, 0x01, 0x0C, 0x02, 0xFE, 0xC0, 0xA0, 0x01, - 0x40, 0x01, 0x00, 0x04, 0xCF, 0x05, 0x09, 0x02, - 0x55, 0x55, 0x9C, 0x06, 0x49, 0x05, 0x9C, 0x06, - 0x09, 0x07, 0x9C, 0x06, 0x49, 0x05, 0x9C, 0x06, - 0x0E, 0x06, 0xF4, 0x16, 0xA0, 0x01, 0x40, 0x01, - 0x00, 0x40, 0x0D, 0xC8, 0x40, 0x01, 0x09, 0x02, - 0x08, 0x00, 0x0E, 0x02, 0x58, 0x09, 0x0F, 0x02, - 0x02, 0x02, 0xFE, 0xCF, 0x49, 0x06, 0xFD, 0x16, - 0x60, 0x04, 0x88, 0xBE, 0xC9, 0xC7, 0x5F, 0x82, - 0x01, 0x16, 0x5B, 0x04, 0xA0, 0x01, 0x40, 0x01, - 0x00, 0x40, 0x0D, 0xC8, 0x40, 0x01, 0x0D, 0x02, - 0x00, 0x01, 0x52, 0x04, 0x8D, 0x07, 0x00, 0x10, - 0x20, 0x20, 0x0A, 0xE0, 0x0A, 0x16, 0x8D, 0x07, - 0x00, 0x08, 0x20, 0x20, 0x10, 0xE0, 0x05, 0x13, - 0x8D, 0x07, 0x00, 0x40, 0x4F, 0x01, 0x01, 0x00, - 0x01, 0x16, 0x5B, 0x04, 0x20, 0xE0, 0x10, 0xE0, - 0x20, 0x07, 0x9C, 0x08, 0x20, 0x07, 0xB4, 0x08, - 0x20, 0x07, 0xCC, 0x08, 0xA0, 0x07, 0xA2, 0x08, - 0x84, 0x02, 0xA0, 0x07, 0xBA, 0x08, 0x84, 0x02, - 0xA0, 0x07, 0xD2, 0x08, 0x84, 0x02, 0xA0, 0x07, - 0x04, 0x09, 0x00, 0x40, 0xE0, 0x04, 0x06, 0x09, - 0xE0, 0x04, 0x08, 0x09, 0x0E, 0xC8, 0x4C, 0x08, - 0x0F, 0xC8, 0x4E, 0x08, 0x0E, 0xC8, 0x8E, 0x08, - 0x0F, 0xC8, 0x90, 0x08, 0xE0, 0x04, 0x5A, 0x08, - 0xE0, 0x04, 0x60, 0x08, 0xE0, 0x02, 0x78, 0x07, - 0xE0, 0x04, 0x94, 0x08, 0x20, 0x40, 0x40, 0xE3, - 0x20, 0xE0, 0x0C, 0xE0, 0x60, 0x04, 0xBC, 0xC6, - 0x80, 0x01, 0x00, 0xF0, 0xC0, 0x01, 0x00, 0x40, - 0x10, 0x10, 0x80, 0x01, 0x00, 0xF0, 0x0D, 0x10, - 0xC0, 0x01, 0x00, 0xF0, 0x20, 0x40, 0x06, 0xE0, - 0x08, 0x10, 0xC0, 0x01, 0x00, 0xF0, 0x80, 0x01, - 0x00, 0x20, 0xE0, 0xC3, 0x94, 0x08, 0x01, 0x16, - 0x5B, 0x04, 0x4B, 0xC0, 0x20, 0x04, 0xDA, 0xEA, - 0x40, 0x01, 0x00, 0x20, 0xFB, 0x16, 0x51, 0x04, - 0xA0, 0xC2, 0xD8, 0x07, 0x4A, 0x01, 0x40, 0x00, - 0x01, 0x16, 0x5B, 0x04, 0xE0, 0x02, 0x78, 0x07, - 0x20, 0x20, 0x0C, 0xE0, 0xEF, 0x16, 0x43, 0xC2, - 0x02, 0x13, 0xA0, 0x06, 0x1A, 0xC3, 0x20, 0x2F, - 0x36, 0x07, 0x20, 0x40, 0x0C, 0xE0, 0xA0, 0x06, - 0xAC, 0xC1, 0xA0, 0xC3, 0x94, 0x08, 0xFB, 0x16, - 0xA0, 0x06, 0x3A, 0xC2, 0x8E, 0x07, 0x04, 0x09, - 0x9E, 0x07, 0x00, 0x80, 0x20, 0x20, 0x10, 0xE0, - 0x05, 0x16, 0x8F, 0x07, 0x4C, 0x08, 0xBF, 0xCF, - 0xBF, 0xCF, 0x9F, 0xC7, 0xA0, 0x06, 0x5A, 0xC2, - 0x20, 0xE8, 0x3C, 0xE3, 0x62, 0x07, 0xA0, 0x06, - 0x3A, 0xC2, 0x20, 0x48, 0x3C, 0xE3, 0x62, 0x07, - 0x20, 0x40, 0x40, 0xE3, 0x20, 0xE0, 0x04, 0xE0, - 0x20, 0x48, 0x10, 0xE0, 0x58, 0x07, 0x5B, 0x04, - 0x80, 0x01, 0x00, 0xF0, 0x20, 0xE0, 0x04, 0xE0, - 0x60, 0x01, 0x60, 0x07, 0x02, 0x00, 0x02, 0x13, - 0x9B, 0x06, 0xB8, 0x10, 0x20, 0xE8, 0x1E, 0xE0, - 0x58, 0x07, 0xB4, 0x10, 0x9B, 0x06, 0x80, 0x03, - 0xE0, 0x02, 0x58, 0x07, 0x00, 0x01, 0x00, 0x40, - 0x07, 0x16, 0x8D, 0x07, 0x00, 0x09, 0xA0, 0x06, - 0x68, 0xB8, 0xE0, 0x02, 0x78, 0x07, 0x5B, 0x04, - 0xC4, 0x01, 0x02, 0x00, 0xE0, 0x02, 0x78, 0x07, - 0x5B, 0x04, 0x0E, 0x68, 0x96, 0x08, 0xE9, 0x04, - 0x0C, 0x00, 0x11, 0x10, 0x0E, 0x02, 0x00, 0x23, - 0x4E, 0xDB, 0x01, 0x00, 0xCC, 0x01, 0x00, 0x04, - 0x4C, 0xD7, 0x1C, 0x10, 0x60, 0xC2, 0x5C, 0x07, - 0x20, 0x06, 0x94, 0x08, 0xA9, 0xC2, 0x08, 0x00, - 0xA9, 0xC3, 0x0C, 0x00, 0xEA, 0x16, 0x29, 0x07, - 0x04, 0x00, 0x69, 0x01, 0x0A, 0x00, 0x01, 0x00, - 0x2D, 0x13, 0x49, 0xC3, 0x2D, 0x02, 0x0E, 0x00, - 0x0A, 0xC3, 0x1D, 0xD3, 0x8C, 0x01, 0x00, 0x84, - 0xCC, 0x01, 0x00, 0x40, 0x0A, 0x01, 0x00, 0x5E, - 0xDD, 0x16, 0x4C, 0xC7, 0xA9, 0xC3, 0x10, 0x00, - 0xE9, 0xC3, 0x12, 0x00, 0x41, 0xCA, 0x10, 0x00, - 0x2F, 0x02, 0x04, 0x00, 0x01, 0x17, 0x8E, 0x05, - 0x8C, 0x07, 0x02, 0x00, 0xA0, 0xC2, 0xF6, 0x07, - 0xA0, 0x06, 0x00, 0xBA, 0x69, 0xC0, 0x10, 0x00, - 0x29, 0xC8, 0x14, 0x00, 0x06, 0x09, 0x29, 0xC8, - 0x16, 0x00, 0x08, 0x09, 0x69, 0x01, 0x0E, 0x00, - 0x00, 0x08, 0x04, 0x16, 0x90, 0x03, 0x7F, 0x00, - 0xA0, 0x06, 0x5A, 0xC2, 0x40, 0x01, 0x00, 0x40, - 0x01, 0x16, 0x51, 0x04, 0x60, 0x04, 0xBE, 0xC1, - 0xA9, 0xC3, 0x0C, 0x00, 0x0B, 0x13, 0x0E, 0x68, - 0x96, 0x08, 0xE9, 0x04, 0x0C, 0x00, 0x29, 0xC8, - 0x06, 0x00, 0x6C, 0x01, 0xA0, 0xC3, 0x00, 0xFC, - 0x01, 0x13, 0x1E, 0x2E, 0x29, 0x07, 0x04, 0x00, - 0x5B, 0x04, 0x81, 0x07, 0x20, 0x20, 0x89, 0x07, - 0x4C, 0x08, 0x41, 0xCE, 0x63, 0xCE, 0x10, 0x00, - 0x63, 0xC6, 0x12, 0x00, 0xA0, 0x06, 0x54, 0xBA, - 0x43, 0xC2, 0x02, 0x13, 0xA0, 0x06, 0x1A, 0xC3, - 0x20, 0xE0, 0x10, 0xE0, 0x60, 0x04, 0xEC, 0xC1, - 0x40, 0x01, 0x00, 0x04, 0xEA, 0x16, 0xA0, 0x06, - 0xAC, 0xC1, 0xA0, 0xC2, 0xF0, 0x07, 0x8C, 0x07, - 0x04, 0x00, 0x8D, 0x07, 0x4C, 0x08, 0xA0, 0xC3, - 0x8E, 0x08, 0xE0, 0xC3, 0x90, 0x08, 0xA0, 0x06, - 0x36, 0xBA, 0xE0, 0xC3, 0x4E, 0x08, 0x4F, 0x01, - 0x01, 0x00, 0x13, 0x16, 0xE0, 0xC2, 0x94, 0x08, - 0xEA, 0x16, 0x60, 0x04, 0xEC, 0xC1, 0xE0, 0xC3, - 0x4E, 0x08, 0x4F, 0x01, 0x01, 0x00, 0x09, 0x16, - 0x60, 0x04, 0xEC, 0xC1, 0xA0, 0x06, 0x54, 0xBA, - 0xE0, 0xC3, 0x4E, 0x08, 0x4F, 0x01, 0x01, 0x00, - 0xD7, 0x13, 0xA0, 0xC2, 0xF0, 0x07, 0x20, 0xC3, - 0x7C, 0x09, 0x8D, 0x07, 0x4C, 0x08, 0x9D, 0xC3, - 0xA0, 0x06, 0x36, 0xBA, 0xC0, 0x06, 0x20, 0xD0, - 0x50, 0x08, 0xC0, 0x06, 0x40, 0x01, 0x00, 0x04, - 0x0A, 0x16, 0x40, 0x01, 0x80, 0x00, 0x07, 0x13, - 0x0E, 0xC8, 0x4C, 0x08, 0x0F, 0xC8, 0x4E, 0x08, - 0xA0, 0x06, 0xA2, 0xC1, 0xD8, 0x10, 0x0E, 0xC8, - 0x8E, 0x08, 0x0F, 0xC8, 0x90, 0x08, 0x40, 0x01, - 0x00, 0x04, 0x0C, 0x13, 0x40, 0x01, 0x20, 0x00, - 0x58, 0x16, 0x81, 0x07, 0x10, 0x20, 0x9F, 0x10, - 0xA0, 0x06, 0xAC, 0xC1, 0xA0, 0xC3, 0x8E, 0x08, - 0xE0, 0xC3, 0x90, 0x08, 0x83, 0x07, 0x98, 0x08, - 0x63, 0x07, 0x04, 0x00, 0x2D, 0x11, 0x83, 0x07, - 0xB0, 0x08, 0x63, 0x07, 0x04, 0x00, 0x28, 0x11, - 0x83, 0x07, 0xC8, 0x08, 0x63, 0x07, 0x04, 0x00, - 0x23, 0x11, 0xC3, 0x60, 0x60, 0xC2, 0x46, 0x07, - 0xE7, 0x13, 0x69, 0x01, 0x0E, 0x00, 0x00, 0x08, - 0xE3, 0x13, 0x00, 0x03, 0x02, 0x00, 0x19, 0xC8, - 0x46, 0x07, 0x03, 0x16, 0xA0, 0x01, 0x3A, 0x07, - 0x20, 0x00, 0x00, 0x03, 0x0F, 0x00, 0xC0, 0x01, - 0x00, 0xF0, 0x80, 0x01, 0x00, 0x20, 0x01, 0x02, - 0x06, 0xC4, 0x60, 0x04, 0x9A, 0xC2, 0x81, 0x07, - 0x80, 0x20, 0xE0, 0xC8, 0x8E, 0x08, 0x14, 0x00, - 0xE0, 0xC8, 0x90, 0x08, 0x16, 0x00, 0xC7, 0x10, - 0xE0, 0xC8, 0x50, 0x08, 0x0E, 0x00, 0xCE, 0xC8, - 0x10, 0x00, 0xCF, 0xC8, 0x12, 0x00, 0x40, 0x01, - 0x20, 0x00, 0xBB, 0x16, 0xE3, 0xC1, 0x06, 0x00, - 0xC7, 0xC8, 0x08, 0x00, 0x07, 0xC8, 0x6C, 0x01, - 0x07, 0xC8, 0xE0, 0x08, 0x08, 0x02, 0x02, 0xFC, - 0xB8, 0x07, 0x00, 0x81, 0xE0, 0xC1, 0xE8, 0x00, - 0x07, 0xCE, 0x20, 0xC8, 0x52, 0x08, 0x92, 0x08, - 0xDA, 0x13, 0xCE, 0xC8, 0x14, 0x00, 0xCF, 0xC8, - 0x16, 0x00, 0x80, 0x01, 0x00, 0x04, 0x82, 0x07, - 0x54, 0x08, 0x32, 0xC1, 0x08, 0x11, 0x72, 0xC1, - 0x92, 0xC1, 0x82, 0x07, 0x8A, 0x08, 0x04, 0xC1, - 0x07, 0x16, 0x60, 0x04, 0x8E, 0xC5, 0x72, 0xC1, - 0xB2, 0xC1, 0x84, 0x01, 0x00, 0x80, 0xF9, 0x13, - 0x04, 0x68, 0x92, 0x08, 0xC7, 0xC1, 0x37, 0x16, - 0x20, 0x98, 0x97, 0x08, 0x85, 0x09, 0x16, 0x16, - 0x81, 0x07, 0x40, 0x20, 0xE0, 0xC1, 0x94, 0x08, - 0x57, 0x13, 0xA0, 0x06, 0xAC, 0xC1, 0xF4, 0x10, - 0xE0, 0xC2, 0x3A, 0x07, 0xE0, 0x42, 0x62, 0x07, - 0xE0, 0x26, 0x3A, 0xE3, 0x02, 0x13, 0xA0, 0x06, - 0x92, 0xC1, 0xA0, 0x06, 0x54, 0xBA, 0x22, 0x10, - 0xA0, 0x06, 0x9C, 0xC1, 0x81, 0x2D, 0x01, 0xC2, - 0xFB, 0x13, 0xA0, 0x05, 0x96, 0x08, 0x23, 0xC8, - 0x08, 0x00, 0x6C, 0x01, 0xA0, 0x07, 0x02, 0xFC, - 0x00, 0x80, 0xC3, 0xC1, 0x27, 0x02, 0x06, 0x00, - 0xA0, 0x06, 0x0C, 0xB5, 0xA3, 0x05, 0x0C, 0x00, - 0x08, 0xC8, 0x6C, 0x01, 0x08, 0xC8, 0xE0, 0x08, - 0x08, 0x02, 0x02, 0xFC, 0xB8, 0x07, 0x00, 0x81, - 0xF8, 0xC1, 0x04, 0xC1, 0x37, 0x13, 0xE0, 0xD2, - 0x03, 0x01, 0xD2, 0x13, 0x0B, 0x02, 0x0A, 0x01, - 0xC4, 0xCE, 0xC7, 0xCE, 0xC5, 0xCE, 0xC6, 0xCE, - 0xFB, 0x04, 0x09, 0x02, 0x00, 0x04, 0x48, 0xA2, - 0xC9, 0xC6, 0x20, 0xA8, 0xE0, 0x08, 0x12, 0x01, - 0x20, 0xC8, 0xF2, 0x07, 0x00, 0x01, 0x47, 0xC2, - 0xC4, 0x81, 0x01, 0x14, 0x44, 0xC2, 0xC9, 0x61, - 0x09, 0xA2, 0x89, 0xA1, 0x01, 0x17, 0x85, 0x05, - 0x09, 0x61, 0xA8, 0x16, 0x82, 0x02, 0x8A, 0x08, - 0x05, 0x16, 0x40, 0x01, 0x10, 0x00, 0x12, 0x13, - 0x60, 0x04, 0xA6, 0xC3, 0x60, 0x04, 0xBC, 0xC4, - 0x60, 0x04, 0x40, 0xC3, 0x81, 0x07, 0x80, 0x20, - 0xFB, 0x10, 0x81, 0x07, 0x80, 0x20, 0xF8, 0x10, - 0x81, 0x07, 0x02, 0x20, 0xF5, 0x10, 0x81, 0x07, - 0x04, 0x20, 0xF2, 0x10, 0x23, 0xC8, 0x08, 0x00, - 0x6C, 0x01, 0x07, 0x05, 0xE0, 0xA1, 0xE8, 0x00, - 0x0C, 0x02, 0x04, 0xFC, 0x07, 0xCF, 0xE0, 0xC2, - 0x92, 0x08, 0xE8, 0x16, 0xE0, 0xD2, 0x03, 0x01, - 0x10, 0x16, 0xE0, 0xC2, 0x3A, 0x07, 0xE0, 0x42, - 0x62, 0x07, 0xE0, 0x26, 0x3A, 0xE3, 0x07, 0x13, - 0x90, 0x03, 0xC8, 0x2F, 0xA0, 0x06, 0x92, 0xC1, - 0xE0, 0xD2, 0x03, 0x01, 0x02, 0x16, 0xA0, 0x06, - 0x54, 0xBA, 0x23, 0xC8, 0x06, 0x00, 0x6C, 0x01, - 0xA3, 0xC2, 0x0E, 0x00, 0x4A, 0x01, 0x00, 0x01, - 0x0B, 0x13, 0x0C, 0x02, 0x0E, 0xFC, 0x5C, 0xC2, - 0x49, 0x02, 0x00, 0x80, 0x0D, 0x02, 0x6C, 0x09, - 0x7D, 0xE2, 0x09, 0xCF, 0x3D, 0xCF, 0x3D, 0xCF, - 0x0C, 0x02, 0x00, 0xFC, 0x6C, 0xC3, 0x06, 0x00, - 0x4D, 0x02, 0xFF, 0xE0, 0x4A, 0x02, 0x00, 0x02, - 0x8A, 0xA2, 0x8A, 0xA2, 0x4A, 0xE3, 0x60, 0xE3, - 0x9E, 0x09, 0x0D, 0xCB, 0x06, 0x00, 0xCD, 0x06, - 0x0B, 0x02, 0x0F, 0x00, 0xEC, 0x82, 0x04, 0x00, - 0xAD, 0x11, 0xEC, 0xC3, 0x0E, 0x00, 0x11, 0x15, - 0x10, 0x13, 0x6C, 0xC2, 0x14, 0x00, 0x49, 0x02, - 0x00, 0x1F, 0xA7, 0x13, 0xC9, 0x06, 0x89, 0x02, - 0x12, 0x00, 0xA3, 0x1B, 0x49, 0x01, 0x01, 0x00, - 0xA0, 0x13, 0xC9, 0xA2, 0xEC, 0x82, 0x04, 0x00, - 0x9C, 0x11, 0x4D, 0xA3, 0x9D, 0x18, 0x14, 0x11, - 0x60, 0x01, 0x6A, 0x09, 0x00, 0x80, 0x18, 0x13, - 0x1D, 0x09, 0xCC, 0xA2, 0xEB, 0xC2, 0x08, 0x00, - 0x7B, 0x09, 0x4B, 0x02, 0x1E, 0x00, 0xA0, 0xC3, - 0xF0, 0x06, 0xAB, 0x23, 0x04, 0xE0, 0x8F, 0x16, - 0x60, 0x27, 0x3E, 0xE3, 0x8C, 0x16, 0x4D, 0xA3, - 0x4D, 0xA3, 0x4D, 0xA3, 0xCD, 0x06, 0x4D, 0x02, - 0x07, 0x00, 0x0D, 0x88, 0xEE, 0x06, 0x0A, 0x15, - 0x90, 0x03, 0xFF, 0x6F, 0x53, 0x2F, 0xA0, 0x05, - 0x94, 0x08, 0xC3, 0x04, 0xC0, 0x01, 0x00, 0x04, - 0x60, 0x04, 0xAA, 0xC3, 0x60, 0x01, 0x6A, 0x09, - 0x00, 0x80, 0xF2, 0x13, 0x01, 0x02, 0x08, 0x20, - 0x60, 0x04, 0xA2, 0xC5, 0x8D, 0x07, 0x00, 0x10, - 0x20, 0x20, 0x0A, 0xE0, 0x0A, 0x16, 0x8D, 0x07, - 0x00, 0x08, 0x20, 0x20, 0x0E, 0xE0, 0x05, 0x13, - 0x8D, 0x07, 0x00, 0x40, 0x4F, 0x01, 0x01, 0x00, - 0x01, 0x16, 0x5B, 0x04, 0x20, 0xE0, 0x0E, 0xE0, - 0xA0, 0x07, 0xFA, 0x08, 0x00, 0x80, 0x0E, 0xC8, - 0xFA, 0x07, 0x0F, 0xC8, 0xFC, 0x07, 0x0E, 0xC8, - 0x3C, 0x08, 0x0F, 0xC8, 0x3E, 0x08, 0xE0, 0x04, - 0x08, 0x08, 0xE0, 0x04, 0x0E, 0x08, 0xE0, 0x02, - 0x98, 0x07, 0x20, 0x40, 0x4C, 0xE3, 0x20, 0x07, - 0x2E, 0x06, 0x60, 0x04, 0x12, 0xCA, 0x00, 0x70, - 0x4B, 0xC0, 0xE0, 0x04, 0x2E, 0x06, 0x0B, 0x10, - 0x20, 0xF0, 0x4B, 0xE3, 0x02, 0x10, 0x20, 0xF0, - 0x4A, 0xE3, 0x4B, 0xC0, 0xE0, 0x04, 0x2E, 0x06, - 0xE0, 0x01, 0x62, 0x07, 0x40, 0x00, 0x20, 0xE8, - 0x46, 0xE3, 0x62, 0x07, 0x20, 0x04, 0xDA, 0xEA, - 0x40, 0x01, 0x00, 0x20, 0x04, 0x13, 0xFA, 0x10, - 0x40, 0x01, 0x00, 0x40, 0xF7, 0x16, 0x20, 0x07, - 0x2E, 0x06, 0x20, 0x50, 0x50, 0xE3, 0x51, 0x04, - 0xF1, 0x10, 0xE0, 0x02, 0x58, 0x07, 0x00, 0x01, - 0x00, 0x40, 0x07, 0x16, 0x8D, 0x07, 0xF6, 0x08, - 0xA0, 0x06, 0x68, 0xB8, 0xE0, 0x02, 0x98, 0x07, - 0x5B, 0x04, 0xC4, 0x01, 0x04, 0x00, 0xE0, 0x02, - 0x98, 0x07, 0x5B, 0x04, 0x60, 0x01, 0x60, 0x07, - 0x04, 0x00, 0x06, 0x16, 0x20, 0xE8, 0x1C, 0xE0, - 0x58, 0x07, 0x80, 0x03, 0xE0, 0x02, 0x98, 0x07, - 0x20, 0xD8, 0xDC, 0x07, 0x17, 0x01, 0x8F, 0x07, - 0x8E, 0xFF, 0x0F, 0xC8, 0x04, 0x01, 0x20, 0xE8, - 0x06, 0xE0, 0x58, 0x07, 0x80, 0x01, 0x00, 0x80, - 0x5B, 0x04, 0xE0, 0xC2, 0x4A, 0x08, 0xC3, 0x82, - 0x03, 0x13, 0xDB, 0x2D, 0x03, 0xC8, 0x4A, 0x08, - 0x49, 0x01, 0x00, 0x01, 0x02, 0x16, 0x60, 0x04, - 0x52, 0xC9, 0xE0, 0xC0, 0xF8, 0x05, 0xFD, 0x13, - 0x03, 0xC8, 0x6C, 0x01, 0x20, 0xC8, 0x00, 0xFC, - 0xF8, 0x05, 0x88, 0x07, 0x02, 0xFC, 0x78, 0xC2, - 0xF8, 0xC1, 0x28, 0x02, 0x00, 0x04, 0x49, 0x01, - 0x00, 0x01, 0x4D, 0x16, 0x09, 0x01, 0x00, 0x5E, - 0x29, 0x16, 0x49, 0x01, 0x02, 0x00, 0x0B, 0x16, - 0x60, 0x01, 0x46, 0x08, 0x00, 0x02, 0x0A, 0x16, - 0x27, 0x02, 0x04, 0x00, 0x07, 0x88, 0x7E, 0x09, - 0x05, 0x12, 0x27, 0x02, 0xFC, 0xFF, 0xA0, 0x01, - 0x46, 0x08, 0x00, 0x02, 0xC7, 0xC1, 0x37, 0x15, - 0xD3, 0x2D, 0xE0, 0xC0, 0x4A, 0x08, 0x07, 0xA8, - 0x48, 0x08, 0x07, 0xA8, 0x44, 0x08, 0x0C, 0x15, - 0x20, 0xC8, 0x3C, 0x08, 0xFA, 0x07, 0x20, 0xC8, - 0x3E, 0x08, 0xFC, 0x07, 0x20, 0xC8, 0x40, 0x08, - 0x3C, 0x08, 0x20, 0xC8, 0x42, 0x08, 0x3E, 0x08, - 0x60, 0x04, 0x52, 0xC9, 0xA0, 0x06, 0x54, 0xBA, - 0xD3, 0x2D, 0xE0, 0xC2, 0x4A, 0x08, 0xC3, 0x82, - 0x01, 0x13, 0xDB, 0x2D, 0x20, 0x88, 0x3E, 0x08, - 0x3A, 0x08, 0x0D, 0x16, 0x20, 0x88, 0x3C, 0x08, - 0x38, 0x08, 0x09, 0x16, 0xE0, 0x04, 0x44, 0x08, - 0x82, 0x07, 0x02, 0x08, 0x04, 0x61, 0xE0, 0x04, - 0x48, 0x08, 0x60, 0x04, 0x1E, 0xCA, 0x20, 0xC8, - 0x38, 0x08, 0xFA, 0x07, 0x20, 0xC8, 0x3A, 0x08, - 0xFC, 0x07, 0x60, 0x04, 0x12, 0xCA, 0x07, 0xA8, - 0x48, 0x08, 0x04, 0xC1, 0x1B, 0x16, 0x82, 0x02, - 0x38, 0x08, 0x0A, 0x16, 0x60, 0x01, 0xFC, 0x07, - 0x01, 0x00, 0x02, 0x16, 0xA0, 0x06, 0x6E, 0xCB, - 0xA0, 0x06, 0xFC, 0xCA, 0x80, 0x01, 0x10, 0x00, - 0x32, 0xC1, 0x07, 0x11, 0x72, 0xC1, 0x92, 0xC1, - 0x82, 0x07, 0x38, 0x08, 0x04, 0xC1, 0x06, 0x16, - 0xEA, 0x10, 0x72, 0xC1, 0xB2, 0xC1, 0x84, 0x01, - 0x00, 0x80, 0xE5, 0x13, 0xE0, 0xD2, 0x03, 0x01, - 0x34, 0x13, 0x0B, 0x02, 0x0A, 0x01, 0xC4, 0xCE, - 0xC7, 0xCE, 0xC5, 0xCE, 0xC6, 0xCE, 0xFB, 0x04, - 0xC8, 0xC6, 0x03, 0xA8, 0x12, 0x01, 0x20, 0xC8, - 0xF8, 0x07, 0x00, 0x01, 0xC7, 0xC2, 0xC4, 0x81, - 0x01, 0x14, 0xC4, 0xC2, 0x0B, 0xA8, 0x44, 0x08, - 0x0B, 0x61, 0x0B, 0xA2, 0x8B, 0xA1, 0x01, 0x17, - 0x85, 0x05, 0xCB, 0x61, 0xC6, 0x16, 0x40, 0x01, - 0x40, 0x00, 0x15, 0x16, 0x87, 0x07, 0x20, 0x00, - 0xE0, 0x61, 0x44, 0x08, 0xC4, 0x81, 0x08, 0x1A, - 0x07, 0xA8, 0x48, 0x08, 0x07, 0xA8, 0x44, 0x08, - 0x07, 0x61, 0x87, 0xA1, 0x01, 0x17, 0x85, 0x05, - 0x80, 0x01, 0x40, 0x00, 0x03, 0xC8, 0x6C, 0x01, - 0xE0, 0xC1, 0x04, 0xFC, 0xAC, 0x10, 0x60, 0x04, - 0xBC, 0xC7, 0x20, 0x01, 0x3A, 0x07, 0x00, 0x70, - 0x04, 0x13, 0xA0, 0x06, 0x28, 0xC7, 0x20, 0x07, - 0x2E, 0x06, 0xA0, 0x06, 0x54, 0xBA, 0xC1, 0x10, - 0xE0, 0xD2, 0x03, 0x01, 0x0A, 0x16, 0x20, 0x01, - 0x3A, 0x07, 0x00, 0x70, 0x04, 0x13, 0xA0, 0x06, - 0x28, 0xC7, 0x20, 0x07, 0x2E, 0x06, 0xA0, 0x06, - 0x54, 0xBA, 0x90, 0x03, 0xBF, 0x4F, 0xD3, 0x2D, - 0x60, 0x01, 0xFC, 0x07, 0x01, 0x00, 0x02, 0x16, - 0xA0, 0x06, 0x6E, 0xCB, 0x60, 0xD2, 0x46, 0x08, - 0x89, 0x01, 0x00, 0xF1, 0xC9, 0x01, 0x00, 0x70, - 0x40, 0x01, 0x10, 0x00, 0x1C, 0x13, 0x20, 0x88, - 0x3E, 0x08, 0x3A, 0x08, 0x04, 0x16, 0x20, 0x88, - 0x3C, 0x08, 0x38, 0x08, 0x14, 0x13, 0x89, 0x01, - 0x00, 0x10, 0x8D, 0x07, 0x44, 0x08, 0x9D, 0x07, - 0x00, 0x50, 0xA0, 0xC2, 0xF6, 0x07, 0x8C, 0x07, - 0x02, 0x00, 0xA0, 0xC3, 0x3C, 0x08, 0xE0, 0xC3, - 0x3E, 0x08, 0x2F, 0x02, 0x04, 0x00, 0x01, 0x17, - 0x8E, 0x05, 0xA0, 0x06, 0x00, 0xBA, 0x8D, 0x07, - 0x46, 0x08, 0x49, 0xC7, 0xA0, 0xC2, 0xF6, 0x07, - 0x8C, 0x07, 0x04, 0x00, 0xA0, 0xC3, 0x38, 0x08, - 0xE0, 0xC3, 0x3A, 0x08, 0xCC, 0xA3, 0x01, 0x17, - 0x8E, 0x05, 0xA0, 0x06, 0x00, 0xBA, 0x20, 0xC8, - 0x3C, 0x08, 0xFC, 0x08, 0x20, 0xC8, 0x3E, 0x08, - 0xFE, 0x08, 0x09, 0x01, 0x00, 0x0C, 0x0C, 0x13, - 0x49, 0x01, 0x00, 0x04, 0x05, 0x16, 0xA0, 0x06, - 0x6C, 0xC7, 0xA0, 0x06, 0x38, 0xC7, 0x04, 0x10, - 0x90, 0x03, 0x7F, 0x40, 0xA0, 0x06, 0x6C, 0xC7, - 0xC0, 0x01, 0x90, 0x00, 0xA0, 0x06, 0xFC, 0xCA, - 0x0B, 0xC8, 0x46, 0x08, 0xE0, 0xC2, 0x42, 0x07, - 0x2D, 0x13, 0xE0, 0xC2, 0x2E, 0x06, 0x2A, 0x13, - 0xE0, 0x02, 0x58, 0x07, 0x8F, 0x07, 0xBF, 0xFF, - 0x0F, 0x2C, 0xE0, 0x02, 0x98, 0x07, 0xE0, 0xC0, - 0x5C, 0x07, 0x03, 0xC8, 0x4A, 0x08, 0x03, 0xC8, - 0x6C, 0x01, 0xC3, 0xC2, 0xCB, 0xA2, 0xEB, 0xC2, - 0x32, 0x0C, 0x32, 0x13, 0x0B, 0xC8, 0x00, 0xFC, - 0x0B, 0xC3, 0x4B, 0xC3, 0x0B, 0xC8, 0x6C, 0x01, - 0xE0, 0xC2, 0x00, 0xFC, 0xFA, 0x16, 0x00, 0x03, - 0x02, 0x00, 0x20, 0xC8, 0xF8, 0x05, 0x00, 0xFC, - 0x02, 0x16, 0x0D, 0xC8, 0xFA, 0x05, 0x0C, 0xC8, - 0xF8, 0x05, 0x00, 0x03, 0x0F, 0x00, 0x03, 0xC8, - 0x6C, 0x01, 0x1A, 0x10, 0xA0, 0xC3, 0x2E, 0x06, - 0x03, 0x13, 0xE0, 0xC0, 0xF8, 0x05, 0x0D, 0x16, - 0x4F, 0x2E, 0xC0, 0x01, 0x00, 0x80, 0xA0, 0x01, - 0x62, 0x07, 0x00, 0x80, 0x8E, 0xC3, 0x03, 0x13, - 0xA0, 0x01, 0x62, 0x07, 0x40, 0x00, 0x60, 0x04, - 0x4E, 0xC7, 0x03, 0xC8, 0x6C, 0x01, 0x20, 0xC8, - 0x00, 0xFC, 0xF8, 0x05, 0x03, 0xC8, 0x4A, 0x08, - 0x60, 0x01, 0x6A, 0x09, 0x00, 0x04, 0x02, 0x13, - 0x60, 0x04, 0xE4, 0xC7, 0x8C, 0x07, 0x0E, 0x00, - 0x20, 0xC2, 0x0E, 0xFC, 0x0A, 0x15, 0x09, 0x13, - 0x20, 0xC2, 0x14, 0xFC, 0x48, 0x02, 0x00, 0x1F, - 0xC8, 0x06, 0x88, 0x02, 0x12, 0x00, 0xF0, 0x1B, - 0x08, 0xA3, 0x88, 0x07, 0x02, 0xFC, 0x78, 0xC2, - 0xF8, 0xC1, 0x28, 0x02, 0x00, 0x04, 0x07, 0x83, - 0xE7, 0x1A, 0xCC, 0x61, 0x07, 0xC8, 0x04, 0xFC, - 0xCC, 0xC1, 0xC0, 0x01, 0x40, 0x00, 0x60, 0x04, - 0xF0, 0xC7, 0x4B, 0xC1, 0xA0, 0xC2, 0xF0, 0x07, - 0x20, 0xC3, 0x7A, 0x09, 0x8D, 0x07, 0xFA, 0x07, - 0x9D, 0xC3, 0xE0, 0xC3, 0xFC, 0x07, 0xA0, 0x06, - 0x00, 0xBA, 0x20, 0xC8, 0x3C, 0x08, 0x40, 0x08, - 0x20, 0xC8, 0x3E, 0x08, 0x42, 0x08, 0x0E, 0xC8, - 0x3C, 0x08, 0x0F, 0xC8, 0x3E, 0x08, 0xC4, 0x04, - 0x82, 0x07, 0x02, 0x08, 0xE0, 0x04, 0x44, 0x08, - 0x40, 0x01, 0x80, 0x00, 0x06, 0x16, 0x0E, 0xC8, - 0x38, 0x08, 0x0F, 0xC8, 0x3A, 0x08, 0xE0, 0x04, - 0x48, 0x08, 0xA0, 0x06, 0x54, 0xBA, 0xE0, 0xC2, - 0xFE, 0x07, 0x0D, 0x11, 0x0E, 0xC8, 0xFA, 0x07, - 0x0F, 0xC8, 0xFC, 0x07, 0x20, 0xC8, 0x40, 0x08, - 0x3C, 0x08, 0x20, 0xC8, 0x42, 0x08, 0x3E, 0x08, - 0xA0, 0x06, 0x32, 0xC7, 0xCB, 0x10, 0x80, 0x01, - 0x80, 0x00, 0x55, 0x04, 0x8B, 0xC0, 0xA0, 0xC2, - 0xF0, 0x07, 0x8C, 0x07, 0x04, 0x00, 0x8D, 0x07, - 0xFA, 0x07, 0xA0, 0xC3, 0x3C, 0x08, 0xE0, 0xC3, - 0x3E, 0x08, 0xA0, 0x06, 0x36, 0xBA, 0x60, 0x01, - 0xFC, 0x07, 0x01, 0x00, 0x04, 0x13, 0xA0, 0x07, - 0xFA, 0x08, 0x00, 0x80, 0x52, 0x04, 0x60, 0x01, - 0x60, 0x07, 0x04, 0x00, 0x07, 0x16, 0x20, 0xD0, - 0x04, 0xE0, 0x20, 0xE8, 0x1A, 0xE0, 0x58, 0x07, - 0x60, 0x04, 0x3E, 0xC7, 0xA0, 0x07, 0xFA, 0x08, - 0x00, 0x40, 0x20, 0xC8, 0x3C, 0x08, 0xFC, 0x08, - 0x20, 0xC8, 0x3E, 0x08, 0xFE, 0x08, 0xA0, 0x06, - 0x6C, 0xC7, 0xA0, 0x06, 0x38, 0xC7, 0xD3, 0x10, - 0xAD, 0xC2, 0x02, 0x00, 0x6D, 0xC2, 0x00, 0x00, - 0x05, 0x16, 0xAA, 0x07, 0x02, 0x00, 0x36, 0x07, - 0x9A, 0x2C, 0x80, 0x03, 0xEA, 0x2C, 0x02, 0x00, - 0x41, 0xCB, 0x00, 0x00, 0x80, 0x03, 0x2D, 0xC3, - 0x18, 0x00, 0xAC, 0x07, 0x02, 0x00, 0x36, 0x07, - 0x20, 0x4B, 0x06, 0xEB, 0x0A, 0x00, 0x20, 0xEB, - 0x00, 0xEB, 0x0A, 0x00, 0x9C, 0x2E, 0x80, 0x03, - 0xA0, 0xC2, 0x22, 0xE0, 0x60, 0x04, 0x8A, 0xA3, - 0xED, 0xC0, 0x18, 0x00, 0xA0, 0x06, 0x3A, 0xCC, - 0x80, 0x03, 0x44, 0xC2, 0xC3, 0xC0, 0x02, 0x13, - 0xA0, 0x06, 0x3A, 0xCC, 0x19, 0xC3, 0x09, 0xCB, - 0x18, 0x00, 0xC9, 0x05, 0x19, 0xCB, 0x16, 0x00, - 0x4C, 0xC2, 0x2C, 0x02, 0x1A, 0x00, 0x0D, 0xCF, - 0x0E, 0xCF, 0x0F, 0xC7, 0x99, 0x00, 0x5B, 0x04, - 0x8C, 0x07, 0x0A, 0x09, 0x9C, 0xC2, 0xA0, 0x22, - 0x14, 0xE0, 0x06, 0x13, 0xA0, 0xC2, 0x58, 0x07, - 0xA0, 0x22, 0x20, 0xE0, 0x01, 0x16, 0x80, 0x03, - 0x03, 0xC1, 0xC3, 0x04, 0x8A, 0x07, 0x04, 0x00, - 0x84, 0xA2, 0x3A, 0xCF, 0x3A, 0xCF, 0x3A, 0xCF, - 0x3A, 0xCF, 0x3A, 0xCF, 0xE0, 0x02, 0x58, 0x07, - 0x8D, 0x07, 0x0A, 0x09, 0x0B, 0xC8, 0xC2, 0x07, - 0xA0, 0x06, 0x44, 0xB8, 0xE0, 0xC2, 0xC2, 0x07, - 0x20, 0xE0, 0x20, 0xE0, 0xE0, 0x02, 0xB8, 0x07, - 0x5B, 0x04, 0x2D, 0xC3, 0x18, 0x00, 0x8C, 0xC2, - 0x60, 0xC2, 0x6C, 0x01, 0x0A, 0xC8, 0x6C, 0x01, - 0xE0, 0xC2, 0x00, 0xFC, 0x02, 0x13, 0x8B, 0xC2, - 0xF9, 0x10, 0x09, 0xC8, 0x6C, 0x01, 0x8B, 0x07, - 0xF8, 0x05, 0x5B, 0xC2, 0x0C, 0x13, 0xCB, 0x05, - 0x5B, 0xC2, 0xCA, 0xC6, 0xE0, 0xC2, 0x6C, 0x01, - 0x09, 0xC8, 0x6C, 0x01, 0x0C, 0xC8, 0x00, 0xFC, - 0x0B, 0xC8, 0x6C, 0x01, 0x02, 0x10, 0xCC, 0xCE, - 0xCA, 0xC6, 0xA0, 0xC2, 0xE0, 0x00, 0xA0, 0x22, - 0x1A, 0xE0, 0x06, 0x16, 0x20, 0xE8, 0x04, 0xE0, - 0x3A, 0x07, 0x20, 0x48, 0x1A, 0xE0, 0xE0, 0x00, - 0x80, 0x03, 0xE0, 0xD3, 0xAB, 0xE3, 0xE0, 0x04, - 0x8E, 0x09, 0xE0, 0xC1, 0xA8, 0x06, 0x05, 0x16, - 0x07, 0x02, 0xA2, 0x06, 0xA0, 0x06, 0x38, 0xB5, - 0x0B, 0x16, 0xE0, 0xC1, 0xBA, 0x06, 0x23, 0x16, - 0x07, 0x02, 0xB4, 0x06, 0xA0, 0x06, 0x38, 0xB5, - 0x1E, 0x13, 0x07, 0x02, 0xB8, 0x06, 0x02, 0x10, - 0x07, 0x02, 0xA6, 0x06, 0x60, 0xC1, 0x02, 0xFC, - 0x25, 0xC8, 0x0C, 0x00, 0x02, 0xFC, 0xC5, 0xC9, - 0x0C, 0x00, 0xF5, 0xCD, 0xF5, 0xCD, 0xF5, 0xCD, - 0xF5, 0xCD, 0xF5, 0xCD, 0xF5, 0xC5, 0xB7, 0x01, - 0x28, 0x00, 0x27, 0x02, 0xF4, 0xFF, 0xA7, 0x07, - 0x04, 0x00, 0x52, 0xCE, 0x20, 0xE8, 0x9E, 0x09, - 0x06, 0xFC, 0x97, 0x2E, 0xD2, 0x10, 0x00, 0x03, - 0x02, 0x00, 0xA0, 0x06, 0x50, 0xB5, 0x00, 0x03, - 0x0F, 0x00, 0x20, 0x2C, 0xF0, 0xED, 0xE0, 0x93, - 0xAB, 0xE3, 0x03, 0x16, 0x81, 0x02, 0x16, 0x00, - 0xC4, 0x16, 0x21, 0xC1, 0x10, 0xEB, 0x54, 0x04, - 0xE0, 0x93, 0x10, 0xE0, 0x03, 0x16, 0xA0, 0xD2, - 0xA8, 0xE3, 0x0B, 0x10, 0xCF, 0xD3, 0x09, 0x16, - 0xA0, 0x23, 0x08, 0xE0, 0x06, 0x16, 0x84, 0x07, - 0x20, 0x00, 0x04, 0xE8, 0xD2, 0x06, 0xA0, 0xD2, - 0x0C, 0xE0, 0x60, 0x04, 0xD2, 0xCE, 0x60, 0x04, - 0x70, 0xD1, 0x22, 0xC1, 0x04, 0x00, 0xE2, 0x04, - 0x02, 0x00, 0x54, 0x04, 0x02, 0xC8, 0x6C, 0x01, - 0x82, 0xA0, 0x22, 0xC8, 0x32, 0x0C, 0x00, 0xFC, - 0x02, 0x02, 0x00, 0xFC, 0xE0, 0x93, 0xAA, 0xE3, - 0x13, 0x16, 0xB0, 0x03, 0x20, 0x98, 0xAA, 0xE3, - 0x65, 0x06, 0x0D, 0x16, 0x8B, 0x07, 0x17, 0xFC, - 0xDB, 0xD2, 0x8B, 0x09, 0x8B, 0x02, 0x15, 0x00, - 0x7B, 0x1B, 0xEB, 0xD2, 0xC4, 0xEA, 0x06, 0x13, - 0x77, 0x15, 0x20, 0x07, 0xA0, 0x09, 0x74, 0x10, - 0xA0, 0x06, 0x02, 0xD0, 0xA0, 0x48, 0x04, 0xE0, - 0x0E, 0x00, 0x85, 0x02, 0x07, 0x00, 0x0E, 0x13, - 0x0E, 0x01, 0x03, 0x00, 0x0B, 0x13, 0xA0, 0x23, - 0x22, 0xE0, 0x03, 0x16, 0xA0, 0xD2, 0x0E, 0xE0, - 0x02, 0x10, 0xA0, 0xD2, 0xA8, 0xE3, 0x8E, 0x01, - 0x03, 0x00, 0x5E, 0x10, 0x05, 0xC8, 0xFC, 0x06, - 0xC3, 0xC0, 0x57, 0x16, 0xA0, 0x43, 0x10, 0xE0, - 0x22, 0x88, 0x0E, 0x00, 0x6C, 0x09, 0x0A, 0x16, - 0x22, 0x88, 0x10, 0x00, 0x6E, 0x09, 0x06, 0x16, - 0x22, 0x88, 0x12, 0x00, 0x70, 0x09, 0x02, 0x16, - 0xA0, 0xE3, 0x10, 0xE0, 0x85, 0x02, 0x09, 0x00, - 0x02, 0x13, 0xA0, 0x06, 0xB8, 0xD7, 0x45, 0xA1, - 0x65, 0xC1, 0xAC, 0xE3, 0x55, 0x04, 0x62, 0xC0, - 0x04, 0x00, 0x22, 0xC8, 0x06, 0x00, 0x6C, 0x01, - 0x82, 0x02, 0x48, 0x04, 0x02, 0x1B, 0xA0, 0x43, - 0x0C, 0xE0, 0x22, 0xC1, 0x0E, 0x00, 0x51, 0x04, - 0x42, 0xC0, 0xE1, 0x04, 0x02, 0x00, 0xA2, 0xC0, - 0x0C, 0x00, 0x22, 0xC1, 0x0A, 0x00, 0x20, 0x21, - 0x18, 0xE0, 0x07, 0x13, 0xA1, 0xC8, 0x0A, 0x00, - 0x0A, 0x00, 0xA1, 0xC8, 0x08, 0x00, 0x08, 0x00, - 0xE2, 0x10, 0x22, 0xC8, 0x06, 0x00, 0x6C, 0x01, - 0xA0, 0x06, 0x66, 0xD6, 0x60, 0x04, 0xB0, 0xCE, - 0x02, 0xC8, 0xD4, 0x06, 0x62, 0xC1, 0x02, 0x00, - 0x65, 0xC1, 0xD8, 0xE3, 0x55, 0x04, 0x0F, 0x10, - 0x0E, 0x10, 0x85, 0x07, 0xF4, 0x03, 0xF5, 0x04, - 0x60, 0xCD, 0xCE, 0xED, 0xA0, 0x06, 0xA2, 0xD8, - 0xA0, 0xE3, 0x0C, 0xE0, 0x20, 0xE8, 0x9E, 0x09, - 0x06, 0x04, 0xA0, 0x2E, 0xF4, 0x03, 0x60, 0x04, - 0xE4, 0xCC, 0xA0, 0x06, 0x26, 0xD5, 0x0C, 0x10, - 0xA0, 0x06, 0x66, 0xD6, 0x09, 0x10, 0xA0, 0x06, - 0x2A, 0xD8, 0x06, 0x10, 0xA0, 0x06, 0x66, 0xD6, - 0x03, 0xC8, 0x2A, 0x09, 0xA0, 0xD2, 0xAA, 0xE3, - 0xA0, 0x06, 0x6E, 0xCF, 0xA0, 0x92, 0x26, 0xE0, - 0x0C, 0x16, 0xE0, 0xD3, 0x26, 0xE0, 0xE0, 0x23, - 0x14, 0xE0, 0x0A, 0x13, 0x0A, 0xC1, 0xC4, 0x83, - 0x07, 0x13, 0xC4, 0xC3, 0x24, 0xC1, 0xDC, 0xE3, - 0x54, 0x04, 0xCA, 0x93, 0xDC, 0x13, 0xCA, 0xD3, - 0xB0, 0x03, 0x0F, 0xD8, 0x59, 0x06, 0x04, 0x71, - 0x24, 0xC1, 0xEC, 0xE3, 0x54, 0x04, 0xA0, 0x23, - 0x0C, 0xE0, 0xD1, 0x13, 0x4D, 0xC3, 0xCF, 0x13, - 0x4D, 0x01, 0x00, 0x04, 0x0B, 0x13, 0x86, 0x07, - 0x02, 0x00, 0x84, 0x07, 0x26, 0x00, 0x46, 0x23, - 0x03, 0x13, 0x44, 0x06, 0x86, 0xA1, 0xFB, 0x10, - 0x46, 0x43, 0xB3, 0x10, 0x84, 0x07, 0x18, 0x00, - 0x8D, 0x01, 0x00, 0x04, 0x85, 0x07, 0xF4, 0x03, - 0xF5, 0x04, 0x60, 0xCD, 0xCE, 0xED, 0xA0, 0x06, - 0xA2, 0xD8, 0x20, 0xE8, 0x9C, 0x09, 0xFE, 0x03, - 0x20, 0xE8, 0x9E, 0x09, 0x06, 0x04, 0xA8, 0x10, - 0x85, 0x07, 0x1C, 0x07, 0x86, 0x07, 0x1A, 0x04, - 0x76, 0x6D, 0x76, 0x6D, 0x76, 0x6D, 0xC6, 0x05, - 0x76, 0x6D, 0x76, 0x6D, 0x76, 0x6D, 0x83, 0x07, - 0x00, 0x90, 0xA9, 0x10, 0x0B, 0xC3, 0x86, 0x07, - 0x00, 0x01, 0x85, 0x07, 0x00, 0x80, 0x20, 0xC1, - 0xD2, 0x06, 0x37, 0x13, 0xC4, 0x04, 0x60, 0xC0, - 0xD2, 0x06, 0x45, 0x20, 0x04, 0x13, 0x84, 0x05, - 0x15, 0x09, 0xF9, 0x16, 0x2E, 0x10, 0xCF, 0xD3, - 0x06, 0x16, 0xE0, 0x23, 0x14, 0xE0, 0x03, 0x16, - 0x0E, 0x01, 0x03, 0x00, 0x03, 0x13, 0xE0, 0x04, - 0xD2, 0x06, 0x23, 0x10, 0x64, 0xD0, 0x1C, 0x07, - 0x46, 0xB0, 0x10, 0x18, 0x01, 0xD9, 0x1C, 0x07, - 0x60, 0x23, 0x20, 0xE0, 0x0B, 0x13, 0x81, 0x07, - 0x18, 0x00, 0x61, 0xC0, 0xFC, 0xE3, 0x11, 0x88, - 0xCE, 0xED, 0x04, 0x13, 0x08, 0x02, 0x18, 0x80, - 0xA0, 0x06, 0xDA, 0xD4, 0x64, 0xD0, 0x28, 0x07, - 0x46, 0xB0, 0x08, 0x18, 0x01, 0xD9, 0x28, 0x07, - 0x46, 0xB0, 0x04, 0x17, 0x83, 0x07, 0x40, 0x80, - 0xA0, 0x06, 0x2A, 0xD8, 0x05, 0x48, 0xD2, 0x06, - 0xCA, 0x16, 0x20, 0xC1, 0x32, 0x09, 0x01, 0x16, - 0x5C, 0x04, 0x04, 0x02, 0x07, 0x00, 0x20, 0x06, - 0x32, 0x09, 0x05, 0x02, 0x00, 0x01, 0xC7, 0x10, - 0x0B, 0xC3, 0xC5, 0x04, 0x42, 0xC0, 0xC7, 0x04, - 0x20, 0xC2, 0x6C, 0x01, 0xE1, 0xA1, 0x04, 0x00, - 0x11, 0xC8, 0x6C, 0x01, 0xFB, 0x16, 0x08, 0xC8, - 0x6C, 0x01, 0xC8, 0x04, 0xA0, 0x43, 0x1A, 0xE0, - 0x22, 0xC1, 0x0E, 0x00, 0x0D, 0x15, 0x0C, 0x13, - 0xA0, 0xE3, 0x1A, 0xE0, 0xA0, 0x06, 0x14, 0xD8, - 0x08, 0xC2, 0x48, 0x13, 0x88, 0x02, 0x12, 0x00, - 0x45, 0x1B, 0x20, 0x22, 0x22, 0xE0, 0x42, 0x13, - 0x02, 0xC1, 0x08, 0xA1, 0x08, 0x05, 0x28, 0x02, - 0xF2, 0xFF, 0x07, 0xA2, 0x83, 0x07, 0x01, 0x80, - 0x88, 0x02, 0x04, 0x00, 0x6E, 0x11, 0x64, 0xC2, - 0x16, 0x00, 0x49, 0xD2, 0x02, 0x16, 0x02, 0x81, - 0x31, 0x16, 0x09, 0x01, 0x00, 0xF0, 0x28, 0x16, - 0x49, 0xC1, 0x45, 0x71, 0xC3, 0x04, 0x85, 0x02, - 0x09, 0x00, 0x7C, 0x13, 0x83, 0x07, 0x02, 0x80, - 0xA4, 0xC1, 0x14, 0x00, 0x88, 0x81, 0x76, 0x16, - 0x83, 0x05, 0x85, 0x02, 0x15, 0x00, 0x13, 0x1B, - 0x83, 0x05, 0x49, 0x99, 0x30, 0xEB, 0x0A, 0x13, - 0x09, 0x98, 0x0E, 0xE0, 0x6B, 0x16, 0x25, 0x98, - 0x30, 0xEB, 0x0C, 0xE0, 0x67, 0x16, 0xE0, 0xC1, - 0xEC, 0x06, 0x64, 0x16, 0xC3, 0x04, 0x52, 0xC2, - 0x0F, 0x13, 0x83, 0x07, 0x09, 0x80, 0xE0, 0xC1, - 0x6A, 0x09, 0x47, 0x01, 0x00, 0x10, 0x5A, 0x16, - 0xA0, 0xC0, 0x6C, 0x01, 0xA0, 0x06, 0xBE, 0xD6, - 0x60, 0x04, 0xB0, 0xCE, 0x60, 0x04, 0xBA, 0xCE, - 0x89, 0x07, 0x0E, 0x07, 0xC7, 0x04, 0xE5, 0xD1, - 0x46, 0xEB, 0x05, 0x13, 0xC7, 0x06, 0x27, 0x02, - 0x5C, 0xEB, 0x77, 0xCE, 0xFE, 0x15, 0x44, 0xC0, - 0x21, 0x02, 0x18, 0x00, 0x28, 0x02, 0xFC, 0xFF, - 0x36, 0x13, 0x91, 0xC1, 0x86, 0xD1, 0x1F, 0x13, - 0xC6, 0x06, 0x87, 0x07, 0x0E, 0x07, 0xF7, 0xC0, - 0x46, 0x02, 0xFF, 0xBF, 0x43, 0x02, 0xFF, 0x3F, - 0xA0, 0x91, 0xF5, 0xED, 0x09, 0x16, 0xB0, 0x03, - 0x20, 0x98, 0x0E, 0xE0, 0x5D, 0x06, 0x0F, 0x16, - 0x21, 0xC8, 0x02, 0x00, 0x0C, 0x07, 0x17, 0x10, - 0x47, 0x82, 0x0C, 0x1B, 0xC6, 0x90, 0xEB, 0x16, - 0x47, 0x06, 0xF7, 0x04, 0xB0, 0x03, 0x20, 0x98, - 0x5D, 0x06, 0x57, 0x06, 0x0C, 0x13, 0x83, 0x07, - 0x05, 0x80, 0x1C, 0x10, 0xD1, 0xC0, 0xE0, 0x20, - 0x16, 0xE0, 0x03, 0x16, 0x83, 0x07, 0x08, 0x80, - 0x15, 0x10, 0x60, 0x44, 0x26, 0xE0, 0x86, 0x71, - 0x46, 0xA0, 0x06, 0x62, 0x83, 0x07, 0x05, 0x80, - 0x08, 0xC2, 0xCB, 0x15, 0x0B, 0x16, 0xC3, 0x04, - 0x87, 0x07, 0x0E, 0x07, 0x77, 0xC0, 0x47, 0x82, - 0x05, 0x1B, 0x60, 0x20, 0x06, 0xE0, 0xFA, 0x16, - 0x83, 0x07, 0x07, 0x80, 0x5C, 0x04, 0xA0, 0x92, - 0x0E, 0xE0, 0x11, 0x16, 0x20, 0xC8, 0x20, 0xE0, - 0x08, 0x07, 0xE0, 0x04, 0x84, 0x01, 0x60, 0x05, - 0x02, 0x07, 0x4B, 0x13, 0x20, 0x48, 0x06, 0xE0, - 0x82, 0x01, 0xA0, 0x06, 0xD0, 0xD4, 0x83, 0x07, - 0x00, 0xC0, 0xA0, 0x06, 0x2A, 0xD8, 0x20, 0xC8, - 0x1E, 0xE0, 0x02, 0x07, 0xA0, 0xE3, 0x04, 0xE0, - 0x08, 0x02, 0x24, 0x80, 0xA0, 0x06, 0xDA, 0xD4, - 0x42, 0x10, 0x20, 0xC1, 0x84, 0x01, 0x44, 0x02, - 0x00, 0x88, 0x2A, 0x13, 0x04, 0x48, 0x84, 0x01, - 0x20, 0x06, 0x02, 0x07, 0xF1, 0x16, 0x60, 0x01, - 0x8E, 0x09, 0x00, 0x80, 0x15, 0x13, 0xA0, 0x23, - 0x22, 0xE0, 0x05, 0x16, 0xA0, 0x43, 0x22, 0xE0, - 0xA0, 0xD2, 0x0E, 0xE0, 0xCF, 0x10, 0xE0, 0x23, - 0x14, 0xE0, 0x04, 0x13, 0x20, 0x98, 0xA9, 0xE3, - 0x65, 0x06, 0x0C, 0x16, 0xA0, 0x92, 0x0E, 0xE0, - 0xC5, 0x13, 0xA0, 0xD2, 0xA8, 0xE3, 0xD3, 0x10, - 0x20, 0xC8, 0x20, 0xE0, 0x08, 0x07, 0x83, 0x07, - 0x00, 0xC0, 0x04, 0x10, 0x83, 0x07, 0x02, 0x00, - 0x60, 0x04, 0xCA, 0xCE, 0x60, 0x04, 0xC0, 0xCE, - 0x20, 0xE8, 0x06, 0xE0, 0x82, 0x01, 0xA0, 0x06, - 0xD0, 0xD4, 0x20, 0x07, 0x02, 0x07, 0xA0, 0x43, - 0x04, 0xE0, 0x20, 0xC8, 0xAE, 0xE4, 0x86, 0x01, - 0x20, 0x88, 0x20, 0xE0, 0x08, 0x07, 0x03, 0x16, - 0x20, 0xC8, 0x78, 0xEB, 0x08, 0x07, 0x60, 0x04, - 0xD2, 0xCE, 0x0E, 0x01, 0x03, 0x00, 0x16, 0x13, - 0xCF, 0xD3, 0x08, 0x16, 0xA0, 0x23, 0x20, 0xE0, - 0x03, 0x16, 0xA0, 0xD2, 0xA8, 0xE3, 0x02, 0x10, - 0xA0, 0xD2, 0x0E, 0xE0, 0x8E, 0x01, 0x03, 0x00, - 0x09, 0x10, 0x60, 0xC1, 0x84, 0x01, 0x60, 0x21, - 0x0A, 0xE0, 0x04, 0x16, 0x83, 0x07, 0x00, 0x84, - 0x60, 0x04, 0xCA, 0xCE, 0x20, 0xC8, 0x2E, 0xE0, - 0x84, 0x01, 0x08, 0x02, 0x06, 0x80, 0xA0, 0x06, - 0xDA, 0xD4, 0x60, 0x04, 0xD2, 0xCE, 0x60, 0xE3, - 0x20, 0xE0, 0x60, 0x04, 0xD2, 0xCE, 0xE0, 0x93, - 0x26, 0xE0, 0x10, 0x16, 0xA0, 0x23, 0x08, 0xE0, - 0x0D, 0x16, 0xA0, 0x23, 0x06, 0xE0, 0x02, 0x13, - 0x60, 0xE3, 0x1C, 0xE0, 0x60, 0xE3, 0x18, 0xE0, - 0xA0, 0x43, 0x06, 0xE0, 0x08, 0x02, 0x3C, 0x80, - 0xA0, 0x06, 0xDA, 0xD4, 0x60, 0x04, 0xD2, 0xCE, - 0xA0, 0x92, 0xA8, 0xE3, 0x03, 0x13, 0xA0, 0x92, - 0xA9, 0xE3, 0x1E, 0x16, 0xE0, 0x23, 0x14, 0xE0, - 0x08, 0x13, 0x20, 0x98, 0xA9, 0xE3, 0x65, 0x06, - 0x04, 0x13, 0x83, 0x07, 0x07, 0x00, 0x60, 0x04, - 0xCA, 0xCE, 0xA0, 0xD2, 0x0E, 0xE0, 0x20, 0xC8, - 0x20, 0xE0, 0x08, 0x07, 0xA0, 0x27, 0x04, 0xE0, - 0x0B, 0x16, 0x20, 0xC8, 0x1E, 0xE0, 0x08, 0x07, - 0xE0, 0x93, 0xA8, 0xE3, 0x05, 0x16, 0xA0, 0x23, - 0x12, 0xE0, 0x02, 0x13, 0x20, 0x06, 0x08, 0x07, - 0x60, 0x04, 0xD2, 0xCE, 0xE0, 0x23, 0x14, 0xE0, - 0x3E, 0x13, 0xB0, 0x03, 0x20, 0x98, 0x0E, 0xE0, - 0x6F, 0x06, 0x0F, 0x16, 0xCF, 0xD3, 0x37, 0x16, - 0xA0, 0xD2, 0xA8, 0xE3, 0x60, 0x04, 0xD2, 0xCE, - 0xA0, 0x92, 0x0C, 0xE0, 0x30, 0x16, 0xE0, 0x23, - 0x14, 0xE0, 0xF6, 0x13, 0x83, 0x07, 0x06, 0x00, - 0x07, 0x10, 0x83, 0x07, 0x05, 0x00, 0xE0, 0x93, - 0x0E, 0xE0, 0x02, 0x16, 0x83, 0x07, 0x07, 0x00, - 0x60, 0x04, 0xCA, 0xCE, 0x60, 0xE3, 0x12, 0xE0, - 0xE0, 0x23, 0x14, 0xE0, 0x11, 0x13, 0x20, 0x98, - 0x0C, 0xE0, 0x65, 0x06, 0x03, 0x16, 0x20, 0xD8, - 0xA9, 0xE3, 0x65, 0x06, 0x14, 0x10, 0x60, 0x01, - 0x8E, 0x09, 0x00, 0x80, 0x10, 0x13, 0x20, 0xC1, - 0x84, 0x01, 0x20, 0x21, 0x06, 0xE0, 0xD2, 0x16, - 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, 0x07, 0x13, - 0x20, 0x48, 0x06, 0xE0, 0x84, 0x01, 0x08, 0x02, - 0x30, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x60, 0x04, - 0xD2, 0xCE, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x20, - 0xFA, 0x16, 0x08, 0x02, 0x78, 0x80, 0xA0, 0x06, - 0xDA, 0xD4, 0x20, 0xC2, 0xA2, 0x09, 0x03, 0x13, - 0x20, 0x06, 0xA2, 0x09, 0x21, 0x13, 0x20, 0xC2, - 0xA4, 0x09, 0xED, 0x13, 0x20, 0x06, 0xA4, 0x09, - 0xEA, 0x16, 0xA0, 0x07, 0xA4, 0x09, 0x05, 0x00, - 0xCD, 0x01, 0x00, 0x04, 0xE4, 0x10, 0x60, 0x01, - 0x8E, 0x09, 0x80, 0x00, 0x3E, 0x13, 0x60, 0x01, - 0x8E, 0x09, 0x00, 0x10, 0x02, 0x16, 0xA0, 0x06, - 0xE6, 0xD5, 0xA0, 0x01, 0x8E, 0x09, 0x00, 0x10, - 0xE0, 0x01, 0x8E, 0x09, 0x80, 0x00, 0x83, 0x07, - 0x00, 0xA8, 0xA0, 0x06, 0x2A, 0xD8, 0x16, 0x10, - 0x60, 0x01, 0x8E, 0x09, 0x00, 0x04, 0x21, 0x13, - 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x10, 0xA0, 0x07, - 0x08, 0x07, 0x05, 0x00, 0x83, 0x07, 0x08, 0xA8, - 0xA0, 0x23, 0x04, 0xE0, 0x05, 0x16, 0x20, 0xC8, - 0x20, 0xE0, 0x08, 0x07, 0x83, 0x07, 0x08, 0xE8, - 0xA0, 0x06, 0x2A, 0xD8, 0xA0, 0x01, 0x8E, 0x09, - 0x00, 0x20, 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x01, - 0xE0, 0x01, 0x82, 0x01, 0x00, 0x08, 0xA0, 0xD2, - 0x0E, 0xE0, 0x83, 0x07, 0x10, 0x80, 0x60, 0x04, - 0xC0, 0xCE, 0x08, 0x02, 0x78, 0x00, 0xA0, 0x06, - 0xDA, 0xD4, 0x83, 0x07, 0x00, 0x82, 0x60, 0x04, - 0xCA, 0xCE, 0x60, 0x04, 0xD2, 0xCE, 0x20, 0x06, - 0x90, 0x09, 0x07, 0x15, 0xA0, 0xD2, 0x10, 0xE0, - 0xCA, 0x06, 0xA0, 0xD2, 0x26, 0xE0, 0xCF, 0x04, - 0xF4, 0x10, 0x08, 0x02, 0x7E, 0x80, 0xA0, 0x06, - 0xDA, 0xD4, 0x20, 0xC2, 0x90, 0x09, 0x88, 0x02, - 0x96, 0x00, 0x0D, 0x1B, 0xEA, 0x16, 0x20, 0x48, - 0x08, 0xE0, 0x82, 0x01, 0xA0, 0x01, 0x8E, 0x09, - 0x00, 0x10, 0xA0, 0x06, 0xE6, 0xD5, 0x83, 0x07, - 0x00, 0x28, 0x60, 0x04, 0xC0, 0xCE, 0x60, 0x01, - 0x8E, 0x09, 0x00, 0x10, 0xDA, 0x16, 0x84, 0x07, - 0x04, 0x00, 0x85, 0x07, 0xF4, 0x03, 0xF5, 0x04, - 0xB5, 0x07, 0x30, 0x06, 0xA0, 0x06, 0xA2, 0xD8, - 0xA0, 0x07, 0xF8, 0x03, 0x34, 0xD4, 0x60, 0x04, - 0xC0, 0xDB, 0xA0, 0x07, 0x90, 0x09, 0xF4, 0x01, - 0x08, 0x02, 0x7E, 0x80, 0xA0, 0x06, 0xDA, 0xD4, - 0x08, 0x02, 0x36, 0x00, 0xA0, 0x06, 0xDA, 0xD4, - 0x20, 0xE8, 0x0C, 0xE0, 0x82, 0x01, 0xA0, 0x23, - 0x18, 0xE0, 0x06, 0x13, 0xA0, 0xE3, 0x18, 0xE0, - 0xE0, 0x2E, 0x00, 0x00, 0x41, 0xC0, 0xFA, 0x16, - 0xA0, 0x06, 0xE6, 0xD5, 0xB2, 0x10, 0x04, 0x02, - 0x64, 0x00, 0x04, 0x06, 0xFE, 0x16, 0x5B, 0x04, - 0xA0, 0xE3, 0x0A, 0xE0, 0x08, 0xC2, 0x02, 0x11, - 0xA0, 0x43, 0x0A, 0xE0, 0x20, 0x42, 0x04, 0xE0, - 0x28, 0x02, 0xFC, 0xE3, 0x58, 0xC0, 0x02, 0xC0, - 0x11, 0x88, 0xCE, 0xED, 0x03, 0x16, 0xD1, 0x2C, - 0x58, 0xC0, 0xD1, 0x04, 0x80, 0xC0, 0x0E, 0x01, - 0x00, 0x10, 0x0F, 0x13, 0x60, 0xCC, 0xCE, 0xED, - 0xC8, 0x05, 0x78, 0xCC, 0x03, 0x16, 0x41, 0x06, - 0x60, 0xCC, 0xD6, 0x06, 0x58, 0xC4, 0x02, 0x16, - 0x60, 0xC4, 0x00, 0x07, 0x21, 0x02, 0xFA, 0xFF, - 0x91, 0x2C, 0x5B, 0x04, 0x0B, 0xC3, 0xA0, 0x06, - 0xC2, 0xD5, 0xA0, 0x06, 0x9C, 0xD5, 0x08, 0xC2, - 0x05, 0x16, 0x62, 0xC2, 0x02, 0x00, 0x60, 0x26, - 0xA8, 0xE4, 0x0D, 0x16, 0x42, 0xC2, 0xC9, 0x05, - 0x60, 0xCE, 0xF2, 0xED, 0x60, 0xC6, 0x7C, 0xEB, - 0xA0, 0x06, 0x10, 0xD6, 0x18, 0xCA, 0x0A, 0x00, - 0x20, 0x46, 0x26, 0xE0, 0x04, 0x16, 0xA0, 0xC0, - 0x6C, 0x01, 0x12, 0x2E, 0x1D, 0x10, 0x12, 0xC1, - 0x05, 0x13, 0x60, 0xC1, 0x6C, 0x01, 0x14, 0x2E, - 0x05, 0xC8, 0x6C, 0x01, 0xD2, 0x04, 0x48, 0x06, - 0x84, 0x07, 0x02, 0x00, 0x48, 0xC1, 0xA0, 0xC0, - 0x6C, 0x01, 0x02, 0xC0, 0xA0, 0x06, 0xA2, 0xD8, - 0x60, 0xC5, 0x02, 0xFC, 0x07, 0x02, 0xA2, 0x06, - 0x25, 0x02, 0xF4, 0xFF, 0x05, 0xC8, 0x02, 0xFC, - 0x20, 0xC2, 0x6C, 0x01, 0xA0, 0x06, 0xFC, 0xB4, - 0x5C, 0x04, 0x42, 0xC2, 0x29, 0x02, 0x08, 0x00, - 0x39, 0xC2, 0x48, 0x02, 0x00, 0xC0, 0x88, 0x02, - 0x00, 0xC0, 0x08, 0x16, 0x60, 0x8E, 0x2E, 0xE0, - 0x05, 0x16, 0x60, 0x86, 0x2E, 0xE0, 0x02, 0x16, - 0xC8, 0x04, 0x5B, 0x04, 0x08, 0x07, 0x5B, 0x04, - 0x20, 0x88, 0x8E, 0xE1, 0x6C, 0x01, 0x02, 0x16, - 0x60, 0x04, 0xBA, 0xCE, 0x5B, 0x04, 0x88, 0x07, - 0xAE, 0x01, 0x20, 0xE8, 0x0E, 0xE0, 0x80, 0x01, - 0x08, 0x06, 0xFE, 0x16, 0x20, 0x48, 0x0E, 0xE0, - 0x80, 0x01, 0x5B, 0x04, 0xC2, 0x04, 0xA0, 0x23, - 0x0C, 0xE0, 0x10, 0x16, 0x20, 0x2F, 0x30, 0x06, - 0x82, 0x07, 0xDF, 0xFF, 0x02, 0x2C, 0x82, 0x02, - 0xF4, 0x03, 0x06, 0x13, 0xE2, 0x04, 0x02, 0x00, - 0xA2, 0xC0, 0x06, 0x00, 0x12, 0x2E, 0xF4, 0x10, - 0xA0, 0x43, 0x0C, 0xE0, 0x5B, 0x04, 0x42, 0xC2, - 0x88, 0x07, 0x0E, 0x00, 0x09, 0xA2, 0x29, 0x02, - 0x08, 0x00, 0x78, 0xCE, 0x78, 0xCE, 0x78, 0xCE, - 0x60, 0xCE, 0x6C, 0x09, 0x60, 0xCE, 0x6E, 0x09, - 0x60, 0xCE, 0x70, 0x09, 0xA0, 0x23, 0x1A, 0xE0, - 0x0F, 0x16, 0x58, 0xC2, 0x49, 0x02, 0x80, 0x1F, - 0x60, 0x2A, 0x14, 0xE0, 0xA0, 0xE8, 0x04, 0xE0, - 0x0E, 0x00, 0x09, 0xC6, 0x49, 0x02, 0x00, 0x1F, - 0xC9, 0x06, 0x09, 0xA2, 0x89, 0xA8, 0x04, 0x00, - 0x28, 0x02, 0x02, 0x00, 0x58, 0xC2, 0x49, 0x0A, - 0x49, 0x02, 0x00, 0xF0, 0x09, 0xD6, 0xE2, 0x04, - 0x06, 0x00, 0x5B, 0x04, 0x00, 0x07, 0x82, 0xC0, - 0x53, 0x13, 0xA0, 0xC0, 0x6C, 0x01, 0xA0, 0xC1, - 0x06, 0xFC, 0x46, 0x02, 0x0F, 0x00, 0x86, 0x02, - 0x01, 0x00, 0x3D, 0x12, 0x06, 0x88, 0xF2, 0x06, - 0x12, 0x16, 0x01, 0x02, 0x0E, 0xFC, 0x31, 0x88, - 0xF4, 0x06, 0x0D, 0x16, 0x31, 0x88, 0xF6, 0x06, - 0x0A, 0x16, 0x31, 0x88, 0xF8, 0x06, 0x07, 0x16, - 0x86, 0x02, 0x02, 0x00, 0x2C, 0x16, 0x20, 0x88, - 0x0A, 0x07, 0xFA, 0x06, 0x28, 0x13, 0x20, 0xC1, - 0x6A, 0x09, 0x44, 0x01, 0x00, 0x08, 0x06, 0x13, - 0x86, 0x02, 0x02, 0x00, 0x20, 0x16, 0x44, 0x01, - 0x80, 0x00, 0x1D, 0x16, 0x00, 0x07, 0xE0, 0x23, - 0x14, 0xE0, 0x19, 0x16, 0x82, 0x02, 0x43, 0x00, - 0x16, 0x13, 0x00, 0x02, 0x02, 0xFC, 0x40, 0xC0, - 0xB0, 0x01, 0x20, 0x00, 0x60, 0x01, 0x6A, 0x09, - 0x01, 0x00, 0x07, 0x16, 0x60, 0xA0, 0x2C, 0x09, - 0x60, 0xCC, 0xEE, 0x05, 0x50, 0xC4, 0x20, 0xC4, - 0x2C, 0x09, 0x80, 0x07, 0x36, 0x07, 0x81, 0x07, - 0x40, 0x00, 0x40, 0x2C, 0xC0, 0x04, 0x84, 0x07, - 0xF2, 0x06, 0x06, 0xCD, 0x01, 0x02, 0x0E, 0xFC, - 0x31, 0xCD, 0x31, 0xCD, 0x31, 0xCD, 0x20, 0xC5, - 0x0A, 0x07, 0x00, 0xC0, 0x01, 0x13, 0x12, 0x2E, - 0xE0, 0x04, 0x6C, 0x01, 0x5B, 0x04, 0x60, 0x01, - 0x8A, 0x09, 0x00, 0x80, 0x12, 0x13, 0x0B, 0xC8, - 0x22, 0x09, 0xA0, 0x06, 0x3E, 0xD7, 0x08, 0x02, - 0x42, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x08, 0x02, - 0x30, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0xE0, 0xC2, - 0x22, 0x09, 0x5B, 0x04, 0x20, 0x48, 0xAC, 0xE4, - 0x80, 0x01, 0x20, 0x48, 0x7E, 0xEB, 0x82, 0x01, - 0x20, 0x48, 0x22, 0xE0, 0xAE, 0x01, 0x20, 0x48, - 0x22, 0xE0, 0x78, 0x09, 0x60, 0x43, 0x18, 0xE0, - 0xA0, 0x43, 0x08, 0xE0, 0x60, 0x01, 0x8A, 0x09, - 0x00, 0x80, 0xEB, 0x13, 0x0B, 0xC3, 0x08, 0x02, - 0x42, 0x00, 0xA0, 0x06, 0xDA, 0xD4, 0x5C, 0x04, - 0x0B, 0xC3, 0x20, 0xE8, 0x0E, 0xE0, 0x82, 0x01, - 0x20, 0xE8, 0x22, 0xE0, 0xAE, 0x01, 0x20, 0xE8, - 0x22, 0xE0, 0x78, 0x09, 0xA0, 0xE3, 0x08, 0xE0, - 0x60, 0xE3, 0x18, 0xE0, 0xA0, 0x43, 0x06, 0xE0, - 0x08, 0x02, 0x3C, 0x80, 0xA0, 0x06, 0xDA, 0xD4, - 0x08, 0x02, 0x42, 0x80, 0xA0, 0x06, 0xDA, 0xD4, - 0x5C, 0x04, 0x0B, 0xC3, 0x83, 0x07, 0x00, 0x68, - 0xA0, 0x06, 0x2A, 0xD8, 0x83, 0x07, 0x10, 0x80, - 0xA0, 0x06, 0x2A, 0xD8, 0x5C, 0x04, 0x0B, 0xC3, - 0xA0, 0x06, 0x14, 0xD8, 0x02, 0xA2, 0x68, 0xC2, - 0x14, 0x00, 0x29, 0x02, 0xFC, 0xFF, 0x24, 0x13, - 0x28, 0x02, 0x18, 0x00, 0x87, 0x07, 0x0E, 0x00, - 0x81, 0x07, 0x0E, 0x07, 0xF1, 0x04, 0x47, 0x06, - 0xFD, 0x15, 0x58, 0xC0, 0xB0, 0x03, 0x01, 0x78, - 0x63, 0x06, 0x41, 0x02, 0x3F, 0x00, 0x0E, 0x13, - 0x81, 0x02, 0x1F, 0x00, 0x0B, 0x1B, 0x41, 0xA0, - 0x61, 0xC0, 0x86, 0xE4, 0xF8, 0xC1, 0xC7, 0x06, - 0xC7, 0x71, 0x47, 0x06, 0x78, 0xCC, 0x47, 0x06, - 0xFD, 0x15, 0x04, 0x10, 0x58, 0xC0, 0xC1, 0x06, - 0x41, 0x70, 0x01, 0xA2, 0x49, 0xC2, 0xE5, 0x15, - 0x5C, 0x04, 0xA0, 0x23, 0x1A, 0xE0, 0x02, 0x13, - 0xC8, 0x04, 0x5B, 0x04, 0x22, 0xC2, 0x14, 0x00, - 0x48, 0x02, 0x00, 0x1F, 0xC8, 0x06, 0x5B, 0x04, - 0x83, 0x02, 0x0F, 0x00, 0x17, 0x1B, 0xA0, 0xC1, - 0xD4, 0x06, 0x35, 0x13, 0x26, 0x02, 0x04, 0x00, - 0xA0, 0xCD, 0xCE, 0xED, 0x83, 0xC5, 0x04, 0x13, - 0x4A, 0xC2, 0x39, 0x0A, 0xC9, 0xE0, 0x83, 0xC5, - 0x86, 0x07, 0x36, 0x07, 0x87, 0x07, 0x10, 0x00, - 0x20, 0xC2, 0xD4, 0x06, 0xE0, 0x04, 0xD4, 0x06, - 0x46, 0x2C, 0x5B, 0x04, 0x60, 0xC0, 0xFE, 0x06, - 0x20, 0xC2, 0x6A, 0x09, 0x48, 0x02, 0x00, 0x60, - 0x20, 0x22, 0x06, 0xE0, 0x04, 0x16, 0x20, 0xE2, - 0x0A, 0xE0, 0x20, 0xE2, 0x18, 0xE0, 0x13, 0x0A, - 0x04, 0x18, 0x41, 0x05, 0x03, 0x48, 0xFE, 0x06, - 0x06, 0x10, 0x83, 0x02, 0x02, 0x00, 0x01, 0x16, - 0x13, 0x09, 0x03, 0xE8, 0xFE, 0x06, 0xC8, 0x40, - 0xC1, 0x40, 0x05, 0x13, 0x88, 0x07, 0x36, 0x07, - 0x89, 0x07, 0x00, 0x40, 0x48, 0x2C, 0x5B, 0x04, - 0xC9, 0x04, 0x24, 0xC1, 0x94, 0xEB, 0x84, 0xC1, - 0x86, 0x71, 0x86, 0xA1, 0x26, 0x02, 0x56, 0xEC, - 0xC4, 0x06, 0x04, 0x71, 0x24, 0x02, 0xC2, 0xEB, - 0x14, 0xD2, 0xC8, 0x09, 0x08, 0xA2, 0xB0, 0x03, - 0x34, 0xD8, 0x5F, 0x06, 0x47, 0x02, 0x0F, 0x00, - 0xC7, 0xA1, 0x28, 0xC2, 0x82, 0xEB, 0x58, 0x04, - 0x76, 0xCD, 0x47, 0x06, 0xFD, 0x16, 0x32, 0x10, - 0x36, 0xC2, 0x26, 0x10, 0x17, 0x09, 0x47, 0xA1, - 0x2D, 0x10, 0x17, 0x09, 0x47, 0x61, 0x2A, 0x10, - 0xA0, 0x43, 0x16, 0xE0, 0x5B, 0x04, 0xA0, 0x43, - 0x16, 0xE0, 0x49, 0xC2, 0x03, 0x16, 0x44, 0xC2, - 0x06, 0xC8, 0x22, 0x09, 0x27, 0xC1, 0x8E, 0xED, - 0x84, 0xC1, 0x86, 0x71, 0x26, 0x02, 0xC4, 0xED, - 0xC4, 0x06, 0x04, 0x71, 0x24, 0x02, 0xAA, 0xED, - 0xD3, 0x10, 0x09, 0xC1, 0xA0, 0xC1, 0x22, 0x09, - 0xC9, 0x04, 0x10, 0x10, 0x36, 0xC2, 0x78, 0xD5, - 0x60, 0x41, 0x22, 0xE0, 0xC5, 0x05, 0x0A, 0x10, - 0x78, 0xCD, 0x47, 0x06, 0xFD, 0x15, 0x06, 0x10, - 0xA0, 0x23, 0x16, 0xE0, 0xCD, 0x16, 0x49, 0xC2, - 0xEC, 0x16, 0xD6, 0x10, 0xA0, 0xE3, 0x16, 0xE0, - 0xBB, 0x10, 0x08, 0x02, 0x5A, 0x80, 0xA0, 0x06, - 0xDA, 0xD4, 0x44, 0x10, 0xA0, 0x92, 0x0C, 0xE0, - 0x15, 0x16, 0x44, 0x02, 0x00, 0x5E, 0x14, 0x16, - 0x20, 0x48, 0xAC, 0xE4, 0x80, 0x01, 0xA0, 0x06, - 0x72, 0xD7, 0x20, 0xC8, 0x9E, 0x01, 0x9E, 0x01, - 0xE0, 0x2E, 0x01, 0x00, 0xA0, 0x43, 0x18, 0xE0, - 0xA0, 0xD2, 0x26, 0xE0, 0x83, 0x07, 0x10, 0x00, - 0xA0, 0x06, 0x2A, 0xD8, 0x60, 0x04, 0xD2, 0xCE, - 0x84, 0x07, 0x08, 0x00, 0x60, 0x04, 0x94, 0xCE, - 0x85, 0x07, 0x03, 0x02, 0x05, 0xC8, 0xCE, 0x06, - 0xA0, 0x43, 0x12, 0xE0, 0xE0, 0x04, 0xFA, 0x06, - 0xA0, 0x06, 0xA4, 0xD7, 0x08, 0x02, 0x48, 0x80, - 0xA0, 0x06, 0xDA, 0xD4, 0x17, 0x10, 0x60, 0x01, - 0x8E, 0x09, 0x00, 0x80, 0x02, 0x16, 0x60, 0x04, - 0x9C, 0xD4, 0xA0, 0x27, 0x2C, 0xE0, 0x04, 0x16, - 0x08, 0x02, 0x54, 0x80, 0xA0, 0x06, 0xDA, 0xD4, - 0x83, 0x07, 0x00, 0xA8, 0x20, 0x88, 0x08, 0x07, - 0x20, 0xE0, 0x02, 0x16, 0x83, 0x07, 0x00, 0xE8, - 0xA0, 0x06, 0x2A, 0xD8, 0x08, 0x02, 0x36, 0x00, - 0xA0, 0x06, 0xDA, 0xD4, 0x20, 0xE8, 0x0C, 0xE0, - 0x82, 0x01, 0xA0, 0x23, 0x18, 0xE0, 0x06, 0x13, - 0xA0, 0xE3, 0x18, 0xE0, 0xE0, 0x2E, 0x00, 0x00, - 0x41, 0xC0, 0xFA, 0x16, 0xA0, 0x06, 0xE6, 0xD5, - 0x82, 0xC0, 0x02, 0x13, 0x4F, 0x02, 0x80, 0xFF, - 0xC4, 0x04, 0x0F, 0xD1, 0xC4, 0x06, 0x60, 0x04, - 0x94, 0xCE, 0xA0, 0x06, 0x32, 0xDA, 0x08, 0x02, - 0x36, 0x80, 0xA0, 0x07, 0xD6, 0x06, 0x20, 0xDA, - 0xA0, 0x06, 0xDA, 0xD4, 0x10, 0x10, 0xA0, 0x06, - 0x32, 0xDA, 0x20, 0xD1, 0xCE, 0x06, 0xE6, 0x13, - 0x20, 0x78, 0x12, 0xE0, 0xCE, 0x06, 0xE2, 0x10, - 0x20, 0xC1, 0x16, 0x04, 0x14, 0x0A, 0xC4, 0x06, - 0x0A, 0x91, 0x01, 0x16, 0x5B, 0x04, 0x60, 0x04, - 0xD2, 0xCE, 0xB0, 0x03, 0x20, 0x98, 0xAB, 0xE3, - 0x65, 0x06, 0x02, 0x13, 0x60, 0x04, 0xBA, 0xCE, - 0x60, 0xC1, 0x94, 0x09, 0x02, 0x13, 0x60, 0x04, - 0x22, 0xDE, 0x60, 0xD1, 0x0E, 0xE0, 0x3D, 0x10, - 0x85, 0x07, 0xBE, 0xEA, 0x35, 0xC8, 0x8A, 0x09, - 0x15, 0xC8, 0x8C, 0x09, 0x0B, 0x10, 0xE0, 0x04, - 0xA0, 0x09, 0x20, 0xD8, 0x2E, 0x09, 0xA6, 0x09, - 0x20, 0xC8, 0xA8, 0x09, 0x8A, 0x09, 0x20, 0xC8, - 0xAA, 0x09, 0x8C, 0x09, 0xE0, 0x04, 0x8E, 0x09, - 0xCA, 0x04, 0xCD, 0x04, 0xCE, 0x04, 0xCF, 0x04, - 0xE0, 0x04, 0xA8, 0x06, 0xE0, 0x04, 0xBA, 0x06, - 0x84, 0x07, 0xA0, 0x01, 0x85, 0x07, 0x10, 0x00, - 0xF4, 0x04, 0x45, 0x06, 0xFD, 0x15, 0x84, 0x07, - 0xD8, 0x06, 0x85, 0x07, 0x34, 0x07, 0x44, 0x61, - 0xF4, 0x04, 0x45, 0x06, 0xFD, 0x15, 0x84, 0x07, - 0xC8, 0x00, 0x04, 0xC8, 0x00, 0x07, 0x84, 0x07, - 0xFF, 0x7F, 0x04, 0xC8, 0xF0, 0x06, 0x84, 0x07, - 0x06, 0x00, 0x04, 0xC8, 0xEE, 0x06, 0x85, 0x07, - 0x02, 0x0C, 0x20, 0xC1, 0x8A, 0x09, 0x01, 0x11, - 0xC5, 0x06, 0xB0, 0x03, 0x05, 0xD8, 0x65, 0x06, - 0x60, 0x04, 0xD2, 0xCE, 0xB0, 0x03, 0x20, 0x98, - 0xAA, 0xE3, 0x65, 0x06, 0x79, 0x16, 0x60, 0xD1, - 0x10, 0xE0, 0xF3, 0x10, 0x60, 0xD1, 0xAB, 0xE3, - 0xA0, 0x01, 0x8E, 0x09, 0x00, 0x02, 0xE0, 0x01, - 0x80, 0x01, 0x00, 0x20, 0xC8, 0x04, 0x20, 0xD2, - 0x80, 0x01, 0x08, 0xC8, 0x9C, 0x09, 0x08, 0xD8, - 0x2E, 0x09, 0xE3, 0x10, 0x20, 0xF8, 0x19, 0xEE, - 0x82, 0x01, 0x20, 0xC8, 0x10, 0xE0, 0xC6, 0x06, - 0x20, 0xC8, 0x20, 0xE0, 0xC8, 0x06, 0x20, 0xC8, - 0xC2, 0xEA, 0x90, 0x09, 0xE0, 0x2E, 0x00, 0x00, - 0xA0, 0x06, 0xE6, 0xD5, 0x20, 0xC8, 0x6C, 0x09, - 0xA0, 0x01, 0x20, 0xC8, 0x6E, 0x09, 0xA2, 0x01, - 0x20, 0xC8, 0x70, 0x09, 0xA4, 0x01, 0x20, 0xC8, - 0x6E, 0x09, 0xB0, 0x01, 0x20, 0xC8, 0x70, 0x09, - 0xB2, 0x01, 0x20, 0xC8, 0x70, 0x09, 0xCC, 0x06, - 0x20, 0xF8, 0x18, 0xEE, 0x80, 0x01, 0xB0, 0x03, - 0xA0, 0x01, 0x8E, 0x09, 0x00, 0x02, 0x20, 0x98, - 0xAA, 0xE3, 0x65, 0x06, 0x3A, 0x13, 0xE0, 0x01, - 0x8E, 0x09, 0x00, 0x02, 0x88, 0x07, 0x56, 0xDF, - 0xE0, 0xC2, 0x8A, 0x09, 0x05, 0x11, 0xA0, 0x01, - 0x8E, 0x09, 0x00, 0x02, 0x88, 0x07, 0x9A, 0xDF, - 0x98, 0x06, 0x08, 0x02, 0x12, 0x80, 0xA0, 0x06, - 0xDA, 0xD4, 0x84, 0x07, 0x0A, 0x00, 0x85, 0x07, - 0xF4, 0x03, 0x20, 0x88, 0xC6, 0x06, 0x20, 0xE0, - 0x08, 0x1B, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, - 0xA5, 0x13, 0x84, 0x07, 0x1C, 0x00, 0x85, 0x07, - 0xF8, 0x03, 0xA0, 0x06, 0xA2, 0xD8, 0x85, 0x07, - 0x42, 0xDC, 0x05, 0xC8, 0xF8, 0x03, 0x20, 0xC8, - 0xA0, 0x09, 0xA0, 0x09, 0x6C, 0x16, 0x20, 0xE8, - 0x9C, 0x09, 0xFE, 0x03, 0x20, 0xE8, 0x9E, 0x09, - 0x06, 0x04, 0xA0, 0x23, 0x0C, 0xE0, 0x32, 0x13, - 0xA0, 0xE3, 0x0C, 0xE0, 0xA0, 0x2E, 0xF4, 0x03, - 0x2D, 0x10, 0xA0, 0x06, 0x56, 0xDF, 0x60, 0x01, - 0x8E, 0x09, 0x00, 0x40, 0x08, 0x13, 0x08, 0x02, - 0x6C, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x22, 0x10, - 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x40, 0x08, 0x02, - 0x60, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x84, 0x07, - 0x2A, 0x00, 0x85, 0x07, 0xF4, 0x03, 0xA0, 0x06, - 0xA2, 0xD8, 0xD5, 0x10, 0xB0, 0x03, 0x20, 0x98, - 0xAA, 0xE3, 0x65, 0x06, 0x0F, 0x16, 0x20, 0x06, - 0x90, 0x09, 0x9A, 0x16, 0x60, 0x01, 0x8A, 0x09, - 0x00, 0x40, 0x39, 0x13, 0xE0, 0x04, 0x8A, 0x09, - 0xE0, 0x04, 0x8C, 0x09, 0xE0, 0x04, 0x8E, 0x09, - 0x60, 0x04, 0x62, 0xDA, 0x60, 0x04, 0xB0, 0xCE, - 0xB0, 0x03, 0x20, 0x98, 0x10, 0xE0, 0x65, 0x06, - 0xF9, 0x16, 0x44, 0x02, 0x00, 0x5E, 0x04, 0x16, - 0x20, 0x06, 0xC6, 0x06, 0x9A, 0x16, 0x0A, 0x10, - 0xB0, 0x03, 0x20, 0x98, 0x10, 0xE0, 0x65, 0x06, - 0xED, 0x16, 0x20, 0x06, 0xC8, 0x06, 0x02, 0x13, - 0x60, 0x04, 0x5A, 0xDB, 0x60, 0x01, 0x8E, 0x09, - 0x00, 0x01, 0x02, 0x16, 0xCE, 0x01, 0x03, 0x00, - 0x0E, 0x01, 0x03, 0x00, 0x03, 0x13, 0x83, 0x07, - 0x00, 0x82, 0x07, 0x10, 0x83, 0x07, 0x01, 0x00, - 0xE0, 0x04, 0x8E, 0x09, 0x20, 0xE8, 0x0C, 0xE0, - 0x82, 0x01, 0x60, 0x04, 0xCA, 0xCE, 0x60, 0x01, - 0x8A, 0x09, 0x00, 0x40, 0xC7, 0x16, 0x83, 0x07, - 0x0D, 0x00, 0xF2, 0x10, 0xB0, 0x03, 0x20, 0x98, - 0xAA, 0xE3, 0x65, 0x06, 0xC7, 0x16, 0x20, 0x88, - 0x98, 0x09, 0x20, 0xE0, 0xF0, 0x16, 0x22, 0xC8, - 0x0E, 0x00, 0xDC, 0x06, 0x22, 0xC8, 0x10, 0x00, - 0xDE, 0x06, 0x22, 0xC8, 0x12, 0x00, 0xE0, 0x06, - 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x80, 0x08, 0x02, - 0x66, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0xB2, 0x10, - 0xA0, 0x07, 0x9A, 0x09, 0x5A, 0x00, 0xA0, 0x07, - 0xA2, 0x09, 0x19, 0x00, 0xA0, 0x07, 0xA4, 0x09, - 0x05, 0x00, 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x20, - 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x04, 0x08, 0x02, - 0x78, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0xB0, 0x03, - 0x20, 0x98, 0xAB, 0xE3, 0x65, 0x06, 0x9A, 0x16, - 0x08, 0x02, 0x72, 0x80, 0xA0, 0x06, 0xDA, 0xD4, - 0x20, 0xE8, 0x0C, 0xE0, 0x82, 0x01, 0xA0, 0x06, - 0xD0, 0xD5, 0x20, 0x06, 0x9A, 0x09, 0xBF, 0x13, - 0x84, 0x07, 0x2C, 0x00, 0x85, 0x07, 0xF4, 0x03, - 0xA0, 0x06, 0xA2, 0xD8, 0x60, 0x04, 0xC0, 0xDB, - 0x20, 0x48, 0x0C, 0xE0, 0x82, 0x01, 0x82, 0x10, - 0x0E, 0x01, 0x03, 0x00, 0x0A, 0x13, 0x08, 0x02, - 0x0C, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0xE0, 0xE3, - 0x14, 0xE0, 0x20, 0xC8, 0xAE, 0xE4, 0x86, 0x01, - 0x26, 0x10, 0x20, 0x48, 0x0C, 0xE0, 0x82, 0x01, - 0xE0, 0x2E, 0x01, 0x00, 0x60, 0xC1, 0x1E, 0x09, - 0x35, 0x0A, 0x05, 0xE8, 0x82, 0x01, 0x20, 0xC1, - 0x6A, 0x09, 0x04, 0x01, 0x06, 0x00, 0x06, 0x13, - 0x20, 0xD8, 0xD0, 0xE1, 0x2F, 0x09, 0x20, 0xD8, - 0xD0, 0xE1, 0x83, 0x01, 0x20, 0x21, 0x22, 0xE0, - 0x03, 0x16, 0x20, 0xE8, 0x22, 0xE0, 0x80, 0x01, - 0x20, 0x21, 0x04, 0xE0, 0x04, 0x16, 0xA0, 0xE3, - 0x14, 0xE0, 0x60, 0x04, 0x0A, 0xD3, 0x08, 0x02, - 0x00, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x20, 0xE8, - 0x08, 0xE0, 0x82, 0x01, 0xE0, 0xC2, 0x8A, 0x09, - 0x02, 0x11, 0x60, 0x04, 0xB0, 0xCE, 0xA0, 0x01, - 0x8E, 0x09, 0x00, 0x04, 0x6B, 0x10, 0x20, 0xC8, - 0xAE, 0xE4, 0x86, 0x01, 0x08, 0x02, 0x00, 0x80, - 0xA0, 0x06, 0xDA, 0xD4, 0x20, 0xC2, 0x1E, 0x09, - 0x08, 0xA2, 0x08, 0x05, 0x28, 0xC8, 0x22, 0xE0, - 0xCA, 0x06, 0x20, 0xC8, 0x20, 0xE0, 0xC6, 0x06, - 0x20, 0xC8, 0x20, 0xE0, 0xC8, 0x06, 0x60, 0xE3, - 0x16, 0xE0, 0x60, 0x04, 0xD2, 0xCE, 0x44, 0xC1, - 0x44, 0x02, 0x00, 0x5E, 0xF8, 0x16, 0x60, 0x25, - 0xA8, 0xE4, 0x0F, 0x16, 0x20, 0x06, 0xC6, 0x06, - 0xF2, 0x16, 0x20, 0x06, 0xCA, 0x06, 0x03, 0x13, - 0xA0, 0x05, 0xCC, 0x06, 0xE6, 0x10, 0xB0, 0x03, - 0x20, 0xD8, 0x0C, 0xE0, 0x65, 0x06, 0x60, 0x04, - 0xD2, 0xCE, 0x20, 0x06, 0xC8, 0x06, 0xE3, 0x16, - 0x20, 0x88, 0x70, 0x09, 0xCC, 0x06, 0x03, 0x16, - 0x83, 0x07, 0x08, 0x00, 0x02, 0x10, 0x83, 0x07, - 0x0C, 0x00, 0x60, 0x04, 0x8A, 0xDC, 0x60, 0x04, - 0xD2, 0xCE, 0xA0, 0x23, 0x08, 0xE0, 0x03, 0x13, - 0x60, 0x23, 0x12, 0xE0, 0x06, 0x16, 0xB0, 0x03, - 0x20, 0xD8, 0xA9, 0xE3, 0x65, 0x06, 0x60, 0x04, - 0xD2, 0xCE, 0x08, 0x02, 0x00, 0x80, 0xA0, 0x06, - 0xDA, 0xD4, 0x60, 0x04, 0xB0, 0xCE, 0x08, 0x02, - 0x00, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x20, 0xC8, - 0x1E, 0xE0, 0xC6, 0x06, 0x20, 0xC8, 0x1E, 0xE0, - 0xC8, 0x06, 0x60, 0xE3, 0x10, 0xE0, 0x60, 0x04, - 0xD2, 0xCE, 0xE0, 0x23, 0x14, 0xE0, 0x30, 0x13, - 0x44, 0xC1, 0x44, 0x02, 0x00, 0x1E, 0xF5, 0x16, - 0x60, 0x25, 0xA8, 0xE4, 0x1D, 0x16, 0x20, 0x06, - 0xC8, 0x06, 0xEF, 0x16, 0x60, 0x01, 0x8E, 0x09, - 0x00, 0x80, 0x13, 0x16, 0x60, 0x01, 0x8E, 0x09, - 0x00, 0x01, 0x0C, 0x16, 0xA0, 0x01, 0x8E, 0x09, - 0x00, 0x01, 0xA0, 0x01, 0x8E, 0x09, 0x80, 0x00, - 0xA0, 0x43, 0x04, 0xE0, 0x83, 0x07, 0x18, 0x68, - 0xA0, 0x06, 0x2A, 0xD8, 0x20, 0xC8, 0xAE, 0xE4, - 0x86, 0x01, 0xC2, 0x04, 0x60, 0x04, 0x2C, 0xE4, - 0x08, 0x02, 0x1E, 0x80, 0xA0, 0x06, 0xDA, 0xD4, - 0x07, 0x10, 0x20, 0x06, 0xC6, 0x06, 0xCD, 0x16, - 0x83, 0x07, 0x09, 0x00, 0xA0, 0x06, 0x8A, 0xDC, - 0x60, 0x04, 0xB0, 0xCE, 0xCE, 0x04, 0xE0, 0x04, - 0x2A, 0x09, 0xE0, 0xD3, 0xAA, 0xE3, 0x8F, 0xC2, - 0x20, 0xC8, 0xB0, 0xE4, 0x86, 0x01, 0x20, 0x48, - 0x08, 0xE0, 0x82, 0x01, 0x86, 0x07, 0x05, 0x00, - 0x84, 0x07, 0x72, 0x06, 0x54, 0xC1, 0x01, 0x13, - 0xD4, 0x2C, 0x24, 0x02, 0x0A, 0x00, 0x06, 0x06, - 0xF9, 0x16, 0x08, 0x02, 0x2A, 0x80, 0xA0, 0x06, - 0xDA, 0xD4, 0x20, 0x2C, 0x1A, 0xE0, 0x60, 0x04, - 0x50, 0xCD, 0xA0, 0x06, 0x3E, 0xD7, 0xCD, 0x04, - 0xA0, 0x23, 0x1C, 0xE0, 0x0D, 0x13, 0x0E, 0x01, - 0x03, 0x00, 0x0A, 0x13, 0xA0, 0xE3, 0x1C, 0xE0, - 0xB0, 0x03, 0x20, 0xD8, 0x10, 0xE0, 0x65, 0x06, - 0xA0, 0xD2, 0x26, 0xE0, 0xCF, 0x04, 0x08, 0x10, - 0x20, 0x2D, 0x01, 0x00, 0xE0, 0xC0, 0x2A, 0x09, - 0xA0, 0x06, 0x2A, 0xD8, 0xA0, 0xD2, 0xAB, 0xE3, - 0x60, 0x04, 0xD2, 0xCE, 0xA0, 0x01, 0x80, 0x01, - 0x00, 0x01, 0xE0, 0x01, 0x80, 0x01, 0x00, 0xAC, - 0xA0, 0x01, 0x82, 0x01, 0x00, 0x03, 0xE0, 0x01, - 0x82, 0x01, 0x00, 0x08, 0x88, 0x07, 0xAE, 0x01, - 0x08, 0x06, 0xFE, 0x16, 0x60, 0x01, 0x8E, 0x09, - 0x00, 0x02, 0x03, 0x16, 0xA0, 0x01, 0x80, 0x01, - 0x00, 0x20, 0xC8, 0x04, 0x20, 0xD2, 0x80, 0x01, - 0x08, 0xC8, 0x9C, 0x09, 0x08, 0xD8, 0x2E, 0x09, - 0xA0, 0x07, 0x9E, 0x09, 0x00, 0x10, 0x5B, 0x04, - 0x20, 0xD8, 0xA6, 0x09, 0x2E, 0x09, 0xE0, 0x01, - 0x80, 0x01, 0x00, 0x04, 0xE0, 0x01, 0x82, 0x01, - 0x00, 0x08, 0xA0, 0x01, 0x82, 0x01, 0x00, 0x03, - 0x20, 0xC2, 0x30, 0x09, 0x03, 0x13, 0xE0, 0x01, - 0x82, 0x01, 0x00, 0x03, 0xA0, 0x01, 0x80, 0x01, - 0x00, 0xA1, 0x20, 0xF8, 0x2E, 0x09, 0x80, 0x01, - 0x88, 0x07, 0xAE, 0x01, 0x08, 0x06, 0xFE, 0x16, - 0xA0, 0x01, 0x80, 0x01, 0x00, 0x0C, 0xE0, 0x04, - 0x9E, 0x01, 0xE0, 0x04, 0x9C, 0x09, 0xE0, 0x04, - 0x9E, 0x09, 0x5B, 0x04, 0x20, 0x01, 0xA8, 0x09, - 0x00, 0x80, 0x11, 0x13, 0xE0, 0x93, 0x26, 0xE0, - 0x0E, 0x16, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, - 0x0A, 0x13, 0x08, 0x02, 0x84, 0x80, 0x00, 0x00, - 0x00, 0xE0, 0xDC, 0x0F, 0xA0, 0x06, 0xDA, 0xD4, - 0x20, 0x48, 0x08, 0xE0, 0x82, 0x01, 0x02, 0x10, - 0x60, 0x04, 0x70, 0xDA, 0x60, 0x04, 0xBA, 0xCE, - 0xA0, 0x06, 0x9C, 0xD5, 0x08, 0xC2, 0x19, 0x13, - 0x83, 0x07, 0x80, 0x80, 0xE0, 0x23, 0x14, 0xE0, - 0x02, 0x13, 0x83, 0x07, 0x0A, 0x00, 0x60, 0x04, - 0xC6, 0xCE, 0x20, 0xC1, 0x06, 0x06, 0x0D, 0x13, - 0xA0, 0x06, 0x9C, 0xD5, 0x08, 0xC2, 0x09, 0x13, - 0x83, 0x07, 0x0B, 0x00, 0xE0, 0x23, 0x14, 0xE0, - 0x02, 0x16, 0x83, 0x07, 0x01, 0x80, 0x60, 0x04, - 0xC6, 0xCE, 0x83, 0x07, 0x0A, 0x80, 0x60, 0x04, - 0xB4, 0xCE, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, - 0x06, 0x16, 0xA0, 0x06, 0xA8, 0xE5, 0x47, 0x10, - 0xD0, 0x03, 0x60, 0x04, 0xB0, 0xD3, 0xE0, 0x93, - 0x0E, 0xE0, 0x5E, 0x13, 0xE0, 0x93, 0x10, 0xE0, - 0x17, 0x13, 0xE0, 0x23, 0x14, 0xE0, 0x04, 0x13, - 0x83, 0x07, 0x07, 0x00, 0x60, 0x04, 0xC6, 0xCE, - 0x83, 0x07, 0x00, 0xA0, 0xA0, 0x06, 0x2A, 0xD8, - 0x83, 0x07, 0x00, 0x48, 0xA0, 0x06, 0x2A, 0xD8, - 0xA0, 0xD2, 0x10, 0xE0, 0x20, 0xC8, 0x1C, 0xE0, - 0xCA, 0x06, 0x20, 0xC8, 0x20, 0xE0, 0xCC, 0x06, - 0xA0, 0x06, 0x3E, 0xD7, 0x08, 0x02, 0x4E, 0x80, - 0xA0, 0x06, 0xDA, 0xD4, 0xA0, 0x23, 0x1C, 0xE0, - 0x20, 0x13, 0x20, 0x88, 0x6C, 0x09, 0x0E, 0x07, - 0x1C, 0x16, 0x20, 0x88, 0x6E, 0x09, 0x10, 0x07, - 0x18, 0x16, 0x20, 0x88, 0x70, 0x09, 0x12, 0x07, - 0x14, 0x16, 0x20, 0x88, 0x0A, 0x07, 0x22, 0xE0, - 0x10, 0x13, 0x20, 0x06, 0xCA, 0x06, 0x38, 0x16, - 0xA0, 0xE3, 0x20, 0xE0, 0x06, 0x10, 0xE0, 0x23, - 0x14, 0xE0, 0xCA, 0x16, 0xA0, 0xE3, 0x22, 0xE0, - 0xC2, 0x04, 0xA0, 0xD2, 0xAA, 0xE3, 0x60, 0x04, - 0xBA, 0xCE, 0x20, 0xC8, 0x1C, 0xE0, 0xCA, 0x06, - 0xA0, 0x88, 0xDC, 0x06, 0x0E, 0x00, 0x10, 0x16, - 0xA0, 0x88, 0xDE, 0x06, 0x10, 0x00, 0x0C, 0x16, - 0xA0, 0x88, 0xE0, 0x06, 0x12, 0x00, 0x08, 0x16, - 0x20, 0x06, 0xCC, 0x06, 0x19, 0x16, 0x20, 0xE8, - 0x0E, 0xE0, 0x82, 0x01, 0xA0, 0xE3, 0x1E, 0xE0, - 0x20, 0xC8, 0x20, 0xE0, 0xCC, 0x06, 0x10, 0x10, - 0xA0, 0x23, 0x10, 0xE0, 0x08, 0x16, 0x64, 0xC1, - 0x06, 0x00, 0x60, 0x21, 0x0C, 0xE0, 0x08, 0x13, - 0xA0, 0xD2, 0xA8, 0xE3, 0x05, 0x10, 0x20, 0x88, - 0x0A, 0x07, 0x08, 0x07, 0x96, 0x12, 0x00, 0x10, - 0x60, 0x04, 0xBA, 0xCE, 0x60, 0x01, 0x8E, 0x09, - 0x00, 0x80, 0x06, 0x16, 0x83, 0x07, 0x00, 0x82, - 0xA0, 0x06, 0x2A, 0xD8, 0x60, 0x04, 0xCA, 0xCE, - 0xE0, 0x93, 0x0E, 0xE0, 0x50, 0x13, 0xE0, 0x93, - 0xA9, 0xE3, 0x4D, 0x13, 0xE0, 0x93, 0xA8, 0xE3, - 0x1C, 0x13, 0xA0, 0x06, 0xA4, 0xD7, 0xA0, 0x23, - 0x10, 0xE0, 0x45, 0x13, 0xA0, 0x23, 0x08, 0xE0, - 0x06, 0x16, 0x60, 0xE3, 0x1E, 0xE0, 0x20, 0xC8, - 0x22, 0xE0, 0x06, 0x07, 0x34, 0x10, 0xE0, 0x23, - 0x14, 0xE0, 0x31, 0x16, 0x60, 0xC1, 0x6A, 0x09, - 0x60, 0x21, 0x12, 0xE0, 0x2C, 0x16, 0xA0, 0x06, - 0x0E, 0xE2, 0x31, 0x10, 0xA0, 0xD2, 0xA8, 0xE3, - 0x2E, 0x10, 0xA0, 0xE3, 0x12, 0xE0, 0xA0, 0x06, - 0x0E, 0xE2, 0x64, 0xC1, 0x06, 0x00, 0x60, 0x21, - 0x0C, 0xE0, 0x25, 0x13, 0x20, 0x88, 0x0E, 0x07, - 0xDC, 0x06, 0x14, 0x16, 0x20, 0x88, 0x10, 0x07, - 0xDE, 0x06, 0x10, 0x16, 0x20, 0x88, 0x12, 0x07, - 0xE0, 0x06, 0x0C, 0x16, 0x20, 0x98, 0xCE, 0x06, - 0xCF, 0x06, 0x15, 0x13, 0x20, 0x06, 0xCE, 0x06, - 0x12, 0x16, 0x60, 0xE3, 0x1A, 0xE0, 0xA0, 0xD2, - 0x0C, 0xE0, 0x0D, 0x10, 0x60, 0xE3, 0x1E, 0xE0, - 0x20, 0xC8, 0x32, 0xE0, 0x06, 0x07, 0xA0, 0x06, - 0x3E, 0xD7, 0x08, 0x02, 0x48, 0x80, 0xA0, 0x06, - 0xDA, 0xD4, 0xA0, 0xD2, 0xA9, 0xE3, 0x60, 0x04, - 0xBA, 0xCE, 0x22, 0x88, 0x0E, 0x00, 0x6C, 0x09, - 0xC9, 0x1A, 0x0B, 0x1B, 0x22, 0x88, 0x10, 0x00, - 0x6E, 0x09, 0xC4, 0x1A, 0x06, 0x1B, 0x22, 0x88, - 0x12, 0x00, 0x70, 0x09, 0xBF, 0x1A, 0x01, 0x1B, - 0x5B, 0x04, 0x60, 0xC1, 0x6C, 0x01, 0x85, 0x02, - 0x43, 0x00, 0xE1, 0x13, 0xE0, 0x93, 0xA8, 0xE3, - 0xDE, 0x16, 0xA0, 0xC8, 0x00, 0xEE, 0x02, 0x00, - 0x84, 0x07, 0x0E, 0x00, 0x42, 0xC1, 0xA0, 0xC0, - 0x6C, 0x01, 0x02, 0xC0, 0x25, 0x02, 0x48, 0x00, - 0x81, 0x07, 0x60, 0xE2, 0x83, 0x07, 0x14, 0xAE, - 0x60, 0x04, 0x9E, 0xE5, 0x02, 0x02, 0x00, 0xFC, - 0xCA, 0x10, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, - 0x06, 0x16, 0x83, 0x07, 0x00, 0x82, 0xA0, 0x06, - 0x2A, 0xD8, 0x60, 0x04, 0xCA, 0xCE, 0x20, 0x98, - 0x0E, 0xE0, 0x65, 0x06, 0x03, 0x16, 0x20, 0xD8, - 0xA8, 0xE3, 0x65, 0x06, 0xE0, 0x93, 0xA9, 0xE3, - 0x0D, 0x13, 0xA0, 0x23, 0x08, 0xE0, 0x19, 0x16, - 0xA0, 0x23, 0x10, 0xE0, 0x16, 0x13, 0x60, 0xE3, - 0x1E, 0xE0, 0x20, 0xC8, 0x20, 0xE0, 0x06, 0x07, - 0xA0, 0x06, 0x3E, 0xD7, 0xA0, 0x43, 0x18, 0xE0, - 0xE0, 0x2E, 0x01, 0x00, 0xA0, 0xD2, 0x26, 0xE0, - 0x83, 0x07, 0x10, 0x00, 0xA0, 0x06, 0x2A, 0xD8, - 0xE0, 0x23, 0x14, 0xE0, 0x02, 0x16, 0xA0, 0x06, - 0x18, 0xD7, 0xA0, 0x43, 0x2C, 0xE0, 0x20, 0xC8, - 0x20, 0xE0, 0x24, 0x09, 0x60, 0x04, 0xBA, 0xCE, - 0xA0, 0x06, 0xA8, 0xE5, 0x01, 0x10, 0x03, 0x10, - 0x20, 0x07, 0xA0, 0x09, 0x03, 0x10, 0xA0, 0x07, - 0xA2, 0x09, 0x19, 0x00, 0x60, 0x04, 0xBA, 0xCE, - 0xA0, 0x43, 0x0E, 0xE0, 0xA0, 0xC1, 0x24, 0x09, - 0x02, 0x13, 0x20, 0x06, 0x24, 0x09, 0xE0, 0x23, - 0x14, 0xE0, 0x03, 0x13, 0xA0, 0x23, 0x08, 0xE0, - 0x29, 0x16, 0x20, 0xC2, 0x8A, 0x09, 0xE4, 0x11, - 0x08, 0x02, 0x42, 0x80, 0xA0, 0x06, 0xDA, 0xD4, - 0xA0, 0x23, 0x08, 0xE0, 0x1F, 0x16, 0xA0, 0x23, - 0x10, 0xE0, 0x0A, 0x16, 0x22, 0xC1, 0x02, 0x00, - 0x20, 0x25, 0xA8, 0xE4, 0x23, 0x16, 0x83, 0x07, - 0x20, 0x80, 0xA0, 0x06, 0x2A, 0xD8, 0x12, 0x10, - 0xA0, 0x06, 0x3E, 0xD7, 0xE0, 0x23, 0x14, 0xE0, - 0x02, 0x16, 0xA0, 0x06, 0x18, 0xD7, 0x60, 0xE3, - 0x1E, 0xE0, 0x20, 0xC8, 0x20, 0xE0, 0x06, 0x07, - 0xA0, 0x23, 0x08, 0xE0, 0x03, 0x16, 0xA0, 0x23, - 0x06, 0xE0, 0x51, 0x13, 0x20, 0x98, 0x0E, 0xE0, - 0x65, 0x06, 0x03, 0x16, 0x20, 0xD8, 0xA8, 0xE3, - 0x65, 0x06, 0x22, 0xC1, 0x02, 0x00, 0x20, 0x25, - 0xA8, 0xE4, 0x0E, 0x13, 0x83, 0x07, 0x20, 0x00, - 0xA0, 0x06, 0x2A, 0xD8, 0x22, 0xC8, 0x0E, 0x00, - 0xE6, 0x06, 0x22, 0xC8, 0x10, 0x00, 0xE8, 0x06, - 0x22, 0xC8, 0x12, 0x00, 0xEA, 0x06, 0x37, 0x10, - 0x22, 0x88, 0x0E, 0x00, 0xDC, 0x06, 0x08, 0x16, - 0x22, 0x88, 0x10, 0x00, 0xDE, 0x06, 0x04, 0x16, - 0x22, 0x88, 0x12, 0x00, 0xE0, 0x06, 0x0B, 0x13, - 0x22, 0xC8, 0x0E, 0x00, 0xDC, 0x06, 0x22, 0xC8, - 0x10, 0x00, 0xDE, 0x06, 0x22, 0xC8, 0x12, 0x00, - 0xE0, 0x06, 0x60, 0xE3, 0x14, 0xE0, 0xA0, 0x23, - 0x0E, 0xE0, 0x08, 0x16, 0xA0, 0xC1, 0x24, 0x09, - 0x1A, 0x16, 0x86, 0x07, 0x00, 0x10, 0x06, 0xE8, - 0xD2, 0x06, 0x15, 0x10, 0xA0, 0xE3, 0x0E, 0xE0, - 0xA0, 0x23, 0x08, 0xE0, 0x09, 0x16, 0xA0, 0xE3, - 0x06, 0xE0, 0xE0, 0x04, 0xE6, 0x06, 0xE0, 0x04, - 0xE8, 0x06, 0xE0, 0x04, 0xEA, 0x06, 0x07, 0x10, - 0x08, 0x02, 0x36, 0x80, 0xA0, 0x07, 0xD6, 0x06, - 0x36, 0xD3, 0xA0, 0x06, 0xDA, 0xD4, 0x60, 0x04, - 0xBA, 0xCE, 0x20, 0x98, 0x65, 0x06, 0x10, 0xE0, - 0x03, 0x16, 0x20, 0xD8, 0x0E, 0xE0, 0x65, 0x06, - 0x60, 0x04, 0xBA, 0xCE, 0xE0, 0x23, 0x14, 0xE0, - 0x02, 0x13, 0x60, 0x04, 0xBA, 0xCE, 0x2E, 0x10, - 0xB0, 0x03, 0x20, 0x98, 0xA9, 0xE3, 0x6F, 0x06, - 0x19, 0x16, 0x24, 0xC2, 0x08, 0x00, 0x16, 0x11, - 0xE0, 0xE3, 0x14, 0xE0, 0x83, 0x07, 0x00, 0x00, - 0xA0, 0x06, 0x2A, 0xD8, 0xA0, 0x23, 0x14, 0xE0, - 0x04, 0x13, 0x08, 0x02, 0x06, 0x80, 0xA0, 0x06, - 0xDA, 0xD4, 0x08, 0x02, 0x1E, 0x00, 0xA0, 0x06, - 0xDA, 0xD4, 0xA0, 0x23, 0x08, 0xE0, 0x02, 0x13, - 0xA0, 0x06, 0x18, 0xD7, 0x82, 0xC0, 0x02, 0x16, - 0x60, 0x04, 0xD2, 0xCE, 0x20, 0xE8, 0x1C, 0xEE, - 0xF0, 0x06, 0x20, 0x99, 0x0E, 0xE0, 0x16, 0x00, - 0x05, 0x16, 0xE0, 0x04, 0xEC, 0x06, 0x20, 0x48, - 0x14, 0xE0, 0xF0, 0x06, 0x83, 0x07, 0x01, 0x00, - 0x60, 0x04, 0xB4, 0xCE, 0x64, 0xC2, 0x14, 0x00, - 0x24, 0x02, 0x18, 0x00, 0xC4, 0xC1, 0xC2, 0x61, - 0x27, 0x02, 0xFC, 0xFF, 0x74, 0xC1, 0x85, 0xC1, - 0x45, 0x71, 0x85, 0x02, 0x27, 0x00, 0x46, 0x16, - 0x54, 0xC1, 0x45, 0x02, 0xCF, 0xFF, 0x42, 0x16, - 0xC8, 0x04, 0x64, 0xC1, 0x08, 0x00, 0x06, 0x15, - 0x05, 0x13, 0x24, 0xC2, 0x0E, 0x00, 0x48, 0x02, - 0x00, 0x1F, 0xC8, 0x06, 0x28, 0x02, 0x11, 0x00, - 0x04, 0xA2, 0x18, 0x98, 0x21, 0xEE, 0x32, 0x16, - 0x42, 0xC1, 0x25, 0x02, 0x04, 0x00, 0x47, 0x65, - 0x35, 0xC2, 0x74, 0xCD, 0x48, 0x06, 0xFD, 0x15, - 0xA0, 0xC0, 0x6C, 0x01, 0x02, 0xC1, 0x04, 0xC8, - 0x6C, 0x01, 0xA0, 0xC1, 0x00, 0xFC, 0x05, 0x13, - 0x20, 0xC8, 0x80, 0xEB, 0x02, 0xFC, 0x06, 0xC1, - 0xF6, 0x10, 0x20, 0xC8, 0x00, 0xEE, 0x02, 0xFC, - 0x02, 0xC8, 0x6C, 0x01, 0x81, 0x07, 0x08, 0xE5, - 0x04, 0xC0, 0x83, 0x07, 0x10, 0x02, 0x84, 0x07, - 0x0E, 0x00, 0x3B, 0x10, 0x84, 0x07, 0x0C, 0x00, - 0xE2, 0xC0, 0x08, 0x00, 0x05, 0x02, 0x00, 0xFC, - 0xA0, 0xC0, 0x6C, 0x01, 0x02, 0xC0, 0x95, 0xC1, - 0x30, 0x13, 0xD5, 0x04, 0x16, 0x2E, 0x02, 0xC8, - 0x6C, 0x01, 0x2B, 0x10, 0xA0, 0xC8, 0x22, 0xEE, - 0x0E, 0x00, 0xA0, 0xC8, 0x24, 0xEE, 0x10, 0x00, - 0xA0, 0xC8, 0x26, 0xEE, 0x12, 0x00, 0x83, 0x07, - 0x06, 0x80, 0x60, 0x04, 0xB4, 0xCE, 0x60, 0x04, - 0xD2, 0xCE, 0x84, 0x07, 0x10, 0x00, 0x85, 0x07, - 0x34, 0x00, 0x09, 0x10, 0x84, 0x07, 0x12, 0x00, - 0x85, 0x07, 0x32, 0x00, 0x04, 0x10, 0x84, 0x07, - 0x14, 0x00, 0x85, 0x07, 0x38, 0x00, 0xA0, 0x06, - 0xC2, 0xD5, 0x85, 0xC8, 0x04, 0x00, 0xA0, 0x06, - 0x10, 0xD6, 0xA0, 0xC8, 0x00, 0xEE, 0x02, 0x00, - 0xA0, 0xC0, 0x6C, 0x01, 0x02, 0xC0, 0x48, 0x06, - 0x48, 0xC1, 0xA0, 0x06, 0xA2, 0xD8, 0x07, 0x02, - 0xA2, 0x06, 0x60, 0xC5, 0x02, 0xFC, 0x25, 0x02, - 0xF4, 0xFF, 0x05, 0xC8, 0x02, 0xFC, 0x20, 0xC2, - 0x6C, 0x01, 0xA0, 0x06, 0xFC, 0xB4, 0x60, 0x04, - 0xB0, 0xCE, 0xA0, 0x06, 0xA2, 0xD8, 0x07, 0x02, - 0xB4, 0x06, 0xEF, 0x10, 0x22, 0x88, 0x12, 0x00, - 0x70, 0x09, 0x08, 0x16, 0x22, 0x88, 0x10, 0x00, - 0x6E, 0x09, 0x04, 0x16, 0x22, 0x88, 0x0E, 0x00, - 0x6C, 0x09, 0x0E, 0x13, 0x22, 0x88, 0x12, 0x00, - 0xE0, 0x06, 0x08, 0x16, 0x22, 0x88, 0x10, 0x00, - 0xDE, 0x06, 0x04, 0x16, 0x22, 0x88, 0x0E, 0x00, - 0xDC, 0x06, 0x01, 0x13, 0xCB, 0x05, 0xCB, 0x05, - 0x5B, 0x04, 0x0B, 0xC3, 0x00, 0x03, 0x02, 0x00, - 0x82, 0x07, 0xC0, 0x00, 0x20, 0xC8, 0x0C, 0x00, - 0xC0, 0x00, 0x20, 0xC8, 0x0E, 0x00, 0xC2, 0x00, - 0x20, 0xC8, 0x10, 0x00, 0xC4, 0x00, 0x20, 0xC8, - 0x12, 0x00, 0xC6, 0x00, 0x20, 0xC8, 0x14, 0x00, - 0xC8, 0x00, 0x20, 0xC8, 0x16, 0x00, 0xCA, 0x00, - 0x20, 0xC8, 0x04, 0x00, 0xCC, 0x00, 0x20, 0xC8, - 0x06, 0x00, 0xCE, 0x00, 0x02, 0xC8, 0x0C, 0x00, - 0xA0, 0x07, 0x0E, 0x00, 0x7E, 0xE6, 0x02, 0xC8, - 0x10, 0x00, 0xA0, 0x07, 0x12, 0x00, 0x88, 0xE6, - 0x02, 0xC8, 0x14, 0x00, 0xA0, 0x07, 0x16, 0x00, - 0xB8, 0xE6, 0x02, 0xC8, 0x04, 0x00, 0xA0, 0x07, - 0x06, 0x00, 0xCE, 0xE6, 0x60, 0x01, 0x1C, 0x01, - 0x04, 0x00, 0x09, 0x16, 0xE0, 0x01, 0x40, 0x01, - 0x00, 0x08, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x40, - 0xE0, 0x01, 0x40, 0x01, 0x00, 0x04, 0xA0, 0x06, - 0x8E, 0xE9, 0x05, 0x02, 0x00, 0x80, 0x05, 0xD8, - 0x80, 0x04, 0xC7, 0x04, 0x00, 0x03, 0x0F, 0x00, - 0x88, 0x07, 0x00, 0x10, 0x09, 0x02, 0x00, 0x20, - 0x8A, 0x07, 0xE6, 0xE6, 0x03, 0x02, 0x3E, 0xE6, - 0x5A, 0x04, 0x00, 0x03, 0x00, 0x00, 0x20, 0xD2, - 0x87, 0x01, 0x06, 0x10, 0x00, 0x03, 0x00, 0x00, - 0x20, 0xC2, 0x8A, 0x01, 0x08, 0x02, 0x00, 0x1A, - 0x60, 0xC2, 0xAE, 0x00, 0x48, 0xDA, 0x80, 0x04, - 0x89, 0x05, 0x89, 0x02, 0x06, 0x00, 0x07, 0x15, - 0x88, 0x07, 0x00, 0x80, 0x48, 0xDA, 0x80, 0x04, - 0x09, 0xC8, 0xAE, 0x00, 0x80, 0x03, 0xE0, 0x02, - 0xA0, 0x00, 0x5C, 0x04, 0x00, 0x03, 0x00, 0x00, - 0x60, 0x01, 0x9C, 0x01, 0x20, 0x00, 0xE2, 0x13, - 0x20, 0xC2, 0x8C, 0x01, 0x08, 0x02, 0x00, 0x1C, - 0xE3, 0x10, 0x00, 0x03, 0x00, 0x00, 0x60, 0x01, - 0x40, 0x01, 0x00, 0x40, 0xEC, 0x16, 0xA0, 0x01, - 0x40, 0x01, 0x00, 0x40, 0x08, 0x02, 0x00, 0x02, - 0xD7, 0x10, 0xB3, 0xC0, 0x92, 0x06, 0xFD, 0x10, - 0xB3, 0xC0, 0x48, 0xC0, 0x72, 0xCC, 0x72, 0xCC, - 0x32, 0xC1, 0x44, 0xCC, 0x72, 0xDC, 0x04, 0x06, - 0xFD, 0x16, 0x5B, 0x04, 0x48, 0xC0, 0x02, 0x02, - 0xD0, 0xE9, 0x84, 0x07, 0x06, 0x00, 0xF6, 0x10, - 0x02, 0x02, 0x1E, 0xE6, 0x49, 0xC0, 0x84, 0x07, - 0x06, 0x00, 0xF0, 0x10, 0xB3, 0xC0, 0x32, 0xC1, - 0x01, 0x02, 0x01, 0x00, 0x44, 0xD0, 0xC1, 0x06, - 0x44, 0x02, 0xFF, 0x00, 0xE7, 0x10, 0x33, 0xC1, - 0x73, 0xC0, 0x44, 0xD1, 0x44, 0x02, 0xFF, 0x00, - 0x45, 0xDC, 0x04, 0x06, 0xFD, 0x16, 0x5A, 0x04, - 0xA0, 0x06, 0x0E, 0xE9, 0x33, 0xC8, 0x9E, 0x01, - 0x5A, 0x04, 0xA0, 0x06, 0x0C, 0xE7, 0x89, 0xC1, - 0xA6, 0x09, 0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, - 0x8A, 0x01, 0x88, 0xC1, 0xA6, 0x09, 0x66, 0x02, - 0x40, 0x00, 0x06, 0xC8, 0x8C, 0x01, 0xC2, 0x04, - 0xC7, 0xC1, 0x03, 0x16, 0x02, 0x06, 0xFC, 0x16, - 0x4D, 0x10, 0x5A, 0x04, 0xA0, 0x06, 0x58, 0xE8, - 0x89, 0xC1, 0xA6, 0x09, 0x66, 0x02, 0x40, 0x00, - 0x06, 0xC8, 0x8A, 0x01, 0x88, 0xC1, 0xA6, 0x09, - 0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, 0x8C, 0x01, - 0x33, 0xC8, 0x9E, 0x01, 0xE8, 0x10, 0x33, 0x8A, - 0x02, 0x00, 0x38, 0x16, 0x73, 0x8A, 0x02, 0x00, - 0x35, 0x16, 0x5A, 0x04, 0x20, 0x8A, 0xCA, 0xE9, - 0x02, 0x00, 0x30, 0x16, 0x60, 0x8A, 0xCE, 0xE9, - 0x02, 0x00, 0x2C, 0x16, 0x82, 0x07, 0x74, 0xEA, - 0x01, 0x10, 0xB3, 0xC0, 0x04, 0x02, 0x80, 0x04, - 0x52, 0xD1, 0x03, 0x13, 0x32, 0x9D, 0x22, 0x16, - 0xFB, 0x10, 0x85, 0x07, 0x00, 0x80, 0x05, 0xD8, - 0x80, 0x04, 0xC7, 0x04, 0x5A, 0x04, 0x20, 0xC8, - 0xC0, 0x00, 0x0C, 0x00, 0x20, 0xC8, 0xC2, 0x00, - 0x0E, 0x00, 0x20, 0xC8, 0xC4, 0x00, 0x10, 0x00, - 0x20, 0xC8, 0xC6, 0x00, 0x12, 0x00, 0x20, 0xC8, - 0xC8, 0x00, 0x14, 0x00, 0x20, 0xC8, 0xCA, 0x00, - 0x16, 0x00, 0x20, 0xC8, 0xCC, 0x00, 0x04, 0x00, - 0x20, 0xC8, 0xCE, 0x00, 0x06, 0x00, 0x00, 0x03, - 0x0F, 0x00, 0xCC, 0x05, 0x5C, 0x04, 0xE0, 0x04, - 0x82, 0x01, 0x02, 0x02, 0x18, 0xE6, 0x32, 0xC8, - 0x82, 0x01, 0x32, 0xC8, 0x80, 0x01, 0xA0, 0x06, - 0x24, 0xE8, 0x12, 0xC8, 0x82, 0x01, 0xCA, 0xC2, - 0x84, 0x07, 0xD0, 0x07, 0xE0, 0x04, 0x84, 0x01, - 0x04, 0x06, 0xFC, 0x16, 0x20, 0xC1, 0x84, 0x01, - 0xE9, 0x16, 0x04, 0x02, 0x32, 0x00, 0x85, 0x07, - 0x00, 0x80, 0x05, 0xD8, 0x80, 0x04, 0xC7, 0x04, - 0x60, 0xC1, 0x86, 0x01, 0x04, 0x06, 0xFC, 0x16, - 0x20, 0xC1, 0x84, 0x01, 0x5B, 0x04, 0xB3, 0xC0, - 0xB3, 0xC4, 0x5B, 0x04, 0x48, 0xC0, 0xB3, 0xC0, - 0x73, 0xA0, 0x42, 0xC4, 0x5B, 0x04, 0x33, 0x88, - 0x84, 0x01, 0xE6, 0x16, 0x5A, 0x04, 0x89, 0xC1, - 0xA6, 0x09, 0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, - 0x8A, 0x01, 0x5B, 0x04, 0xC5, 0x04, 0xA0, 0x07, - 0x9C, 0x01, 0x40, 0x00, 0x60, 0x01, 0x9C, 0x01, - 0x40, 0x00, 0x03, 0x13, 0x05, 0x06, 0xF7, 0x16, - 0x5C, 0x04, 0x5B, 0x04, 0xA0, 0x06, 0xAC, 0xE8, - 0x60, 0xC0, 0x40, 0x01, 0x05, 0xC8, 0x40, 0x01, - 0x02, 0xC5, 0x01, 0xC8, 0x40, 0x01, 0x5A, 0x04, - 0xA0, 0x06, 0xAC, 0xE8, 0x08, 0xA1, 0xF4, 0x10, - 0xB3, 0xC0, 0x33, 0xC1, 0x60, 0xC1, 0x40, 0x01, - 0x85, 0x01, 0x00, 0x04, 0xC5, 0x01, 0x00, 0x10, - 0x5B, 0x04, 0x08, 0xC1, 0x09, 0xC2, 0x44, 0xC2, - 0x5B, 0x04, 0x05, 0x02, 0xC8, 0x00, 0x05, 0x06, - 0xFE, 0x16, 0x5B, 0x04, 0x33, 0xC1, 0x03, 0xC0, - 0xC4, 0xC0, 0x5B, 0x04, 0xC0, 0xC0, 0x5B, 0x04, - 0xE0, 0x94, 0x9E, 0x01, 0xC2, 0x16, 0xC3, 0x05, - 0x5B, 0x04, 0x73, 0xC0, 0xA0, 0x06, 0x26, 0xE9, - 0x2D, 0x02, 0x08, 0x00, 0x85, 0x07, 0x08, 0x00, - 0x71, 0x9F, 0xB7, 0x16, 0x05, 0x06, 0xFC, 0x16, - 0x5A, 0x04, 0x02, 0x02, 0x24, 0xE6, 0x60, 0x04, - 0x10, 0xE7, 0xE9, 0x8C, 0x04, 0x00, 0xAD, 0x16, - 0x5B, 0x04, 0x20, 0xC1, 0x80, 0x01, 0x85, 0x07, - 0xD0, 0x07, 0xE0, 0x01, 0x80, 0x01, 0x00, 0x04, - 0x45, 0x06, 0xFE, 0x16, 0x04, 0xC8, 0x80, 0x01, - 0x5B, 0x04, 0x33, 0xC1, 0x48, 0xC3, 0x04, 0xC1, - 0x04, 0x13, 0x2D, 0x02, 0x00, 0x04, 0x04, 0x06, - 0xFC, 0x16, 0x5B, 0x04, 0x8D, 0xC3, 0xA0, 0x06, - 0x26, 0xE9, 0x8D, 0xC1, 0xA6, 0x09, 0x66, 0x02, - 0x40, 0x00, 0x86, 0xC7, 0x5A, 0x04, 0x8D, 0xC1, - 0xA6, 0x09, 0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, - 0x8A, 0x01, 0x5B, 0x04, 0x8D, 0xC1, 0xA6, 0x09, - 0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, 0x8C, 0x01, - 0x5B, 0x04, 0x4D, 0xC0, 0x04, 0x02, 0x28, 0x00, - 0x85, 0x07, 0x00, 0x55, 0x60, 0x04, 0x34, 0xE7, - 0x4D, 0xC0, 0xB3, 0xC0, 0x32, 0xC1, 0x60, 0x04, - 0xF8, 0xE6, 0x33, 0xC1, 0x60, 0x01, 0x1C, 0x01, - 0x04, 0x00, 0x01, 0x16, 0x5B, 0x04, 0xC4, 0xC0, - 0x5B, 0x04, 0x89, 0x07, 0x66, 0xE5, 0x39, 0xC2, - 0x07, 0x13, 0x39, 0xC6, 0x39, 0x86, 0x25, 0x16, - 0x39, 0xC6, 0x39, 0x86, 0x22, 0x16, 0xF7, 0x10, - 0x02, 0x02, 0xAC, 0xE9, 0xC4, 0x04, 0xC5, 0x04, - 0x39, 0xC2, 0x02, 0x13, 0x60, 0x04, 0xE8, 0xE9, - 0x02, 0x02, 0xBA, 0xE9, 0xC4, 0x04, 0x39, 0xC2, - 0x03, 0x13, 0x79, 0xC1, 0x60, 0x04, 0xE8, 0xE9, - 0x02, 0x02, 0xCA, 0xE9, 0xC5, 0x04, 0x39, 0xC2, - 0x03, 0x13, 0x39, 0xC1, 0x60, 0x04, 0xE8, 0xE9, - 0x79, 0xC0, 0xB9, 0xC0, 0x81, 0x60, 0xC2, 0x05, - 0x12, 0x09, 0xF1, 0x04, 0x02, 0x06, 0xFD, 0x16, - 0x5B, 0x04, 0x5C, 0x04, 0x01, 0x02, 0xAA, 0xAA, - 0x01, 0xC6, 0x44, 0xE0, 0x45, 0x40, 0x58, 0x80, - 0xF8, 0x16, 0x01, 0x02, 0x14, 0x00, 0x01, 0x06, - 0xFE, 0x16, 0x01, 0x02, 0x55, 0x55, 0x01, 0xC6, - 0x44, 0xE0, 0x45, 0x40, 0x58, 0x80, 0xED, 0x16, - 0x52, 0x04, 0xE0, 0x02, 0xA0, 0x00, 0x88, 0x07, - 0xC0, 0x00, 0x09, 0x02, 0x62, 0xEA, 0x84, 0x07, - 0x2A, 0xE6, 0x05, 0x02, 0x01, 0x00, 0x8B, 0xC2, - 0xCC, 0x04, 0xA0, 0x06, 0x6C, 0xEA, 0x60, 0x2C, - 0x01, 0x00, 0x99, 0x06, 0xA0, 0x2C, 0x02, 0x00, - 0x99, 0x06, 0x20, 0x2D, 0x04, 0x00, 0x99, 0x06, - 0x20, 0x2E, 0x08, 0x00, 0x99, 0x06, 0xA0, 0x2F, - 0x10, 0x00, 0x8C, 0x05, 0x09, 0x16, 0x80, 0xCC, - 0x81, 0xC4, 0x83, 0x07, 0xB0, 0xEA, 0x88, 0xC0, - 0x02, 0x04, 0x8C, 0x05, 0x01, 0x16, 0x33, 0x10, - 0xE0, 0x02, 0xA0, 0x00, 0x5A, 0x04, 0x8C, 0x05, - 0xFB, 0x16, 0x80, 0xCC, 0x81, 0xC4, 0x15, 0x0A, - 0xB4, 0xC0, 0x12, 0xC0, 0x88, 0xCC, 0x52, 0xC0, - 0xB4, 0xC4, 0x42, 0x06, 0x5B, 0x04, 0x2D, 0x07, - 0x18, 0x00, 0x41, 0x8B, 0x0A, 0x00, 0xEC, 0x16, - 0xC1, 0x82, 0xEA, 0x16, 0xC2, 0x02, 0x42, 0x02, - 0x00, 0x02, 0xE6, 0x16, 0x80, 0x03, 0x81, 0x07, - 0x01, 0x00, 0xF1, 0x10, 0x01, 0x02, 0x02, 0x00, - 0xEE, 0x10, 0x01, 0x02, 0x04, 0x00, 0xEB, 0x10, - 0x01, 0x02, 0x08, 0x00, 0xE8, 0x10, 0x01, 0x02, - 0x10, 0x00, 0xE5, 0x10, 0xA1, 0x02, 0x41, 0x8B, - 0x10, 0x00, 0x02, 0x13, 0x60, 0x04, 0x5C, 0xEA, - 0x2D, 0x07, 0x18, 0x00, 0x80, 0x03, 0x09, 0x02, - 0x00, 0x08, 0x03, 0x02, 0x04, 0x00, 0xC7, 0x04, - 0xA0, 0x06, 0xDC, 0xEB, 0x60, 0x01, 0x1C, 0x01, - 0x04, 0x00, 0x1C, 0x16, 0xA0, 0x01, 0x40, 0x01, - 0x00, 0x08, 0xE0, 0x01, 0x40, 0x01, 0x00, 0x10, - 0x04, 0x02, 0x01, 0x00, 0x44, 0xCE, 0xC4, 0x06, - 0x44, 0xC6, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x10, - 0x49, 0x06, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x40, - 0xE0, 0x01, 0x40, 0x01, 0x00, 0x04, 0xE0, 0x01, - 0x40, 0x01, 0x00, 0x08, 0xA0, 0x06, 0x7A, 0xEC, - 0xA0, 0x06, 0x7A, 0xEC, 0xC7, 0x05, 0x04, 0x02, - 0xE4, 0xE4, 0xE0, 0x04, 0xD0, 0x03, 0x74, 0xC1, - 0xB4, 0xC1, 0x86, 0x05, 0x1C, 0x13, 0xE0, 0x02, - 0xC0, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, 0xC0, - 0x80, 0xC0, 0xC0, 0xC0, 0x00, 0xC1, 0x40, 0xC1, - 0x80, 0xC1, 0xC0, 0xC1, 0x00, 0xC2, 0x40, 0xC2, - 0x80, 0xC2, 0xC0, 0xC2, 0x00, 0xC3, 0x40, 0xC3, - 0x80, 0xC3, 0xC0, 0xC3, 0xA0, 0x04, 0xAA, 0x00, - 0xD0, 0x03, 0xD0, 0x03, 0x3F, 0x10, 0x85, 0x05, - 0x85, 0x81, 0xE1, 0x13, 0xE4, 0x10, 0xC7, 0x05, - 0x05, 0x02, 0xFF, 0x7F, 0x45, 0xA1, 0xD0, 0x03, - 0xD0, 0x03, 0x34, 0x10, 0xC0, 0xCC, 0xC1, 0xC4, - 0x03, 0x02, 0x28, 0x00, 0xA0, 0x06, 0xDC, 0xEB, - 0xE0, 0x01, 0x42, 0x01, 0x00, 0x10, 0xC7, 0x05, - 0xD0, 0x03, 0xD0, 0x03, 0x27, 0x10, 0xC7, 0x05, - 0xA0, 0xC1, 0x4A, 0x01, 0xA0, 0x07, 0x4A, 0x01, - 0x00, 0x0E, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x02, - 0x20, 0x07, 0x44, 0x01, 0x60, 0xC1, 0x44, 0x01, - 0x85, 0x02, 0x00, 0xFF, 0x17, 0x16, 0xE0, 0x01, - 0x40, 0x01, 0x00, 0x22, 0x05, 0x02, 0xC0, 0x00, - 0x05, 0x06, 0xD0, 0x03, 0xFD, 0x16, 0x60, 0xC1, - 0x46, 0x01, 0x85, 0x02, 0x00, 0xFF, 0x0A, 0x13, - 0x05, 0x02, 0x93, 0x33, 0x05, 0x06, 0x00, 0x10, - 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, - 0xD0, 0x03, 0xF8, 0x16, 0x51, 0x10, 0x06, 0xC8, - 0x4A, 0x01, 0xC0, 0xCC, 0xC1, 0xC4, 0x4B, 0x10, - 0x13, 0xC0, 0xC8, 0xCC, 0x53, 0xC0, 0x02, 0x02, - 0xEC, 0xEB, 0xC2, 0xC4, 0x43, 0x06, 0x5B, 0x04, - 0x60, 0xC0, 0xAE, 0x00, 0xC4, 0x02, 0x44, 0x02, - 0x0F, 0x00, 0x44, 0x88, 0xCA, 0xE4, 0x3C, 0x16, - 0x81, 0x02, 0x08, 0x00, 0x27, 0x13, 0x21, 0xC1, - 0xDC, 0xE4, 0x14, 0xC1, 0x21, 0x21, 0xBA, 0xE4, - 0x33, 0x16, 0x21, 0xC1, 0xC2, 0xE4, 0x81, 0x02, - 0x00, 0x00, 0x0B, 0x13, 0x0D, 0x02, 0xA0, 0x00, - 0x84, 0x83, 0x09, 0x13, 0xC4, 0x05, 0x84, 0x83, - 0x06, 0x13, 0xC4, 0x05, 0x84, 0x83, 0x03, 0x13, - 0x23, 0x10, 0x0E, 0x81, 0x21, 0x16, 0x21, 0xC1, - 0xDC, 0xE4, 0x21, 0x45, 0xBA, 0xE4, 0xE0, 0x01, - 0x42, 0x01, 0x00, 0x10, 0xA0, 0x01, 0x42, 0x01, - 0x00, 0x10, 0xA1, 0xC3, 0xD4, 0xE4, 0x0F, 0x02, - 0x2F, 0x00, 0x80, 0x03, 0xA0, 0x01, 0x40, 0x01, - 0x00, 0x02, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x80, - 0x6D, 0xC0, 0x0A, 0x00, 0x09, 0x13, 0x81, 0x02, - 0x5C, 0x12, 0x06, 0x1B, 0x0E, 0x02, 0xD2, 0xEB, - 0x0F, 0x02, 0x0F, 0x00, 0x80, 0x03, 0xCA, 0x05, - 0xE0, 0x02, 0xA0, 0x00, 0x5A, 0x04, 0x59, 0xCE, - 0x20, 0x88, 0xE4, 0xE4, 0xE4, 0xE4, 0xF8, 0x10, - 0xC1, 0x04, 0x48, 0x62, 0x89, 0x05, 0xA0, 0xC0, - 0x6C, 0x01, 0x08, 0xC8, 0x6C, 0x01, 0x03, 0x02, - 0x00, 0xFC, 0x04, 0x02, 0x00, 0x02, 0x73, 0xA0, - 0x04, 0x06, 0xFD, 0x16, 0x88, 0x05, 0x09, 0x06, - 0xF4, 0x16, 0x02, 0xC8, 0x6C, 0x01, 0x81, 0x86, - 0x02, 0x16, 0xD0, 0x03, 0xCB, 0x05, 0x5B, 0x04, - 0x43, 0x28, 0x31, 0x29, 0x38, 0x39, 0x2D, 0x33, - 0x38, 0x38, 0x42, 0x20, 0x20, 0x59, 0x49, 0x54, - 0x4B, 0xC2, 0xA8, 0x02, 0x98, 0x00, 0x83, 0x07, - 0x02, 0x00, 0x28, 0x02, 0x08, 0x00, 0x23, 0xC6, - 0x36, 0xE5, 0x48, 0x06, 0xC4, 0xC0, 0x73, 0x0A, - 0x65, 0x17, 0xA0, 0x06, 0xAA, 0xED, 0xC8, 0xC1, - 0xC7, 0x05, 0x03, 0x02, 0xA5, 0x00, 0xB0, 0x03, - 0xF8, 0xCD, 0xF8, 0xCD, 0xA6, 0x02, 0x06, 0x62, - 0x88, 0x02, 0x0A, 0x00, 0x57, 0x16, 0x03, 0x29, - 0x55, 0x16, 0x05, 0x29, 0xC4, 0x80, 0x52, 0x16, - 0x15, 0x09, 0x50, 0x17, 0x15, 0x09, 0x4E, 0x18, - 0x85, 0x02, 0x29, 0x00, 0x4B, 0x16, 0xC6, 0x05, - 0x96, 0x00, 0x03, 0x07, 0xC4, 0x04, 0x45, 0x06, - 0x95, 0x00, 0x44, 0x05, 0x43, 0x16, 0x44, 0x81, - 0x41, 0x16, 0x00, 0x03, 0x05, 0x00, 0xC4, 0x02, - 0x00, 0x03, 0x0A, 0x00, 0x44, 0x02, 0x0F, 0x00, - 0x84, 0x02, 0x05, 0x00, 0x37, 0x16, 0xC4, 0x02, - 0x00, 0x03, 0x0F, 0x00, 0x44, 0x02, 0x0F, 0x00, - 0x84, 0x02, 0x0A, 0x00, 0x2F, 0x16, 0x04, 0x02, - 0xFE, 0xFF, 0x2C, 0x13, 0x2B, 0x15, 0x2A, 0x1A, - 0x84, 0x05, 0x28, 0x12, 0x27, 0x15, 0x26, 0x1A, - 0x25, 0x18, 0x84, 0x05, 0x23, 0x16, 0x22, 0x1B, - 0x21, 0x17, 0x84, 0x05, 0x1F, 0x13, 0x1E, 0x1A, - 0x1D, 0x11, 0x04, 0x06, 0x1B, 0x16, 0xA5, 0x02, - 0xC5, 0xC1, 0x25, 0x02, 0x06, 0x00, 0x03, 0x02, - 0xA5, 0xA5, 0x83, 0xC1, 0x95, 0x00, 0x03, 0x38, - 0x94, 0x00, 0x83, 0x02, 0x2E, 0x6B, 0x0E, 0x16, - 0x84, 0x02, 0x59, 0x1C, 0x0B, 0x16, 0x24, 0x02, - 0x69, 0x00, 0x95, 0x00, 0x03, 0x3C, 0x94, 0x00, - 0x83, 0x81, 0x04, 0x16, 0x84, 0x02, 0x69, 0x00, - 0x01, 0x16, 0xC9, 0x05, 0x59, 0x04, 0xC3, 0xD0, - 0xFD, 0x13, 0x01, 0x1C, 0xFB, 0x10, 0xE0, 0x90, - 0x3D, 0xE5, 0xF8, 0x16, 0xC3, 0x06, 0xC3, 0xD0, - 0xF5, 0x1C, 0xF4, 0x16, 0xE0, 0x90, 0x3A, 0xE5, - 0xF1, 0x16, 0x5B, 0x04, 0x0B, 0xC3, 0x09, 0x02, - 0x3E, 0xE5, 0xA0, 0x06, 0x92, 0xE9, 0xCC, 0x05, - 0x5C, 0x04, 0x88, 0x07, 0x00, 0xA0, 0x89, 0x07, - 0xFE, 0xFF, 0xA8, 0x09, 0xA9, 0x09, 0x8A, 0x07, - 0x02, 0xE0, 0xA0, 0x06, 0x84, 0xEC, 0x00, 0x00, - 0x88, 0x07, 0x00, 0x90, 0x89, 0x07, 0xFE, 0x9F, - 0xA8, 0x09, 0xA9, 0x09, 0x8A, 0x07, 0x78, 0xE0, - 0xA0, 0x06, 0x84, 0xEC, 0x00, 0x00, 0xA0, 0x06, - 0xC4, 0xEC, 0x00, 0x00, 0xE6, 0x10, 0xE5, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, - 0x00, 0x08, 0x11, 0xE3, 0x6C, 0xCC, 0x00, 0x80, - 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, - 0x00, 0x04, 0x00, 0x02, 0x00, 0x01, 0x80, 0x00, - 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 0x00, - 0x04, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0xFF, - 0xFF, 0x00, 0xF0, 0xFF, 0x00, 0xF0, 0x0F, 0x00, - 0xFF, 0xFF, 0xFF, 0x7F, 0x03, 0x00, 0x00, 0x00, - 0xC3, 0x00, 0xE7, 0xE7, 0xF3, 0xE7, 0xF1, 0xF1, - 0x43, 0x28, 0x20, 0x29, 0x4F, 0x43, 0x59, 0x50, - 0x49, 0x52, 0x48, 0x47, 0x20, 0x54, 0x42, 0x49, - 0x20, 0x4D, 0x39, 0x31, 0x33, 0x38, 0x34, 0x2C, - 0x35, 0x2C, 0x36, 0x2C, 0x43, 0x28, 0x20, 0x29, - 0x4F, 0x43, 0x59, 0x50, 0x49, 0x52, 0x48, 0x47, - 0x20, 0x54, 0x49, 0x54, 0x31, 0x20, 0x38, 0x39, - 0x2D, 0x33, 0x39, 0x38, 0x39, 0x2C, 0x2D, 0x30, - 0x38, 0x39, 0x00, 0x00, 0x61, 0x9B, 0xC4, 0xEC, - 0x0E, 0xEA, 0xDE, 0xE5, 0xC8, 0xED, 0x00, 0x00, - 0xC4, 0x00, 0xB8, 0xAF, 0x4A, 0x06, 0x50, 0x06, - 0x4C, 0x06, 0xDC, 0xCC, 0x4E, 0x06, 0x0F, 0x00, - 0x32, 0x06, 0x01, 0x00, 0x50, 0x07, 0x58, 0x07, - 0x52, 0x07, 0x70, 0xB5, 0x54, 0x07, 0x0F, 0x00, - 0x38, 0x07, 0x01, 0x00, 0xBA, 0x00, 0xA0, 0x00, - 0xBC, 0x00, 0xD6, 0xED, 0xBE, 0x00, 0x0F, 0x00, - 0x5E, 0x07, 0x3A, 0x07, 0x62, 0x07, 0x40, 0x80, - 0x64, 0x07, 0x54, 0xBA, 0x66, 0x07, 0x36, 0xBA, - 0x68, 0x07, 0x40, 0xB8, 0x98, 0x07, 0x00, 0x80, - 0x78, 0x07, 0x00, 0x80, 0xE2, 0x08, 0x04, 0x00, - 0xE4, 0x08, 0x01, 0x00, 0xEC, 0x08, 0x08, 0x00, - 0xF6, 0x08, 0x0A, 0x00, 0xF8, 0x08, 0x06, 0x00, - 0x00, 0x09, 0x0C, 0x00, 0x02, 0x09, 0x04, 0x00, - 0xAE, 0x01, 0x00, 0x00, 0x1E, 0x09, 0x00, 0x00, - 0x66, 0x09, 0x00, 0x00, 0x0C, 0x06, 0x13, 0x00, - 0x0A, 0x06, 0x20, 0x00, 0x00, 0x00, 0xE0, 0x00, - 0x86, 0xA3, 0xE0, 0x00, 0xE6, 0xA2, 0xE0, 0x00, - 0x86, 0xA3, 0xE0, 0x00, 0x02, 0xA5, 0xE0, 0x00, - 0x5E, 0xA6, 0xE0, 0x00, 0x66, 0xA9, 0xE0, 0x00, - 0x12, 0xA4, 0xC0, 0x00, 0x22, 0xA4, 0xE0, 0x00, - 0x86, 0xA3, 0xE0, 0x00, 0x86, 0xA3, 0xC0, 0x00, - 0x74, 0xA4, 0xE0, 0x00, 0x86, 0xA3, 0xE0, 0x00, - 0x86, 0xA3, 0xE0, 0x00, 0x86, 0xA3, 0xE0, 0x00, - 0x86, 0xA3, 0xE0, 0x00, 0x86, 0xA3, 0xC0, 0x00, - 0xDE, 0xAF, 0xC0, 0x00, 0x48, 0xB0, 0xC0, 0x00, - 0x84, 0xB0, 0xC0, 0x00, 0xF4, 0xB0, 0xC0, 0x00, - 0x76, 0xB1, 0xE0, 0x00, 0xE4, 0xB2, 0xE0, 0x00, - 0x8A, 0xB2, 0xE0, 0x00, 0xF4, 0xB3, 0xE0, 0x00, - 0x7C, 0xB3, 0xE0, 0x00, 0xC6, 0xAA, 0xC0, 0x00, - 0x36, 0xAB, 0xC0, 0x00, 0x90, 0xAB, 0xC0, 0x00, - 0xC2, 0xAB, 0xC0, 0x00, 0xEA, 0xAA, 0xC0, 0x00, - 0x80, 0xA3, 0xC0, 0x00, 0x80, 0xA3, 0x00, 0x3F, - 0x00, 0x7F, 0x00, 0x5E, 0x30, 0x00, 0x28, 0x00, - 0x43, 0x00, 0xB6, 0xA6, 0xB6, 0xA6, 0x1C, 0xA5, - 0x14, 0xA5, 0x46, 0xA5, 0x46, 0xA5, 0x62, 0xA5, - 0xB6, 0xA6, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x08, 0x00, 0x20, 0x00, 0x08, - 0x00, 0x80, 0x00, 0x08, 0x00, 0x01, 0x00, 0x10, - 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, - 0x14, 0x00, 0x0E, 0x10, 0x0C, 0x0C, 0x0A, 0x0A, - 0x0A, 0x0A, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x98, 0x07, 0x7E, 0xCA, 0x58, 0x07, - 0xF8, 0xB8, 0x58, 0x07, 0xFE, 0xB7, 0x58, 0x07, - 0x68, 0xB9, 0x58, 0x07, 0xD0, 0xB8, 0x98, 0x07, - 0x5A, 0xC7, 0x98, 0x07, 0x52, 0xC7, 0x78, 0x07, - 0xC2, 0xC1, 0x58, 0x07, 0x30, 0xB9, 0x98, 0x07, - 0x38, 0xCA, 0x78, 0x07, 0x96, 0xC2, 0x58, 0x07, - 0x6A, 0xC7, 0x58, 0x07, 0xE0, 0xB8, 0x58, 0x07, - 0x1E, 0xB9, 0x58, 0x07, 0xE2, 0xB9, 0x98, 0x07, - 0xAE, 0xCB, 0x98, 0x07, 0x8E, 0xC7, 0x78, 0x07, - 0x56, 0xC2, 0xB8, 0x07, 0x14, 0xCC, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xA2, 0xBA, 0x16, 0xC1, - 0xCA, 0xC1, 0xD6, 0xC6, 0x8A, 0xBD, 0xC2, 0xBD, - 0xE0, 0xBD, 0x6A, 0xBE, 0x8E, 0xBE, 0xAA, 0xBE, - 0x22, 0xBF, 0x22, 0xBF, 0x56, 0xBE, 0xC8, 0xBF, - 0x10, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, - 0x00, 0x0C, 0x01, 0x0F, 0xFF, 0xFE, 0x00, 0x58, - 0x00, 0x0E, 0xFF, 0xFE, 0x0E, 0x00, 0x00, 0x70, - 0x40, 0x80, 0x00, 0x5E, 0xA0, 0xC0, 0xDF, 0xFF, - 0x00, 0x18, 0x00, 0xE0, 0x00, 0x78, 0x00, 0x50, - 0x00, 0x60, 0x00, 0x70, 0x00, 0x0C, 0x06, 0x00, - 0x00, 0x00, 0x84, 0xE3, 0xE6, 0x07, 0xF4, 0x07, - 0x08, 0x00, 0x00, 0x00, 0x8A, 0xE3, 0xEA, 0x07, - 0xF4, 0x07, 0x06, 0x00, 0x40, 0x00, 0x00, 0x0A, - 0xE6, 0x07, 0xEE, 0x07, 0x08, 0x00, 0x40, 0x00, - 0x06, 0x0A, 0xEA, 0x07, 0xEE, 0x07, 0x00, 0x00, - 0xE2, 0xC1, 0x8B, 0xD4, 0xFF, 0xFF, 0xD7, 0xD1, - 0xD9, 0xC5, 0xD4, 0xC3, 0x3B, 0x59, 0x34, 0x09, - 0xFC, 0x05, 0x6C, 0x09, 0xD8, 0x06, 0x06, 0x04, - 0xBA, 0xEA, 0x30, 0x09, 0x48, 0x04, 0x80, 0x08, - 0x06, 0x00, 0x0A, 0x06, 0x0E, 0x0C, 0xBA, 0xCE, - 0x2E, 0xE0, 0x56, 0xE0, 0x50, 0xE1, 0x66, 0xE2, - 0xEC, 0xE2, 0x4C, 0xE3, 0xFE, 0xE3, 0xBA, 0xCE, - 0x80, 0xE4, 0x10, 0xE4, 0x14, 0xE0, 0x1C, 0xE4, - 0x1C, 0xE4, 0x46, 0xE5, 0x50, 0xE5, 0x5A, 0xE5, - 0xBA, 0xCE, 0xA6, 0xDC, 0xBA, 0xCE, 0x44, 0xDA, - 0xE6, 0xDF, 0x70, 0xDA, 0xDE, 0xDE, 0xB0, 0xCE, - 0x16, 0xDB, 0x3A, 0xDD, 0xB8, 0xDD, 0x34, 0xDE, - 0x58, 0xDE, 0x16, 0xDB, 0xDA, 0xDC, 0x08, 0xCF, - 0xB0, 0xCE, 0xA8, 0xD9, 0x8A, 0xD9, 0x44, 0xD9, - 0xB0, 0xCE, 0xEA, 0xDE, 0xB0, 0xCE, 0x72, 0x06, - 0xF6, 0xD2, 0x08, 0x07, 0x72, 0x06, 0x54, 0xD2, - 0xF4, 0x01, 0x72, 0x06, 0x34, 0xD2, 0x08, 0x07, - 0x7C, 0x06, 0x5A, 0xDC, 0x04, 0x00, 0x7C, 0x06, - 0x78, 0xD2, 0x00, 0x00, 0x7C, 0x06, 0xCC, 0xDE, - 0xFA, 0x00, 0x86, 0x06, 0xAC, 0xD1, 0x05, 0x00, - 0x90, 0x06, 0x1C, 0xDF, 0x28, 0x00, 0x90, 0x06, - 0x50, 0xD3, 0x04, 0x01, 0x90, 0x06, 0x00, 0x00, - 0x02, 0x00, 0x90, 0x06, 0x80, 0xD2, 0xBC, 0x02, - 0x9A, 0x06, 0x06, 0xD3, 0xDC, 0x05, 0x9A, 0x06, - 0xAA, 0xD2, 0x64, 0x00, 0x9A, 0x06, 0x0A, 0xD3, - 0x14, 0x00, 0x9A, 0x06, 0xE2, 0xE0, 0x40, 0x06, - 0x9A, 0x06, 0x12, 0xD3, 0x64, 0x00, 0x7C, 0x06, - 0x16, 0xDC, 0x04, 0x00, 0x7C, 0x06, 0xE6, 0xDA, - 0x16, 0x00, 0x7C, 0x06, 0xFA, 0xDB, 0x05, 0x00, - 0x7C, 0x06, 0x00, 0xDD, 0x14, 0x00, 0x9A, 0x06, - 0x7C, 0xD3, 0x14, 0x00, 0x9A, 0x06, 0x38, 0xD4, - 0x02, 0x00, 0x7C, 0x06, 0x0C, 0xE0, 0x19, 0x00, - 0x00, 0x00, 0x0A, 0x07, 0x0E, 0x07, 0x04, 0x07, - 0xD8, 0x06, 0x00, 0x07, 0xF0, 0x06, 0xEE, 0x06, - 0xEC, 0x06, 0x0C, 0x07, 0xE6, 0x06, 0x18, 0x07, - 0x92, 0x09, 0x94, 0x09, 0x96, 0x09, 0x98, 0x09, - 0x00, 0x50, 0xCC, 0x00, 0x03, 0x00, 0x00, 0x84, - 0x00, 0xA8, 0x00, 0xA0, 0x00, 0x20, 0x00, 0x80, - 0x00, 0x40, 0x00, 0x08, 0x00, 0x40, 0x00, 0x80, - 0x00, 0x40, 0x00, 0x10, 0x82, 0xEC, 0x48, 0xEB, - 0x62, 0xEB, 0x7C, 0xEB, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x09, 0x00, 0x09, 0x00, 0xEA, 0xEB, - 0x52, 0xEB, 0x68, 0xEB, 0x82, 0xEB, 0x40, 0x01, - 0x42, 0x01, 0x42, 0x01, 0x42, 0x01, 0x00, 0x00, - 0x7F, 0x00, 0xA0, 0x00, 0xFF, 0x00, 0x10, 0x02, - 0x1F, 0x02, 0x30, 0x02, 0x3F, 0x02, 0x50, 0x02, - 0x5F, 0x02, 0x70, 0x02, 0x7F, 0x02, 0x90, 0x02, - 0x9F, 0x02, 0xB0, 0x02, 0xBF, 0x02, 0xD0, 0x02, - 0xDF, 0x02, 0xE1, 0x02, 0xFF, 0x02, 0x01, 0x03, - 0x7F, 0x03, 0x81, 0x03, 0x8F, 0x03, 0x91, 0x03, - 0x9F, 0x03, 0xA1, 0x03, 0xAF, 0x03, 0xB1, 0x03, - 0xBF, 0x03, 0xC1, 0x03, 0xCF, 0x03, 0xE1, 0x03, - 0xFF, 0x03, 0xC0, 0x07, 0xFF, 0x07, 0x00, 0x0C, - 0xFF, 0x0F, 0x00, 0x30, 0xFF, 0x37, 0xFF, 0xFF, - 0xFF, 0xFF, 0xBC, 0xFE, 0x07, 0x00, 0x5E, 0x02, - 0x00, 0x01, 0xFF, 0xBA, 0x80, 0xBA, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0C, 0x01, 0x0A, 0x01, - 0x0E, 0x01, 0x10, 0x01, 0x14, 0x01, 0x00, 0x00, - 0x12, 0x01, 0x00, 0xF8, 0x16, 0x01, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x1C, 0x01, - 0x82, 0x01, 0x66, 0x96, 0x66, 0x96, 0x55, 0x55, - 0x00, 0x00, 0x82, 0x01, 0x2A, 0x8A, 0x2A, 0x8A, - 0x18, 0xC9, 0x18, 0xC9, 0x86, 0x01, 0xAA, 0xA2, - 0x1E, 0xA0, 0x55, 0x55, 0x1E, 0x54, 0x8A, 0x01, - 0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, - 0x8C, 0x01, 0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, - 0x00, 0x00, 0x8E, 0x01, 0x00, 0x50, 0x00, 0x00, - 0x00, 0xA8, 0x00, 0x00, 0x90, 0x01, 0x00, 0x50, - 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x92, 0x01, - 0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, - 0x94, 0x01, 0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, - 0x00, 0x00, 0x96, 0x01, 0x00, 0x50, 0x00, 0x00, - 0x00, 0xA8, 0x00, 0x00, 0x98, 0x01, 0x00, 0x50, - 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x9A, 0x01, - 0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, - 0x9C, 0x01, 0x55, 0x55, 0xC0, 0x7F, 0xAA, 0xAA, - 0xC0, 0x7F, 0x00, 0x00, 0xA2, 0x01, 0xA4, 0x01, - 0xA8, 0x01, 0xAA, 0x01, 0xAE, 0x01, 0xB0, 0x01, - 0xB2, 0x01, 0x80, 0x01, 0x00, 0x00, 0x88, 0x01, - 0x00, 0xFF, 0x9E, 0x01, 0xFF, 0x00, 0xA0, 0x01, - 0x00, 0x80, 0xAC, 0x01, 0x00, 0x80, 0x00, 0x00, - 0xA6, 0x01, 0x00, 0x80, 0x00, 0x00, 0x80, 0x01, - 0xBC, 0x01, 0x00, 0x88, 0x00, 0x06, 0x00, 0xC8, - 0x00, 0x00, 0x00, 0x80, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x80, 0x02, 0x00, 0x44, 0x00, 0x92, 0xEA, - 0x48, 0x00, 0x98, 0xEA, 0x50, 0x00, 0x9E, 0xEA, - 0x60, 0x00, 0xA4, 0xEA, 0x78, 0x00, 0xAA, 0xEA, - 0x0A, 0xE8, 0x18, 0xE7, 0x3C, 0xEA, 0x2A, 0xE7, - 0x14, 0x55, 0xA0, 0x01, 0xEC, 0xE6, 0xD0, 0xE9, - 0x46, 0xE7, 0xA0, 0xE7, 0x00, 0xE7, 0x58, 0xE8, - 0x00, 0x00, 0x1E, 0x00, 0x46, 0xE7, 0x92, 0xE7, - 0x00, 0x41, 0x01, 0x41, 0xB6, 0xE7, 0x73, 0xEA, - 0x18, 0xE7, 0x48, 0xEA, 0xEC, 0xE6, 0x04, 0xEA, - 0x56, 0xE7, 0x62, 0xE7, 0xB6, 0xE7, 0x6E, 0xEA, - 0x62, 0xE8, 0x00, 0x00, 0x36, 0xE8, 0xEC, 0xE6, - 0xFA, 0xE9, 0x56, 0xE7, 0x62, 0xE7, 0x36, 0xE8, - 0x62, 0xE8, 0x00, 0x00, 0xEC, 0xE6, 0xF0, 0xE9, - 0x0C, 0xE7, 0x4A, 0xE7, 0x62, 0xE7, 0x36, 0xE8, - 0xEC, 0xE6, 0xFA, 0xE9, 0x56, 0xE7, 0x62, 0xE7, - 0x36, 0xE8, 0x62, 0xE8, 0x00, 0x20, 0x2A, 0xE7, - 0x14, 0x55, 0xA0, 0x01, 0x18, 0xE7, 0x50, 0xEA, - 0xEC, 0xE6, 0xD0, 0xE9, 0x58, 0xE8, 0x50, 0x55, - 0x0C, 0x00, 0x46, 0xE7, 0x92, 0xE7, 0x00, 0x01, - 0x00, 0x00, 0xB6, 0xE7, 0x75, 0xEA, 0x00, 0xE7, - 0x58, 0xE8, 0x55, 0x55, 0x0C, 0x00, 0x56, 0xE7, - 0xA0, 0xE7, 0x00, 0xE7, 0x58, 0xE8, 0xFF, 0xFF, - 0x08, 0x00, 0x58, 0xE8, 0x02, 0x10, 0x06, 0x00, - 0x46, 0xE7, 0x92, 0xE7, 0x00, 0x01, 0x01, 0x01, - 0xB6, 0xE7, 0x80, 0xEA, 0x00, 0xE7, 0x58, 0xE8, - 0x00, 0xC0, 0x08, 0x00, 0x58, 0xE8, 0xFF, 0xFF, - 0x0A, 0x00, 0x58, 0xE8, 0xFF, 0xFF, 0x0C, 0x00, - 0x58, 0xE8, 0x0D, 0x10, 0x06, 0x00, 0x46, 0xE7, - 0x92, 0xE7, 0x00, 0x01, 0x01, 0x01, 0xB6, 0xE7, - 0x74, 0xEA, 0x62, 0xE8, 0x08, 0x20, 0x00, 0xE7, - 0x52, 0xE8, 0x82, 0x01, 0x02, 0xC9, 0x46, 0xE7, - 0xB6, 0xE7, 0x80, 0xEA, 0x62, 0xE8, 0x34, 0x20, - 0x00, 0xE7, 0x58, 0xE8, 0x00, 0x10, 0x06, 0x00, - 0x46, 0xE7, 0xC6, 0xE8, 0xB6, 0xE7, 0x78, 0xEA, - 0x52, 0xE8, 0x9C, 0x01, 0x40, 0x00, 0x18, 0xE7, - 0x50, 0xEA, 0x2A, 0xE7, 0xFF, 0x00, 0x80, 0x07, - 0x26, 0xE9, 0x03, 0x00, 0x66, 0xE9, 0x74, 0xE9, - 0x12, 0xEA, 0x38, 0xE9, 0x00, 0x00, 0x74, 0xE9, - 0x1C, 0xEA, 0x38, 0xE9, 0x04, 0x00, 0x74, 0xE9, - 0x24, 0xEA, 0x38, 0xE9, 0x07, 0x00, 0x74, 0xE9, - 0x2C, 0xEA, 0x26, 0xE9, 0x01, 0x00, 0x74, 0xE9, - 0x34, 0xEA, 0x38, 0xE9, 0x02, 0x00, 0x74, 0xE9, - 0x34, 0xEA, 0x38, 0xE9, 0x06, 0x00, 0x74, 0xE9, - 0x34, 0xEA, 0x38, 0xE9, 0x05, 0x00, 0x74, 0xE9, - 0x34, 0xEA, 0x26, 0xE9, 0x01, 0x00, 0x4A, 0xE9, - 0x26, 0xE9, 0x03, 0x00, 0x58, 0xE9, 0x62, 0xE7, - 0xE6, 0xE8, 0xD8, 0xE9, 0x01, 0x00, 0xE6, 0xE8, - 0x25, 0xEA, 0x02, 0x00, 0xE6, 0xE8, 0x2F, 0xEA, - 0x06, 0x00, 0xE6, 0xE8, 0x3A, 0xEA, 0x05, 0x00, - 0xB6, 0xE7, 0x74, 0xEA, 0x36, 0xE8, 0xEC, 0xE6, - 0xD0, 0xE9, 0x56, 0xE7, 0xC6, 0xE8, 0x0C, 0xE7, - 0x92, 0xE7, 0x00, 0x01, 0x00, 0x80, 0xB6, 0xE7, - 0x78, 0xEA, 0x00, 0xE7, 0xFE, 0xE8, 0x52, 0xE8, - 0x80, 0x01, 0x41, 0x8E, 0x4A, 0xE7, 0x92, 0xE7, - 0x00, 0x01, 0x01, 0x1B, 0x06, 0xE9, 0xE4, 0xFF, - 0xB6, 0xE7, 0x7C, 0xEA, 0xBE, 0xE8, 0x18, 0xE7, - 0x56, 0xEA, 0x0C, 0xE7, 0x6A, 0xE8, 0x3C, 0xE7, - 0x00, 0xE0, 0xC6, 0xE8, 0xB6, 0xE7, 0x86, 0xEA, - 0x3C, 0xE7, 0x00, 0xE8, 0x62, 0xE7, 0xB6, 0xE7, - 0x85, 0xEA, 0x3C, 0xE7, 0x00, 0x08, 0xC6, 0xE8, - 0xB6, 0xE7, 0x86, 0xEA, 0x3C, 0xE7, 0x00, 0xF8, - 0x62, 0xE7, 0xB6, 0xE7, 0x85, 0xEA, 0x52, 0xE8, - 0x80, 0x01, 0x00, 0x02, 0x3C, 0xE7, 0x00, 0xE0, - 0x62, 0xE7, 0xB6, 0xE7, 0x85, 0xEA, 0x52, 0xE8, - 0x84, 0x01, 0x00, 0x00, 0x62, 0xE8, 0x34, 0x00, - 0x3C, 0xE7, 0x00, 0x00, 0xC6, 0xE8, 0x62, 0xE8, - 0x34, 0x60, 0x0E, 0xE9, 0x52, 0xE8, 0x84, 0x01, - 0x00, 0x00, 0xB6, 0xE7, 0x86, 0xEA, 0x52, 0xE8, - 0x82, 0x01, 0x00, 0xC8, 0x3C, 0xE7, 0x00, 0xE0, - 0xC6, 0xE8, 0x3C, 0xE7, 0x00, 0x10, 0xC6, 0xE8, - 0x62, 0xE8, 0x34, 0x60, 0x52, 0xE8, 0x80, 0x01, - 0x00, 0x06, 0x3C, 0xE7, 0x10, 0x00, 0x78, 0xE8, - 0x36, 0xE8, 0x52, 0xE8, 0x84, 0x01, 0x00, 0x00, - 0x62, 0xE8, 0x34, 0x00, 0xEC, 0xE6, 0xD0, 0xE9, - 0x18, 0xE7, 0x5C, 0xEA, 0xD0, 0xE8, 0x92, 0xE9, - 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0xF0, - 0x06, 0x00, 0x00, 0xC7, 0xA0, 0xE7, 0xDC, 0xE8, - 0x00, 0xE0, 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, - 0x40, 0xD0, 0x06, 0x00, 0x00, 0xE0, 0xA0, 0xE7, - 0xDC, 0xE8, 0x00, 0xC0, 0x00, 0xE7, 0x0C, 0xE7, - 0x70, 0xE7, 0x40, 0x90, 0x06, 0x00, 0x00, 0xA0, - 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x80, 0x00, 0xE7, - 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0x50, 0x06, 0x00, - 0x00, 0x60, 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x40, - 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0x10, - 0x06, 0x00, 0x00, 0x20, 0xA0, 0xE7, 0xDC, 0xE8, - 0x00, 0x00, 0xD0, 0xE8, 0x92, 0xE9, 0x00, 0xE7, - 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0xD0, 0x06, 0x00, - 0x00, 0xA6, 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0xC0, - 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0x90, - 0x06, 0x00, 0x00, 0xC0, 0xA0, 0xE7, 0xDC, 0xE8, - 0x00, 0x80, 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, - 0x40, 0x50, 0x06, 0x00, 0x00, 0x40, 0xA0, 0xE7, - 0xDC, 0xE8, 0x00, 0x40, 0x00, 0xE7, 0x0C, 0xE7, - 0x70, 0xE7, 0x40, 0x70, 0x06, 0x00, 0x00, 0x60, - 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x60, 0x7E, 0xE9, - 0x90, 0xE9, 0x18, 0xE7, 0x62, 0xEA, 0xEC, 0xE6, - 0xD0, 0xE9, 0xA4, 0xE8, 0x55, 0x55, 0x16, 0x00, - 0x46, 0xE7, 0x92, 0xE7, 0x00, 0x00, 0x00, 0x00, - 0xB6, 0xE7, 0x8B, 0xEA, 0x0A, 0xE8, 0x18, 0xE7, - 0x62, 0xEA, 0x58, 0xE8, 0x55, 0x55, 0x16, 0x00, - 0x00, 0xE7, 0x46, 0xE7, 0xA0, 0xE7, 0x2A, 0xE7, - 0xFF, 0x00, 0x00, 0x08, 0x2A, 0xE7, 0xFF, 0x00, - 0x00, 0x0C, 0x2A, 0xE7, 0xFF, 0x00, 0x00, 0x10, - 0x2A, 0xE7, 0xFF, 0x00, 0x00, 0x14, 0x2A, 0xE7, - 0xFF, 0x00, 0x00, 0x18, 0x2A, 0xE7, 0xFF, 0x00, - 0x00, 0x1C, 0x2A, 0xE7, 0xFF, 0x00, 0x00, 0x20, - 0x2A, 0xE7, 0xFF, 0x00, 0x00, 0x24, 0x2A, 0xE7, - 0xFF, 0x00, 0x00, 0x28, 0x2A, 0xE7, 0xFF, 0x00, - 0x00, 0x2C, 0xD2, 0xE7, 0x00, 0xE7, 0x0C, 0xE7, - 0x70, 0xE7, 0x40, 0x30, 0x06, 0x00, 0x00, 0x01, - 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x20, 0x00, 0xE7, - 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0x70, 0x06, 0x00, - 0x00, 0x43, 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x60, - 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0xB0, - 0x06, 0x00, 0x00, 0x85, 0xA0, 0xE7, 0xDC, 0xE8, - 0x00, 0xA0, 0xD8, 0xE8, 0x00, 0x01, 0x03, 0x01, - 0x01, 0x01, 0x00, 0x00, 0x00, 0x81, 0x1A, 0x00, - 0x40, 0x10, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x72, 0x82, - 0x4A, 0xA9, 0xA5, 0x5A, 0xDA, 0xE7, 0x03, 0x09, - 0x11, 0x9D, 0x00, 0x00, 0x00, 0x81, 0x04, 0x00, - 0xD8, 0x90, 0x00, 0x10, 0x00, 0x00, 0x00, 0x81, - 0x04, 0x00, 0xD8, 0x90, 0xD8, 0xB4, 0x00, 0x00, - 0x00, 0x81, 0x08, 0x00, 0xD8, 0x90, 0x46, 0x16, - 0x00, 0x40, 0xD8, 0xB4, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x80, 0x13, 0x00, 0x40, 0x10, 0x16, 0x00, - 0x00, 0x00, 0x00, 0x80, 0x10, 0x00, 0x15, 0x00, - 0x00, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x15, 0x00, - 0x00, 0x00, 0x00, 0x81, 0x0F, 0x00, 0x06, 0x00, - 0x00, 0x00, 0x00, 0x80, 0x12, 0x00, 0x0A, 0x80, - 0x40, 0x9E, 0x00, 0xC8, 0x00, 0x00, 0x5E, 0x80, - 0x0F, 0x00, 0x06, 0x80, 0x40, 0xFE, 0x00, 0xCC, - 0x00, 0x00, 0x04, 0x80, 0x40, 0x8E, 0x00, 0xC9, - 0x04, 0x80, 0x00, 0x06, 0x00, 0xCC, 0x04, 0x80, - 0x40, 0x0A, 0x00, 0xC8, 0x0A, 0x80, 0x40, 0x8A, - 0x00, 0xC8, 0x00, 0x00, 0x5E, 0x80, 0x0F, 0x00, - 0x0A, 0x08, 0x80, 0x1C, 0x0A, 0x00, 0x1C, 0x1A, - 0x00, 0x80, 0x1C, 0x0C, 0x00, 0x80, 0x1C, 0x1A, - 0x00, 0x80, 0x1A, 0x0E, 0x80, 0x1C, 0x04, 0x00, - 0x00, 0x80, 0x80, 0x02, 0x02, 0x00, 0x00, 0x80, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x80, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x58, 0x07, 0x0C, 0xB8, - 0x16, 0xE0, 0xE2, 0x08, 0xEC, 0x08, 0xF6, 0x08, - 0x16, 0xE0, 0x00, 0x09, 0x0A, 0x09, 0x00, 0x00, - 0x00, 0x00, 0xE2, 0x08, 0x00, 0x00, 0xEC, 0x08, - 0xF6, 0x08, 0x00, 0x09, 0x00, 0x00, 0xB8, 0x07, - 0xCA, 0xCB, 0x80, 0x02, 0xB8, 0x07, 0xE8, 0xCB, - 0x84, 0xFF, 0xB8, 0x07, 0x0A, 0xCC, 0xB8, 0x07, - 0x84, 0xCC, 0x6E, 0xCD, 0x62, 0xCD, 0x88, 0xCD, - 0x90, 0xCE, 0x84, 0xCD, 0x92, 0xCE, 0x92, 0xCE, - 0x92, 0xCE, 0x8C, 0xCD, 0x96, 0xCD, 0x38, 0xCE, - 0x82, 0xCE, 0x92, 0xCE, 0x92, 0xCE, 0x92, 0xCE, - 0x92, 0xCE, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x08, 0x00, 0x08, 0x01, 0x05, 0x08, - 0x08, 0x08, 0x03, 0x08, 0x03, 0x03, 0x03, 0x03, - 0x00, 0x00, 0x04, 0x02, 0x04, 0x04, 0x00, 0x04, - 0x0A, 0x08, 0x00, 0x00, 0x10, 0x0C, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x18, 0x00, 0x1A, 0x00, 0x00, - 0x04, 0x41, 0x06, 0x0B, 0x08, 0xC2, 0x00, 0xE6, - 0x00, 0xE7, 0x04, 0x06, 0x04, 0x07, 0x04, 0x03, - 0x06, 0x04, 0x04, 0x05, 0x04, 0x88, 0x04, 0xCF, - 0x04, 0xCD, 0x03, 0x00, 0x05, 0x00, 0x1C, 0x00, - 0x00, 0x0C, 0x00, 0x80, 0xD2, 0xD8, 0xDA, 0xD8, - 0x1E, 0xD9, 0xDE, 0xD8, 0xEA, 0xD8, 0xF0, 0xD8, - 0x14, 0xD9, 0xE4, 0xD8, 0x32, 0xD9, 0x00, 0x06, - 0x00, 0x00, 0x03, 0x07, 0x0A, 0x0E, 0x0F, 0x14, - 0x26, 0x2A, 0x52, 0x42, 0x50, 0x48, 0x5D, 0x4D, - 0x62, 0x62, 0x6D, 0x57, 0x46, 0x39, 0x1A, 0x1D, - 0x7C, 0x76, 0x1F, 0x23, 0x15, 0x1D, 0x74, 0x6F, - 0x84, 0x7C, 0x8B, 0x82, 0x92, 0x89, 0x00, 0x00, - 0x32, 0x2F, 0x3F, 0x34, 0x32, 0x01, 0x01, 0x57, - 0x32, 0x11, 0x81, 0x51, 0x02, 0x56, 0x03, 0x55, - 0x54, 0x11, 0x56, 0x81, 0x55, 0x02, 0x54, 0x02, - 0x56, 0x81, 0x01, 0x76, 0x02, 0x34, 0x02, 0x55, - 0x81, 0x54, 0x02, 0x58, 0x02, 0x55, 0x81, 0x54, - 0x02, 0x58, 0x11, 0x12, 0x02, 0x52, 0x58, 0x83, - 0x52, 0x05, 0x83, 0x04, 0x02, 0x58, 0x08, 0x55, - 0x58, 0x83, 0x55, 0x02, 0x81, 0x02, 0x05, 0x58, - 0x03, 0x52, 0x5C, 0x15, 0x53, 0x5B, 0x52, 0x87, - 0x11, 0x03, 0x41, 0x51, 0x78, 0x51, 0x34, 0x11, - 0x81, 0x11, 0x20, 0x31, 0x54, 0x57, 0x01, 0x53, - 0x5A, 0x12, 0x81, 0x51, 0x20, 0x31, 0x5B, 0x57, - 0x01, 0x5A, 0x01, 0x11, 0x51, 0x11, 0x31, 0x81, - 0x57, 0x20, 0x15, 0x01, 0x13, 0x01, 0x11, 0x01, - 0x11, 0x11, 0x81, 0x51, 0x05, 0x58, 0x02, 0x52, - 0x5B, 0x54, 0x5D, 0x81, 0x52, 0x05, 0x54, 0x02, - 0x58, 0x81, 0x50, 0x02, 0x13, 0x03, 0x58, 0x81, - 0x50, 0x02, 0x11, 0x03, 0x81, 0x54, 0x72, 0x5D, - 0x50, 0x03, 0x13, 0x03, 0x13, 0x01, 0x40, 0x54, - 0x0E, 0x00, 0x20, 0x06, 0x56, 0x06, 0x0C, 0xDA, - 0x24, 0x00, 0x02, 0x10, 0x16, 0x00, 0x02, 0x00, - 0x01, 0x04, 0x08, 0x07, 0x0C, 0xDA, 0x20, 0x00, - 0x03, 0x10, 0x12, 0x00, 0x03, 0x00, 0x4E, 0xD9, - 0x14, 0x8E, 0x20, 0x00, 0x04, 0x10, 0x12, 0x00, - 0x04, 0x00, 0xD2, 0xCE, 0x20, 0x00, 0x05, 0xE0, - 0x12, 0x00, 0x05, 0x00, 0xD2, 0xCE, 0x20, 0x00, - 0x06, 0xE0, 0x12, 0x00, 0x06, 0x00, 0xE8, 0xDD, - 0x12, 0x00, 0x01, 0xE0, 0x6C, 0x09, 0xCC, 0x06, - 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x30, 0x06, - 0x42, 0xDC, 0xF0, 0x05, 0x00, 0xE0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xE2, 0x05, 0x08, 0x00, - 0x26, 0xFF, 0xDC, 0x05, 0x00, 0x00, 0x30, 0x06, - 0xF8, 0xDB, 0x1E, 0x00, 0x01, 0xE0, 0x10, 0x00, - 0x11, 0x30, 0x0C, 0x04, 0x01, 0x00, 0x0E, 0x04, - 0x02, 0x00, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x06, 0x32, 0xDD, 0x12, 0x00, 0x01, 0xE0, - 0x04, 0x00, 0x13, 0x30, 0x74, 0xDE, 0x3E, 0x00, - 0x00, 0xE0, 0x00, 0xC0, 0x00, 0x00, 0x02, 0x00, - 0x30, 0x00, 0x20, 0x50, 0x23, 0x0C, 0xFC, 0x05, - 0x52, 0x06, 0x56, 0x06, 0x00, 0x00, 0x00, 0x81, - 0x16, 0x00, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0x00, - 0x10, 0x00, 0x08, 0x00, 0x2A, 0x40, 0x2A, 0x04, - 0x56, 0x06, 0x26, 0x00, 0x19, 0xED, 0x2B, 0x06, - 0x72, 0x09, 0x22, 0x00, 0x24, 0x00, 0x2F, 0xED, - 0x23, 0x0C, 0xFC, 0x05, 0x28, 0x08, 0x34, 0x09, - 0x29, 0x08, 0x58, 0x07, 0x78, 0x07, 0x98, 0x07, - 0x23, 0x00, 0x2A, 0x00, 0x3D, 0xED, 0x06, 0x04, - 0xF0, 0x06, 0x07, 0x04, 0xEE, 0x06, 0x24, 0x00, - 0xD2, 0xCE, 0x34, 0x00, 0x00, 0xE0, 0x00, 0xC0, - 0x00, 0x00, 0x10, 0x00, 0x26, 0x00, 0x25, 0x40, - 0xD2, 0xCE, 0x20, 0x00, 0x00, 0xE0, 0x00, 0xC0, - 0x00, 0x00, 0x10, 0x00, 0x12, 0x00, 0x26, 0x40, - 0xD2, 0xCE, 0x1A, 0x00, 0x00, 0xE0, 0x0C, 0x00, - 0x27, 0x60, 0x0A, 0x08, 0xE6, 0x06, 0xD2, 0xCE, - 0x24, 0x00, 0x00, 0xE0, 0x16, 0x00, 0x28, 0x60, - 0x30, 0x04, 0x06, 0x07, 0x52, 0xCF, 0x00, 0x81, - 0x30, 0x00, 0x00, 0xE0, 0x22, 0x00, 0x29, 0x60, - 0x2D, 0x08, 0x1C, 0x07, 0x2E, 0x08, 0x22, 0x07, - 0x00, 0x00, 0x08, 0x02, 0x06, 0x01, 0x14, 0x06, - 0x18, 0x08, 0x20, 0x0C, 0x26, 0x0E, 0x30, 0x0F, - 0x34, 0x11, 0x3E, 0x12, 0x42, 0x14, 0x46, 0x16, - 0x1C, 0x0A, 0x4A, 0x18, 0x13, 0x03, 0x11, 0x83, - 0x01, 0x11, 0x11, 0x81, 0x12, 0x81, 0x13, 0x01, - 0x52, 0x83, 0x81, 0x85, 0x85, 0x11, 0x12, 0x81, - 0x12, 0x81, 0x19, 0x81, 0x60, 0x85, 0x00, 0xC0, - 0x00, 0x00, 0x08, 0x00, 0x6C, 0x09, 0x00, 0x00, - 0x30, 0x06, 0x08, 0xE5, 0x54, 0x06, 0x50, 0x06, - 0x38, 0x02, 0x21, 0x04, 0x1E, 0x09, 0x0B, 0x06, - 0xD8, 0x06, 0x02, 0x08, 0xDC, 0x06, 0x00, 0xC0, - 0xFF, 0xFF, 0xFF, 0xFF, 0x41, 0x00, 0x41, 0x00, - 0x14, 0xAE, 0x00, 0x00, 0x00, 0x81, 0x09, 0x04, - 0x0C, 0x07, 0x41, 0x00, 0x41, 0x00, 0x14, 0x02, - 0x00, 0x00, 0x00, 0x81, 0x0B, 0x06, 0xD8, 0x06, - 0x2C, 0x06, 0x76, 0x09, 0x22, 0x14, 0x3A, 0x09, - 0x41, 0x00, 0x41, 0x00, 0x54, 0x02, 0x00, 0x00, - 0x00, 0x81, 0xD8, 0x06, 0x00, 0x84, 0x00, 0x48, - 0xFC, 0xFF, 0x09, 0x00, 0x00, 0xC0, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xB8, 0xFF, 0x20, 0x00, - 0x43, 0x28, 0x31, 0x29, 0x38, 0x39, 0x2D, 0x33, - 0x39, 0x38, 0x39, 0x2C, 0x2D, 0x30, 0x38, 0x39, - 0x54, 0x20, 0x78, 0x65, 0x73, 0x61, 0x49, 0x20, - 0x73, 0x6E, 0x72, 0x74, 0x6D, 0x75, 0x6E, 0x65, - 0x73, 0x74, 0x28, 0x0A, 0x29, 0x43, 0x39, 0x31, - 0x33, 0x38, 0x34, 0x2C, 0x35, 0x2C, 0x36, 0x2C, - 0x49, 0x20, 0x4D, 0x42, 0x43, 0x20, 0x72, 0x6F, - 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xF8, 0xFF, 0x01, 0x00, 0x34, 0x90, - 0x00, 0x00, 0xFA, 0xFF, 0x01, 0x00, 0xB8, 0xFF, - 0x00, 0x00, 0xFC, 0xFF, 0x02, 0x00, 0x80, 0x00, - 0x3E, 0xA0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -#endif /* CONFIG_SKTR */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/syncppp.c linux/drivers/net/syncppp.c --- v2.3.20/linux/drivers/net/syncppp.c Thu Aug 26 13:05:38 1999 +++ linux/drivers/net/syncppp.c Wed Dec 31 16:00:00 1969 @@ -1,1315 +0,0 @@ -/* - * NET3: A (fairly minimal) implementation of synchronous PPP for Linux - * as well as a CISCO HDLC implementation. See the copyright - * message below for the original source. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the license, or (at your option) any later version. - * - * Note however. This code is also used in a different form by FreeBSD. - * Therefore when making any non OS specific change please consider - * contributing it back to the original author under the terms - * below in addition. - * -- Alan - * - * Port for Linux-2.1 by Jan "Yenya" Kasprzak - */ - -/* - * Synchronous PPP/Cisco link level subroutines. - * Keepalive protocol implemented in both Cisco and PPP modes. - * - * Copyright (C) 1994 Cronyx Ltd. - * Author: Serge Vakulenko, - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "syncppp.h" - -#define MAXALIVECNT 6 /* max. alive packets */ - -#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ -#define PPP_UI 0x03 /* Unnumbered Information */ -#define PPP_IP 0x0021 /* Internet Protocol */ -#define PPP_ISO 0x0023 /* ISO OSI Protocol */ -#define PPP_XNS 0x0025 /* Xerox NS Protocol */ -#define PPP_IPX 0x002b /* Novell IPX Protocol */ -#define PPP_LCP 0xc021 /* Link Control Protocol */ -#define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */ - -#define LCP_CONF_REQ 1 /* PPP LCP configure request */ -#define LCP_CONF_ACK 2 /* PPP LCP configure acknowledge */ -#define LCP_CONF_NAK 3 /* PPP LCP configure negative ack */ -#define LCP_CONF_REJ 4 /* PPP LCP configure reject */ -#define LCP_TERM_REQ 5 /* PPP LCP terminate request */ -#define LCP_TERM_ACK 6 /* PPP LCP terminate acknowledge */ -#define LCP_CODE_REJ 7 /* PPP LCP code reject */ -#define LCP_PROTO_REJ 8 /* PPP LCP protocol reject */ -#define LCP_ECHO_REQ 9 /* PPP LCP echo request */ -#define LCP_ECHO_REPLY 10 /* PPP LCP echo reply */ -#define LCP_DISC_REQ 11 /* PPP LCP discard request */ - -#define LCP_OPT_MRU 1 /* maximum receive unit */ -#define LCP_OPT_ASYNC_MAP 2 /* async control character map */ -#define LCP_OPT_AUTH_PROTO 3 /* authentication protocol */ -#define LCP_OPT_QUAL_PROTO 4 /* quality protocol */ -#define LCP_OPT_MAGIC 5 /* magic number */ -#define LCP_OPT_RESERVED 6 /* reserved */ -#define LCP_OPT_PROTO_COMP 7 /* protocol field compression */ -#define LCP_OPT_ADDR_COMP 8 /* address/control field compression */ - -#define IPCP_CONF_REQ LCP_CONF_REQ /* PPP IPCP configure request */ -#define IPCP_CONF_ACK LCP_CONF_ACK /* PPP IPCP configure acknowledge */ -#define IPCP_CONF_NAK LCP_CONF_NAK /* PPP IPCP configure negative ack */ -#define IPCP_CONF_REJ LCP_CONF_REJ /* PPP IPCP configure reject */ -#define IPCP_TERM_REQ LCP_TERM_REQ /* PPP IPCP terminate request */ -#define IPCP_TERM_ACK LCP_TERM_ACK /* PPP IPCP terminate acknowledge */ -#define IPCP_CODE_REJ LCP_CODE_REJ /* PPP IPCP code reject */ - -#define CISCO_MULTICAST 0x8f /* Cisco multicast address */ -#define CISCO_UNICAST 0x0f /* Cisco unicast address */ -#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */ -#define CISCO_ADDR_REQ 0 /* Cisco address request */ -#define CISCO_ADDR_REPLY 1 /* Cisco address reply */ -#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ - -struct ppp_header { - u8 address; - u8 control; - u16 protocol; -}; -#define PPP_HEADER_LEN sizeof (struct ppp_header) - -struct lcp_header { - u8 type; - u8 ident; - u16 len; -}; -#define LCP_HEADER_LEN sizeof (struct lcp_header) - -struct cisco_packet { - u32 type; - u32 par1; - u32 par2; - u16 rel; - u16 time0; - u16 time1; -}; -#define CISCO_PACKET_LEN 18 -#define CISCO_BIG_PACKET_LEN 20 - -static struct sppp *spppq; -static struct timer_list sppp_keepalive_timer; - -static void sppp_keepalive (unsigned long dummy); -static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, - u8 ident, u16 len, void *data); -static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2); -static void sppp_lcp_input (struct sppp *sp, struct sk_buff *m); -static void sppp_cisco_input (struct sppp *sp, struct sk_buff *m); -static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *m); -static void sppp_lcp_open (struct sppp *sp); -static void sppp_ipcp_open (struct sppp *sp); -static int sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, - int len, u32 *magic); -static void sppp_cp_timeout (unsigned long arg); -static char *sppp_lcp_type_name (u8 type); -static char *sppp_ipcp_type_name (u8 type); -static void sppp_print_bytes (u8 *p, u16 len); - -static int debug = 0; - -/* - * Interface down stub - */ - -static void if_down(struct net_device *dev) -{ - ; -} - -/* - * Timeout routine activations. - */ - -static void sppp_set_timeout(struct sppp *p,int s) -{ - if (! (p->pp_flags & PP_TIMO)) - { - init_timer(&p->pp_timer); - p->pp_timer.function=sppp_cp_timeout; - p->pp_timer.expires=jiffies+s*HZ; - p->pp_timer.data=(unsigned long)p; - p->pp_flags |= PP_TIMO; - add_timer(&p->pp_timer); - } -} - -static void sppp_clear_timeout(struct sppp *p) -{ - if (p->pp_flags & PP_TIMO) - { - del_timer(&p->pp_timer); - p->pp_flags &= ~PP_TIMO; - } -} - -/* - * Process the received packet. - */ - -void sppp_input (struct net_device *dev, struct sk_buff *skb) -{ - struct ppp_header *h; - struct sppp *sp = &((struct ppp_device *)dev)->sppp; - - skb->dev=dev; - skb->mac.raw=skb->data; - - if (dev->flags & IFF_UP) - { - /* Count received bytes, add FCS and one flag */ - sp->ibytes+= skb->len + 3; - sp->ipkts++; - } - - if (skb->len <= PPP_HEADER_LEN) { - /* Too small packet, drop it. */ - if (sp->pp_flags & PP_DEBUG) - printk (KERN_DEBUG "%s: input packet is too small, %d bytes\n", - dev->name, skb->len); -drop: kfree_skb(skb); - return; - } - - /* Get PPP header. */ - h = (struct ppp_header *)skb->data; - skb_pull(skb,sizeof(struct ppp_header)); - - switch (h->address) { - default: /* Invalid PPP packet. */ -invalid: if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid input packet <0x%x 0x%x 0x%x>\n", - dev->name, - h->address, h->control, ntohs (h->protocol)); - goto drop; - case PPP_ALLSTATIONS: - if (h->control != PPP_UI) - goto invalid; - if (sp->pp_flags & PP_CISCO) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: PPP packet in Cisco mode <0x%x 0x%x 0x%x>\n", - dev->name, - h->address, h->control, ntohs (h->protocol)); - goto drop; - } - switch (ntohs (h->protocol)) { - default: - if (sp->lcp.state == LCP_STATE_OPENED) - sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ, - ++sp->pp_seq, skb->len + 2, - &h->protocol); - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid input protocol <0x%x 0x%x 0x%x>\n", - dev->name, - h->address, h->control, ntohs (h->protocol)); - goto drop; - case PPP_LCP: - sppp_lcp_input (sp, skb); - kfree_skb(skb); - return; - case PPP_IPCP: - if (sp->lcp.state == LCP_STATE_OPENED) - sppp_ipcp_input (sp, skb); - else - printk(KERN_DEBUG "IPCP when still waiting LCP finish.\n"); - kfree_skb(skb); - return; - case PPP_IP: - if (sp->ipcp.state == IPCP_STATE_OPENED) { - if(sp->pp_flags&PP_DEBUG) - printk(KERN_DEBUG "Yow an IP frame.\n"); - skb->protocol=htons(ETH_P_IP); - netif_rx(skb); - return; - } - break; -#ifdef IPX - case PPP_IPX: - /* IPX IPXCP not implemented yet */ - if (sp->lcp.state == LCP_STATE_OPENED) { - skb->protocol=htons(ETH_P_IPX); - netif_rx(skb); - return; - } - break; -#endif - } - break; - case CISCO_MULTICAST: - case CISCO_UNICAST: - /* Don't check the control field here (RFC 1547). */ - if (! (sp->pp_flags & PP_CISCO)) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: Cisco packet in PPP mode <0x%x 0x%x 0x%x>\n", - dev->name, - h->address, h->control, ntohs (h->protocol)); - goto drop; - } - switch (ntohs (h->protocol)) { - default: - goto invalid; - case CISCO_KEEPALIVE: - sppp_cisco_input (sp, skb); - kfree_skb(skb); - return; -#ifdef CONFIG_INET - case ETH_P_IP: - skb->protocol=htons(ETH_P_IP); - netif_rx(skb); - return; -#endif -#ifdef CONFIG_IPX - case ETH_P_IPX: - skb->protocol=htons(ETH_P_IPX); - netif_rx(skb); - return; -#endif - } - break; - } - kfree_skb(skb); -} - -EXPORT_SYMBOL(sppp_input); - -/* - * Handle transmit packets. - */ - -static int sppp_hard_header(struct sk_buff *skb, struct net_device *dev, __u16 type, - void *daddr, void *saddr, unsigned int len) -{ - struct sppp *sp = &((struct ppp_device *)dev)->sppp; - struct ppp_header *h; - skb_push(skb,sizeof(struct ppp_header)); - h=(struct ppp_header *)skb->data; - if(sp->pp_flags&PP_CISCO) - { - h->address = CISCO_MULTICAST; - h->control = 0; - } - else - { - h->address = PPP_ALLSTATIONS; - h->control = PPP_UI; - } - if(sp->pp_flags & PP_CISCO) - { - h->protocol = htons(type); - } - else switch(type) - { - case ETH_P_IP: - h->protocol = htons(PPP_IP); - break; - case ETH_P_IPX: - h->protocol = htons(PPP_IPX); - break; - } - return sizeof(struct ppp_header); -} - -static int sppp_rebuild_header(struct sk_buff *skb) -{ - return 0; -} - -/* - * Send keepalive packets, every 10 seconds. - */ - -static void sppp_keepalive (unsigned long dummy) -{ - struct sppp *sp; - unsigned long flags; - save_flags(flags); - cli(); - - for (sp=spppq; sp; sp=sp->pp_next) - { - struct net_device *dev = sp->pp_if; - - /* Keepalive mode disabled or channel down? */ - if (! (sp->pp_flags & PP_KEEPALIVE) || - ! (dev->flags & IFF_RUNNING)) - continue; - - /* No keepalive in PPP mode if LCP not opened yet. */ - if (! (sp->pp_flags & PP_CISCO) && - sp->lcp.state != LCP_STATE_OPENED) - continue; - - if (sp->pp_alivecnt == MAXALIVECNT) { - /* No keepalive packets got. Stop the interface. */ - printk (KERN_WARNING "%s: down\n", dev->name); - if_down (dev); - if (! (sp->pp_flags & PP_CISCO)) { - /* Shut down the PPP link. */ - sp->lcp.magic = jiffies; - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - sppp_clear_timeout (sp); - /* Initiate negotiation. */ - sppp_lcp_open (sp); - } - } - if (sp->pp_alivecnt <= MAXALIVECNT) - ++sp->pp_alivecnt; - if (sp->pp_flags & PP_CISCO) - sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq, - sp->pp_rseq); - else if (sp->lcp.state == LCP_STATE_OPENED) { - long nmagic = htonl (sp->lcp.magic); - sp->lcp.echoid = ++sp->pp_seq; - sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ, - sp->lcp.echoid, 4, &nmagic); - } - } - restore_flags(flags); - sppp_keepalive_timer.expires=jiffies+10*HZ; - add_timer(&sppp_keepalive_timer); -} - -/* - * Handle incoming PPP Link Control Protocol packets. - */ - -static void sppp_lcp_input (struct sppp *sp, struct sk_buff *skb) -{ - struct lcp_header *h; - struct net_device *dev = sp->pp_if; - int len = skb->len; - u8 *p, opt[6]; - u32 rmagic; - - if (len < 4) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid lcp packet length: %d bytes\n", - dev->name, len); - return; - } - h = (struct lcp_header *)skb->data; - skb_pull(skb,sizeof(struct lcp_header *)); - - if (sp->pp_flags & PP_DEBUG) - { - char state = '?'; - switch (sp->lcp.state) { - case LCP_STATE_CLOSED: state = 'C'; break; - case LCP_STATE_ACK_RCVD: state = 'R'; break; - case LCP_STATE_ACK_SENT: state = 'S'; break; - case LCP_STATE_OPENED: state = 'O'; break; - } - printk (KERN_WARNING "%s: lcp input(%c): %d bytes <%s id=%xh len=%xh", - dev->name, state, len, - sppp_lcp_type_name (h->type), h->ident, ntohs (h->len)); - if (len > 4) - sppp_print_bytes ((u8*) (h+1), len-4); - printk (">\n"); - } - if (len > ntohs (h->len)) - len = ntohs (h->len); - switch (h->type) { - default: - /* Unknown packet type -- send Code-Reject packet. */ - sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq, - skb->len, h); - break; - case LCP_CONF_REQ: - if (len < 4) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_DEBUG"%s: invalid lcp configure request packet length: %d bytes\n", - dev->name, len); - break; - } - if (len>4 && !sppp_lcp_conf_parse_options (sp, h, len, &rmagic)) - goto badreq; - if (rmagic == sp->lcp.magic) { - /* Local and remote magics equal -- loopback? */ - if (sp->pp_loopcnt >= MAXALIVECNT*5) { - printk (KERN_WARNING "%s: loopback\n", - dev->name); - sp->pp_loopcnt = 0; - if (dev->flags & IFF_UP) { - if_down (dev); - } - } else if (sp->pp_flags & PP_DEBUG) - printk (KERN_DEBUG "%s: conf req: magic glitch\n", - dev->name); - ++sp->pp_loopcnt; - - /* MUST send Conf-Nack packet. */ - rmagic = ~sp->lcp.magic; - opt[0] = LCP_OPT_MAGIC; - opt[1] = sizeof (opt); - opt[2] = rmagic >> 24; - opt[3] = rmagic >> 16; - opt[4] = rmagic >> 8; - opt[5] = rmagic; - sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK, - h->ident, sizeof (opt), &opt); -badreq: - switch (sp->lcp.state) { - case LCP_STATE_OPENED: - /* Initiate renegotiation. */ - sppp_lcp_open (sp); - /* fall through... */ - case LCP_STATE_ACK_SENT: - /* Go to closed state. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - } - break; - } - /* Send Configure-Ack packet. */ - sp->pp_loopcnt = 0; - sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK, - h->ident, len-4, h+1); - /* Change the state. */ - switch (sp->lcp.state) { - case LCP_STATE_CLOSED: - sp->lcp.state = LCP_STATE_ACK_SENT; - break; - case LCP_STATE_ACK_RCVD: - sp->lcp.state = LCP_STATE_OPENED; - sppp_ipcp_open (sp); - break; - case LCP_STATE_OPENED: -#if 0 - /* Remote magic changed -- close session. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - /* Initiate renegotiation. */ - sppp_lcp_open (sp); - /* An ACK has already been sent. */ - sp->lcp.state = LCP_STATE_ACK_SENT; -#endif - break; - } - break; - case LCP_CONF_ACK: - if (h->ident != sp->lcp.confid) - break; - sppp_clear_timeout (sp); - if (! (dev->flags & IFF_UP) && - (dev->flags & IFF_RUNNING)) { - /* Coming out of loopback mode. */ - dev->flags |= IFF_UP; - printk (KERN_INFO "%s: up\n", dev->name); - } - switch (sp->lcp.state) { - case LCP_STATE_CLOSED: - sp->lcp.state = LCP_STATE_ACK_RCVD; - sppp_set_timeout (sp, 5); - break; - case LCP_STATE_ACK_SENT: - sp->lcp.state = LCP_STATE_OPENED; - sppp_ipcp_open (sp); - break; - } - break; - case LCP_CONF_NAK: - if (h->ident != sp->lcp.confid) - break; - p = (u8*) (h+1); - if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) { - rmagic = (u32)p[2] << 24 | - (u32)p[3] << 16 | p[4] << 8 | p[5]; - if (rmagic == ~sp->lcp.magic) { - int newmagic; - if (sp->pp_flags & PP_DEBUG) - printk (KERN_DEBUG "%s: conf nak: magic glitch\n", - dev->name); - get_random_bytes(&newmagic, sizeof(newmagic)); - sp->lcp.magic += newmagic; - } else - sp->lcp.magic = rmagic; - } - if (sp->lcp.state != LCP_STATE_ACK_SENT) { - /* Go to closed state. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - } - /* The link will be renegotiated after timeout, - * to avoid endless req-nack loop. */ - sppp_clear_timeout (sp); - sppp_set_timeout (sp, 2); - break; - case LCP_CONF_REJ: - if (h->ident != sp->lcp.confid) - break; - sppp_clear_timeout (sp); - /* Initiate renegotiation. */ - sppp_lcp_open (sp); - if (sp->lcp.state != LCP_STATE_ACK_SENT) { - /* Go to closed state. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - } - break; - case LCP_TERM_REQ: - sppp_clear_timeout (sp); - /* Send Terminate-Ack packet. */ - sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, 0); - /* Go to closed state. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - /* Initiate renegotiation. */ - sppp_lcp_open (sp); - break; - case LCP_TERM_ACK: - case LCP_CODE_REJ: - case LCP_PROTO_REJ: - /* Ignore for now. */ - break; - case LCP_DISC_REQ: - /* Discard the packet. */ - break; - case LCP_ECHO_REQ: - if (sp->lcp.state != LCP_STATE_OPENED) - break; - if (len < 8) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid lcp echo request packet length: %d bytes\n", - dev->name, len); - break; - } - if (ntohl (*(long*)(h+1)) == sp->lcp.magic) { - /* Line loopback mode detected. */ - printk (KERN_WARNING "%s: loopback\n", dev->name); - if_down (dev); - - /* Shut down the PPP link. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - sppp_clear_timeout (sp); - /* Initiate negotiation. */ - sppp_lcp_open (sp); - break; - } - *(long*)(h+1) = htonl (sp->lcp.magic); - sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REPLY, h->ident, len-4, h+1); - break; - case LCP_ECHO_REPLY: - if (h->ident != sp->lcp.echoid) - break; - if (len < 8) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid lcp echo reply packet length: %d bytes\n", - dev->name, len); - break; - } - if (ntohl (*(long*)(h+1)) != sp->lcp.magic) - sp->pp_alivecnt = 0; - break; - } -} - -/* - * Handle incoming Cisco keepalive protocol packets. - */ - -static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb) -{ - struct cisco_packet *h; - struct net_device *dev = sp->pp_if; - - if (skb->len != CISCO_PACKET_LEN && skb->len != CISCO_BIG_PACKET_LEN) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid cisco packet length: %d bytes\n", - dev->name, skb->len); - return; - } - h = (struct cisco_packet *)skb->data; - skb_pull(skb, sizeof(struct cisco_packet*)); - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: cisco input: %d bytes <%lxh %xh %xh %xh %xh-%xh>\n", - dev->name, skb->len, - ntohl (h->type), h->par1, h->par2, h->rel, - h->time0, h->time1); - switch (ntohl (h->type)) { - default: - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: unknown cisco packet type: 0x%lx\n", - dev->name, ntohl (h->type)); - break; - case CISCO_ADDR_REPLY: - /* Reply on address request, ignore */ - break; - case CISCO_KEEPALIVE_REQ: - sp->pp_alivecnt = 0; - sp->pp_rseq = ntohl (h->par1); - if (sp->pp_seq == sp->pp_rseq) { - /* Local and remote sequence numbers are equal. - * Probably, the line is in loopback mode. */ - int newseq; - if (sp->pp_loopcnt >= MAXALIVECNT) { - printk (KERN_WARNING "%s: loopback\n", - dev->name); - sp->pp_loopcnt = 0; - if (dev->flags & IFF_UP) { - if_down (dev); - } - } - ++sp->pp_loopcnt; - - /* Generate new local sequence number */ - get_random_bytes(&newseq, sizeof(newseq)); - sp->pp_seq ^= newseq; - break; - } - sp->pp_loopcnt = 0; - if (! (dev->flags & IFF_UP) && - (dev->flags & IFF_RUNNING)) { - dev->flags |= IFF_UP; - printk (KERN_INFO "%s: up\n", dev->name); - } - break; - case CISCO_ADDR_REQ: - /* Stolen from net/ipv4/devinet.c -- SIOCGIFADDR ioctl */ - { - struct in_device *in_dev; - struct in_ifaddr *ifa; - u32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */ - - if ((in_dev=in_dev_get(dev)) != NULL) - { - read_lock(&in_dev->lock); - for (ifa=in_dev->ifa_list; ifa != NULL; - ifa=ifa->ifa_next) { - if (strcmp(dev->name, ifa->ifa_label) == 0) - { - addr = ifa->ifa_local; - mask = ifa->ifa_mask; - break; - } - } - read_unlock(&in_dev->lock); - in_dev_put(in_dev); - } - /* I hope both addr and mask are in the net order */ - sppp_cisco_send (sp, CISCO_ADDR_REPLY, addr, mask); - break; - } - } -} - -/* - * Send PPP LCP packet. - */ - -static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, - u8 ident, u16 len, void *data) -{ - struct ppp_header *h; - struct lcp_header *lh; - struct sk_buff *skb; - struct net_device *dev = sp->pp_if; - - skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+LCP_HEADER_LEN+len, - GFP_ATOMIC); - if (skb==NULL) - return; - - skb_reserve(skb,dev->hard_header_len); - - h = (struct ppp_header *)skb_put(skb, sizeof(struct ppp_header)); - h->address = PPP_ALLSTATIONS; /* broadcast address */ - h->control = PPP_UI; /* Unnumbered Info */ - h->protocol = htons (proto); /* Link Control Protocol */ - - lh = (struct lcp_header *)skb_put(skb, sizeof(struct lcp_header)); - lh->type = type; - lh->ident = ident; - lh->len = htons (LCP_HEADER_LEN + len); - - if (len) - memcpy(skb_put(skb,len),data, len); - - if (sp->pp_flags & PP_DEBUG) { - printk (KERN_WARNING "%s: %s output <%s id=%xh len=%xh", - dev->name, - proto==PPP_LCP ? "lcp" : "ipcp", - proto==PPP_LCP ? sppp_lcp_type_name (lh->type) : - sppp_ipcp_type_name (lh->type), lh->ident, - ntohs (lh->len)); - if (len) - sppp_print_bytes ((u8*) (lh+1), len); - printk (">\n"); - } - sp->obytes += skb->len; - /* Control is high priority so it doesnt get queued behind data */ - skb->priority=TC_PRIO_CONTROL; - skb->dev = dev; - dev_queue_xmit(skb); -} - -/* - * Send Cisco keepalive packet. - */ - -static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2) -{ - struct ppp_header *h; - struct cisco_packet *ch; - struct sk_buff *skb; - struct net_device *dev = sp->pp_if; - u32 t = jiffies * 1000/HZ; - - skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+CISCO_PACKET_LEN, - GFP_ATOMIC); - - if(skb==NULL) - return; - - skb_reserve(skb, dev->hard_header_len); - h = (struct ppp_header *)skb_put (skb, sizeof(struct ppp_header)); - h->address = CISCO_MULTICAST; - h->control = 0; - h->protocol = htons (CISCO_KEEPALIVE); - - ch = (struct cisco_packet*)skb_put(skb, CISCO_PACKET_LEN); - ch->type = htonl (type); - ch->par1 = htonl (par1); - ch->par2 = htonl (par2); - ch->rel = -1; - ch->time0 = htons ((u16) (t >> 16)); - ch->time1 = htons ((u16) t); - - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: cisco output: <%lxh %xh %xh %xh %xh-%xh>\n", - dev->name, ntohl (ch->type), ch->par1, - ch->par2, ch->rel, ch->time0, ch->time1); - sp->obytes += skb->len; - skb->priority=TC_PRIO_CONTROL; - skb->dev = dev; - dev_queue_xmit(skb); -} - - -int sppp_close (struct net_device *dev) -{ - struct sppp *sp = &((struct ppp_device *)dev)->sppp; - dev->flags &= ~IFF_RUNNING; - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - sppp_clear_timeout (sp); - return 0; -} - -EXPORT_SYMBOL(sppp_close); - - -int sppp_open (struct net_device *dev) -{ - struct sppp *sp = &((struct ppp_device *)dev)->sppp; - sppp_close(dev); - dev->flags |= IFF_RUNNING; - if (!(sp->pp_flags & PP_CISCO)) - sppp_lcp_open (sp); - return 0; -} - -EXPORT_SYMBOL(sppp_open); - -int sppp_reopen (struct net_device *dev) -{ - struct sppp *sp = &((struct ppp_device *)dev)->sppp; - sppp_close(dev); - dev->flags |= IFF_RUNNING; - if (!(sp->pp_flags & PP_CISCO)) - { - sp->lcp.magic = jiffies; - ++sp->pp_seq; - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - /* Give it a moment for the line to settle then go */ - sppp_set_timeout (sp, 1); - } - return 0; -} - -EXPORT_SYMBOL(sppp_reopen); - -int sppp_change_mtu(struct net_device *dev, int new_mtu) -{ - if(new_mtu<128||new_mtu>PPP_MTU||(dev->flags&IFF_UP)) - return -EINVAL; - dev->mtu=new_mtu; - return 0; -} - -EXPORT_SYMBOL(sppp_change_mtu); - -int sppp_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct sppp *sp = &((struct ppp_device *)dev)->sppp; - - if(dev->flags&IFF_UP) - return -EBUSY; - - if(!capable(CAP_NET_ADMIN)) - return -EPERM; - - switch(cmd) - { - case SPPPIOCCISCO: - sp->pp_flags|=PP_CISCO; - dev->type = ARPHRD_HDLC; - break; - case SPPPIOCPPP: - sp->pp_flags&=~PP_CISCO; - dev->type = ARPHRD_PPP; - break; - case SPPPIOCDEBUG: - sp->pp_flags&=~PP_DEBUG; - if(ifr->ifr_flags) - sp->pp_flags|=PP_DEBUG; - break; - default: - return -EINVAL; - } - return 0; -} - -EXPORT_SYMBOL(sppp_do_ioctl); - -void sppp_attach(struct ppp_device *pd) -{ - struct net_device *dev=&pd->dev; - struct sppp *sp = &pd->sppp; - - /* Initialize keepalive handler. */ - if (! spppq) - { - init_timer(&sppp_keepalive_timer); - sppp_keepalive_timer.expires=jiffies+10*HZ; - sppp_keepalive_timer.function=sppp_keepalive; - add_timer(&sppp_keepalive_timer); - } - /* Insert new entry into the keepalive list. */ - sp->pp_next = spppq; - spppq = sp; - - sp->pp_loopcnt = 0; - sp->pp_alivecnt = 0; - sp->pp_seq = 0; - sp->pp_rseq = 0; - sp->pp_flags = PP_KEEPALIVE|PP_CISCO|debug;/*PP_DEBUG;*/ - sp->lcp.magic = 0; - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - sp->pp_if = dev; - - /* - * Device specific setup. All but interrupt handler and - * hard_start_xmit. - */ - - dev->hard_header = sppp_hard_header; - dev->rebuild_header = sppp_rebuild_header; - dev->tx_queue_len = 10; - dev->type = ARPHRD_HDLC; - dev->addr_len = 0; - dev->hard_header_len = sizeof(struct ppp_header); - dev->mtu = PPP_MTU; - /* - * These 4 are callers but MUST also call sppp_ functions - */ - dev->do_ioctl = sppp_do_ioctl; -#if 0 - dev->get_stats = NULL; /* Let the driver override these */ - dev->open = sppp_open; - dev->stop = sppp_close; -#endif - dev->change_mtu = sppp_change_mtu; - dev->hard_header_cache = NULL; - dev->header_cache_update = NULL; - dev->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP; - dev_init_buffers(dev); -} - -EXPORT_SYMBOL(sppp_attach); - -void sppp_detach (struct net_device *dev) -{ - struct sppp **q, *p, *sp = &((struct ppp_device *)dev)->sppp; - - - /* Remove the entry from the keepalive list. */ - for (q = &spppq; (p = *q); q = &p->pp_next) - if (p == sp) { - *q = p->pp_next; - break; - } - - /* Stop keepalive handler. */ - if (! spppq) - del_timer(&sppp_keepalive_timer); - sppp_clear_timeout (sp); -} - -EXPORT_SYMBOL(sppp_detach); - -/* - * Analyze the LCP Configure-Request options list - * for the presence of unknown options. - * If the request contains unknown options, build and - * send Configure-reject packet, containing only unknown options. - */ -static int -sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, - int len, u32 *magic) -{ - u8 *buf, *r, *p; - int rlen; - - len -= 4; - buf = r = kmalloc (len, GFP_ATOMIC); - if (! buf) - return (0); - - p = (void*) (h+1); - for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { - switch (*p) { - case LCP_OPT_MAGIC: - /* Magic number -- extract. */ - if (len >= 6 && p[1] == 6) { - *magic = (u32)p[2] << 24 | - (u32)p[3] << 16 | p[4] << 8 | p[5]; - continue; - } - break; - case LCP_OPT_ASYNC_MAP: - /* Async control character map -- check to be zero. */ - if (len >= 6 && p[1] == 6 && ! p[2] && ! p[3] && - ! p[4] && ! p[5]) - continue; - break; - case LCP_OPT_MRU: - /* Maximum receive unit -- always OK. */ - continue; - default: - /* Others not supported. */ - break; - } - /* Add the option to rejected list. */ - memcpy(r, p, p[1]); - r += p[1]; - rlen += p[1]; - } - if (rlen) - sppp_cp_send (sp, PPP_LCP, LCP_CONF_REJ, h->ident, rlen, buf); - kfree(buf); - return (rlen == 0); -} - -static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *skb) -{ - struct lcp_header *h; - struct net_device *dev = sp->pp_if; - int len = skb->len; - - if (len < 4) - { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid ipcp packet length: %d bytes\n", - dev->name, len); - return; - } - h = (struct lcp_header *)skb->data; - skb_pull(skb,sizeof(struct lcp_header)); - if (sp->pp_flags & PP_DEBUG) { - printk (KERN_WARNING "%s: ipcp input: %d bytes <%s id=%xh len=%xh", - dev->name, len, - sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len)); - if (len > 4) - sppp_print_bytes ((u8*) (h+1), len-4); - printk (">\n"); - } - if (len > ntohs (h->len)) - len = ntohs (h->len); - switch (h->type) { - default: - /* Unknown packet type -- send Code-Reject packet. */ - sppp_cp_send (sp, PPP_IPCP, IPCP_CODE_REJ, ++sp->pp_seq, len, h); - break; - case IPCP_CONF_REQ: - if (len < 4) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid ipcp configure request packet length: %d bytes\n", - dev->name, len); - return; - } - if (len > 4) { - sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident, - len-4, h+1); - - switch (sp->ipcp.state) { - case IPCP_STATE_OPENED: - /* Initiate renegotiation. */ - sppp_ipcp_open (sp); - /* fall through... */ - case IPCP_STATE_ACK_SENT: - /* Go to closed state. */ - sp->ipcp.state = IPCP_STATE_CLOSED; - } - } else { - /* Send Configure-Ack packet. */ - sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident, - 0, 0); - /* Change the state. */ - if (sp->ipcp.state == IPCP_STATE_ACK_RCVD) - sp->ipcp.state = IPCP_STATE_OPENED; - else - sp->ipcp.state = IPCP_STATE_ACK_SENT; - } - break; - case IPCP_CONF_ACK: - if (h->ident != sp->ipcp.confid) - break; - sppp_clear_timeout (sp); - switch (sp->ipcp.state) { - case IPCP_STATE_CLOSED: - sp->ipcp.state = IPCP_STATE_ACK_RCVD; - sppp_set_timeout (sp, 5); - break; - case IPCP_STATE_ACK_SENT: - sp->ipcp.state = IPCP_STATE_OPENED; - break; - } - break; - case IPCP_CONF_NAK: - case IPCP_CONF_REJ: - if (h->ident != sp->ipcp.confid) - break; - sppp_clear_timeout (sp); - /* Initiate renegotiation. */ - sppp_ipcp_open (sp); - if (sp->ipcp.state != IPCP_STATE_ACK_SENT) - /* Go to closed state. */ - sp->ipcp.state = IPCP_STATE_CLOSED; - break; - case IPCP_TERM_REQ: - /* Send Terminate-Ack packet. */ - sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, 0); - /* Go to closed state. */ - sp->ipcp.state = IPCP_STATE_CLOSED; - /* Initiate renegotiation. */ - sppp_ipcp_open (sp); - break; - case IPCP_TERM_ACK: - /* Ignore for now. */ - case IPCP_CODE_REJ: - /* Ignore for now. */ - break; - } -} - -static void sppp_lcp_open (struct sppp *sp) -{ - char opt[6]; - - if (! sp->lcp.magic) - sp->lcp.magic = jiffies; - opt[0] = LCP_OPT_MAGIC; - opt[1] = sizeof (opt); - opt[2] = sp->lcp.magic >> 24; - opt[3] = sp->lcp.magic >> 16; - opt[4] = sp->lcp.magic >> 8; - opt[5] = sp->lcp.magic; - sp->lcp.confid = ++sp->pp_seq; - sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, sp->lcp.confid, - sizeof (opt), &opt); - sppp_set_timeout (sp, 2); -} - -static void sppp_ipcp_open (struct sppp *sp) -{ - sp->ipcp.confid = ++sp->pp_seq; - sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0, 0); - sppp_set_timeout (sp, 2); -} - -/* - * Process PPP control protocol timeouts. - */ - -static void sppp_cp_timeout (unsigned long arg) -{ - struct sppp *sp = (struct sppp*) arg; - unsigned long flags; - save_flags(flags); - cli(); - - sp->pp_flags &= ~PP_TIMO; - if (! (sp->pp_if->flags & IFF_RUNNING) || (sp->pp_flags & PP_CISCO)) { - restore_flags(flags); - return; - } - switch (sp->lcp.state) { - case LCP_STATE_CLOSED: - /* No ACK for Configure-Request, retry. */ - sppp_lcp_open (sp); - break; - case LCP_STATE_ACK_RCVD: - /* ACK got, but no Configure-Request for peer, retry. */ - sppp_lcp_open (sp); - sp->lcp.state = LCP_STATE_CLOSED; - break; - case LCP_STATE_ACK_SENT: - /* ACK sent but no ACK for Configure-Request, retry. */ - sppp_lcp_open (sp); - break; - case LCP_STATE_OPENED: - /* LCP is already OK, try IPCP. */ - switch (sp->ipcp.state) { - case IPCP_STATE_CLOSED: - /* No ACK for Configure-Request, retry. */ - sppp_ipcp_open (sp); - break; - case IPCP_STATE_ACK_RCVD: - /* ACK got, but no Configure-Request for peer, retry. */ - sppp_ipcp_open (sp); - sp->ipcp.state = IPCP_STATE_CLOSED; - break; - case IPCP_STATE_ACK_SENT: - /* ACK sent but no ACK for Configure-Request, retry. */ - sppp_ipcp_open (sp); - break; - case IPCP_STATE_OPENED: - /* IPCP is OK. */ - break; - } - break; - } - restore_flags(flags); -} - -static char *sppp_lcp_type_name (u8 type) -{ - static char buf [8]; - switch (type) { - case LCP_CONF_REQ: return ("conf-req"); - case LCP_CONF_ACK: return ("conf-ack"); - case LCP_CONF_NAK: return ("conf-nack"); - case LCP_CONF_REJ: return ("conf-rej"); - case LCP_TERM_REQ: return ("term-req"); - case LCP_TERM_ACK: return ("term-ack"); - case LCP_CODE_REJ: return ("code-rej"); - case LCP_PROTO_REJ: return ("proto-rej"); - case LCP_ECHO_REQ: return ("echo-req"); - case LCP_ECHO_REPLY: return ("echo-reply"); - case LCP_DISC_REQ: return ("discard-req"); - } - sprintf (buf, "%xh", type); - return (buf); -} - -static char *sppp_ipcp_type_name (u8 type) -{ - static char buf [8]; - switch (type) { - case IPCP_CONF_REQ: return ("conf-req"); - case IPCP_CONF_ACK: return ("conf-ack"); - case IPCP_CONF_NAK: return ("conf-nack"); - case IPCP_CONF_REJ: return ("conf-rej"); - case IPCP_TERM_REQ: return ("term-req"); - case IPCP_TERM_ACK: return ("term-ack"); - case IPCP_CODE_REJ: return ("code-rej"); - } - sprintf (buf, "%xh", type); - return (buf); -} - -static void sppp_print_bytes (u_char *p, u16 len) -{ - printk (" %x", *p++); - while (--len > 0) - printk ("-%x", *p++); -} - -/* - * Protocol glue. This drives the deferred processing mode the poorer - * cards use. - */ - -int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p) -{ - sppp_input(dev,skb); - return 0; -} - -EXPORT_SYMBOL(sppp_rcv); - -struct packet_type sppp_packet_type= -{ - 0, - NULL, - sppp_rcv, - NULL, - NULL -}; - - -void sync_ppp_init(void) -{ - printk(KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n"); - printk(KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & Jan \"Yenya\" Kasprzak.\n"); - sppp_packet_type.type=htons(ETH_P_WAN_PPP); - dev_add_pack(&sppp_packet_type); -} - -#ifdef MODULE - -int init_module(void) -{ - if(debug) - debug=PP_DEBUG; - sync_ppp_init(); - return 0; -} - -void cleanup_module(void) -{ - dev_remove_pack(&sppp_packet_type); -} - -#endif diff -u --recursive --new-file v2.3.20/linux/drivers/net/syncppp.h linux/drivers/net/syncppp.h --- v2.3.20/linux/drivers/net/syncppp.h Wed Aug 18 11:36:45 1999 +++ linux/drivers/net/syncppp.h Wed Dec 31 16:00:00 1969 @@ -1,91 +0,0 @@ -/* - * Defines for synchronous PPP/Cisco link level subroutines. - * - * Copyright (C) 1994 Cronyx Ltd. - * Author: Serge Vakulenko, - * - * This software is distributed with NO WARRANTIES, not even the implied - * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Authors grant any other persons or organizations permission to use - * or modify this software as long as this message is kept with the software, - * all derivative works or modified versions. - * - * Version 1.7, Wed Jun 7 22:12:02 MSD 1995 - * - * - * - */ - -#ifndef _SYNCPPP_H_ -#define _SYNCPPP_H_ 1 - -#ifdef __KERNEL__ -struct slcp { - u16 state; /* state machine */ - u32 magic; /* local magic number */ - u_char echoid; /* id of last keepalive echo request */ - u_char confid; /* id of last configuration request */ -}; - -struct sipcp { - u16 state; /* state machine */ - u_char confid; /* id of last configuration request */ -}; - -struct sppp -{ - struct sppp * pp_next; /* next interface in keepalive list */ - u32 pp_flags; /* use Cisco protocol instead of PPP */ - u16 pp_alivecnt; /* keepalive packets counter */ - u16 pp_loopcnt; /* loopback detection counter */ - u32 pp_seq; /* local sequence number */ - u32 pp_rseq; /* remote sequence number */ - struct slcp lcp; /* LCP params */ - struct sipcp ipcp; /* IPCP params */ - u32 ibytes,obytes; /* Bytes in/out */ - u32 ipkts,opkts; /* Packets in/out */ - struct timer_list pp_timer; - struct net_device *pp_if; -}; - -struct ppp_device -{ - struct net_device dev; /* Network device */ - struct sppp sppp; /* Synchronous PPP */ -}; - -#define PP_KEEPALIVE 0x01 /* use keepalive protocol */ -#define PP_CISCO 0x02 /* use Cisco protocol instead of PPP */ -#define PP_TIMO 0x04 /* cp_timeout routine active */ -#define PP_DEBUG 0x08 - -#define PPP_MTU 1500 /* max. transmit unit */ - -#define LCP_STATE_CLOSED 0 /* LCP state: closed (conf-req sent) */ -#define LCP_STATE_ACK_RCVD 1 /* LCP state: conf-ack received */ -#define LCP_STATE_ACK_SENT 2 /* LCP state: conf-ack sent */ -#define LCP_STATE_OPENED 3 /* LCP state: opened */ - -#define IPCP_STATE_CLOSED 0 /* IPCP state: closed (conf-req sent) */ -#define IPCP_STATE_ACK_RCVD 1 /* IPCP state: conf-ack received */ -#define IPCP_STATE_ACK_SENT 2 /* IPCP state: conf-ack sent */ -#define IPCP_STATE_OPENED 3 /* IPCP state: opened */ - -void sppp_attach (struct ppp_device *pd); -void sppp_detach (struct net_device *dev); -void sppp_input (struct net_device *dev, struct sk_buff *m); -int sppp_do_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd); -struct sk_buff *sppp_dequeue (struct net_device *dev); -int sppp_isempty (struct net_device *dev); -void sppp_flush (struct net_device *dev); -int sppp_open (struct net_device *dev); -int sppp_reopen (struct net_device *dev); -int sppp_close (struct net_device *dev); -#endif - -#define SPPPIOCCISCO (SIOCDEVPRIVATE) -#define SPPPIOCPPP (SIOCDEVPRIVATE+1) -#define SPPPIOCDEBUG (SIOCDEVPRIVATE+2) - -#endif /* _SYNCPPP_H_ */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/tokenring/Config.in linux/drivers/net/tokenring/Config.in --- v2.3.20/linux/drivers/net/tokenring/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tokenring/Config.in Mon Oct 11 10:13:24 1999 @@ -0,0 +1,15 @@ +# +# Token Ring driver configuration +# + +mainmenu_option next_comment +comment 'Token Ring driver support' + +bool 'Token Ring driver support' CONFIG_TR +if [ "$CONFIG_TR" = "y" ]; then + tristate ' IBM Tropic chipset based adapter support' CONFIG_IBMTR + tristate ' IBM Olympic chipset PCI adapter support' CONFIG_IBMOL + tristate ' SysKonnect adapter support' CONFIG_SKTR +fi + +endmenu diff -u --recursive --new-file v2.3.20/linux/drivers/net/tokenring/Makefile linux/drivers/net/tokenring/Makefile --- v2.3.20/linux/drivers/net/tokenring/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tokenring/Makefile Mon Oct 11 10:13:24 1999 @@ -0,0 +1,51 @@ +# +# Makefile for drivers/net/tokenring +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now inherited from the +# parent makefile. +# + +# +# Note : at this point, these files are compiled on all systems. +# In the future, some of these should be built conditionally. +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + + +L_TARGET := tr.a +L_OBJS := +M_OBJS := + +ifeq ($(CONFIG_IBMTR),y) + L_OBJS += ibmtr.o +else + ifeq ($(CONFIG_IBMTR),m) + M_OBJS += ibmtr.o + endif +endif + +ifeq ($(CONFIG_IBMOL),y) + L_OBJS += olympic.o +else + ifeq ($(CONFIG_IBMOL),m) + M_OBJS += olympic.o + endif +endif + +ifeq ($(CONFIG_SKTR),y) + L_OBJS += sktr.o +else + ifeq ($(CONFIG_SKTR),m) + M_OBJS += sktr.o + endif +endif + +include $(TOPDIR)/Rules.make + diff -u --recursive --new-file v2.3.20/linux/drivers/net/tokenring/ibmtr.c linux/drivers/net/tokenring/ibmtr.c --- v2.3.20/linux/drivers/net/tokenring/ibmtr.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tokenring/ibmtr.c Mon Oct 11 10:13:24 1999 @@ -0,0 +1,1809 @@ +/* ibmtr.c: A shared-memory IBM Token Ring 16/4 driver for linux + * + * Written 1993 by Mark Swanson and Peter De Schrijver. + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + * This device driver should work with Any IBM Token Ring Card that does + * not use DMA. + * + * I used Donald Becker's (becker@cesdis.gsfc.nasa.gov) device driver work + * as a base for most of my initial work. + * + * Changes by Peter De Schrijver (Peter.Deschrijver@linux.cc.kuleuven.ac.be) : + * + * + changed name to ibmtr.c in anticipation of other tr boards. + * + changed reset code and adapter open code. + * + added SAP open code. + * + a first attempt to write interrupt, transmit and receive routines. + * + * Changes by David W. Morris (dwm@shell.portal.com) : + * 941003 dwm: - Restructure tok_probe for multiple adapters, devices. + * + Add comments, misc reorg for clarity. + * + Flatten interrupt handler levels. + * + * Changes by Farzad Farid (farzy@zen.via.ecp.fr) + * and Pascal Andre (andre@chimay.via.ecp.fr) (March 9 1995) : + * + multi ring support clean up. + * + RFC1042 compliance enhanced. + * + * Changes by Pascal Andre (andre@chimay.via.ecp.fr) (September 7 1995) : + * + bug correction in tr_tx + * + removed redundant information display + * + some code reworking + * + * Changes by Michel Lespinasse (walken@via.ecp.fr), + * Yann Doussot (doussot@via.ecp.fr) and Pascal Andre (andre@via.ecp.fr) + * (February 18, 1996) : + * + modified shared memory and mmio access port the driver to + * alpha platform (structure access -> readb/writeb) + * + * Changes by Steve Kipisz (bungy@ibm.net or kipisz@vnet.ibm.com) + * (January 18 1996): + * + swapped WWOR and WWCR in ibmtr.h + * + moved some init code from tok_probe into trdev_init. The + * PCMCIA code can call trdev_init to complete initializing + * the driver. + * + added -DPCMCIA to support PCMCIA + * + detecting PCMCIA Card Removal in interrupt handler. If + * ISRP is FF, then a PCMCIA card has been removed + * + * Changes by Paul Norton (pnorton@cts.com) : + * + restructured the READ.LOG logic to prevent the transmit SRB + * from being rudely overwritten before the transmit cycle is + * complete. (August 15 1996) + * + completed multiple adapter support. (November 20 1996) + * + implemented csum_partial_copy in tr_rx and increased receive + * buffer size and count. Minor fixes. (March 15, 1997) + * + * Changes by Christopher Turcksin + * + 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 : + * + 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 + +#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 \n" +" v2.2.0 12/30/98 Joel Sloan \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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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; isrb+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;idev_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; isrb+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; iinit_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; immio + 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_waitedtrans_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] && (ibase_addr = io[i]; + dev_ibmtr[i]->irq = irq[i]; + dev_ibmtr[i]->mem_start = mem[i]; + dev_ibmtr[i]->init = &ibmtr_probe; + + if (register_trdev(dev_ibmtr[i]) != 0) { + kfree_s(dev_ibmtr[i], sizeof(struct net_device)); + dev_ibmtr[i] = NULL; + if (i == 0) { + printk("ibmtr: register_trdev() returned non-zero.\n"); + return -EIO; + } else { + return 0; + } + } + } + return 0; +} + +void cleanup_module(void) +{ + int i; + + for (i = 0; i < IBMTR_MAX_ADAPTERS; i++) + if (dev_ibmtr[i]) { + unregister_trdev(dev_ibmtr[i]); + free_irq(dev_ibmtr[i]->irq, dev_ibmtr[i]); + release_region(dev_ibmtr[i]->base_addr, IBMTR_IO_EXTENT); + kfree_s(dev_ibmtr[i]->priv, sizeof(struct tok_info)); + kfree_s(dev_ibmtr[i], sizeof(struct net_device)); + dev_ibmtr[i] = NULL; + } +} +#endif /* MODULE */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/tokenring/ibmtr.h linux/drivers/net/tokenring/ibmtr.h --- v2.3.20/linux/drivers/net/tokenring/ibmtr.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tokenring/ibmtr.h Mon Oct 11 10:13:24 1999 @@ -0,0 +1,449 @@ +/* Definitions for an IBM Token Ring card. */ +/* This file is distributed under the GNU GPL */ + +/* ported to the Alpha architecture 02/20/96 (just used the HZ macro) */ + +#define TR_RETRY_INTERVAL (5*HZ) /* 500 on PC = 5 s */ +#define TR_RESET_INTERVAL (HZ/20) /* 5 on PC = 50 ms */ +#define TR_BUSY_INTERVAL (HZ/5) /* 5 on PC = 200 ms */ +#define TR_SPIN_INTERVAL (3*HZ) /* 3 seconds before init timeout */ +#define TR_RETRIES 6 /* number of open retries */ + +#define TR_ISA 1 +#define TR_MCA 2 +#define TR_ISAPNP 3 +#define NOTOK 0 +#define TOKDEBUG 1 + +#define IBMTR_SHARED_RAM_SIZE 0x10000 +#define IBMTR_IO_EXTENT 4 +#define IBMTR_MAX_ADAPTERS 2 + +#define CHANNEL_ID 0X1F30 +#define AIP 0X1F00 +#define AIPCHKSUM1 0X1F60 +#define AIPCHKSUM2 0X1FF0 +#define AIPADAPTYPE 0X1FA0 +#define AIPDATARATE 0X1FA2 +#define AIPEARLYTOKEN 0X1FA4 +#define AIPAVAILSHRAM 0X1FA6 +#define AIPSHRAMPAGE 0X1FA8 +#define AIP4MBDHB 0X1FAA +#define AIP16MBDHB 0X1FAC +#define AIPFID 0X1FBA + +/* Note, 0xA20 == 0x220 since motherboard decodes 10 bits. I left everything + the way my documentation had it, ie: 0x0A20. */ +#define ADAPTINTCNTRL 0x02f0 /* Adapter interrupt control */ +#define ADAPTRESET 0x1 /* Control Adapter reset (add to base) */ +#define ADAPTRESETREL 0x2 /* Release Adapter from reset ( """) */ +#define ADAPTINTREL 0x3 /* Adapter interrupt release */ + +#define MMIOStartLocP 0x0a20 /* Primary adapter's starting MMIO area */ +#define MMIOStartLocA 0x0a24 /* Alternate adapter's starting MMIO area */ + +#define GLOBAL_INT_ENABLE 0x02f0 + +/* MMIO bits 0-4 select register */ +#define RRR_EVEN 0x00 /* Shared RAM relocation registers - even and odd */ +/* Used to set the starting address of shared RAM */ +/* Bits 1 through 7 of this register map to bits 13 through 19 of the shared RAM address.*/ +/* ie: 0x02 sets RAM address to ...ato! issy su wazzoo !! GODZILLA!!! */ +#define RRR_ODD 0x01 +/* Bits 2 and 3 of this register can be read to determine shared RAM size */ +/* 00 for 8k, 01 for 16k, 10 for 32k, 11 for 64k */ +#define WRBR_EVEN 0x02 /* Write region base registers - even and odd */ +#define WRBR_ODD 0x03 +#define WWOR_EVEN 0x04 /* Write window open registers - even and odd */ +#define WWOR_ODD 0x05 +#define WWCR_EVEN 0x06 /* Write window close registers - even and odd */ +#define WWCR_ODD 0x07 + +/* Interrupt status registers - PC system - even and odd */ +#define ISRP_EVEN 0x08 + +#define TCR_INT 0x10 /* Bit 4 - Timer interrupt. The TVR_EVEN timer has + expired. */ +#define ERR_INT 0x08 /* Bit 3 - Error interrupt. The adapter has had an + internal error. */ +#define ACCESS_INT 0x04 /* Bit 2 - Access interrupt. You have attempted to + write to an invalid area of shared RAM or an invalid + register within the MMIO. */ +/* In addition, the following bits within ISRP_EVEN can be turned on or off by you */ +/* to control the interrupt processing: */ +#define INT_IRQ 0x80 /* Bit 7 - If 0 the adapter will issue a CHCK, if 1 and + IRQ. This should normally be set (by you) to 1. */ +#define INT_ENABLE 0x40 /* Bit 6 - Interrupt enable. If 0, no interrupts will + occur. If 1, interrupts will occur normally. + Normally set to 1. */ +/* Bit 0 - Primary or alternate adapter. Set to zero if this adapter is the primary adapter,*/ +/* 1 if this adapter is the alternate adapter. */ + + +#define ISRP_ODD 0x09 + +#define ADAP_CHK_INT 0x40 /* Bit 6 - Adapter check. the adapter has + encountered a serious problem and has closed + itself. Whoa. */ +#define SRB_RESP_INT 0x20 /* Bit 5 - SRB response. The adapter has accepted + an SRB request and set the return code within + the SRB. */ +#define ASB_FREE_INT 0x10 /* Bit 4 - ASB free. The adapter has read the ASB + and this area can be safely reused. This interrupt + is only used if your application has set the ASB + free request bit in ISRA_ODD or if an error was + detected in your response. */ +#define ARB_CMD_INT 0x08 /* Bit 3 - ARB command. The adapter has given you a + command for action. The command is located in the + ARB area of shared memory. */ +#define SSB_RESP_INT 0x04 /* Bit 2 - SSB response. The adapter has posted a + response to your SRB (the response is located in + the SSB area of shared memory). */ +/* Bit 1 - Bridge frame forward complete. */ + + + +#define ISRA_EVEN 0x0A /* Interrupt status registers - adapter - even and odd */ +/* Bit 7 - Internal parity error (on adapter's internal bus) */ +/* Bit 6 - Timer interrupt pending */ +/* Bit 5 - Access interrupt (attempt by adapter to access illegal address) */ +/* Bit 4 - Adapter microcode problem (microcode dead-man timer expired) */ +/* Bit 3 - Adapter processor check status */ +/* Bit 2 - Reserved */ +/* Bit 1 - Adapter hardware interrupt mask (prevents internal interrupts) */ +/* Bit 0 - Adapter software interrupt mask (prevents internal software interrupts) */ + +#define ISRA_ODD 0x0B +#define CMD_IN_SRB 0x20 /* Bit 5 - Indicates that you have placed a new + command in the SRB and are ready for the adapter to + process the command. */ +#define RESP_IN_ASB 0x10 /* Bit 4 - Indicates that you have placed a response + (an ASB) in the shared RAM which is available for + the adapter's use. */ +/* Bit 3 - Indicates that you are ready to put an SRB in the shared RAM, but that a previous */ +/* command is still pending. The adapter will then interrupt you when the previous */ +/* command is completed */ +/* Bit 2 - Indicates that you are ready to put an ASB in the shared RAM, but that a previous */ +/* ASB is still pending. The adapter will then interrupt you when the previous ASB */ +/* is copied. */ +#define ARB_FREE 0x2 +#define SSB_FREE 0x1 + +#define TCR_EVEN 0x0C /* Timer control registers - even and odd */ +#define TCR_ODD 0x0D +#define TVR_EVEN 0x0E /* Timer value registers - even and odd */ +#define TVR_ODD 0x0F +#define SRPR_EVEN 0x10 /* Shared RAM paging registers - even and odd */ +#define SRPR_ENABLE_PAGING 0xc0 +#define SRPR_ODD 0x11 /* Not used. */ +#define TOKREAD 0x60 +#define TOKOR 0x40 +#define TOKAND 0x20 +#define TOKWRITE 0x00 + +/* MMIO bits 5-6 select operation */ +/* 00 is used to write to a register */ +/* 01 is used to bitwise AND a byte with a register */ +/* 10 is used to bitwise OR a byte with a register */ +/* 11 is used to read from a register */ + +/* MMIO bits 7-8 select area of interest.. see below */ +/* 00 selects attachment control area. */ +/* 01 is reserved. */ +/* 10 selects adapter identification area A containing the adapter encoded address. */ +/* 11 selects the adapter identification area B containing test patterns. */ + +#define PCCHANNELID 5049434F3631313039393020 +#define MCCHANNELID 4D4152533633583435313820 + +#define ACA_OFFSET 0x1e00 +#define ACA_SET 0x40 +#define ACA_RESET 0x20 +#define ACA_RW 0x00 + +#ifdef ENABLE_PAGING +#define SET_PAGE(x) (writeb(((x>>8)&ti.page_mask), \ + ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN)) +#else +#define SET_PAGE(x) +#endif + +typedef enum { IN_PROGRESS, SUCCESS, FAILURE, CLOSED } open_state; + +/* do_tok_int possible values */ +#define FIRST_INT 1 +#define NOT_FIRST 2 + +struct tok_info { + unsigned char irq; + __u32 mmio; + unsigned char hw_address[32]; + unsigned char adapter_type; + unsigned char data_rate; + unsigned char token_release; + unsigned char avail_shared_ram; + unsigned char shared_ram_paging; + unsigned short dhb_size4mb; + unsigned short rbuf_len4; + unsigned short rbuf_cnt4; + unsigned short maxmtu4; + unsigned short dhb_size16mb; + unsigned short rbuf_len16; + unsigned short rbuf_cnt16; + unsigned short maxmtu16; + /* Additions by David Morris */ + unsigned char do_tok_int; + wait_queue_head_t wait_for_tok_int; + wait_queue_head_t wait_for_reset; + unsigned char sram_base; + /* Additions by Peter De Schrijver */ + unsigned char page_mask; /* mask to select RAM page to Map*/ + unsigned char mapped_ram_size; /* size of RAM page */ + __u32 sram; /* Shared memory base address */ + __u32 init_srb; /* Initial System Request Block address */ + __u32 srb; /* System Request Block address */ + __u32 ssb; /* System Status Block address */ + __u32 arb; /* Adapter Request Block address */ + __u32 asb; /* Adapter Status Block address */ + unsigned short exsap_station_id; + unsigned short global_int_enable; + struct sk_buff *current_skb; + struct net_device_stats tr_stats; + unsigned char auto_ringspeedsave; + open_state open_status; + unsigned char readlog_pending; + unsigned short adapter_int_enable; /* Adapter-specific int enable */ + struct timer_list tr_timer; + unsigned char ring_speed; + __u32 func_addr; + unsigned int retry_count; + spinlock_t lock; /* SMP protection */ +}; + +/* token ring adapter commands */ +#define DIR_INTERRUPT 0x00 /* struct srb_interrupt */ +#define DIR_MOD_OPEN_PARAMS 0x01 +#define DIR_OPEN_ADAPTER 0x03 /* struct dir_open_adapter */ +#define DIR_CLOSE_ADAPTER 0x04 +#define DIR_SET_GRP_ADDR 0x06 +#define DIR_SET_FUNC_ADDR 0x07 /* struct srb_set_funct_addr */ +#define DIR_READ_LOG 0x08 /* struct srb_read_log */ +#define DLC_OPEN_SAP 0x15 /* struct dlc_open_sap */ +#define DLC_CLOSE_SAP 0x16 +#define DATA_LOST 0x20 /* struct asb_rec */ +#define REC_DATA 0x81 /* struct arb_rec_req */ +#define XMIT_DATA_REQ 0x82 /* struct arb_xmit_req */ +#define DLC_STATUS 0x83 /* struct arb_dlc_status */ +#define RING_STAT_CHANGE 0x84 /* struct dlc_open_sap ??? */ + +/* DIR_OPEN_ADAPTER options */ +#define OPEN_PASS_BCON_MAC 0x0100 +#define NUM_RCV_BUF 2 +#define RCV_BUF_LEN 1024 +#define DHB_LENGTH 2048 +#define NUM_DHB 2 +#define DLC_MAX_SAP 2 +#define DLC_MAX_STA 1 + +/* DLC_OPEN_SAP options */ +#define MAX_I_FIELD 0x0088 +#define SAP_OPEN_IND_SAP 0x04 +#define SAP_OPEN_PRIORITY 0x20 +#define SAP_OPEN_STATION_CNT 0x1 +#define XMIT_DIR_FRAME 0x0A +#define XMIT_UI_FRAME 0x0d +#define XMIT_XID_CMD 0x0e +#define XMIT_TEST_CMD 0x11 + +/* srb close return code */ +#define SIGNAL_LOSS 0x8000 +#define HARD_ERROR 0x4000 +#define XMIT_BEACON 0x1000 +#define LOBE_FAULT 0x0800 +#define AUTO_REMOVAL 0x0400 +#define REMOVE_RECV 0x0100 +#define LOG_OVERFLOW 0x0080 +#define RING_RECOVER 0x0020 + +struct srb_init_response { + unsigned char command; + unsigned char init_status; + unsigned char init_status_2; + unsigned char reserved[3]; + __u16 bring_up_code; + __u16 encoded_address; + __u16 level_address; + __u16 adapter_address; + __u16 parms_address; + __u16 mac_address; +}; + +struct dir_open_adapter { + unsigned char command; + char reserved[7]; + __u16 open_options; + unsigned char node_address[6]; + unsigned char group_address[4]; + unsigned char funct_address[4]; + __u16 num_rcv_buf; + __u16 rcv_buf_len; + __u16 dhb_length; + unsigned char num_dhb; + char reserved2; + unsigned char dlc_max_sap; + unsigned char dlc_max_sta; + unsigned char dlc_max_gsap; + unsigned char dlc_max_gmem; + unsigned char dlc_t1_tick_1; + unsigned char dlc_t2_tick_1; + unsigned char dlc_ti_tick_1; + unsigned char dlc_t1_tick_2; + unsigned char dlc_t2_tick_2; + unsigned char dlc_ti_tick_2; + unsigned char product_id[18]; +}; + +struct srb_open_response { + unsigned char command; + unsigned char reserved1; + unsigned char ret_code; + unsigned char reserved2[3]; + __u16 error_code; + __u16 asb_addr; + __u16 srb_addr; + __u16 arb_addr; + __u16 ssb_addr; +}; + +struct dlc_open_sap { + unsigned char command; + unsigned char reserved1; + unsigned char ret_code; + unsigned char reserved2; + __u16 station_id; + unsigned char timer_t1; + unsigned char timer_t2; + unsigned char timer_ti; + unsigned char maxout; + unsigned char maxin; + unsigned char maxout_incr; + unsigned char max_retry_count; + unsigned char gsap_max_mem; + __u16 max_i_field; + unsigned char sap_value; + unsigned char sap_options; + unsigned char station_count; + unsigned char sap_gsap_mem; + unsigned char gsap[0]; +}; + +struct srb_xmit { + unsigned char command; + unsigned char cmd_corr; + unsigned char ret_code; + unsigned char reserved1; + __u16 station_id; +}; + +struct srb_interrupt { + unsigned char command; + unsigned char cmd_corr; + unsigned char ret_code; +}; + +struct srb_read_log { + unsigned char command; + unsigned char reserved1; + unsigned char ret_code; + unsigned char reserved2; + unsigned char line_errors; + unsigned char internal_errors; + unsigned char burst_errors; + unsigned char A_C_errors; + unsigned char abort_delimiters; + unsigned char reserved3; + unsigned char lost_frames; + unsigned char recv_congest_count; + unsigned char frame_copied_errors; + unsigned char frequency_errors; + unsigned char token_errors; +}; + +struct asb_xmit_resp { + unsigned char command; + unsigned char cmd_corr; + unsigned char ret_code; + unsigned char reserved; + __u16 station_id; + __u16 frame_length; + unsigned char hdr_length; + unsigned char rsap_value; +}; + +struct arb_xmit_req { + unsigned char command; + unsigned char cmd_corr; + unsigned char reserved1[2]; + __u16 station_id; + __u16 dhb_address; +}; + +struct arb_rec_req { + unsigned char command; + unsigned char reserved1[3]; + __u16 station_id; + __u16 rec_buf_addr; + unsigned char lan_hdr_len; + unsigned char dlc_hdr_len; + __u16 frame_len; + unsigned char msg_type; +}; + +struct asb_rec { + unsigned char command; + unsigned char reserved1; + unsigned char ret_code; + unsigned char reserved2; + __u16 station_id; + __u16 rec_buf_addr; +}; + +struct rec_buf { + /* unsigned char reserved1[2]; */ + __u16 buf_ptr; + unsigned char reserved2; + __u16 buf_len; + unsigned char data[0]; +}; + +struct arb_dlc_status { + unsigned char command; + unsigned char reserved1[3]; + __u16 station_id; + __u16 status; + unsigned char frmr_data[5]; + unsigned char access_prio; + unsigned char rem_addr[TR_ALEN]; + unsigned char rsap_value; +}; + +struct arb_ring_stat_change { + unsigned char command; + unsigned char reserved1[5]; + __u16 ring_status; +}; + +struct srb_close_adapter { + unsigned char command; + unsigned char reserved1; + unsigned char ret_code; +}; + +struct srb_set_funct_addr { + unsigned char command; + unsigned char reserved1; + unsigned char ret_code; + unsigned char reserved2[3]; + unsigned char funct_address[4]; +}; + diff -u --recursive --new-file v2.3.20/linux/drivers/net/tokenring/olympic.c linux/drivers/net/tokenring/olympic.c --- v2.3.20/linux/drivers/net/tokenring/olympic.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tokenring/olympic.c Mon Oct 11 10:13:24 1999 @@ -0,0 +1,1667 @@ +/* + * olympic.c (c) 1999 Peter De Schrijver All Rights Reserved + * 1999 Mike Phillips (phillim@amtrak.com) + * + * Linux driver for IBM PCI tokenring cards based on the Pit/Pit-Phy/Olympic + * chipset. + * + * Base Driver Skeleton: + * Written 1993-94 by Donald Becker. + * + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. + * + * Thanks to Erik De Cock, Adrian Bridgett and Frank Fiene for their + * assistance and perserverance with the testing of this driver. + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + * 4/27/99 - Alpha Release 0.1.0 + * First release to the public + * + * 6/8/99 - Official Release 0.2.0 + * Merged into the kernel code + * 8/18/99 - Updated driver for 2.3.13 kernel to use new pci + * resource. Driver also reports the card name returned by + * the pci resource. + * + * To Do: + * + * Sanitize for smp + * + * If Problems do Occur + * Most problems can be rectified by either closing and opening the interface + * (ifconfig down and up) or rmmod and insmod'ing the driver (a bit difficult + * if compiled into the kernel). + */ + +/* Change OLYMPIC_DEBUG to 1 to get verbose, and I mean really verbose, messages */ + +#define OLYMPIC_DEBUG 0 + +/* Change OLYMPIC_NETWORK_MONITOR to receive mac frames through the arb channel. + * Will also create a /proc/net/olympic_tr entry if proc_fs is compiled into the + * kernel. + * Intended to be used to create a ring-error reporting network module + * i.e. it will give you the source address of beaconers on the ring + */ + +#define OLYMPIC_NETWORK_MONITOR 0 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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;iolympic_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;ipkt_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;iolympic_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;irx_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(posoffset+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; (iinit = &olympic_probe; + + if (register_trdev(dev_olympic[i]) != 0) { + kfree_s(dev_olympic[i], sizeof(struct net_device)); + dev_olympic[i] = NULL; + if (i == 0) { + printk("Olympic: No IBM PCI Token Ring cards found in system.\n"); + return -EIO; + } else { + printk("Olympic: %d IBM PCI Token Ring card(s) found in system.\n",i) ; + return 0; + } + } + } + + return 0; +} + +void cleanup_module(void) +{ + int i; + + for (i = 0; i < OLYMPIC_MAX_ADAPTERS; i++) + if (dev_olympic[i]) { + unregister_trdev(dev_olympic[i]); + release_region(dev_olympic[i]->base_addr, OLYMPIC_IO_SPACE); + kfree_s(dev_olympic[i]->priv, sizeof(struct olympic_private)); + kfree_s(dev_olympic[i], sizeof(struct net_device)); + dev_olympic[i] = NULL; + } + +#if OLYMPIC_NETWORK_MONITOR +#ifdef CONFIG_PROC_FS + remove_proc_entry("net/olympic_tr", NULL) ; +#endif +#endif +} +#endif /* MODULE */ + diff -u --recursive --new-file v2.3.20/linux/drivers/net/tokenring/olympic.h linux/drivers/net/tokenring/olympic.h --- v2.3.20/linux/drivers/net/tokenring/olympic.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tokenring/olympic.h Mon Oct 11 10:13:24 1999 @@ -0,0 +1,304 @@ +/* + * olympic.h (c) 1999 Peter De Schrijver All Rights Reserved + * 1999 Mike Phillips (phillim@amtrak.com) + * + * Linux driver for IBM PCI tokenring cards based on the olympic and the PIT/PHY chipset. + * + * Base Driver Skeleton: + * Written 1993-94 by Donald Becker. + * + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + */ + +#define CID 0x4e + +#define BCTL 0x70 +#define BCTL_SOFTRESET (1<<15) +#define BCTL_MIMREB (1<<6) + +#define GPR 0x4a +#define GPR_OPTI_BF (1<<6) +#define GPR_NEPTUNE_BF (1<<4) +#define GPR_AUTOSENSE (1<<2) +#define GPR_16MBPS (1<<3) + +#define PAG 0x85 +#define LBC 0x8e + +#define LISR 0x10 +#define LISR_SUM 0x14 +#define LISR_RWM 0x18 + +#define LISR_LIE (1<<15) +#define LISR_SLIM (1<<13) +#define LISR_SLI (1<<12) +#define LISR_PCMSRMASK (1<<11) +#define LISR_PCMSRINT (1<<10) +#define LISR_WOLMASK (1<<9) +#define LISR_WOL (1<<8) +#define LISR_SRB_CMD (1<<5) +#define LISR_ASB_REPLY (1<<4) +#define LISR_ASB_FREE_REQ (1<<2) +#define LISR_ARB_FREE (1<<1) +#define LISR_TRB_FRAME (1<<0) + +#define SISR 0x20 +#define SISR_SUM 0x24 +#define SISR_RWM 0x28 +#define SISR_RR 0x2C +#define SISR_RESMASK 0x30 +#define SISR_MASK 0x54 +#define SISR_MASK_SUM 0x58 +#define SISR_MASK_RWM 0x5C + +#define SISR_TX2_IDLE (1<<31) +#define SISR_TX2_HALT (1<<29) +#define SISR_TX2_EOF (1<<28) +#define SISR_TX1_IDLE (1<<27) +#define SISR_TX1_HALT (1<<25) +#define SISR_TX1_EOF (1<<24) +#define SISR_TIMEOUT (1<<23) +#define SISR_RX_NOBUF (1<<22) +#define SISR_RX_STATUS (1<<21) +#define SISR_RX_HALT (1<<18) +#define SISR_RX_EOF_EARLY (1<<16) +#define SISR_MI (1<<15) +#define SISR_PI (1<<13) +#define SISR_ERR (1<<9) +#define SISR_ADAPTER_CHECK (1<<6) +#define SISR_SRB_REPLY (1<<5) +#define SISR_ASB_FREE (1<<4) +#define SISR_ARB_CMD (1<<3) +#define SISR_TRB_REPLY (1<<2) + +#define EISR 0x34 +#define EISR_RWM 0x38 +#define EISR_MASK 0x3c + +#define LAPA 0x60 +#define LAPWWO 0x64 +#define LAPWWC 0x68 +#define LAPCTL 0x6C +#define LAIPD 0x78 +#define LAIPDDINC 0x7C + +#define TIMER 0x50 + +#define CLKCTL 0x74 + +#define PM_CON 0x4 + +#define BMCTL_SUM 0x40 +#define BMCTL_RWM 0x44 +#define BMCTL_TX2_DIS (1<<30) +#define BMCTL_TX1_DIS (1<<26) +#define BMCTL_RX_DIS (1<<22) + +#define BMASR 0xcc + +#define RXDESCQ 0x90 +#define RXDESCQCNT 0x94 +#define RXCDA 0x98 +#define RXENQ 0x9C +#define RXSTATQ 0xA0 +#define RXSTATQCNT 0xA4 +#define RXCSA 0xA8 +#define RXCLEN 0xAC +#define RXHLEN 0xAE + +#define TXDESCQ_1 0xb0 +#define TXDESCQ_2 0xd0 +#define TXDESCQCNT_1 0xb4 +#define TXDESCQCNT_2 0xd4 +#define TXCDA_1 0xb8 +#define TXCDA_2 0xd8 +#define TXENQ_1 0xbc +#define TXENQ_2 0xdc +#define TXSTATQ_1 0xc0 +#define TXSTATQ_2 0xe0 +#define TXSTATQCNT_1 0xc4 +#define TXSTATQCNT_2 0xe4 +#define TXCSA_1 0xc8 +#define TXCSA_2 0xe8 + +#define OLYMPIC_IO_SPACE 256 + +#define SRB_COMMAND_SIZE 50 + +#define OLYMPIC_MAX_ADAPTERS 8 /* 0x08 __MODULE_STRING can't hand 0xnn */ + +/* Defines for LAN STATUS CHANGE reports */ +#define LSC_SIG_LOSS 0x8000 +#define LSC_HARD_ERR 0x4000 +#define LSC_SOFT_ERR 0x2000 +#define LSC_TRAN_BCN 0x1000 +#define LSC_LWF 0x0800 +#define LSC_ARW 0x0400 +#define LSC_FPE 0x0200 +#define LSC_RR 0x0100 +#define LSC_CO 0x0080 +#define LSC_SS 0x0040 +#define LSC_RING_REC 0x0020 +#define LSC_SR_CO 0x0010 +#define LSC_FDX_MODE 0x0004 + +/* Defines for OPEN ADAPTER command */ + +#define OPEN_ADAPTER_EXT_WRAP (1<<15) +#define OPEN_ADAPTER_DIS_HARDEE (1<<14) +#define OPEN_ADAPTER_DIS_SOFTERR (1<<13) +#define OPEN_ADAPTER_PASS_ADC_MAC (1<<12) +#define OPEN_ADAPTER_PASS_ATT_MAC (1<<11) +#define OPEN_ADAPTER_ENABLE_EC (1<<10) +#define OPEN_ADAPTER_CONTENDER (1<<8) +#define OPEN_ADAPTER_PASS_BEACON (1<<7) +#define OPEN_ADAPTER_ENABLE_FDX (1<<6) +#define OPEN_ADAPTER_ENABLE_RPL (1<<5) +#define OPEN_ADAPTER_INHIBIT_ETR (1<<4) +#define OPEN_ADAPTER_INTERNAL_WRAP (1<<3) +#define OPEN_ADAPTER_USE_OPTS2 (1<<0) + +#define OPEN_ADAPTER_2_ENABLE_ONNOW (1<<15) + +/* Defines for SRB Commands */ + +#define SRB_ACCESS_REGISTER 0x1f +#define SRB_CLOSE_ADAPTER 0x04 +#define SRB_CONFIGURE_BRIDGE 0x0c +#define SRB_CONFIGURE_WAKEUP_EVENT 0x1a +#define SRB_MODIFY_BRIDGE_PARMS 0x15 +#define SRB_MODIFY_OPEN_OPTIONS 0x01 +#define SRB_MODIFY_RECEIVE_OPTIONS 0x17 +#define SRB_NO_OPERATION 0x00 +#define SRB_OPEN_ADAPTER 0x03 +#define SRB_READ_LOG 0x08 +#define SRB_READ_SR_COUNTERS 0x16 +#define SRB_RESET_GROUP_ADDRESS 0x02 +#define SRB_SAVE_CONFIGURATION 0x1b +#define SRB_SET_BRIDGE_PARMS 0x09 +#define SRB_SET_BRIDGE_TARGETS 0x10 +#define SRB_SET_FUNC_ADDRESS 0x07 +#define SRB_SET_GROUP_ADDRESS 0x06 +#define SRB_SET_GROUP_ADDR_OPTIONS 0x11 +#define SRB_UPDATE_WAKEUP_PATTERN 0x19 + +/* Clear return code */ + +#define OLYMPIC_CLEAR_RET_CODE 0xfe + +/* ARB Commands */ +#define ARB_RECEIVE_DATA 0x81 +#define ARB_LAN_CHANGE_STATUS 0x84 +/* ASB Response commands */ + +#define ASB_RECEIVE_DATA 0x81 + + +/* Olympic defaults for buffers */ + +#define OLYMPIC_RX_RING_SIZE 16 /* should be a power of 2 */ +#define OLYMPIC_TX_RING_SIZE 8 /* should be a power of 2 */ + +#define PKT_BUF_SZ 4096 /* Default packet size */ + +/* Olympic data structures */ + +struct olympic_tx_desc { + __u32 buffer; + __u32 status_length; +}; + +struct olympic_tx_status { + __u32 status; +}; + +struct olympic_rx_desc { + __u32 buffer; + __u32 res_length ; +}; + +struct olympic_rx_status { + __u32 fragmentcnt_framelen; + __u32 status_buffercnt; +}; + +struct mac_receive_buffer { + __u16 next ; + __u8 padding ; + __u8 frame_status ; + __u16 buffer_length ; + __u8 frame_data ; +}; + +struct olympic_private { + + __u16 srb; + __u16 trb; + __u16 arb; + __u16 asb; + + __u8 *olympic_mmio; + __u8 *olympic_lap; + char *olympic_card_name ; + + volatile int srb_queued; /* True if an SRB is still posted */ + wait_queue_head_t srb_wait; + + volatile int asb_queued; /* True if an ASB is posted */ + + volatile int trb_queued; /* True if a TRB is posted */ + wait_queue_head_t trb_wait ; + + struct olympic_rx_desc olympic_rx_ring[OLYMPIC_RX_RING_SIZE]; + struct olympic_tx_desc olympic_tx_ring[OLYMPIC_TX_RING_SIZE]; + struct olympic_rx_status olympic_rx_status_ring[OLYMPIC_RX_RING_SIZE]; + struct olympic_tx_status olympic_tx_status_ring[OLYMPIC_TX_RING_SIZE]; + struct sk_buff *tx_ring_skb[OLYMPIC_TX_RING_SIZE], *rx_ring_skb[OLYMPIC_RX_RING_SIZE]; + int tx_ring_free, tx_ring_last_status, rx_ring_last_received,rx_status_last_received, free_tx_ring_entries; + + struct net_device_stats olympic_stats ; + __u16 olympic_lan_status ; + __u8 olympic_ring_speed ; + __u16 pkt_buf_sz ; + __u8 olympic_receive_options, olympic_copy_all_options, olympic_message_level; + __u8 olympic_multicast_set ; + __u16 olympic_addr_table_addr, olympic_parms_addr ; + __u8 olympic_laa[6] ; +}; + +struct olympic_adapter_addr_table { + + __u8 node_addr[6] ; + __u8 reserved[4] ; + __u8 func_addr[4] ; +} ; + +struct olympic_parameters_table { + + __u8 phys_addr[4] ; + __u8 up_node_addr[6] ; + __u8 up_phys_addr[6] ; + __u8 poll_addr[6] ; + __u16 reserved ; + __u16 acc_priority ; + __u16 auth_source_class ; + __u16 att_code ; + __u8 source_addr[6] ; + __u16 beacon_type ; + __u16 major_vector ; + __u16 lan_status ; + __u16 soft_error_time ; + __u16 reserved1 ; + __u16 local_ring ; + __u16 mon_error ; + __u16 beacon_transmit ; + __u16 beacon_receive ; + __u16 frame_correl ; + __u8 beacon_naun[6] ; + __u32 reserved2 ; + __u8 beacon_phys[4] ; +}; diff -u --recursive --new-file v2.3.20/linux/drivers/net/tokenring/sktr.c linux/drivers/net/tokenring/sktr.c --- v2.3.20/linux/drivers/net/tokenring/sktr.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tokenring/sktr.c Mon Oct 11 10:13:24 1999 @@ -0,0 +1,2707 @@ +/* + * sktr.c: A network driver for the SysKonnect Token Ring ISA/PCI Adapters. + * + * Written 1997 by Christoph Goos + * + * A fine result of the Linux Systems Network Architecture Project. + * http://samba.anu.edu.au/linux-sna/ + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + * This device driver works with the following SysKonnect adapters: + * - SysKonnect TR4/16(+) ISA (SK-4190) + * - SysKonnect TR4/16(+) PCI (SK-4590) + * - SysKonnect TR4/16 PCI (SK-4591) + * + * Sources: + * - The hardware related parts of this driver are take from + * the SysKonnect Token Ring driver for Windows NT. + * - I used the IBM Token Ring driver 'ibmtr.c' as a base for this + * driver, as well as the 'skeleton.c' driver by Donald Becker. + * - Also various other drivers in the linux source tree were taken + * as samples for some tasks. + * + * Maintainer(s): + * JS Jay Schulist jschlst@samba.anu.edu.au + * CG Christoph Goos cgoos@syskonnect.de + * AF Adam Fritzler mid@auk.cx + * + * Modification History: + * 29-Aug-97 CG Created + * 04-Apr-98 CG Fixed problems caused by tok_timer_check + * 10-Apr-98 CG Fixed lockups at cable disconnection + * 27-May-98 JS Formated to Linux Kernel Format + * 31-May-98 JS Hacked in PCI support + * 16-Jun-98 JS Modulized for multiple cards with one driver + * 21-Sep-99 CG Fixed source routing issues for 2.2 kernels + * 21-Sep-99 AF Added multicast changes recommended by + * Jochen Friedrich (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 +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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; iVam->ocpl.NodeAddr[i] = mac->CurrentAddress[i]; + */ + + tp->ocpl.GroupAddr = 0; + tp->ocpl.FunctAddr = 0; + tp->ocpl.RxListSize = SWAPB(RplSize); + tp->ocpl.TxListSize = SWAPB(TplSize); + tp->ocpl.BufSize = SWAPB(BufferSize); + tp->ocpl.Reserved = 0; + tp->ocpl.TXBufMin = TX_BUF_MIN; + tp->ocpl.TXBufMax = TX_BUF_MAX; + + Addr = htonl(virt_to_bus(tp->ProductID)); + + tp->ocpl.ProdIDAddr[0] = LOWORD(Addr); + tp->ocpl.ProdIDAddr[1] = HIWORD(Addr); + + return; +} + +/* + * Send OPEN command to adapter + */ +static void sktr_open_adapter(struct net_device *dev) +{ + struct net_local *tp = (struct net_local *)dev->priv; + + if(tp->OpenCommandIssued) + return; + + tp->OpenCommandIssued = 1; + sktr_exec_cmd(dev, OC_OPEN); + + return; +} + +/* + * Clear the adapter's interrupt flag. Clear system interrupt enable + * (SINTEN): disable adapter to system interrupts. + */ +static void sktr_disable_interrupts(struct net_device *dev) +{ + outb(0, dev->base_addr + SIFACL); + + return; +} + +/* + * Set the adapter's interrupt flag. Set system interrupt enable + * (SINTEN): enable adapter to system interrupts. + */ +static void sktr_enable_interrupts(struct net_device *dev) +{ + outb(ACL_SINTEN, dev->base_addr + SIFACL); + + return; +} + +/* + * Put command in command queue, try to execute it. + */ +static void sktr_exec_cmd(struct net_device *dev, unsigned short Command) +{ + struct net_local *tp = (struct net_local *)dev->priv; + + tp->CMDqueue |= Command; + sktr_chk_outstanding_cmds(dev); + + return; +} + +/* + * Gets skb from system, queues it and checks if it can be sent + */ +static int sktr_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct net_local *tp = (struct net_local *)dev->priv; + + if(dev->tbusy) + { + /* + * If we get here, some higher level has decided we are broken. + * There should really be a "kick me" function call instead. + * + * Resetting the token ring adapter takes a long time so just + * fake transmission time and go on trying. Our own timeout + * routine is in sktr_timer_chk() + */ + dev->tbusy = 0; + dev->trans_start = jiffies; + return (1); + } + + /* + * If some higher layer thinks we've missed an tx-done interrupt we + * are passed NULL. + */ + if(skb == NULL) + return (0); + + /* + * Block a timer-based transmit from overlapping. This could better be + * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. + */ + if(test_and_set_bit(0, (void*)&dev->tbusy) != 0) + { + printk("%s: Transmitter access conflict.\n", dev->name); + return (1); + } + + if(tp->QueueSkb == 0) + return (1); /* Return with tbusy set: queue full */ + + tp->QueueSkb--; + skb_queue_tail(&tp->SendSkbQueue, skb); + sktr_hardware_send_packet(dev, tp); + if(tp->QueueSkb > 0) + dev->tbusy = 0; + + return (0); +} + +/* + * Move frames from internal skb queue into adapter tx queue + */ +static void sktr_hardware_send_packet(struct net_device *dev, struct net_local* tp) +{ + TPL *tpl; + short length; + unsigned char *buf, *newbuf; + struct sk_buff *skb; + int i; + + for(;;) + { + /* Try to get a free TPL from the chain. + * + * NOTE: We *must* always leave one unused TPL in the chain, + * because otherwise the adapter might send frames twice. + */ + if(tp->TplFree->NextTPLPtr->BusyFlag) /* No free TPL */ + { + printk(KERN_INFO "%s: No free TPL\n", dev->name); + return; + } + + /* Send first buffer from queue */ + skb = skb_dequeue(&tp->SendSkbQueue); + if(skb == NULL) + return; + + tp->QueueSkb++; + /* Is buffer reachable for Busmaster-DMA? */ + if(tp->DeviceType == SK_ISA && + virt_to_bus((void*)(((long) skb->data) + skb->len)) + > ISA_MAX_ADDRESS) + { + /* Copy frame to local buffer */ + i = tp->TplFree->TPLIndex; + length = skb->len; + buf = tp->LocalTxBuffers[i]; + memcpy(buf, skb->data, length); + newbuf = buf; + } + else + { + /* Send direct from skb->data */ + length = skb->len; + newbuf = skb->data; + } + + /* Source address in packet? */ + sktr_chk_src_addr(newbuf, dev->dev_addr); + + tp->LastSendTime = jiffies; + tpl = tp->TplFree; /* Get the "free" TPL */ + tpl->BusyFlag = 1; /* Mark TPL as busy */ + tp->TplFree = tpl->NextTPLPtr; + + /* Save the skb for delayed return of skb to system */ + tpl->Skb = skb; + tpl->FragList[0].DataCount = (unsigned short) SWAPB(length); + tpl->FragList[0].DataAddr = htonl(virt_to_bus(newbuf)); + + /* Write the data length in the transmit list. */ + tpl->FrameSize = (unsigned short) SWAPB(length); + tpl->MData = newbuf; + + /* Transmit the frame and set the status values. */ + sktr_write_tpl_status(tpl, TX_VALID | TX_START_FRAME + | TX_END_FRAME | TX_PASS_SRC_ADDR + | TX_FRAME_IRQ); + + /* Let adapter send the frame. */ + sktr_exec_sifcmd(dev, CMD_TX_VALID); + } + + return; +} + +/* + * Write the given value to the 'Status' field of the specified TPL. + * NOTE: This function should be used whenever the status of any TPL must be + * modified by the driver, because the compiler may otherwise change the + * order of instructions such that writing the TPL status may be executed at + * an undesireable time. When this function is used, the status is always + * written when the function is called. + */ +static void sktr_write_tpl_status(TPL *tpl, unsigned int Status) +{ + tpl->Status = Status; +} + +static void sktr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr) +{ + unsigned char SRBit; + + if((((unsigned long)frame[8]) & ~0x80) != 0) /* Compare 4 bytes */ + return; + if((unsigned short)frame[12] != 0) /* Compare 2 bytes */ + return; + + SRBit = frame[8] & 0x80; + memcpy(&frame[8], hw_addr, 6); + frame[8] |= SRBit; + + return; +} + +/* + * The timer routine: Check if adapter still open and working, reopen if not. + */ +static void sktr_timer_chk(unsigned long data) +{ + struct net_device *dev = (struct net_device*)data; + struct net_local *tp = (struct net_local*)dev->priv; + + if(tp->HaltInProgress) + return; + + sktr_chk_outstanding_cmds(dev); + if(time_before(tp->LastSendTime + SEND_TIMEOUT, jiffies) + && (tp->QueueSkb < MAX_TX_QUEUE || tp->TplFree != tp->TplBusy)) + { + /* Anything to send, but stalled to long */ + tp->LastSendTime = jiffies; + sktr_exec_cmd(dev, OC_CLOSE); /* Does reopen automatically */ + } + + tp->timer.expires = jiffies + 2*HZ; + add_timer(&tp->timer); + + if(tp->AdapterOpenFlag || tp->ReOpenInProgress) + return; + tp->ReOpenInProgress = 1; + sktr_open_adapter(dev); + + return; +} + +/* + * The typical workload of the driver: Handle the network interface interrupts. + */ +static void sktr_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct net_local *tp; + int ioaddr; + unsigned short irq_type; + + if(dev == NULL) + { + printk("%s: irq %d for unknown device.\n", dev->name, irq); + return; + } + + dev->interrupt = 1; + + ioaddr = dev->base_addr; + tp = (struct net_local *)dev->priv; + + irq_type = inw(ioaddr + SIFSTS); + + while(irq_type & STS_SYSTEM_IRQ) + { + irq_type &= STS_IRQ_MASK; + + if(!sktr_chk_ssb(tp, irq_type)) + { + printk(KERN_INFO "%s: DATA LATE occurred\n", dev->name); + break; + } + + switch(irq_type) + { + case STS_IRQ_RECEIVE_STATUS: + sktr_reset_interrupt(dev); + sktr_rcv_status_irq(dev); + break; + + case STS_IRQ_TRANSMIT_STATUS: + /* Check if TRANSMIT.HALT command is complete */ + if(tp->ssb.Parm[0] & COMMAND_COMPLETE) + { + tp->TransmitCommandActive = 0; + tp->TransmitHaltScheduled = 0; + + /* Issue a new transmit command. */ + sktr_exec_cmd(dev, OC_TRANSMIT); + } + + sktr_reset_interrupt(dev); + sktr_tx_status_irq(dev); + break; + + case STS_IRQ_COMMAND_STATUS: + /* The SSB contains status of last command + * other than receive/transmit. + */ + sktr_cmd_status_irq(dev); + break; + + case STS_IRQ_SCB_CLEAR: + /* The SCB is free for another command. */ + tp->ScbInUse = 0; + sktr_chk_outstanding_cmds(dev); + break; + + case STS_IRQ_RING_STATUS: + sktr_ring_status_irq(dev); + break; + + case STS_IRQ_ADAPTER_CHECK: + sktr_chk_irq(dev); + break; + + default: + printk(KERN_INFO "Unknown Token Ring IRQ\n"); + break; + } + + /* Reset system interrupt if not already done. */ + if(irq_type != STS_IRQ_TRANSMIT_STATUS + && irq_type != STS_IRQ_RECEIVE_STATUS) + { + sktr_reset_interrupt(dev); + } + + irq_type = inw(ioaddr + SIFSTS); + } + + dev->interrupt = 0; + + return; +} + +/* + * Reset the INTERRUPT SYSTEM bit and issue SSB CLEAR command. + */ +static void sktr_reset_interrupt(struct net_device *dev) +{ + struct net_local *tp = (struct net_local *)dev->priv; + SSB *ssb = &tp->ssb; + + /* + * [Workaround for "Data Late"] + * Set all fields of the SSB to well-defined values so we can + * check if the adapter has written the SSB. + */ + + ssb->STS = (unsigned short) -1; + ssb->Parm[0] = (unsigned short) -1; + ssb->Parm[1] = (unsigned short) -1; + ssb->Parm[2] = (unsigned short) -1; + + /* Free SSB by issuing SSB_CLEAR command after reading IRQ code + * and clear STS_SYSTEM_IRQ bit: enable adapter for further interrupts. + */ + sktr_exec_sifcmd(dev, CMD_SSB_CLEAR | CMD_CLEAR_SYSTEM_IRQ); + + return; +} + +/* + * Check if the SSB has actually been written by the adapter. + */ +static unsigned char sktr_chk_ssb(struct net_local *tp, unsigned short IrqType) +{ + SSB *ssb = &tp->ssb; /* The address of the SSB. */ + + /* C 0 1 2 INTERRUPT CODE + * - - - - -------------- + * 1 1 1 1 TRANSMIT STATUS + * 1 1 1 1 RECEIVE STATUS + * 1 ? ? 0 COMMAND STATUS + * 0 0 0 0 SCB CLEAR + * 1 1 0 0 RING STATUS + * 0 0 0 0 ADAPTER CHECK + * + * 0 = SSB field not affected by interrupt + * 1 = SSB field is affected by interrupt + * + * C = SSB ADDRESS +0: COMMAND + * 0 = SSB ADDRESS +2: STATUS 0 + * 1 = SSB ADDRESS +4: STATUS 1 + * 2 = SSB ADDRESS +6: STATUS 2 + */ + + /* Check if this interrupt does use the SSB. */ + + if(IrqType != STS_IRQ_TRANSMIT_STATUS + && IrqType != STS_IRQ_RECEIVE_STATUS + && IrqType != STS_IRQ_COMMAND_STATUS + && IrqType != STS_IRQ_RING_STATUS) + { + return (1); /* SSB not involved. */ + } + + /* Note: All fields of the SSB have been set to all ones (-1) after it + * has last been used by the software (see DriverIsr()). + * + * Check if the affected SSB fields are still unchanged. + */ + + if(ssb->STS == (unsigned short) -1) + return (0); /* Command field not yet available. */ + if(IrqType == STS_IRQ_COMMAND_STATUS) + return (1); /* Status fields not always affected. */ + if(ssb->Parm[0] == (unsigned short) -1) + return (0); /* Status 1 field not yet available. */ + if(IrqType == STS_IRQ_RING_STATUS) + return (1); /* Status 2 & 3 fields not affected. */ + + /* Note: At this point, the interrupt is either TRANSMIT or RECEIVE. */ + if(ssb->Parm[1] == (unsigned short) -1) + return (0); /* Status 2 field not yet available. */ + if(ssb->Parm[2] == (unsigned short) -1) + return (0); /* Status 3 field not yet available. */ + + return (1); /* All SSB fields have been written by the adapter. */ +} + +/* + * Evaluates the command results status in the SSB status field. + */ +static void sktr_cmd_status_irq(struct net_device *dev) +{ + struct net_local *tp = (struct net_local *)dev->priv; + unsigned short ssb_cmd, ssb_parm_0; + unsigned short ssb_parm_1; + char *open_err = "Open error -"; + char *code_err = "Open code -"; + + /* Copy the ssb values to local variables */ + ssb_cmd = tp->ssb.STS; + ssb_parm_0 = tp->ssb.Parm[0]; + ssb_parm_1 = tp->ssb.Parm[1]; + + if(ssb_cmd == OPEN) + { + tp->Sleeping = 0; + if(!tp->ReOpenInProgress) + wake_up_interruptible(&tp->wait_for_tok_int); + + tp->OpenCommandIssued = 0; + tp->ScbInUse = 0; + + if((ssb_parm_0 & 0x00FF) == GOOD_COMPLETION) + { + /* Success, the adapter is open. */ + tp->LobeWireFaultLogged = 0; + tp->AdapterOpenFlag = 1; + tp->AdapterVirtOpenFlag = 1; + tp->TransmitCommandActive = 0; + sktr_exec_cmd(dev, OC_TRANSMIT); + sktr_exec_cmd(dev, OC_RECEIVE); + + if(tp->ReOpenInProgress) + tp->ReOpenInProgress = 0; + + return; + } + else /* The adapter did not open. */ + { + if(ssb_parm_0 & NODE_ADDR_ERROR) + printk(KERN_INFO "%s: Node address error\n", + dev->name); + if(ssb_parm_0 & LIST_SIZE_ERROR) + printk(KERN_INFO "%s: List size error\n", + dev->name); + if(ssb_parm_0 & BUF_SIZE_ERROR) + printk(KERN_INFO "%s: Buffer size error\n", + dev->name); + if(ssb_parm_0 & TX_BUF_COUNT_ERROR) + printk(KERN_INFO "%s: Tx buffer count error\n", + dev->name); + if(ssb_parm_0 & INVALID_OPEN_OPTION) + printk(KERN_INFO "%s: Invalid open option\n", + dev->name); + if(ssb_parm_0 & OPEN_ERROR) + { + /* Show the open phase. */ + switch(ssb_parm_0 & OPEN_PHASES_MASK) + { + case LOBE_MEDIA_TEST: + if(!tp->LobeWireFaultLogged) + { + tp->LobeWireFaultLogged = 1; + printk(KERN_INFO "%s: %s Lobe wire fault (check cable !).\n", dev->name, open_err); + } + tp->ReOpenInProgress = 1; + tp->AdapterOpenFlag = 0; + tp->AdapterVirtOpenFlag = 1; + sktr_open_adapter(dev); + return; + + case PHYSICAL_INSERTION: + printk(KERN_INFO "%s: %s Physical insertion.\n", dev->name, open_err); + break; + + case ADDRESS_VERIFICATION: + printk(KERN_INFO "%s: %s Address verification.\n", dev->name, open_err); + break; + + case PARTICIPATION_IN_RING_POLL: + printk(KERN_INFO "%s: %s Participation in ring poll.\n", dev->name, open_err); + break; + + case REQUEST_INITIALISATION: + printk(KERN_INFO "%s: %s Request initialisation.\n", dev->name, open_err); + break; + + case FULLDUPLEX_CHECK: + printk(KERN_INFO "%s: %s Full duplex check.\n", dev->name, open_err); + break; + + default: + printk(KERN_INFO "%s: %s Unknown open phase\n", dev->name, open_err); + break; + } + + /* Show the open errors. */ + switch(ssb_parm_0 & OPEN_ERROR_CODES_MASK) + { + case OPEN_FUNCTION_FAILURE: + printk(KERN_INFO "%s: %s OPEN_FUNCTION_FAILURE", dev->name, code_err); + tp->LastOpenStatus = + OPEN_FUNCTION_FAILURE; + break; + + case OPEN_SIGNAL_LOSS: + printk(KERN_INFO "%s: %s OPEN_SIGNAL_LOSS\n", dev->name, code_err); + tp->LastOpenStatus = + OPEN_SIGNAL_LOSS; + break; + + case OPEN_TIMEOUT: + printk(KERN_INFO "%s: %s OPEN_TIMEOUT\n", dev->name, code_err); + tp->LastOpenStatus = + OPEN_TIMEOUT; + break; + + case OPEN_RING_FAILURE: + printk(KERN_INFO "%s: %s OPEN_RING_FAILURE\n", dev->name, code_err); + tp->LastOpenStatus = + OPEN_RING_FAILURE; + break; + + case OPEN_RING_BEACONING: + printk(KERN_INFO "%s: %s OPEN_RING_BEACONING\n", dev->name, code_err); + tp->LastOpenStatus = + OPEN_RING_BEACONING; + break; + + case OPEN_DUPLICATE_NODEADDR: + printk(KERN_INFO "%s: %s OPEN_DUPLICATE_NODEADDR\n", dev->name, code_err); + tp->LastOpenStatus = + OPEN_DUPLICATE_NODEADDR; + break; + + case OPEN_REQUEST_INIT: + printk(KERN_INFO "%s: %s OPEN_REQUEST_INIT\n", dev->name, code_err); + tp->LastOpenStatus = + OPEN_REQUEST_INIT; + break; + + case OPEN_REMOVE_RECEIVED: + printk(KERN_INFO "%s: %s OPEN_REMOVE_RECEIVED", dev->name, code_err); + tp->LastOpenStatus = + OPEN_REMOVE_RECEIVED; + break; + + case OPEN_FULLDUPLEX_SET: + printk(KERN_INFO "%s: %s OPEN_FULLDUPLEX_SET\n", dev->name, code_err); + tp->LastOpenStatus = + OPEN_FULLDUPLEX_SET; + break; + + default: + printk(KERN_INFO "%s: %s Unknown open err code", dev->name, code_err); + tp->LastOpenStatus = + OPEN_FUNCTION_FAILURE; + break; + } + } + + tp->AdapterOpenFlag = 0; + tp->AdapterVirtOpenFlag = 0; + + return; + } + } + else + { + if(ssb_cmd != READ_ERROR_LOG) + return; + + /* Add values from the error log table to the MAC + * statistics counters and update the errorlogtable + * memory. + */ + tp->MacStat.line_errors += tp->errorlogtable.Line_Error; + tp->MacStat.burst_errors += tp->errorlogtable.Burst_Error; + tp->MacStat.A_C_errors += tp->errorlogtable.ARI_FCI_Error; + tp->MacStat.lost_frames += tp->errorlogtable.Lost_Frame_Error; + tp->MacStat.recv_congest_count += tp->errorlogtable.Rx_Congest_Error; + tp->MacStat.rx_errors += tp->errorlogtable.Rx_Congest_Error; + tp->MacStat.frame_copied_errors += tp->errorlogtable.Frame_Copied_Error; + tp->MacStat.token_errors += tp->errorlogtable.Token_Error; + tp->MacStat.dummy1 += tp->errorlogtable.DMA_Bus_Error; + tp->MacStat.dummy1 += tp->errorlogtable.DMA_Parity_Error; + tp->MacStat.abort_delimiters += tp->errorlogtable.AbortDelimeters; + tp->MacStat.frequency_errors += tp->errorlogtable.Frequency_Error; + tp->MacStat.internal_errors += tp->errorlogtable.Internal_Error; + } + + return; +} + +/* + * The inverse routine to sktr_open(). + */ +static int sktr_close(struct net_device *dev) +{ + struct net_local *tp = (struct net_local *)dev->priv; + + dev->tbusy = 1; + dev->start = 0; + + del_timer(&tp->timer); + + /* Flush the Tx and disable Rx here. */ + + tp->HaltInProgress = 1; + sktr_exec_cmd(dev, OC_CLOSE); + tp->timer.expires = jiffies + 1*HZ; + tp->timer.function = sktr_timer_end_wait; + tp->timer.data = (unsigned long)dev; + add_timer(&tp->timer); + + sktr_enable_interrupts(dev); + + tp->Sleeping = 1; + interruptible_sleep_on(&tp->wait_for_tok_int); + tp->TransmitCommandActive = 0; + + del_timer(&tp->timer); + sktr_disable_interrupts(dev); + + if(dev->dma > 0) + { + unsigned long flags=claim_dma_lock(); + disable_dma(dev->dma); + release_dma_lock(flags); + } + + outw(0xFF00, dev->base_addr + SIFCMD); + if(dev->dma > 0) + outb(0xff, dev->base_addr + POSREG); + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + + sktr_cancel_tx_queue(tp); + + return (0); +} + +/* + * Get the current statistics. This may be called with the card open + * or closed. + */ +static struct enet_statistics *sktr_get_stats(struct net_device *dev) +{ + struct net_local *tp = (struct net_local *)dev->priv; + + return ((struct enet_statistics *)&tp->MacStat); +} + +/* + * Set or clear the multicast filter for this adapter. + */ +static void sktr_set_multicast_list(struct net_device *dev) +{ + struct net_local *tp = (struct net_local *)dev->priv; + unsigned int OpenOptions; + + OpenOptions = tp->ocpl.OPENOptions & + ~(PASS_ADAPTER_MAC_FRAMES + | PASS_ATTENTION_FRAMES + | PASS_BEACON_MAC_FRAMES + | COPY_ALL_MAC_FRAMES + | COPY_ALL_NON_MAC_FRAMES); + + tp->ocpl.FunctAddr = 0; + + if(dev->flags & IFF_PROMISC) + /* Enable promiscuous mode */ + OpenOptions |= COPY_ALL_NON_MAC_FRAMES | + COPY_ALL_MAC_FRAMES; + else + { + if(dev->flags & IFF_ALLMULTI) + { + /* Disable promiscuous mode, use normal mode. */ + tp->ocpl.FunctAddr = 0xFFFFFFFF; + + } + else + { + int i; + struct dev_mc_list *mclist = dev->mc_list; + for (i=0; i< dev->mc_count; i++) + { + ((char *)(&tp->ocpl.FunctAddr))[0] |= + mclist->dmi_addr[2]; + ((char *)(&tp->ocpl.FunctAddr))[1] |= + mclist->dmi_addr[3]; + ((char *)(&tp->ocpl.FunctAddr))[2] |= + mclist->dmi_addr[4]; + ((char *)(&tp->ocpl.FunctAddr))[3] |= + mclist->dmi_addr[5]; + mclist = mclist->next; + } + } + sktr_exec_cmd(dev, OC_SET_FUNCT_ADDR); + } + + tp->ocpl.OPENOptions = OpenOptions; + sktr_exec_cmd(dev, OC_MODIFY_OPEN_PARMS); + return; +} + +/* + * Wait for some time (microseconds) + * + * udelay() is a bit harsh, but using a looser timer causes + * the bring-up-diags to stall indefinitly. + * + */ + +static void sktr_wait(unsigned long time) +{ + udelay(time); + return; +} + +/* + * Write a command value to the SIFCMD register + */ +static void sktr_exec_sifcmd(struct net_device *dev, unsigned int WriteValue) +{ + int ioaddr = dev->base_addr; + unsigned short cmd; + unsigned short SifStsValue; + unsigned long loop_counter; + + WriteValue = ((WriteValue ^ CMD_SYSTEM_IRQ) | CMD_INTERRUPT_ADAPTER); + cmd = (unsigned short)WriteValue; + loop_counter = 0,5 * 800000; + do { + SifStsValue = inw(ioaddr + SIFSTS); + } while((SifStsValue & CMD_INTERRUPT_ADAPTER) && loop_counter--); + outw(cmd, ioaddr + SIFCMD); + + return; +} + +/* + * Processes adapter hardware reset, halts adapter and downloads firmware, + * clears the halt bit. + */ +static int sktr_reset_adapter(struct net_device *dev) +{ + struct net_local *tp = (struct net_local *)dev->priv; + unsigned short *fw_ptr = (unsigned short *)&sktr_code; + unsigned short count, c; + int ioaddr = dev->base_addr; + + /* Hardware adapter reset */ + outw(ACL_ARESET, ioaddr + SIFACL); + sktr_wait(40); + + c = inw(ioaddr + SIFACL); + sktr_wait(20); + + if(dev->dma == 0) /* For PCI adapters */ + { + c &= ~(ACL_SPEED4 | ACL_SPEED16); /* Clear bits */ + if(tp->DataRate == SPEED_4) + c |= ACL_SPEED4; /* Set 4Mbps */ + else + c |= ACL_SPEED16; /* Set 16Mbps */ + } + + /* In case a command is pending - forget it */ + tp->ScbInUse = 0; + + c &= ~ACL_ARESET; /* Clear adapter reset bit */ + c |= ACL_CPHALT; /* Halt adapter CPU, allow download */ + c &= ~ACL_PSDMAEN; /* Clear pseudo dma bit */ + outw(c, ioaddr + SIFACL); + sktr_wait(40); + + /* Download firmware via DIO interface: */ + do { + /* Download first address part */ + outw(*fw_ptr, ioaddr + SIFADX); + fw_ptr++; + + /* Download second address part */ + outw(*fw_ptr, ioaddr + SIFADD); + fw_ptr++; + + if((count = *fw_ptr) != 0) /* Load loop counter */ + { + fw_ptr++; /* Download block data */ + for(; count > 0; count--) + { + outw(*fw_ptr, ioaddr + SIFINC); + fw_ptr++; + } + } + else /* Stop, if last block downloaded */ + { + c = inw(ioaddr + SIFACL); + c &= (~ACL_CPHALT | ACL_SINTEN); + + /* Clear CPHALT and start BUD */ + outw(c, ioaddr + SIFACL); + return (1); + } + } while(count == 0); + + return (-1); +} + +/* + * Starts bring up diagnostics of token ring adapter and evaluates + * diagnostic results. + */ +static int sktr_bringup_diags(struct net_device *dev) +{ + int loop_cnt, retry_cnt; + unsigned short Status; + int ioaddr = dev->base_addr; + + sktr_wait(HALF_SECOND); + sktr_exec_sifcmd(dev, EXEC_SOFT_RESET); + sktr_wait(HALF_SECOND); + + retry_cnt = BUD_MAX_RETRIES; /* maximal number of retrys */ + + do { + retry_cnt--; + if(sktr_debug > 3) + printk(KERN_INFO "BUD-Status: \n"); + loop_cnt = BUD_MAX_LOOPCNT; /* maximum: three seconds*/ + do { /* Inspect BUD results */ + loop_cnt--; + sktr_wait(HALF_SECOND); + Status = inw(ioaddr + SIFSTS); + Status &= STS_MASK; + + if(sktr_debug > 3) + printk(KERN_INFO " %04X \n", Status); + /* BUD successfully completed */ + if(Status == STS_INITIALIZE) + return (1); + /* Unrecoverable hardware error, BUD not completed? */ + } while((loop_cnt > 0) && ((Status & (STS_ERROR | STS_TEST)) + != (STS_ERROR | STS_TEST))); + + /* Error preventing completion of BUD */ + if(retry_cnt > 0) + { + printk(KERN_INFO "%s: Adapter Software Reset.\n", + dev->name); + sktr_exec_sifcmd(dev, EXEC_SOFT_RESET); + sktr_wait(HALF_SECOND); + } + } while(retry_cnt > 0); + + Status = inw(ioaddr + SIFSTS); + Status &= STS_ERROR_MASK; /* Hardware error occurred! */ + + printk(KERN_INFO "%s: Bring Up Diagnostics Error (%04X) occurred\n", + dev->name, Status); + + return (-1); +} + +/* + * Copy initialisation data to adapter memory, beginning at address + * 1:0A00; Starting DMA test and evaluating result bits. + */ +static int sktr_init_adapter(struct net_device *dev) +{ + struct net_local *tp = (struct net_local *)dev->priv; + + const unsigned char SCB_Test[6] = {0x00, 0x00, 0xC1, 0xE2, 0xD4, 0x8B}; + const unsigned char SSB_Test[8] = {0xFF, 0xFF, 0xD1, 0xD7, + 0xC5, 0xD9, 0xC3, 0xD4}; + void *ptr = (void *)&tp->ipb; + unsigned short *ipb_ptr = (unsigned short *)ptr; + unsigned char *cb_ptr = (unsigned char *) &tp->scb; + unsigned char *sb_ptr = (unsigned char *) &tp->ssb; + unsigned short Status; + int i, loop_cnt, retry_cnt; + int ioaddr = dev->base_addr; + + /* Normalize: byte order low/high, word order high/low! (only IPB!) */ + tp->ipb.SCB_Addr = SWAPW(virt_to_bus(&tp->scb)); + tp->ipb.SSB_Addr = SWAPW(virt_to_bus(&tp->ssb)); + + /* Maximum: three initialization retries */ + retry_cnt = INIT_MAX_RETRIES; + + do { + retry_cnt--; + + /* Transfer initialization block */ + outw(0x0001, ioaddr + SIFADX); + + /* To address 0001:0A00 of adapter RAM */ + outw(0x0A00, ioaddr + SIFADD); + + /* Write 11 words to adapter RAM */ + for(i = 0; i < 11; i++) + outw(ipb_ptr[i], ioaddr + SIFINC); + + /* Execute SCB adapter command */ + sktr_exec_sifcmd(dev, CMD_EXECUTE); + + loop_cnt = INIT_MAX_LOOPCNT; /* Maximum: 11 seconds */ + + /* While remaining retries, no error and not completed */ + do { + Status = 0; + loop_cnt--; + sktr_wait(HALF_SECOND); + + /* Mask interesting status bits */ + Status = inw(ioaddr + SIFSTS); + Status &= STS_MASK; + } while(((Status &(STS_INITIALIZE | STS_ERROR | STS_TEST)) != 0) + && ((Status & STS_ERROR) == 0) && (loop_cnt != 0)); + + if((Status & (STS_INITIALIZE | STS_ERROR | STS_TEST)) == 0) + { + /* Initialization completed without error */ + i = 0; + do { /* Test if contents of SCB is valid */ + if(SCB_Test[i] != *(cb_ptr + i)) + /* DMA data error: wrong data in SCB */ + return (-1); + i++; + } while(i < 6); + + i = 0; + do { /* Test if contents of SSB is valid */ + if(SSB_Test[i] != *(sb_ptr + i)) + /* DMA data error: wrong data in SSB */ + return (-1); + i++; + } while (i < 8); + + return (1); /* Adapter successfully initialized */ + } + else + { + if((Status & STS_ERROR) != 0) + { + /* Initialization error occurred */ + Status = inw(ioaddr + SIFSTS); + Status &= STS_ERROR_MASK; + /* ShowInitialisationErrorCode(Status); */ + return (-1); /* Unrecoverable error */ + } + else + { + if(retry_cnt > 0) + { + /* Reset adapter and try init again */ + sktr_exec_sifcmd(dev, EXEC_SOFT_RESET); + sktr_wait(HALF_SECOND); + } + } + } + } while(retry_cnt > 0); + + return (-1); +} + +/* + * Check for outstanding commands in command queue and tries to execute + * command immediately. Corresponding command flag in command queue is cleared. + */ +static void sktr_chk_outstanding_cmds(struct net_device *dev) +{ + struct net_local *tp = (struct net_local *)dev->priv; + unsigned long Addr = 0; + unsigned char i = 0; + + if(tp->CMDqueue == 0) + return; /* No command execution */ + + /* If SCB in use: no command */ + if(tp->ScbInUse == 1) + return; + + /* Check if adapter is opened, avoiding COMMAND_REJECT + * interrupt by the adapter! + */ + if(tp->AdapterOpenFlag == 0) + { + if(tp->CMDqueue & OC_OPEN) + { + /* Execute OPEN command */ + tp->CMDqueue ^= OC_OPEN; + + /* Copy the 18 bytes of the product ID */ + while((AdapterName[i] != '\0') && (i < PROD_ID_SIZE)) + { + tp->ProductID[i] = AdapterName[i]; + i++; + } + + Addr = htonl(virt_to_bus(&tp->ocpl)); + tp->scb.Parm[0] = LOWORD(Addr); + tp->scb.Parm[1] = HIWORD(Addr); + tp->scb.CMD = OPEN; + } + else + /* No OPEN command queued, but adapter closed. Note: + * We'll try to re-open the adapter in DriverPoll() + */ + return; /* No adapter command issued */ + } + else + { + /* Adapter is open; evaluate command queue: try to execute + * outstanding commands (depending on priority!) CLOSE + * command queued + */ + if(tp->CMDqueue & OC_CLOSE) + { + tp->CMDqueue ^= OC_CLOSE; + tp->AdapterOpenFlag = 0; + tp->scb.Parm[0] = 0; /* Parm[0], Parm[1] are ignored */ + tp->scb.Parm[1] = 0; /* but should be set to zero! */ + tp->scb.CMD = CLOSE; + if(!tp->HaltInProgress) + tp->CMDqueue |= OC_OPEN; /* re-open adapter */ + else + tp->CMDqueue = 0; /* no more commands */ + } + else + { + if(tp->CMDqueue & OC_RECEIVE) + { + tp->CMDqueue ^= OC_RECEIVE; + Addr = htonl(virt_to_bus(tp->RplHead)); + tp->scb.Parm[0] = LOWORD(Addr); + tp->scb.Parm[1] = HIWORD(Addr); + tp->scb.CMD = RECEIVE; + } + else + { + if(tp->CMDqueue & OC_TRANSMIT_HALT) + { + /* NOTE: TRANSMIT.HALT must be checked + * before TRANSMIT. + */ + tp->CMDqueue ^= OC_TRANSMIT_HALT; + tp->scb.CMD = TRANSMIT_HALT; + + /* Parm[0] and Parm[1] are ignored + * but should be set to zero! + */ + tp->scb.Parm[0] = 0; + tp->scb.Parm[1] = 0; + } + else + { + if(tp->CMDqueue & OC_TRANSMIT) + { + /* NOTE: TRANSMIT must be + * checked after TRANSMIT.HALT + */ + if(tp->TransmitCommandActive) + { + if(!tp->TransmitHaltScheduled) + { + tp->TransmitHaltScheduled = 1; + sktr_exec_cmd(dev, OC_TRANSMIT_HALT) ; + } + tp->TransmitCommandActive = 0; + return; + } + + tp->CMDqueue ^= OC_TRANSMIT; + sktr_cancel_tx_queue(tp); + Addr = htonl(virt_to_bus(tp->TplBusy)); + tp->scb.Parm[0] = LOWORD(Addr); + tp->scb.Parm[1] = HIWORD(Addr); + tp->scb.CMD = TRANSMIT; + tp->TransmitCommandActive = 1; + } + else + { + if(tp->CMDqueue & OC_MODIFY_OPEN_PARMS) + { + tp->CMDqueue ^= OC_MODIFY_OPEN_PARMS; + tp->scb.Parm[0] = tp->ocpl.OPENOptions; /* new OPEN options*/ + tp->scb.Parm[0] |= ENABLE_FULL_DUPLEX_SELECTION; + tp->scb.Parm[1] = 0; /* is ignored but should be zero */ + tp->scb.CMD = MODIFY_OPEN_PARMS; + } + else + { + if(tp->CMDqueue & OC_SET_FUNCT_ADDR) + { + tp->CMDqueue ^= OC_SET_FUNCT_ADDR; + tp->scb.Parm[0] = LOWORD(tp->ocpl.FunctAddr); + tp->scb.Parm[1] = HIWORD(tp->ocpl.FunctAddr); + tp->scb.CMD = SET_FUNCT_ADDR; + } + else + { + if(tp->CMDqueue & OC_SET_GROUP_ADDR) + { + tp->CMDqueue ^= OC_SET_GROUP_ADDR; + tp->scb.Parm[0] = LOWORD(tp->ocpl.GroupAddr); + tp->scb.Parm[1] = HIWORD(tp->ocpl.GroupAddr); + tp->scb.CMD = SET_GROUP_ADDR; + } + else + { + if(tp->CMDqueue & OC_READ_ERROR_LOG) + { + tp->CMDqueue ^= OC_READ_ERROR_LOG; + Addr = htonl(virt_to_bus(&tp->errorlogtable)); + tp->scb.Parm[0] = LOWORD(Addr); + tp->scb.Parm[1] = HIWORD(Addr); + tp->scb.CMD = READ_ERROR_LOG; + } + else + { + printk(KERN_WARNING "CheckForOutstandingCommand: unknown Command\n"); + tp->CMDqueue = 0; + return; + } + } + } + } + } + } + } + } + } + + tp->ScbInUse = 1; /* Set semaphore: SCB in use. */ + + /* Execute SCB and generate IRQ when done. */ + sktr_exec_sifcmd(dev, CMD_EXECUTE | CMD_SCB_REQUEST); + + return; +} + +/* + * IRQ conditions: signal loss on the ring, transmit or receive of beacon + * frames (disabled if bit 1 of OPEN option is set); report error MAC + * frame transmit (disabled if bit 2 of OPEN option is set); open or short + * cirquit fault on the lobe is detected; remove MAC frame received; + * error counter overflow (255); opened adapter is the only station in ring. + * After some of the IRQs the adapter is closed! + */ +static void sktr_ring_status_irq(struct net_device *dev) +{ + struct net_local *tp = (struct net_local *)dev->priv; + + tp->CurrentRingStatus = SWAPB(tp->ssb.Parm[0]); + + /* First: fill up statistics */ + if(tp->ssb.Parm[0] & SIGNAL_LOSS) + { + printk(KERN_INFO "%s: Signal Loss\n", dev->name); + tp->MacStat.line_errors++; + } + + /* Adapter is closed, but initialized */ + if(tp->ssb.Parm[0] & LOBE_WIRE_FAULT) + { + printk(KERN_INFO "%s: Lobe Wire Fault, Reopen Adapter\n", + dev->name); + tp->MacStat.line_errors++; + } + + if(tp->ssb.Parm[0] & RING_RECOVERY) + printk(KERN_INFO "%s: Ring Recovery\n", dev->name); + + /* Counter overflow: read error log */ + if(tp->ssb.Parm[0] & COUNTER_OVERFLOW) + { + printk(KERN_INFO "%s: Counter Overflow\n", dev->name); + sktr_exec_cmd(dev, OC_READ_ERROR_LOG); + } + + /* Adapter is closed, but initialized */ + if(tp->ssb.Parm[0] & REMOVE_RECEIVED) + printk(KERN_INFO "%s: Remove Received, Reopen Adapter\n", + dev->name); + + /* Adapter is closed, but initialized */ + if(tp->ssb.Parm[0] & AUTO_REMOVAL_ERROR) + printk(KERN_INFO "%s: Auto Removal Error, Reopen Adapter\n", + dev->name); + + if(tp->ssb.Parm[0] & HARD_ERROR) + printk(KERN_INFO "%s: Hard Error\n", dev->name); + + if(tp->ssb.Parm[0] & SOFT_ERROR) + printk(KERN_INFO "%s: Soft Error\n", dev->name); + + if(tp->ssb.Parm[0] & TRANSMIT_BEACON) + printk(KERN_INFO "%s: Transmit Beacon\n", dev->name); + + if(tp->ssb.Parm[0] & SINGLE_STATION) + printk(KERN_INFO "%s: Single Station\n", dev->name); + + /* Check if adapter has been closed */ + if(tp->ssb.Parm[0] & ADAPTER_CLOSED) + { + printk(KERN_INFO "%s: Adapter closed (Reopening)," + "QueueSkb %d, CurrentRingStat %x\n", + dev->name, tp->QueueSkb, tp->CurrentRingStatus); + tp->AdapterOpenFlag = 0; + sktr_open_adapter(dev); + } + + return; +} + +/* + * Issued if adapter has encountered an unrecoverable hardware + * or software error. + */ +static void sktr_chk_irq(struct net_device *dev) +{ + int i; + unsigned short AdapterCheckBlock[4]; + unsigned short ioaddr = dev->base_addr; + struct net_local *tp = (struct net_local *)dev->priv; + + tp->AdapterOpenFlag = 0; /* Adapter closed now */ + + /* Page number of adapter memory */ + outw(0x0001, ioaddr + SIFADX); + /* Address offset */ + outw(CHECKADDR, ioaddr + SIFADR); + + /* Reading 8 byte adapter check block. */ + for(i = 0; i < 4; i++) + AdapterCheckBlock[i] = inw(ioaddr + SIFINC); + + if(sktr_debug > 3) + { + printk("%s: AdapterCheckBlock: ", dev->name); + for (i = 0; i < 4; i++) + printk("%04X", AdapterCheckBlock[i]); + printk("\n"); + } + + switch(AdapterCheckBlock[0]) + { + case DIO_PARITY: + printk(KERN_INFO "%s: DIO parity error\n", dev->name); + break; + + case DMA_READ_ABORT: + printk(KERN_INFO "%s DMA read operation aborted:\n", + dev->name); + switch (AdapterCheckBlock[1]) + { + case 0: + printk(KERN_INFO "Timeout\n"); + printk(KERN_INFO "Address: %04X %04X\n", + AdapterCheckBlock[2], + AdapterCheckBlock[3]); + break; + + case 1: + printk(KERN_INFO "Parity error\n"); + printk(KERN_INFO "Address: %04X %04X\n", + AdapterCheckBlock[2], + AdapterCheckBlock[3]); + break; + + case 2: + printk(KERN_INFO "Bus error\n"); + printk(KERN_INFO "Address: %04X %04X\n", + AdapterCheckBlock[2], + AdapterCheckBlock[3]); + break; + + default: + printk(KERN_INFO "Unknown error.\n"); + break; + } + break; + + case DMA_WRITE_ABORT: + printk(KERN_INFO "%s: DMA write operation aborted: \n", + dev->name); + switch (AdapterCheckBlock[1]) + { + case 0: + printk(KERN_INFO "Timeout\n"); + printk(KERN_INFO "Address: %04X %04X\n", + AdapterCheckBlock[2], + AdapterCheckBlock[3]); + break; + + case 1: + printk(KERN_INFO "Parity error\n"); + printk(KERN_INFO "Address: %04X %04X\n", + AdapterCheckBlock[2], + AdapterCheckBlock[3]); + break; + + case 2: + printk(KERN_INFO "Bus error\n"); + printk(KERN_INFO "Address: %04X %04X\n", + AdapterCheckBlock[2], + AdapterCheckBlock[3]); + break; + + default: + printk(KERN_INFO "Unknown error.\n"); + break; + } + break; + + case ILLEGAL_OP_CODE: + printk("%s: Illegal operation code in firmware\n", + dev->name); + /* Parm[0-3]: adapter internal register R13-R15 */ + break; + + case PARITY_ERRORS: + printk("%s: Adapter internal bus parity error\n", + dev->name); + /* Parm[0-3]: adapter internal register R13-R15 */ + break; + + case RAM_DATA_ERROR: + printk("%s: RAM data error\n", dev->name); + /* Parm[0-1]: MSW/LSW address of RAM location. */ + break; + + case RAM_PARITY_ERROR: + printk("%s: RAM parity error\n", dev->name); + /* Parm[0-1]: MSW/LSW address of RAM location. */ + break; + + case RING_UNDERRUN: + printk("%s: Internal DMA underrun detected\n", + dev->name); + break; + + case INVALID_IRQ: + printk("%s: Unrecognized interrupt detected\n", + dev->name); + /* Parm[0-3]: adapter internal register R13-R15 */ + break; + + case INVALID_ERROR_IRQ: + printk("%s: Unrecognized error interrupt detected\n", + dev->name); + /* Parm[0-3]: adapter internal register R13-R15 */ + break; + + case INVALID_XOP: + printk("%s: Unrecognized XOP request detected\n", + dev->name); + /* Parm[0-3]: adapter internal register R13-R15 */ + break; + + default: + printk("%s: Unknown status", dev->name); + break; + } + + if(sktr_chipset_init(dev) == 1) + { + /* Restart of firmware successful */ + tp->AdapterOpenFlag = 1; + } + + return; +} + +/* + * Internal adapter pointer to RAM data are copied from adapter into + * host system. + */ +static void sktr_read_ptr(struct net_device *dev) +{ + struct net_local *tp = (struct net_local *)dev->priv; + unsigned short adapterram; + + sktr_read_ram(dev, (unsigned char *)&tp->intptrs.BurnedInAddrPtr, + ADAPTER_INT_PTRS, 16); + sktr_read_ram(dev, (unsigned char *)&adapterram, + (unsigned short)SWAPB(tp->intptrs.AdapterRAMPtr), 2); + + printk(KERN_INFO "%s: Adapter RAM size: %d K\n", + dev->name, SWAPB(adapterram)); + + return; +} + +/* + * Reads a number of bytes from adapter to system memory. + */ +static void sktr_read_ram(struct net_device *dev, unsigned char *Data, + unsigned short Address, int Length) +{ + int i; + unsigned short old_sifadx, old_sifadr, InWord; + unsigned short ioaddr = dev->base_addr; + + /* Save the current values */ + old_sifadx = inw(ioaddr + SIFADX); + old_sifadr = inw(ioaddr + SIFADR); + + /* Page number of adapter memory */ + outw(0x0001, ioaddr + SIFADX); + /* Address offset in adapter RAM */ + outw(Address, ioaddr + SIFADR); + + /* Copy len byte from adapter memory to system data area. */ + i = 0; + for(;;) + { + InWord = inw(ioaddr + SIFINC); + + *(Data + i) = HIBYTE(InWord); /* Write first byte */ + if(++i == Length) /* All is done break */ + break; + + *(Data + i) = LOBYTE(InWord); /* Write second byte */ + if (++i == Length) /* All is done break */ + break; + } + + /* Restore original values */ + outw(old_sifadx, ioaddr + SIFADX); + outw(old_sifadr, ioaddr + SIFADR); + + return; +} + +/* + * Reads MAC address from adapter ROM. + */ +static void sktr_read_addr(struct net_device *dev, unsigned char *Address) +{ + int i, In; + unsigned short ioaddr = dev->base_addr; + + /* Address: 0000:0000 */ + outw(0, ioaddr + SIFADX); + outw(0, ioaddr + SIFADR); + + /* Read six byte MAC address data */ + for(i = 0; i < 6; i++) + { + In = inw(ioaddr + SIFINC); + *(Address + i) = (unsigned char)(In >> 8); + } + + return; +} + +/* + * Cancel all queued packets in the transmission queue. + */ +static void sktr_cancel_tx_queue(struct net_local* tp) +{ + TPL *tpl; + struct sk_buff *skb; + + /* + * NOTE: There must not be an active TRANSMIT command pending, when + * this function is called. + */ + if(tp->TransmitCommandActive) + return; + + for(;;) + { + tpl = tp->TplBusy; + if(!tpl->BusyFlag) + break; + /* "Remove" TPL from busy list. */ + tp->TplBusy = tpl->NextTPLPtr; + sktr_write_tpl_status(tpl, 0); /* Clear VALID bit */ + tpl->BusyFlag = 0; /* "free" TPL */ + + printk(KERN_INFO "Cancel tx (%08lXh).\n", (unsigned long)tpl); + + dev_kfree_skb(tpl->Skb); + } + + for(;;) + { + skb = skb_dequeue(&tp->SendSkbQueue); + if(skb == NULL) + break; + tp->QueueSkb++; + dev_kfree_skb(skb); + } + + return; +} + +/* + * This function is called whenever a transmit interrupt is generated by the + * adapter. For a command complete interrupt, it is checked if we have to + * issue a new transmit command or not. + */ +static void sktr_tx_status_irq(struct net_device *dev) +{ + struct net_local *tp = (struct net_local *)dev->priv; + unsigned char HighByte, HighAc, LowAc; + TPL *tpl; + + /* NOTE: At this point the SSB from TRANSMIT STATUS is no longer + * available, because the CLEAR SSB command has already been issued. + * + * Process all complete transmissions. + */ + + for(;;) + { + tpl = tp->TplBusy; + if(!tpl->BusyFlag || (tpl->Status + & (TX_VALID | TX_FRAME_COMPLETE)) + != TX_FRAME_COMPLETE) + { + break; + } + + /* "Remove" TPL from busy list. */ + tp->TplBusy = tpl->NextTPLPtr ; + + if(sktr_debug > 3) + sktr_dump(tpl->MData, SWAPB(tpl->FrameSize)); + + /* Check the transmit status field only for directed frames*/ + if(DIRECTED_FRAME(tpl) && (tpl->Status & TX_ERROR) == 0) + { + HighByte = GET_TRANSMIT_STATUS_HIGH_BYTE(tpl->Status); + HighAc = GET_FRAME_STATUS_HIGH_AC(HighByte); + LowAc = GET_FRAME_STATUS_LOW_AC(HighByte); + + if((HighAc != LowAc) || (HighAc == AC_NOT_RECOGNIZED)) + { + printk(KERN_INFO "%s: (DA=%08lX not recognized)", + dev->name, + *(unsigned long *)&tpl->MData[2+2]); + } + else + { + if(sktr_debug > 3) + printk("%s: Directed frame tx'd\n", + dev->name); + } + } + else + { + if(!DIRECTED_FRAME(tpl)) + { + if(sktr_debug > 3) + printk("%s: Broadcast frame tx'd\n", + dev->name); + } + } + + tp->MacStat.tx_packets++; + dev_kfree_skb(tpl->Skb); + tpl->BusyFlag = 0; /* "free" TPL */ + } + + dev->tbusy = 0; + if(tp->QueueSkb < MAX_TX_QUEUE) + sktr_hardware_send_packet(dev, tp); + + return; +} + +/* + * Called if a frame receive interrupt is generated by the adapter. + * Check if the frame is valid and indicate it to system. + */ +static void sktr_rcv_status_irq(struct net_device *dev) +{ + struct net_local *tp = (struct net_local *)dev->priv; + unsigned char *ReceiveDataPtr; + struct sk_buff *skb; + unsigned int Length, Length2; + RPL *rpl; + RPL *SaveHead; + + /* NOTE: At this point the SSB from RECEIVE STATUS is no longer + * available, because the CLEAR SSB command has already been issued. + * + * Process all complete receives. + */ + + for(;;) + { + rpl = tp->RplHead; + if(rpl->Status & RX_VALID) + break; /* RPL still in use by adapter */ + + /* Forward RPLHead pointer to next list. */ + SaveHead = tp->RplHead; + tp->RplHead = rpl->NextRPLPtr; + + /* Get the frame size (Byte swap for Intel). + * Do this early (see workaround comment below) + */ + Length = (unsigned short)SWAPB(rpl->FrameSize); + + /* Check if the Frame_Start, Frame_End and + * Frame_Complete bits are set. + */ + if((rpl->Status & VALID_SINGLE_BUFFER_FRAME) + == VALID_SINGLE_BUFFER_FRAME) + { + ReceiveDataPtr = rpl->MData; + + /* Workaround for delayed write of FrameSize on ISA + * (FrameSize is false but valid-bit is reset) + * Frame size is set to zero when the RPL is freed. + * Length2 is there because there have also been + * cases where the FrameSize was partially written + */ + Length2 = (unsigned short)SWAPB(rpl->FrameSize); + + if(Length == 0 || Length != Length2) + { + tp->RplHead = SaveHead; + break; /* Return to sktr_interrupt */ + } + + /* Drop frames sent by myself */ + if(sktr_chk_frame(dev, rpl->MData)) + { + if(rpl->Skb != NULL) + dev_kfree_skb(rpl->Skb); + } + else + { + sktr_update_rcv_stats(tp,ReceiveDataPtr,Length); + + if(sktr_debug > 3) + printk("%s: Packet Length %04X (%d)\n", + dev->name, Length, Length); + + /* Indicate the received frame to system. + * The source routing padding is no more + * necessary with 2.2.x kernel. + * See: OpenOptions in sktr_init_opb() + */ + skb = rpl->Skb; + if(rpl->SkbStat == SKB_UNAVAILABLE) + { + /* Try again to allocate skb */ + skb = dev_alloc_skb(tp->MaxPacketSize); + if(skb == NULL) + { + /* Update Stats ?? */ + } + else + { + skb->dev = dev; + skb_put(skb, tp->MaxPacketSize); + rpl->SkbStat = SKB_DATA_COPY; + ReceiveDataPtr = rpl->MData; + } + } + + if(rpl->SkbStat == SKB_DATA_COPY + || rpl->SkbStat == SKB_DMA_DIRECT) + { + if(rpl->SkbStat == SKB_DATA_COPY) + { + memmove(skb->data, ReceiveDataPtr, Length); + } + + /* Deliver frame to system */ + rpl->Skb = NULL; + skb_trim(skb,Length); + skb->dev = dev; + skb->protocol = tr_type_trans(skb,dev); + netif_rx(skb); + } + } + } + else /* Invalid frame */ + { + if(rpl->Skb != NULL) + dev_kfree_skb(rpl->Skb); + + /* Skip list. */ + if(rpl->Status & RX_START_FRAME) + /* Frame start bit is set -> overflow. */ + tp->MacStat.rx_errors++; + } + + /* Allocate new skb for rpl */ + rpl->Skb = dev_alloc_skb(tp->MaxPacketSize); + + /* skb == NULL ? then use local buffer */ + if(rpl->Skb == NULL) + { + rpl->SkbStat = SKB_UNAVAILABLE; + rpl->FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[rpl->RPLIndex])); + rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex]; + } + else /* skb != NULL */ + { + rpl->Skb->dev = dev; + skb_put(rpl->Skb, tp->MaxPacketSize); + + /* Data unreachable for DMA ? then use local buffer */ + if(tp->DeviceType == SK_ISA && + virt_to_bus(rpl->Skb->data) + tp->MaxPacketSize + > ISA_MAX_ADDRESS) + { + rpl->SkbStat = SKB_DATA_COPY; + rpl->FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[rpl->RPLIndex])); + rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex]; + } + else + { + /* DMA directly in skb->data */ + rpl->SkbStat = SKB_DMA_DIRECT; + rpl->FragList[0].DataAddr = htonl(virt_to_bus(rpl->Skb->data)); + rpl->MData = rpl->Skb->data; + } + } + + rpl->FragList[0].DataCount = SWAPB(tp->MaxPacketSize); + rpl->FrameSize = 0; + + /* Pass the last RPL back to the adapter */ + tp->RplTail->FrameSize = 0; + + /* Reset the CSTAT field in the list. */ + sktr_write_rpl_status(tp->RplTail, RX_VALID | RX_FRAME_IRQ); + + /* Current RPL becomes last one in list. */ + tp->RplTail = tp->RplTail->NextRPLPtr; + + /* Inform adapter about RPL valid. */ + sktr_exec_sifcmd(dev, CMD_RX_VALID); + } + + return; +} + +/* + * This function should be used whenever the status of any RPL must be + * modified by the driver, because the compiler may otherwise change the + * order of instructions such that writing the RPL status may be executed + * at an undesireable time. When this function is used, the status is + * always written when the function is called. + */ +static void sktr_write_rpl_status(RPL *rpl, unsigned int Status) +{ + rpl->Status = Status; + + return; +} + +/* + * The function updates the statistic counters in mac->MacStat. + * It differtiates between directed and broadcast/multicast ( ==functional) + * frames. + */ +static void sktr_update_rcv_stats(struct net_local *tp, unsigned char DataPtr[], + unsigned int Length) +{ + tp->MacStat.rx_packets++; + + /* Test functional bit */ + if(DataPtr[2] & GROUP_BIT) + tp->MacStat.multicast++; + + return; +} + +/* + * Check if it is a frame of myself. Compare source address with my current + * address in reverse direction, and mask out the TR_RII. + */ +static unsigned char sktr_chk_frame(struct net_device *dev, unsigned char *Addr) +{ + int i; + + for(i = 5; i > 0; i--) + { + if(Addr[8 + i] != dev->dev_addr[i]) + return (0); + } + + /* Mask out RIF bit. */ + if((Addr[8] & ~TR_RII) != (unsigned char)(dev->dev_addr[0])) + return (0); + + return (1); /* It is my frame. */ +} + +/* + * Dump Packet (data) + */ +static void sktr_dump(unsigned char *Data, int length) +{ + int i, j; + + for (i = 0, j = 0; i < length / 8; i++, j += 8) + { + printk(KERN_DEBUG "%02x %02x %02x %02x %02x %02x %02x %02x\n", + Data[j+0],Data[j+1],Data[j+2],Data[j+3], + Data[j+4],Data[j+5],Data[j+6],Data[j+7]); + } + + return; +} + +#ifdef MODULE + +static struct net_device* dev_sktr[SKTR_MAX_ADAPTERS]; +static int io[SKTR_MAX_ADAPTERS] = { 0, 0 }; +static int irq[SKTR_MAX_ADAPTERS] = { 0, 0 }; +static int mem[SKTR_MAX_ADAPTERS] = { 0, 0 }; + +MODULE_PARM(io, "1-" __MODULE_STRING(SKTR_MAX_ADAPTERS) "i"); +MODULE_PARM(irq, "1-" __MODULE_STRING(SKTR_MAX_ADAPTERS) "i"); +MODULE_PARM(mem, "1-" __MODULE_STRING(SKTR_MAX_ADAPTERS) "i"); + +int init_module(void) +{ + int i; + + for(i = 0; i < SKTR_MAX_ADAPTERS; i++) + { + irq[i] = 0; + mem[i] = 0; + dev_sktr[i] = NULL; + dev_sktr[i] = init_trdev(dev_sktr[i], 0); + if(dev_sktr[i] == NULL) + return (-ENOMEM); + + dev_sktr[i]->base_addr = io[i]; + dev_sktr[i]->irq = irq[i]; + dev_sktr[i]->mem_start = mem[i]; + dev_sktr[i]->init = &sktr_probe; + + if(register_trdev(dev_sktr[i]) != 0) + { + kfree_s(dev_sktr[i], sizeof(struct net_device)); + dev_sktr[i] = NULL; + if(i == 0) + { + printk("sktr: register_trdev() returned non-zero.\n"); + return (-EIO); + } + else + return (0); + } + } + + return (0); +} + +void cleanup_module(void) +{ + int i; + + for(i = 0; i < SKTR_MAX_ADAPTERS; i++) + { + if(dev_sktr[i]) + { + unregister_trdev(dev_sktr[i]); + release_region(dev_sktr[i]->base_addr, SKTR_IO_EXTENT); + if(dev_sktr[i]->irq) + free_irq(dev_sktr[i]->irq, dev_sktr[i]); + if(dev_sktr[i]->dma > 0) + free_dma(dev_sktr[i]->dma); + if(dev_sktr[i]->priv) + kfree_s(dev_sktr[i]->priv, sizeof(struct net_local)); + kfree_s(dev_sktr[i], sizeof(struct net_device)); + dev_sktr[i] = NULL; + } + } +} +#endif /* MODULE */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/tokenring/sktr.h linux/drivers/net/tokenring/sktr.h --- v2.3.20/linux/drivers/net/tokenring/sktr.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tokenring/sktr.h Mon Oct 11 10:13:24 1999 @@ -0,0 +1,1103 @@ +/* sktr.h: SysKonnect TokenRing driver for Linux + * + * Authors: + * - Christoph Goos + */ + +#ifndef __LINUX_SKTR_H +#define __LINUX_SKTR_H + +#ifdef __KERNEL__ + +#define SKTR_MAX_ADAPTERS 7 + +#define SEND_TIMEOUT 10*HZ + +#define TR_RCF_LONGEST_FRAME_MASK 0x0070 +#define TR_RCF_FRAME4K 0x0030 + +#define SK_ISA 0 +#define SK_PCI 1 + +/*------------------------------------------------------------------*/ +/* Bit order for adapter communication with DMA */ +/* -------------------------------------------------------------- */ +/* Bit 8 | 9| 10| 11|| 12| 13| 14| 15|| 0| 1| 2| 3|| 4| 5| 6| 7| */ +/* -------------------------------------------------------------- */ +/* The bytes in a word must be byte swapped. Also, if a double */ +/* word is used for storage, then the words, as well as the bytes, */ +/* must be swapped. */ +/* Bit order for adapter communication with DIO */ +/* -------------------------------------------------------------- */ +/* Bit 0 | 1| 2| 3|| 4| 5| 6| 7|| 8| 9| 10| 11|| 12| 13| 14| 15| */ +/* -------------------------------------------------------------- */ +/*------------------------------------------------------------------*/ + +/* Swap bytes of a word. */ +#define SWAPB(x) (((unsigned short)((x) << 8)) | ((unsigned short)((x) >> 8))) + +/* Swap words of a long. */ +#define SWAPW(x) (((x) << 16) | ((x) >> 16)) + +/* Get the low byte of a word. */ +#define LOBYTE(w) ((unsigned char)(w)) + +/* Get the high byte of a word. */ +#define HIBYTE(w) ((unsigned char)((unsigned short)(w) >> 8)) + +/* Get the low word of a long. */ +#define LOWORD(l) ((unsigned short)(l)) + +/* Get the high word of a long. */ +#define HIWORD(l) ((unsigned short)((unsigned long)(l) >> 16)) + + + +/* Token ring adapter I/O addresses for normal mode. */ +#define SIFDAT 0L /* SIF/DMA data. */ +#define SIFINC 2L /* IO Word data with auto increment. */ +#define SIFINH 3L /* IO Byte data with auto increment. */ +#define SIFADR 4L /* SIF/DMA Address. */ +#define SIFCMD 6L /* SIF Command. */ +#define SIFSTS 6L /* SIF Status. */ +#define SIFACL 8L /* SIF Adapter Control Register. */ +#define SIFADD 10L /* SIF/DMA Address. */ +#define SIFADX 12L +#define DMALEN 14L /* SIF DMA length. */ +#define POSREG 16L /* Adapter Program Option Select (POS) + * Register: base IO address + 16 byte. + */ +#define POSREG_2 24L /* only for TR4/16+ adapter + * base IO address + 24 byte. + */ + + +/* SIFCMD command codes (high-low) */ +#define CMD_INTERRUPT_ADAPTER 0x8000 /* Cause internal adapter interrupt */ +#define CMD_ADAPTER_RESET 0x4000 /* Hardware reset of adapter */ +#define CMD_SSB_CLEAR 0x2000 /* Acknowledge to adapter to + * system interrupts. + */ +#define CMD_EXECUTE 0x1000 /* Execute SCB command */ +#define CMD_SCB_REQUEST 0x0800 /* Request adapter to interrupt + * system when SCB is available for + * another command. + */ +#define CMD_RX_CONTINUE 0x0400 /* Continue receive after odd pointer + * stop. (odd pointer receive method) + */ +#define CMD_RX_VALID 0x0200 /* Now actual RPL is valid. */ +#define CMD_TX_VALID 0x0100 /* Now actual TPL is valid. (valid + * bit receive/transmit method) + */ +#define CMD_SYSTEM_IRQ 0x0080 /* Adapter-to-attached-system + * interrupt is reset. + */ +#define CMD_CLEAR_SYSTEM_IRQ 0x0080 /* Clear SYSTEM_INTERRUPT bit. + * (write: 1=ignore, 0=reset) + */ +#define EXEC_SOFT_RESET 0xFF00 /* adapter soft reset. (restart + * adapter after hardware reset) + */ + + +/* ACL commands (high-low) */ +#define ACL_SWHLDA 0x0800 /* Software hold acknowledge. */ +#define ACL_SWDDIR 0x0400 /* Data transfer direction. */ +#define ACL_SWHRQ 0x0200 /* Pseudo DMA operation. */ +#define ACL_PSDMAEN 0x0100 /* Enable pseudo system DMA. */ +#define ACL_ARESET 0x0080 /* Adapter hardware reset command. + * (held in reset condition as + * long as bit is set) + */ +#define ACL_CPHALT 0x0040 /* Communication processor halt. + * (can only be set while ACL_ARESET + * bit is set; prevents adapter + * processor from executing code while + * downloading firmware) + */ +#define ACL_BOOT 0x0020 +#define ACL_SINTEN 0x0008 /* System interrupt enable/disable + * (1/0): can be written if ACL_ARESET + * is zero. + */ +#define ACL_SPEED4 0x0003 +#define ACL_SPEED16 0x0001 +#define PS_DMA_MASK (ACL_SWHRQ | ACL_PSDMAEN) + + +/* SIFSTS register return codes (high-low) */ +#define STS_SYSTEM_IRQ 0x0080 /* Adapter-to-attached-system + * interrupt is valid. + */ +#define STS_INITIALIZE 0x0040 /* INITIALIZE status. (ready to + * initialize) + */ +#define STS_TEST 0x0020 /* TEST status. (BUD not completed) */ +#define STS_ERROR 0x0010 /* ERROR status. (unrecoverable + * HW error occurred) + */ +#define STS_MASK 0x00F0 /* Mask interesting status bits. */ +#define STS_ERROR_MASK 0x000F /* Get Error Code by masking the + * interrupt code bits. + */ +#define ADAPTER_INT_PTRS 0x0A00 /* Address offset of adapter internal + * pointers 01:0a00 (high-low) have to + * be read after init and before open. + */ + + +/* Interrupt Codes (only MAC IRQs) */ +#define STS_IRQ_ADAPTER_CHECK 0x0000 /* unrecoverable hardware or + * software error. + */ +#define STS_IRQ_RING_STATUS 0x0004 /* SSB is updated with ring status. */ +#define STS_IRQ_SCB_CLEAR 0x0006 /* SCB clear, following an + * SCB_REQUEST IRQ. + */ +#define STS_IRQ_COMMAND_STATUS 0x0008 /* SSB is updated with command + * status. + */ +#define STS_IRQ_RECEIVE_STATUS 0x000A /* SSB is updated with receive + * status. + */ +#define STS_IRQ_TRANSMIT_STATUS 0x000C /* SSB is updated with transmit + * status + */ +#define STS_IRQ_MASK 0x000F /* = STS_ERROR_MASK. */ + + +/* TRANSMIT_STATUS completion code: (SSB.Parm[0]) */ +#define COMMAND_COMPLETE 0x0080 /* TRANSMIT command completed + * (avoid this!) issue another transmit + * to send additional frames. + */ +#define FRAME_COMPLETE 0x0040 /* Frame has been transmitted; + * INTERRUPT_FRAME bit was set in the + * CSTAT request; indication of possibly + * more than one frame transmissions! + * SSB.Parm[0-1]: 32 bit pointer to + * TPL of last frame. + */ +#define LIST_ERROR 0x0020 /* Error in one of the TPLs that + * compose the frame; TRANSMIT + * terminated; Parm[1-2]: 32 bit pointer + * to TPL which starts the error + * frame; error details in bits 8-13. + * (14?) + */ +#define FRAME_SIZE_ERROR 0x8000 /* FRAME_SIZE does not equal the sum of + * the valid DATA_COUNT fields; + * FRAME_SIZE less than header plus + * information field. (15 bytes + + * routing field) Or if FRAME_SIZE + * was specified as zero in one list. + */ +#define TX_THRESHOLD 0x4000 /* FRAME_SIZE greater than (BUFFER_SIZE + * - 9) * TX_BUF_MAX. + */ +#define ODD_ADDRESS 0x2000 /* Odd forward pointer value is + * read on a list without END_FRAME + * indication. + */ +#define FRAME_ERROR 0x1000 /* START_FRAME bit is (not) anticipated, + * but (not) set. + */ +#define ACCESS_PRIORITY_ERROR 0x0800 /* Access priority requested has not + * been allowed. + */ +#define UNENABLED_MAC_FRAME 0x0400 /* MAC frame has source class of zero + * or MAC frame PCF ATTN field is + * greater than one. + */ +#define ILLEGAL_FRAME_FORMAT 0x0200 /* Bit 0 or FC field was set to one. */ + + +/* + * Since we need to support some functions even if the adapter is in a + * CLOSED state, we have a (pseudo-) command queue which holds commands + * that are outstandig to be executed. + * + * Each time a command completes, an interrupt occurs and the next + * command is executed. The command queue is actually a simple word with + * a bit for each outstandig command. Therefore the commands will not be + * executed in the order they have been queued. + * + * The following defines the command code bits and the command queue: + */ +#define OC_OPEN 0x0001 /* OPEN command */ +#define OC_TRANSMIT 0x0002 /* TRANSMIT command */ +#define OC_TRANSMIT_HALT 0x0004 /* TRANSMIT_HALT command */ +#define OC_RECEIVE 0x0008 /* RECEIVE command */ +#define OC_CLOSE 0x0010 /* CLOSE command */ +#define OC_SET_GROUP_ADDR 0x0020 /* SET_GROUP_ADDR command */ +#define OC_SET_FUNCT_ADDR 0x0040 /* SET_FUNCT_ADDR command */ +#define OC_READ_ERROR_LOG 0x0080 /* READ_ERROR_LOG command */ +#define OC_READ_ADAPTER 0x0100 /* READ_ADAPTER command */ +#define OC_MODIFY_OPEN_PARMS 0x0400 /* MODIFY_OPEN_PARMS command */ +#define OC_RESTORE_OPEN_PARMS 0x0800 /* RESTORE_OPEN_PARMS command */ +#define OC_SET_FIRST_16_GROUP 0x1000 /* SET_FIRST_16_GROUP command */ +#define OC_SET_BRIDGE_PARMS 0x2000 /* SET_BRIDGE_PARMS command */ +#define OC_CONFIG_BRIDGE_PARMS 0x4000 /* CONFIG_BRIDGE_PARMS command */ + +#define OPEN 0x0300 /* C: open command. S: completion. */ +#define TRANSMIT 0x0400 /* C: transmit command. S: completion + * status. (reject: COMMAND_REJECT if + * adapter not opened, TRANSMIT already + * issued or address passed in the SCB + * not word aligned) + */ +#define TRANSMIT_HALT 0x0500 /* C: interrupt TX TPL chain; if no + * TRANSMIT command issued, the command + * is ignored. (completion with TRANSMIT + * status (0x0400)!) + */ +#define RECEIVE 0x0600 /* C: receive command. S: completion + * status. (reject: COMMAND_REJECT if + * adapter not opened, RECEIVE already + * issued or address passed in the SCB + * not word aligned) + */ +#define CLOSE 0x0700 /* C: close adapter. S: completion. + * (COMMAND_REJECT if adapter not open) + */ +#define SET_GROUP_ADDR 0x0800 /* C: alter adapter group address after + * OPEN. S: completion. (COMMAND_REJECT + * if adapter not open) + */ +#define SET_FUNCT_ADDR 0x0900 /* C: alter adapter functional address + * after OPEN. S: completion. + * (COMMAND_REJECT if adapter not open) + */ +#define READ_ERROR_LOG 0x0A00 /* C: read adapter error counters. + * S: completion. (command ignored + * if adapter not open!) + */ +#define READ_ADAPTER 0x0B00 /* C: read data from adapter memory. + * (important: after init and before + * open!) S: completion. (ADAPTER_CHECK + * interrupt if undefined storage area + * read) + */ +#define MODIFY_OPEN_PARMS 0x0D00 /* C: modify some adapter operational + * parameters. (bit correspondend to + * WRAP_INTERFACE is ignored) + * S: completion. (reject: + * COMMAND_REJECT) + */ +#define RESTORE_OPEN_PARMS 0x0E00 /* C: modify some adapter operational + * parameters. (bit correspondend + * to WRAP_INTERFACE is ignored) + * S: completion. (reject: + * COMMAND_REJECT) + */ +#define SET_FIRST_16_GROUP 0x0F00 /* C: alter the first two bytes in + * adapter group address. + * S: completion. (reject: + * COMMAND_REJECT) + */ +#define SET_BRIDGE_PARMS 0x1000 /* C: values and conditions for the + * adapter hardware to use when frames + * are copied for forwarding. + * S: completion. (reject: + * COMMAND_REJECT) + */ +#define CONFIG_BRIDGE_PARMS 0x1100 /* C: .. + * S: completion. (reject: + * COMMAND_REJECT) + */ + +#define SPEED_4 4 +#define SPEED_16 16 /* Default transmission speed */ + + +/* Initialization Parameter Block (IPB); word alignment necessary! */ +#define BURST_SIZE 0x0018 /* Default burst size */ +#define BURST_MODE 0x9F00 /* Burst mode enable */ +#define DMA_RETRIES 0x0505 /* Magic DMA retry number... */ + +#define CYCLE_TIME 3 /* Default AT-bus cycle time: 500 ns + * (later adapter version: fix cycle time!) + */ +#define LINE_SPEED_BIT 0x80 + +/* Macro definition for the wait function. */ +#define ONE_SECOND_TICKS 1000000 +#define HALF_SECOND (ONE_SECOND_TICKS / 2) +#define ONE_SECOND (ONE_SECOND_TICKS) +#define TWO_SECONDS (ONE_SECOND_TICKS * 2) +#define THREE_SECONDS (ONE_SECOND_TICKS * 3) +#define FOUR_SECONDS (ONE_SECOND_TICKS * 4) +#define FIVE_SECONDS (ONE_SECOND_TICKS * 5) + +#define BUFFER_SIZE 2048 /* Buffers on Adapter */ + +#pragma pack(1) +typedef struct { + unsigned short Init_Options; /* Initialize with burst mode; + * LLC disabled. (MAC only) + */ + + /* Interrupt vectors the adapter places on attached system bus. */ + unsigned char CMD_Status_IV; /* Interrupt vector: command status. */ + unsigned char TX_IV; /* Interrupt vector: transmit. */ + unsigned char RX_IV; /* Interrupt vector: receive. */ + unsigned char Ring_Status_IV; /* Interrupt vector: ring status. */ + unsigned char SCB_Clear_IV; /* Interrupt vector: SCB clear. */ + unsigned char Adapter_CHK_IV; /* Interrupt vector: adapter check. */ + + unsigned short RX_Burst_Size; /* Max. number of transfer cycles. */ + unsigned short TX_Burst_Size; /* During DMA burst; even value! */ + unsigned short DMA_Abort_Thrhld; /* Number of DMA retries. */ + + unsigned long SCB_Addr; /* SCB address: even, word aligned, high-low. */ + unsigned long SSB_Addr; /* SSB address: even, word aligned, high-low. */ +} IPB, *IPB_Ptr; +#pragma pack() + +/* + * OPEN Command Parameter List (OCPL) (can be reused, if the adapter has to + * be reopened) + */ +#define BUFFER_SIZE 2048 /* Buffers on Adapter. */ +#define TPL_SIZE 8+6*TX_FRAG_NUM /* Depending on fragments per TPL. */ +#define RPL_SIZE 14 /* (with TI firmware v2.26 handling + * up to nine fragments possible) + */ +#define TX_BUF_MIN 20 /* ??? (Stephan: calculation with */ +#define TX_BUF_MAX 40 /* BUFFER_SIZE and MAX_FRAME_SIZE) ??? + */ +#define DISABLE_EARLY_TOKEN_RELEASE 0x1000 + +/* OPEN Options (high-low) */ +#define WRAP_INTERFACE 0x0080 /* Inserting omitted for test + * purposes; transmit data appears + * as receive data. (usefull for + * testing; change: CLOSE necessary) + */ +#define DISABLE_HARD_ERROR 0x0040 /* On HARD_ERROR & TRANSMIT_BEACON + * no RING.STATUS interrupt. + */ +#define DISABLE_SOFT_ERROR 0x0020 /* On SOFT_ERROR, no RING.STATUS + * interrupt. + */ +#define PASS_ADAPTER_MAC_FRAMES 0x0010 /* Passing unsupported MAC frames + * to system. + */ +#define PASS_ATTENTION_FRAMES 0x0008 /* All changed attention MAC frames are + * passed to the system. + */ +#define PAD_ROUTING_FIELD 0x0004 /* Routing field is padded to 18 + * bytes. + */ +#define FRAME_HOLD 0x0002 /* Adapter waits for entire frame before + * initiating DMA transfer; otherwise: + * DMA transfer initiation if internal + * buffer filled. + */ +#define CONTENDER 0x0001 /* Adapter participates in the monitor + * contention process. + */ +#define PASS_BEACON_MAC_FRAMES 0x8000 /* Adapter passes beacon MAC frames + * to the system. + */ +#define EARLY_TOKEN_RELEASE 0x1000 /* Only valid in 16 Mbps operation; + * 0 = ETR. (no effect in 4 Mbps + * operation) + */ +#define COPY_ALL_MAC_FRAMES 0x0400 /* All MAC frames are copied to + * the system. (after OPEN: duplicate + * address test (DAT) MAC frame is + * first received frame copied to the + * system) + */ +#define COPY_ALL_NON_MAC_FRAMES 0x0200 /* All non MAC frames are copied to + * the system. + */ +#define PASS_FIRST_BUF_ONLY 0x0100 /* Passes only first internal buffer + * of each received frame; FrameSize + * of RPLs must contain internal + * BUFFER_SIZE bits for promiscous mode. + */ +#define ENABLE_FULL_DUPLEX_SELECTION 0x2000 /* Enable the use of full-duplex + * settings with bits in byte 22 in + * ocpl. (new feature in firmware + * version 3.09) + */ + +/* Full-duplex settings */ +#define OPEN_FULL_DUPLEX_OFF 0x0000 +#define OPEN_FULL_DUPLEX_ON 0x00c0 +#define OPEN_FULL_DUPLEX_AUTO 0x0080 + +#define PROD_ID_SIZE 18 /* Length of product ID. */ + +#define TX_FRAG_NUM 3 /* Number of fragments used in one TPL. */ +#define TX_MORE_FRAGMENTS 0x8000 /* Bit set in DataCount to indicate more + * fragments following. + */ + +#define ISA_MAX_ADDRESS 0x00ffffff + +#pragma pack(1) +typedef struct { + unsigned short OPENOptions; + unsigned char NodeAddr[6]; /* Adapter node address; use ROM + * address + */ + unsigned long GroupAddr; /* Multicast: high order + * bytes = 0xC000 + */ + unsigned long FunctAddr; /* High order bytes = 0xC000 */ + unsigned short RxListSize; /* RPL size: 0 (=26), 14, 20 or + * 26 bytes read by the adapter. + * (Depending on the number of + * fragments/list) + */ + unsigned short TxListSize; /* TPL size */ + unsigned short BufSize; /* Is automatically rounded up to the + * nearest nK boundary. + */ + unsigned short FullDuplex; + unsigned short Reserved; + unsigned char TXBufMin; /* Number of adapter buffers reserved + * for transmission a minimum of 2 + * buffers must be allocated. + */ + unsigned char TXBufMax; /* Maximum number of adapter buffers + * for transmit; a minimum of 2 buffers + * must be available for receive. + * Default: 6 + */ + unsigned short ProdIDAddr[2]; /* Pointer to product ID. */ +} OPB, *OPB_Ptr; +#pragma pack() + +/* + * SCB: adapter commands enabled by the host system started by writing + * CMD_INTERRUPT_ADAPTER | CMD_EXECUTE (|SCB_REQUEST) to the SIFCMD IO + * register. (special case: | CMD_SYSTEM_IRQ for initialization) + */ +#pragma pack(1) +typedef struct { + unsigned short CMD; /* Command code */ + unsigned short Parm[2]; /* Pointer to Command Parameter Block */ +} SCB; /* System Command Block (32 bit physical address; big endian)*/ +#pragma pack() + +/* + * SSB: adapter command return status can be evaluated after COMMAND_STATUS + * adapter to system interrupt after reading SSB, the availability of the SSB + * has to be told the adapter by writing CMD_INTERRUPT_ADAPTER | CMD_SSB_CLEAR + * in the SIFCMD IO register. + */ +#pragma pack(1) +typedef struct { + unsigned short STS; /* Status code */ + unsigned short Parm[3]; /* Parameter or pointer to Status Parameter + * Block. + */ +} SSB; /* System Status Block (big endian - physical address) */ +#pragma pack() + +typedef struct { + unsigned short BurnedInAddrPtr; /* Pointer to adapter burned in + * address. (BIA) + */ + unsigned short SoftwareLevelPtr;/* Pointer to software level data. */ + unsigned short AdapterAddrPtr; /* Pointer to adapter addresses. */ + unsigned short AdapterParmsPtr; /* Pointer to adapter parameters. */ + unsigned short MACBufferPtr; /* Pointer to MAC buffer. (internal) */ + unsigned short LLCCountersPtr; /* Pointer to LLC counters. */ + unsigned short SpeedFlagPtr; /* Pointer to data rate flag. + * (4/16 Mbps) + */ + unsigned short AdapterRAMPtr; /* Pointer to adapter RAM found. (KB) */ +} INTPTRS; /* Adapter internal pointers */ + +#pragma pack(1) +typedef struct { + unsigned char Line_Error; /* Line error: code violation in + * frame or in a token, or FCS error. + */ + unsigned char Internal_Error; /* IBM specific. (Reserved_1) */ + unsigned char Burst_Error; + unsigned char ARI_FCI_Error; /* ARI/FCI bit zero in AMP or + * SMP MAC frame. + */ + unsigned char AbortDelimeters; /* IBM specific. (Reserved_2) */ + unsigned char Reserved_3; + unsigned char Lost_Frame_Error; /* Receive of end of transmitted + * frame failed. + */ + unsigned char Rx_Congest_Error; /* Adapter in repeat mode has not + * enough buffer space to copy incoming + * frame. + */ + unsigned char Frame_Copied_Error;/* ARI bit not zero in frame + * addressed to adapter. + */ + unsigned char Frequency_Error; /* IBM specific. (Reserved_4) */ + unsigned char Token_Error; /* (active only in monitor station) */ + unsigned char Reserved_5; + unsigned char DMA_Bus_Error; /* DMA bus errors not exceeding the + * abort thresholds. + */ + unsigned char DMA_Parity_Error; /* DMA parity errors not exceeding + * the abort thresholds. + */ +} ERRORTAB; /* Adapter error counters */ +#pragma pack() + + +/*--------------------- Send and Receive definitions -------------------*/ +#pragma pack(1) +typedef struct { + unsigned short DataCount; /* Value 0, even and odd values are + * permitted; value is unaltered most + * significant bit set: following + * fragments last fragment: most + * significant bit is not evaluated. + * (???) + */ + unsigned long DataAddr; /* Pointer to frame data fragment; + * even or odd. + */ +} Fragment; +#pragma pack() + +#define MAX_FRAG_NUMBERS 9 /* Maximal number of fragments possible to use + * in one RPL/TPL. (depending on TI firmware + * version) + */ +#define MAX_TX_QUEUE 10 /* Maximal number of skb's queued in driver. */ + +/* + * AC (1), FC (1), Dst (6), Src (6), RIF (18), Data (4472) = 4504 + * The packet size can be one of the follows: 548, 1502, 2084, 4504, 8176, + * 11439, 17832. Refer to TMS380 Second Generation Token Ring User's Guide + * Page 2-27. + */ +#define HEADER_SIZE (1 + 1 + 6 + 6) +#define SRC_SIZE 18 +#define MIN_DATA_SIZE 516 +#define DEFAULT_DATA_SIZE 4472 +#define MAX_DATA_SIZE 17800 + +#define DEFAULT_PACKET_SIZE (HEADER_SIZE + SRC_SIZE + DEFAULT_DATA_SIZE) +#define MIN_PACKET_SIZE (HEADER_SIZE + SRC_SIZE + MIN_DATA_SIZE) +#define MAX_PACKET_SIZE (HEADER_SIZE + SRC_SIZE + MAX_DATA_SIZE) + +/* + * Macros to deal with the frame status field. + */ +#define AC_NOT_RECOGNIZED 0x00 +#define GROUP_BIT 0x80 +#define GET_TRANSMIT_STATUS_HIGH_BYTE(Ts) ((unsigned char)((Ts) >> 8)) +#define GET_FRAME_STATUS_HIGH_AC(Fs) ((unsigned char)(((Fs) & 0xC0) >> 6)) +#define GET_FRAME_STATUS_LOW_AC(Fs) ((unsigned char)(((Fs) & 0x0C) >> 2)) +#define DIRECTED_FRAME(Context) (!((Context)->MData[2] & GROUP_BIT)) + + +/*--------------------- Send Functions ---------------------------------*/ +/* define TX_CSTAT _REQUEST (R) and _COMPLETE (C) values (high-low) */ + +#define TX_VALID 0x0080 /* R: set via TRANSMIT.VALID interrupt. + * C: always reset to zero! + */ +#define TX_FRAME_COMPLETE 0x0040 /* R: must be reset to zero. + * C: set to one. + */ +#define TX_START_FRAME 0x0020 /* R: start of a frame: 1 + * C: unchanged. + */ +#define TX_END_FRAME 0x0010 /* R: end of a frame: 1 + * C: unchanged. + */ +#define TX_FRAME_IRQ 0x0008 /* R: request interrupt generation + * after transmission. + * C: unchanged. + */ +#define TX_ERROR 0x0004 /* R: reserved. + * C: set to one if Error occurred. + */ +#define TX_INTERFRAME_WAIT 0x0004 +#define TX_PASS_CRC 0x0002 /* R: set if CRC value is already + * calculated. (valid only in + * FRAME_START TPL) + * C: unchanged. + */ +#define TX_PASS_SRC_ADDR 0x0001 /* R: adapter uses explicit frame + * source address and does not overwrite + * with the adapter node address. + * (valid only in FRAME_START TPL) + * + * C: unchanged. + */ +#define TX_STRIP_FS 0xFF00 /* R: reserved. + * C: if no Transmission Error, + * field contains copy of FS byte after + * stripping of frame. + */ + +/* + * Structure of Transmit Parameter Lists (TPLs) (only one frame every TPL, + * but possibly multiple TPLs for one frame) the length of the TPLs has to be + * initialized in the OPL. (OPEN parameter list) + */ +#define TPL_NUM 9 /* Number of Transmit Parameter Lists. + * !! MUST BE >= 3 !! + */ + +#pragma pack(1) +typedef struct s_TPL TPL; + +struct s_TPL { /* Transmit Parameter List (align on even word boundaries) */ + unsigned long NextTPLAddr; /* Pointer to next TPL in chain; if + * pointer is odd: this is the last + * TPL. Pointing to itself can cause + * problems! + */ + volatile unsigned short Status; /* Initialized by the adapter: + * CSTAT_REQUEST important: update least + * significant bit first! Set by the + * adapter: CSTAT_COMPLETE status. + */ + unsigned short FrameSize; /* Number of bytes to be transmitted + * as a frame including AC/FC, + * Destination, Source, Routing field + * not including CRC, FS, End Delimiter + * (valid only if START_FRAME bit in + * CSTAT nonzero) must not be zero in + * any list; maximum value: (BUFFER_SIZE + * - 8) * TX_BUF_MAX sum of DataCount + * values in FragmentList must equal + * Frame_Size value in START_FRAME TPL! + * frame data fragment list. + */ + + /* TPL/RPL size in OPEN parameter list depending on maximal + * numbers of fragments used in one parameter list. + */ + Fragment FragList[TX_FRAG_NUM]; /* Maximum: nine frame fragments in one + * TPL actual version of firmware: 9 + * fragments possible. + */ +#pragma pack() + + /* Special proprietary data and precalculations */ + + TPL *NextTPLPtr; /* Pointer to next TPL in chain. */ + unsigned char *MData; + struct sk_buff *Skb; + unsigned char TPLIndex; + volatile unsigned char BusyFlag;/* Flag: TPL busy? */ +}; + +/* ---------------------Receive Functions-------------------------------* + * define RECEIVE_CSTAT_REQUEST (R) and RECEIVE_CSTAT_COMPLETE (C) values. + * (high-low) + */ +#define RX_VALID 0x0080 /* R: set; tell adapter with + * RECEIVE.VALID interrupt. + * C: reset to zero. + */ +#define RX_FRAME_COMPLETE 0x0040 /* R: must be reset to zero, + * C: set to one. + */ +#define RX_START_FRAME 0x0020 /* R: must be reset to zero. + * C: set to one on the list. + */ +#define RX_END_FRAME 0x0010 /* R: must be reset to zero. + * C: set to one on the list + * that ends the frame. + */ +#define RX_FRAME_IRQ 0x0008 /* R: request interrupt generation + * after receive. + * C: unchanged. + */ +#define RX_INTERFRAME_WAIT 0x0004 /* R: after receiving a frame: + * interrupt and wait for a + * RECEIVE.CONTINUE. + * C: unchanged. + */ +#define RX_PASS_CRC 0x0002 /* R: if set, the adapter includes + * the CRC in data passed. (last four + * bytes; valid only if FRAME_START is + * set) + * C: set, if CRC is included in + * received data. + */ +#define RX_PASS_SRC_ADDR 0x0001 /* R: adapter uses explicit frame + * source address and does not + * overwrite with the adapter node + * address. (valid only if FRAME_START + * is set) + * C: unchanged. + */ +#define RX_RECEIVE_FS 0xFC00 /* R: reserved; must be reset to zero. + * C: on lists with START_FRAME, field + * contains frame status field from + * received frame; otherwise cleared. + */ +#define RX_ADDR_MATCH 0x0300 /* R: reserved; must be reset to zero. + * C: address match code mask. + */ +#define RX_STATUS_MASK 0x00FF /* Mask for receive status bits. */ + +#define RX_INTERN_ADDR_MATCH 0x0100 /* C: internally address match. */ +#define RX_EXTERN_ADDR_MATCH 0x0200 /* C: externally matched via + * XMATCH/XFAIL interface. + */ +#define RX_INTEXT_ADDR_MATCH 0x0300 /* C: internally and externally + * matched. + */ +#define RX_READY (RX_VALID | RX_FRAME_IRQ) /* Ready for receive. */ + +/* Constants for Command Status Interrupt. + * COMMAND_REJECT status field bit functions (SSB.Parm[0]) + */ +#define ILLEGAL_COMMAND 0x0080 /* Set if an unknown command + * is issued to the adapter + */ +#define ADDRESS_ERROR 0x0040 /* Set if any address field in + * the SCB is odd. (not word aligned) + */ +#define ADAPTER_OPEN 0x0020 /* Command issued illegal with + * open adapter. + */ +#define ADAPTER_CLOSE 0x0010 /* Command issued illegal with + * closed adapter. + */ +#define SAME_COMMAND 0x0008 /* Command issued with same command + * already executing. + */ + +/* OPEN_COMPLETION values (SSB.Parm[0], MSB) */ +#define NODE_ADDR_ERROR 0x0040 /* Wrong address or BIA read + * zero address. + */ +#define LIST_SIZE_ERROR 0x0020 /* If List_Size value not in 0, + * 14, 20, 26. + */ +#define BUF_SIZE_ERROR 0x0010 /* Not enough available memory for + * two buffers. + */ +#define TX_BUF_COUNT_ERROR 0x0004 /* Remaining receive buffers less than + * two. + */ +#define OPEN_ERROR 0x0002 /* Error during ring insertion; more + * information in bits 8-15. + */ + +/* Standard return codes */ +#define GOOD_COMPLETION 0x0080 /* =OPEN_SUCCESSFULL */ +#define INVALID_OPEN_OPTION 0x0001 /* OPEN options are not supported by + * the adapter. + */ + +/* OPEN phases; details of OPEN_ERROR (SSB.Parm[0], LSB) */ +#define OPEN_PHASES_MASK 0xF000 /* Check only the bits 8-11. */ +#define LOBE_MEDIA_TEST 0x1000 +#define PHYSICAL_INSERTION 0x2000 +#define ADDRESS_VERIFICATION 0x3000 +#define PARTICIPATION_IN_RING_POLL 0x4000 +#define REQUEST_INITIALISATION 0x5000 +#define FULLDUPLEX_CHECK 0x6000 + +/* OPEN error codes; details of OPEN_ERROR (SSB.Parm[0], LSB) */ +#define OPEN_ERROR_CODES_MASK 0x0F00 /* Check only the bits 12-15. */ +#define OPEN_FUNCTION_FAILURE 0x0100 /* Unable to transmit to itself or + * frames received before insertion. + */ +#define OPEN_SIGNAL_LOSS 0x0200 /* Signal loss condition detected at + * receiver. + */ +#define OPEN_TIMEOUT 0x0500 /* Insertion timer expired before + * logical insertion. + */ +#define OPEN_RING_FAILURE 0x0600 /* Unable to receive own ring purge + * MAC frames. + */ +#define OPEN_RING_BEACONING 0x0700 /* Beacon MAC frame received after + * ring insertion. + */ +#define OPEN_DUPLICATE_NODEADDR 0x0800 /* Other station in ring found + * with the same address. + */ +#define OPEN_REQUEST_INIT 0x0900 /* RPS present but does not respond. */ +#define OPEN_REMOVE_RECEIVED 0x0A00 /* Adapter received a remove adapter + * MAC frame. + */ +#define OPEN_FULLDUPLEX_SET 0x0D00 /* Got this with full duplex on when + * trying to connect to a normal ring. + */ + +/* SET_BRIDGE_PARMS return codes: */ +#define BRIDGE_INVALID_MAX_LEN 0x4000 /* MAX_ROUTING_FIELD_LENGTH odd, + * less than 6 or > 30. + */ +#define BRIDGE_INVALID_SRC_RING 0x2000 /* SOURCE_RING number zero, too large + * or = TARGET_RING. + */ +#define BRIDGE_INVALID_TRG_RING 0x1000 /* TARGET_RING number zero, too large + * or = SOURCE_RING. + */ +#define BRIDGE_INVALID_BRDGE_NO 0x0800 /* BRIDGE_NUMBER too large. */ +#define BRIDGE_INVALID_OPTIONS 0x0400 /* Invalid bridge options. */ +#define BRIDGE_DIAGS_FAILED 0x0200 /* Diagnostics of TMS380SRA failed. */ +#define BRIDGE_NO_SRA 0x0100 /* The TMS380SRA does not exist in HW + * configuration. + */ + +/* + * Bring Up Diagnostics error codes. + */ +#define BUD_INITIAL_ERROR 0x0 +#define BUD_CHECKSUM_ERROR 0x1 +#define BUD_ADAPTER_RAM_ERROR 0x2 +#define BUD_INSTRUCTION_ERROR 0x3 +#define BUD_CONTEXT_ERROR 0x4 +#define BUD_PROTOCOL_ERROR 0x5 +#define BUD_INTERFACE_ERROR 0x6 + +/* BUD constants */ +#define BUD_MAX_RETRIES 3 +#define BUD_MAX_LOOPCNT 6 +#define BUD_TIMEOUT 3000 + +/* Initialization constants */ +#define INIT_MAX_RETRIES 3 /* Maximum three retries. */ +#define INIT_MAX_LOOPCNT 22 /* Maximum loop counts. */ + +/* RING STATUS field values (high/low) */ +#define SIGNAL_LOSS 0x0080 /* Loss of signal on the ring + * detected. + */ +#define HARD_ERROR 0x0040 /* Transmitting or receiving beacon + * frames. + */ +#define SOFT_ERROR 0x0020 /* Report error MAC frame + * transmitted. + */ +#define TRANSMIT_BEACON 0x0010 /* Transmitting beacon frames on the + * ring. + */ +#define LOBE_WIRE_FAULT 0x0008 /* Open or short circuit in the + * cable to concentrator; adapter + * closed. + */ +#define AUTO_REMOVAL_ERROR 0x0004 /* Lobe wrap test failed, deinserted; + * adapter closed. + */ +#define REMOVE_RECEIVED 0x0001 /* Received a remove ring station MAC + * MAC frame request; adapter closed. + */ +#define COUNTER_OVERFLOW 0x8000 /* Overflow of one of the adapters + * error counters; READ.ERROR.LOG. + */ +#define SINGLE_STATION 0x4000 /* Adapter is the only station on the + * ring. + */ +#define RING_RECOVERY 0x2000 /* Claim token MAC frames on the ring; + * reset after ring purge frame. + */ + +#define ADAPTER_CLOSED (LOBE_WIRE_FAULT | AUTO_REMOVAL_ERROR |\ + REMOVE_RECEIVED) + +/* Adapter_check_block.Status field bit assignments: */ +#define DIO_PARITY 0x8000 /* Adapter detects bad parity + * through direct I/O access. + */ +#define DMA_READ_ABORT 0x4000 /* Aborting DMA read operation + * from system Parm[0]: 0=timeout, + * 1=parity error, 2=bus error; + * Parm[1]: 32 bit pointer to host + * system address at failure. + */ +#define DMA_WRITE_ABORT 0x2000 /* Aborting DMA write operation + * to system. (parameters analogous to + * DMA_READ_ABORT) + */ +#define ILLEGAL_OP_CODE 0x1000 /* Illegal operation code in the + * the adapters firmware Parm[0]-2: + * communications processor registers + * R13-R15. + */ +#define PARITY_ERRORS 0x0800 /* Adapter detects internal bus + * parity error. + */ +#define RAM_DATA_ERROR 0x0080 /* Valid only during RAM testing; + * RAM data error Parm[0-1]: 32 bit + * pointer to RAM location. + */ +#define RAM_PARITY_ERROR 0x0040 /* Valid only during RAM testing; + * RAM parity error Parm[0-1]: 32 bit + * pointer to RAM location. + */ +#define RING_UNDERRUN 0x0020 /* Internal DMA underrun when + * transmitting onto ring. + */ +#define INVALID_IRQ 0x0008 /* Unrecognized interrupt generated + * internal to adapter Parm[0-2]: + * adapter register R13-R15. + */ +#define INVALID_ERROR_IRQ 0x0004 /* Unrecognized error interrupt + * generated Parm[0-2]: adapter register + * R13-R15. + */ +#define INVALID_XOP 0x0002 /* Unrecognized XOP request in + * communication processor Parm[0-2]: + * adapter register R13-R15. + */ +#define CHECKADDR 0x05E0 /* Adapter check status information + * address offset. + */ +#define ROM_PAGE_0 0x0000 /* Adapter ROM page 0. */ + +/* + * RECEIVE.STATUS interrupt result SSB values: (high-low) + * (RECEIVE_COMPLETE field bit definitions in SSB.Parm[0]) + */ +#define RX_COMPLETE 0x0080 /* SSB.Parm[0]; SSB.Parm[1]: 32 + * bit pointer to last RPL. + */ +#define RX_SUSPENDED 0x0040 /* SSB.Parm[0]; SSB.Parm[1]: 32 + * bit pointer to RPL with odd + * forward pointer. + */ + +/* Valid receive CSTAT: */ +#define RX_FRAME_CONTROL_BITS (RX_VALID | RX_START_FRAME | RX_END_FRAME | \ + RX_FRAME_COMPLETE) +#define VALID_SINGLE_BUFFER_FRAME (RX_START_FRAME | RX_END_FRAME | \ + RX_FRAME_COMPLETE) + +typedef enum SKB_STAT SKB_STAT; +enum SKB_STAT { + SKB_UNAVAILABLE, + SKB_DMA_DIRECT, + SKB_DATA_COPY +}; + +/* Receive Parameter List (RPL) The length of the RPLs has to be initialized + * in the OPL. (OPEN parameter list) + */ +#define RPL_NUM 3 + +#define RX_FRAG_NUM 1 /* Maximal number of used fragments in one RPL. + * (up to firmware v2.24: 3, now: up to 9) + */ + +#pragma pack(1) +typedef struct s_RPL RPL; +struct s_RPL { /* Receive Parameter List */ + unsigned long NextRPLAddr; /* Pointer to next RPL in chain + * (normalized = physical 32 bit + * address) if pointer is odd: this + * is last RPL. Pointing to itself can + * cause problems! + */ + volatile unsigned short Status; /* Set by creation of Receive Parameter + * List RECEIVE_CSTAT_COMPLETE set by + * adapter in lists that start or end + * a frame. + */ + volatile unsigned short FrameSize; /* Number of bytes received as a + * frame including AC/FC, Destination, + * Source, Routing field not including + * CRC, FS (Frame Status), End Delimiter + * (valid only if START_FRAME bit in + * CSTAT nonzero) must not be zero in + * any list; maximum value: (BUFFER_SIZE + * - 8) * TX_BUF_MAX sum of DataCount + * values in FragmentList must equal + * Frame_Size value in START_FRAME TPL! + * frame data fragment list + */ + + /* TPL/RPL size in OPEN parameter list depending on maximal numbers + * of fragments used in one parameter list. + */ + Fragment FragList[RX_FRAG_NUM]; /* Maximum: nine frame fragments in + * one TPL. Actual version of firmware: + * 9 fragments possible. + */ +#pragma pack() + + /* Special proprietary data and precalculations. */ + RPL *NextRPLPtr; /* Logical pointer to next RPL in chain. */ + unsigned char *MData; + struct sk_buff *Skb; + SKB_STAT SkbStat; + int RPLIndex; +}; + +/* Information that need to be kept for each board. */ +typedef struct net_local { +#pragma pack(1) + IPB ipb; /* Initialization Parameter Block. */ + SCB scb; /* System Command Block: system to adapter + * communication. + */ + SSB ssb; /* System Status Block: adapter to system + * communication. + */ + OPB ocpl; /* Open Options Parameter Block. */ + + ERRORTAB errorlogtable; /* Adapter statistic error counters. + * (read from adapter memory) + */ + unsigned char ProductID[PROD_ID_SIZE + 1]; /* Product ID */ +#pragma pack() + + TPL Tpl[TPL_NUM]; + TPL *TplFree; + TPL *TplBusy; + unsigned char LocalTxBuffers[TPL_NUM][DEFAULT_PACKET_SIZE]; + + RPL Rpl[RPL_NUM]; + RPL *RplHead; + RPL *RplTail; + unsigned char LocalRxBuffers[RPL_NUM][DEFAULT_PACKET_SIZE]; + + int DataRate; + unsigned char ScbInUse; + unsigned short CMDqueue; + + unsigned int DeviceType; + + unsigned long AdapterOpenFlag:1; + unsigned long AdapterVirtOpenFlag:1; + unsigned long OpenCommandIssued:1; + unsigned long TransmitCommandActive:1; + unsigned long TransmitHaltScheduled:1; + unsigned long HaltInProgress:1; + unsigned long LobeWireFaultLogged:1; + unsigned long ReOpenInProgress:1; + unsigned long Sleeping:1; + + unsigned long LastOpenStatus; + unsigned short CurrentRingStatus; + unsigned long MaxPacketSize; + + unsigned long StartTime; + unsigned long LastSendTime; + + struct sk_buff_head SendSkbQueue; + unsigned short QueueSkb; + + struct tr_statistics MacStat; /* MAC statistics structure */ + + struct timer_list timer; + + wait_queue_head_t wait_for_tok_int; + + INTPTRS intptrs; /* Internal adapter pointer. Must be read + * before OPEN command. + */ +} NET_LOCAL; + +#endif /* __KERNEL__ */ +#endif /* __LINUX_SKTR_H */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/tokenring/sktr_firmware.h linux/drivers/net/tokenring/sktr_firmware.h --- v2.3.20/linux/drivers/net/tokenring/sktr_firmware.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tokenring/sktr_firmware.h Mon Oct 11 10:13:24 1999 @@ -0,0 +1,3616 @@ +/* + * The firmware this driver downloads into the tokenring card is a + * separate program and is not GPL'd source code, even though the Linux + * side driver and the routine that loads this data into the card are. + * + * This firmware is licensed to you strictly for use in conjunction + * with the use of SysKonnect TokenRing adapters. There is no + * waranty expressed or implied about its fitness for any purpose. + */ + +/* sktr_firmware.h: SysKonnect TokenRing driver firmware dump for Linux. + * + * Notes: + * - Loaded from sktr_reset_adapter upon adapter reset. + * + * Authors: + * - Christoph Goos + */ + +#include + +#if defined(CONFIG_SKTR) || defined(CONFIG_SKTR_MODULE) + +unsigned char sktr_code[] = { + 0x00, 0x00, 0x00, 0xA0, 0x00, 0x20, 0x68, 0x54, + 0x73, 0x69, 0x63, 0x20, 0x64, 0x6F, 0x20, 0x65, + 0x73, 0x69, 0x72, 0x20, 0x6C, 0x65, 0x61, 0x65, + 0x65, 0x73, 0x20, 0x64, 0x6E, 0x75, 0x65, 0x64, + 0x20, 0x72, 0x69, 0x6C, 0x65, 0x63, 0x63, 0x6E, + 0x20, 0x65, 0x6E, 0x4F, 0x79, 0x6C, 0x20, 0x2C, + 0x6C, 0x41, 0x20, 0x6C, 0x69, 0x72, 0x68, 0x67, + 0x73, 0x74, 0x72, 0x20, 0x73, 0x65, 0x72, 0x65, + 0x65, 0x76, 0x2E, 0x64, 0x60, 0x01, 0x42, 0x01, + 0x00, 0x08, 0x08, 0x16, 0xB0, 0x03, 0xE0, 0x04, + 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0xFF, 0xFF, + 0xFC, 0x13, 0x80, 0x03, 0xA0, 0x07, 0x42, 0x01, + 0x00, 0x08, 0x20, 0x07, 0x00, 0x00, 0xE0, 0x04, + 0x00, 0x01, 0x8B, 0x07, 0x00, 0x3D, 0x60, 0x01, + 0x42, 0x01, 0x80, 0x00, 0x09, 0x13, 0x8B, 0x07, + 0x00, 0x2D, 0x20, 0xC0, 0x4E, 0x01, 0x80, 0x02, + 0x41, 0x0F, 0x02, 0x11, 0x8B, 0x07, 0x00, 0x3D, + 0x0B, 0xC8, 0x4A, 0x01, 0x00, 0x02, 0x00, 0x90, + 0xA0, 0x09, 0x00, 0xC8, 0x66, 0x01, 0xE0, 0x02, + 0xA0, 0x00, 0xA0, 0x07, 0x04, 0x01, 0x20, 0x00, + 0xA0, 0x01, 0x40, 0x01, 0x00, 0xFE, 0x20, 0x48, + 0x2A, 0xE0, 0x42, 0x01, 0xE0, 0x04, 0x02, 0x01, + 0xE0, 0x04, 0x60, 0x09, 0xE0, 0x04, 0x82, 0x01, + 0x60, 0x01, 0x1C, 0x01, 0x04, 0x00, 0x03, 0x16, + 0xE0, 0x01, 0x40, 0x01, 0x00, 0x0C, 0xA0, 0x06, + 0xBC, 0xA1, 0xA0, 0x07, 0x04, 0x01, 0x2D, 0x00, + 0x20, 0xC2, 0x00, 0xE0, 0x88, 0x02, 0x11, 0xE3, + 0x14, 0x16, 0xA0, 0x07, 0x04, 0x01, 0x2E, 0x00, + 0x60, 0x01, 0x42, 0x01, 0x00, 0x03, 0x0D, 0x16, + 0xA0, 0x07, 0x04, 0x01, 0x21, 0x00, 0x88, 0x07, + 0x00, 0xA0, 0x89, 0x07, 0xFE, 0xFF, 0xA8, 0x09, + 0xA9, 0x09, 0x8A, 0x07, 0x02, 0xE0, 0xA0, 0x06, + 0x84, 0xEC, 0x56, 0x10, 0x88, 0x07, 0x00, 0x90, + 0x89, 0x07, 0xFE, 0x9F, 0xA8, 0x09, 0xA9, 0x09, + 0x8A, 0x07, 0x78, 0xE0, 0xA0, 0x06, 0x84, 0xEC, + 0x4B, 0x10, 0xA0, 0x05, 0x04, 0x01, 0x88, 0x07, + 0x08, 0x00, 0x89, 0x07, 0x7A, 0x00, 0x00, 0x03, + 0x01, 0x00, 0xA0, 0x06, 0xD2, 0xAC, 0x40, 0x10, + 0xA0, 0x06, 0xBC, 0xA1, 0xE0, 0x02, 0xF4, 0x03, + 0x88, 0x07, 0xA0, 0x00, 0x89, 0x07, 0xFE, 0x00, + 0xA0, 0x06, 0xD2, 0xAC, 0x35, 0x10, 0xE0, 0x02, + 0xA0, 0x00, 0xE0, 0x04, 0x7E, 0x01, 0xC8, 0x04, + 0x09, 0x02, 0xF2, 0x03, 0x48, 0x62, 0xE0, 0xC1, + 0x40, 0x01, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x04, + 0x18, 0xCE, 0x09, 0x06, 0xFD, 0x16, 0xA0, 0x01, + 0x40, 0x01, 0x00, 0x40, 0x07, 0xC8, 0x40, 0x01, + 0x88, 0x07, 0xF4, 0x03, 0x89, 0x07, 0xFE, 0x3F, + 0xA0, 0x06, 0xD2, 0xAC, 0x19, 0x10, 0xE0, 0x02, + 0xA0, 0x00, 0xA0, 0x06, 0xFA, 0xAD, 0x14, 0x10, + 0x08, 0xC8, 0x44, 0x04, 0x09, 0xC8, 0x46, 0x04, + 0xA0, 0x06, 0x28, 0xAD, 0x0D, 0x10, 0x81, 0x07, + 0x7C, 0xE0, 0xB1, 0xC0, 0x26, 0x13, 0x01, 0xC8, + 0xE0, 0x00, 0xA0, 0x05, 0x04, 0x01, 0x92, 0x06, + 0x03, 0x10, 0x60, 0xC0, 0xE0, 0x00, 0xF5, 0x10, + 0xE0, 0x01, 0x04, 0x01, 0x10, 0x00, 0xB0, 0x03, + 0xFF, 0x10, 0xA0, 0x01, 0x04, 0x01, 0x00, 0x80, + 0x80, 0x03, 0x80, 0x07, 0xA0, 0x00, 0xC2, 0x04, + 0x80, 0xCC, 0x81, 0x07, 0xAA, 0xA1, 0x82, 0x02, + 0x1E, 0x00, 0x02, 0x16, 0x81, 0x07, 0xB4, 0xA1, + 0x81, 0xC4, 0x81, 0x8C, 0xE9, 0x16, 0x82, 0x02, + 0x7C, 0x00, 0xF2, 0x16, 0x00, 0x03, 0x0F, 0x00, + 0x5B, 0x04, 0x81, 0x07, 0x08, 0xE1, 0x82, 0x07, + 0x04, 0x00, 0xE0, 0x04, 0x80, 0x01, 0xE0, 0x04, + 0x82, 0x01, 0x91, 0xC4, 0xB1, 0x8C, 0xD8, 0x16, + 0x82, 0x02, 0x7C, 0x00, 0xFA, 0x16, 0x20, 0xC8, + 0x04, 0xE0, 0x82, 0x01, 0x20, 0xE8, 0x0C, 0xE0, + 0x82, 0x01, 0x20, 0xC8, 0x10, 0xE0, 0x80, 0x01, + 0x81, 0x07, 0x86, 0xE0, 0xB1, 0xC0, 0x07, 0x13, + 0xB1, 0xC4, 0xFC, 0x10, 0xA0, 0x07, 0x04, 0x01, + 0x2E, 0x00, 0x60, 0x04, 0xAA, 0xA1, 0x81, 0x07, + 0x34, 0xE0, 0x82, 0x07, 0xFC, 0x05, 0x83, 0x07, + 0x0A, 0x00, 0xB1, 0xCC, 0x43, 0x06, 0xFD, 0x16, + 0x02, 0x02, 0x00, 0x06, 0x60, 0xD0, 0x4E, 0x01, + 0xED, 0x13, 0x21, 0x02, 0x00, 0xF7, 0x21, 0x02, + 0x00, 0xC0, 0x81, 0xDC, 0x60, 0xD0, 0x4F, 0x01, + 0xC1, 0xC0, 0x41, 0x09, 0x21, 0x02, 0x00, 0xF0, + 0x81, 0xDC, 0x43, 0x02, 0x00, 0x0F, 0x23, 0x02, + 0x00, 0xF0, 0x83, 0xDC, 0x01, 0x02, 0x32, 0x0C, + 0xA0, 0xC0, 0x44, 0x04, 0xE0, 0xC0, 0x46, 0x04, + 0x03, 0xC1, 0x02, 0x61, 0x84, 0x05, 0x04, 0xC8, + 0x48, 0x04, 0x03, 0xC1, 0x84, 0x05, 0x04, 0xA1, + 0x01, 0xA1, 0x04, 0xC8, 0x30, 0x0C, 0x03, 0xC1, + 0x84, 0x05, 0xF1, 0x04, 0x04, 0x06, 0xFD, 0x16, + 0x08, 0x02, 0x00, 0xA0, 0xA8, 0x09, 0x60, 0xC2, + 0x30, 0x0C, 0x29, 0x02, 0xFF, 0x03, 0xA9, 0x09, + 0x29, 0x02, 0x40, 0x00, 0x80, 0x07, 0x00, 0x90, + 0xA0, 0x09, 0x8A, 0x07, 0xFE, 0x9F, 0x2A, 0x02, + 0xFF, 0x03, 0xAA, 0x09, 0x01, 0x02, 0x32, 0x0C, + 0x05, 0x02, 0x00, 0x00, 0x03, 0xC1, 0x84, 0x05, + 0x11, 0x07, 0xC1, 0x05, 0x85, 0x05, 0x04, 0x06, + 0x0B, 0x13, 0x85, 0x80, 0xF9, 0x1A, 0x05, 0x80, + 0xF8, 0x1A, 0x85, 0x82, 0xF5, 0x1A, 0x05, 0x82, + 0xF4, 0x1A, 0x45, 0x82, 0xF1, 0x1A, 0xF1, 0x10, + 0x20, 0x2D, 0x02, 0x00, 0x60, 0x01, 0x40, 0x01, + 0x00, 0x40, 0x06, 0x16, 0x8A, 0x07, 0x00, 0x08, + 0xA0, 0x01, 0x40, 0x01, 0x00, 0x40, 0x48, 0x10, + 0x60, 0x01, 0x42, 0x01, 0x00, 0x80, 0x06, 0x16, + 0x8A, 0x07, 0x00, 0x10, 0xA0, 0x01, 0x42, 0x01, + 0x00, 0x80, 0x3E, 0x10, 0x60, 0x01, 0x02, 0x01, + 0x00, 0x10, 0x0A, 0x16, 0x60, 0x01, 0x00, 0x01, + 0x00, 0x04, 0x06, 0x16, 0x8A, 0x07, 0x00, 0x80, + 0xA0, 0x01, 0x02, 0x01, 0x00, 0x10, 0x30, 0x10, + 0x60, 0x01, 0x02, 0x01, 0x00, 0x08, 0x0A, 0x16, + 0x60, 0x01, 0x00, 0x01, 0x00, 0x04, 0x06, 0x16, + 0xA0, 0x01, 0x02, 0x01, 0x00, 0x08, 0x0D, 0x02, + 0x01, 0x00, 0x0D, 0x10, 0x60, 0x01, 0x02, 0x01, + 0x00, 0x04, 0x16, 0x16, 0x60, 0x01, 0x00, 0x01, + 0x00, 0x08, 0x12, 0x16, 0xA0, 0x01, 0x02, 0x01, + 0x00, 0x04, 0x0D, 0x02, 0x02, 0x00, 0xA0, 0xC3, + 0x0E, 0x01, 0xE0, 0xC3, 0x10, 0x01, 0x8A, 0x07, + 0x00, 0x20, 0x60, 0x01, 0x00, 0x01, 0x00, 0x80, + 0x0B, 0x13, 0x8A, 0x07, 0x00, 0x40, 0x08, 0x10, + 0x8A, 0x07, 0x04, 0x00, 0x05, 0x10, 0x8A, 0x07, + 0x02, 0x00, 0x02, 0x10, 0x8A, 0x07, 0x08, 0x00, + 0x00, 0x03, 0x00, 0x00, 0xE0, 0x04, 0x82, 0x01, + 0x8B, 0x07, 0xE0, 0x05, 0xCA, 0xCE, 0xCD, 0xCE, + 0xCE, 0xCE, 0xCF, 0xC6, 0x20, 0xC3, 0x58, 0x07, + 0x20, 0x23, 0x04, 0xE0, 0x12, 0x13, 0x8B, 0x07, + 0x18, 0xFF, 0x8A, 0x02, 0x00, 0x80, 0x0A, 0x13, + 0x8B, 0x05, 0xCD, 0xA2, 0x8A, 0x02, 0x00, 0x40, + 0x05, 0x13, 0x8A, 0x02, 0x00, 0x20, 0x02, 0x13, + 0x8B, 0x07, 0x1D, 0xFF, 0x0B, 0xC8, 0x04, 0x01, + 0x0D, 0x10, 0x20, 0xD3, 0x05, 0x01, 0xFD, 0x11, + 0x20, 0xD8, 0xDF, 0x07, 0x17, 0x01, 0x8B, 0x07, + 0x80, 0xFF, 0x0B, 0xC8, 0x04, 0x01, 0x20, 0xE8, + 0x0A, 0xE0, 0x00, 0x01, 0xE0, 0xC2, 0x04, 0x01, + 0xE0, 0x22, 0x86, 0xE1, 0xFB, 0x16, 0xE0, 0x02, + 0xA0, 0x00, 0xE0, 0x04, 0x82, 0x01, 0x20, 0xE8, + 0x0A, 0xE0, 0x00, 0x01, 0xE0, 0xC2, 0x00, 0x01, + 0xE0, 0x22, 0x06, 0xE0, 0xF8, 0x13, 0xA0, 0x01, + 0x40, 0x01, 0x00, 0xF6, 0x60, 0x04, 0x90, 0xA0, + 0x00, 0x03, 0x02, 0x00, 0xA0, 0x07, 0x02, 0x01, + 0xFF, 0xDF, 0x90, 0x03, 0xFF, 0xFF, 0x80, 0x03, + 0x00, 0x03, 0x02, 0x00, 0x09, 0x07, 0xA0, 0xC2, + 0x04, 0x01, 0x8A, 0x01, 0x80, 0x00, 0x4A, 0x52, + 0x89, 0xD2, 0x0A, 0xC8, 0x04, 0x01, 0xA0, 0xD2, + 0x04, 0x01, 0xF9, 0x16, 0x49, 0x05, 0x89, 0x01, + 0x00, 0x80, 0x49, 0x01, 0x00, 0x40, 0x0E, 0x13, + 0x09, 0xF8, 0x3A, 0x07, 0x60, 0xC2, 0x36, 0x07, + 0x03, 0x16, 0x90, 0x03, 0xFF, 0xFF, 0x80, 0x03, + 0xE0, 0x04, 0x36, 0x07, 0x54, 0x04, 0x90, 0x03, + 0xFF, 0xFF, 0x80, 0x03, 0x60, 0x22, 0x86, 0xE1, + 0xC2, 0x13, 0xE0, 0x04, 0x82, 0x01, 0x60, 0x04, + 0xE0, 0xA3, 0x00, 0x03, 0x02, 0x00, 0xA0, 0x07, + 0x62, 0x09, 0xE8, 0x03, 0xC9, 0x04, 0xA0, 0xC1, + 0x34, 0x06, 0x04, 0x16, 0xA0, 0x06, 0x50, 0xB5, + 0xE0, 0x04, 0x20, 0x09, 0x86, 0x07, 0xE8, 0x05, + 0xA0, 0x01, 0x40, 0x01, 0x00, 0x80, 0x20, 0xC2, + 0x84, 0x01, 0x20, 0x48, 0x08, 0xE0, 0x84, 0x01, + 0x20, 0x22, 0x08, 0xE0, 0x08, 0x13, 0x60, 0x01, + 0xAE, 0x01, 0x01, 0x00, 0x04, 0x16, 0xE0, 0x01, + 0x34, 0x06, 0x00, 0x80, 0x06, 0x10, 0x20, 0xC2, + 0x32, 0x09, 0x06, 0x13, 0xE0, 0x01, 0x34, 0x06, + 0x00, 0x08, 0xE0, 0x04, 0x30, 0x06, 0x09, 0x07, + 0xA0, 0x05, 0xEE, 0x05, 0x20, 0x06, 0xEC, 0x05, + 0x02, 0x16, 0x16, 0xC2, 0x03, 0x16, 0x49, 0xC2, + 0x12, 0x16, 0x80, 0x03, 0x98, 0xC5, 0xE8, 0xC1, + 0x02, 0x00, 0xE0, 0xE9, 0x14, 0xE0, 0x04, 0x00, + 0xD7, 0x04, 0x27, 0x02, 0x08, 0x00, 0xA0, 0x06, + 0xE6, 0xB4, 0x16, 0xC2, 0x04, 0x13, 0x28, 0xC8, + 0x08, 0x00, 0xEC, 0x05, 0xEF, 0x13, 0x54, 0x04, + 0x00, 0x03, 0x02, 0x00, 0xE0, 0xC1, 0x86, 0x01, + 0x47, 0x02, 0x0E, 0x00, 0xA7, 0xC2, 0x90, 0xE1, + 0x5A, 0x04, 0x8A, 0x07, 0x00, 0xA0, 0x0A, 0xC8, + 0x86, 0x01, 0xC7, 0xA1, 0x27, 0x02, 0x98, 0xE1, + 0x37, 0xE8, 0x34, 0x06, 0x17, 0xE8, 0xD2, 0x06, + 0xE0, 0x04, 0x30, 0x06, 0x60, 0x04, 0xF2, 0xA9, + 0x0A, 0xE8, 0xD2, 0x06, 0xE0, 0x01, 0x34, 0x06, + 0x00, 0x08, 0xE0, 0x04, 0x30, 0x06, 0x20, 0xE0, + 0x18, 0xE0, 0x5B, 0x04, 0xA0, 0x05, 0x20, 0x09, + 0x20, 0x88, 0x20, 0x09, 0x16, 0xE0, 0xE5, 0x1A, + 0xE0, 0x04, 0x20, 0x09, 0xA0, 0x06, 0xD0, 0xD5, + 0x80, 0x03, 0xA0, 0x05, 0x32, 0x09, 0x80, 0x03, + 0x01, 0xC3, 0xFB, 0x13, 0x60, 0x01, 0x6A, 0x09, + 0x01, 0x00, 0x78, 0x13, 0xA0, 0x05, 0x32, 0x09, + 0x75, 0x10, 0x41, 0xC0, 0x06, 0x13, 0x01, 0xC8, + 0x6C, 0x01, 0xE0, 0xC2, 0x02, 0xFC, 0x01, 0x11, + 0x7B, 0x10, 0x60, 0x01, 0x9C, 0x01, 0x40, 0x00, + 0x79, 0x16, 0x20, 0xD8, 0x2F, 0x09, 0x83, 0x01, + 0x41, 0xC0, 0x04, 0x13, 0x01, 0xC8, 0x8A, 0x01, + 0x01, 0xC8, 0x18, 0x09, 0x86, 0x07, 0x43, 0x00, + 0x06, 0xC8, 0x6C, 0x01, 0x07, 0x02, 0x02, 0xFC, + 0x17, 0xC2, 0x60, 0x04, 0xFA, 0xA6, 0xE0, 0x04, + 0x18, 0x09, 0xC7, 0x61, 0x08, 0x07, 0x60, 0x01, + 0x06, 0xFC, 0x40, 0x00, 0x02, 0x13, 0x08, 0x02, + 0x01, 0x00, 0x09, 0x10, 0x4C, 0xC2, 0x20, 0xC3, + 0x00, 0xFC, 0x2A, 0x13, 0x0C, 0xC8, 0x6C, 0x01, + 0xE0, 0xC2, 0x02, 0xFC, 0x1B, 0x11, 0x4B, 0x01, + 0x00, 0x01, 0xF4, 0x16, 0xC8, 0x22, 0x12, 0x13, + 0xCB, 0x01, 0x00, 0x40, 0x0B, 0xC8, 0x02, 0xFC, + 0x0D, 0x10, 0xE0, 0xC1, 0x18, 0x09, 0x01, 0xC3, + 0x21, 0x13, 0x4C, 0xC2, 0x15, 0x13, 0x0C, 0xC8, + 0x6C, 0x01, 0xE0, 0xC2, 0x02, 0xFC, 0x06, 0x11, + 0xCC, 0x81, 0xD5, 0x13, 0x4C, 0xC2, 0x20, 0xC3, + 0x00, 0xFC, 0xF4, 0x10, 0x09, 0xC8, 0x6C, 0x01, + 0xE0, 0xC2, 0x02, 0xFC, 0x1E, 0x16, 0xA0, 0x07, + 0x02, 0xFC, 0x00, 0x80, 0x09, 0xC3, 0x19, 0x10, + 0x09, 0xC8, 0x6C, 0x01, 0xE0, 0xC2, 0x02, 0xFC, + 0x05, 0x16, 0xA0, 0x07, 0x02, 0xFC, 0x00, 0x80, + 0x09, 0xC3, 0x0F, 0x10, 0xE0, 0xC2, 0x02, 0x0C, + 0x01, 0x11, 0x1E, 0x10, 0x20, 0xD8, 0x00, 0xE2, + 0x83, 0x01, 0x8B, 0x09, 0x8B, 0x09, 0x8B, 0x09, + 0x8B, 0x09, 0xA0, 0x07, 0x8A, 0x01, 0x43, 0x00, + 0x13, 0x10, 0x0C, 0xC8, 0x8A, 0x01, 0x0C, 0xC8, + 0x18, 0x09, 0x0E, 0x10, 0x00, 0x03, 0x02, 0x00, + 0xE0, 0xC0, 0x6C, 0x01, 0x20, 0xC3, 0x8A, 0x01, + 0x20, 0x98, 0x83, 0x01, 0x00, 0xE2, 0x81, 0x13, + 0x60, 0x01, 0x9C, 0x01, 0x40, 0x00, 0xB9, 0x13, + 0x01, 0x83, 0x31, 0x16, 0x03, 0xC8, 0x6C, 0x01, + 0x40, 0x01, 0x10, 0x00, 0x14, 0x16, 0xE0, 0xC2, + 0x2E, 0x06, 0x11, 0x13, 0xE0, 0xC2, 0xF8, 0x05, + 0x0E, 0x13, 0xE0, 0x01, 0x3A, 0x07, 0x00, 0x80, + 0x80, 0x01, 0x10, 0x00, 0xE0, 0xC2, 0x36, 0x07, + 0x06, 0x13, 0xE0, 0x04, 0x36, 0x07, 0x80, 0x01, + 0x20, 0x00, 0x60, 0x04, 0xF2, 0xA9, 0x40, 0x01, + 0x20, 0x00, 0xF9, 0x13, 0x90, 0x03, 0xFF, 0x11, + 0x80, 0x03, 0x08, 0x01, 0x00, 0x04, 0x19, 0x16, + 0x60, 0x01, 0x6A, 0x09, 0x01, 0x00, 0x15, 0x16, + 0x88, 0x01, 0x00, 0x1A, 0xC8, 0x01, 0x00, 0x01, + 0xC8, 0xC5, 0x0F, 0x10, 0xE0, 0x04, 0x18, 0x09, + 0xC0, 0x01, 0x04, 0x00, 0x15, 0x10, 0x81, 0xC1, + 0x01, 0xC8, 0x6C, 0x01, 0x07, 0x02, 0x00, 0xFC, + 0x77, 0xC0, 0x17, 0xC2, 0x48, 0x01, 0x00, 0x18, + 0xE4, 0x13, 0x40, 0x01, 0x40, 0x00, 0x15, 0x16, + 0x80, 0x01, 0x45, 0x00, 0x46, 0xC1, 0x20, 0xD0, + 0x07, 0xFC, 0x60, 0x81, 0x18, 0x09, 0xE6, 0x13, + 0xE0, 0xC2, 0x08, 0xFC, 0x08, 0x11, 0xE0, 0xC2, + 0x0E, 0xFC, 0x07, 0x15, 0x06, 0x13, 0xE0, 0xC2, + 0x14, 0xFC, 0x03, 0x15, 0x02, 0x13, 0xC0, 0x01, + 0x01, 0x00, 0x48, 0x01, 0x00, 0x01, 0x11, 0x13, + 0x40, 0x01, 0x80, 0x40, 0x69, 0x13, 0x60, 0x04, + 0x66, 0xA6, 0x48, 0x01, 0x01, 0x00, 0x03, 0x16, + 0x40, 0x01, 0x00, 0x40, 0x0B, 0x16, 0xC8, 0x01, + 0x00, 0x40, 0xA0, 0x05, 0x32, 0x09, 0xC8, 0xC5, + 0x05, 0x10, 0xC0, 0x01, 0x40, 0x00, 0x40, 0x01, + 0x04, 0x00, 0xEF, 0x13, 0xB7, 0x01, 0x20, 0x00, + 0xD7, 0xC2, 0xC4, 0x62, 0x0B, 0x05, 0x2B, 0x02, + 0xFC, 0xFF, 0xCB, 0xC5, 0x02, 0x15, 0x46, 0x81, + 0x6A, 0x13, 0x08, 0x01, 0x00, 0x5E, 0x67, 0x16, + 0x08, 0x01, 0x88, 0x00, 0x13, 0x16, 0x86, 0x02, + 0x43, 0x00, 0x25, 0x16, 0x40, 0x01, 0x00, 0x40, + 0x0B, 0x13, 0x08, 0x01, 0x03, 0x00, 0x08, 0x13, + 0x84, 0xC2, 0x2A, 0x02, 0xD8, 0xFF, 0x06, 0xC8, + 0x6C, 0x01, 0x0A, 0x68, 0x04, 0xFC, 0x73, 0x10, + 0x60, 0x04, 0xD2, 0xA8, 0x40, 0x01, 0x01, 0x00, + 0xEA, 0x13, 0x08, 0x01, 0x02, 0x00, 0xE7, 0x16, + 0x48, 0x01, 0x01, 0x00, 0xE4, 0x16, 0x40, 0x01, + 0x00, 0x40, 0x04, 0x16, 0x60, 0x01, 0xA8, 0x09, + 0x80, 0x00, 0xDD, 0x13, 0x8A, 0x07, 0x80, 0x00, + 0xA0, 0x06, 0x32, 0xA5, 0xD8, 0x10, 0x00, 0xC0, + 0xE7, 0x11, 0x60, 0xC2, 0x6A, 0x09, 0x40, 0x01, + 0x00, 0x40, 0x0A, 0x13, 0x48, 0x01, 0x01, 0x00, + 0x34, 0x13, 0x48, 0x01, 0x02, 0x00, 0x0A, 0x13, + 0x49, 0x01, 0x04, 0x00, 0xD9, 0x16, 0x06, 0x10, + 0x49, 0x01, 0x02, 0x00, 0x03, 0x13, 0x08, 0x01, + 0x03, 0x00, 0x6E, 0x13, 0x49, 0x01, 0x01, 0x00, + 0x12, 0x13, 0x40, 0x01, 0x80, 0x40, 0x01, 0x16, + 0x46, 0xC1, 0xE0, 0x04, 0x00, 0xFC, 0x87, 0x07, + 0xF8, 0x05, 0x17, 0xC2, 0x14, 0x13, 0xC7, 0x05, + 0x17, 0xC8, 0x6C, 0x01, 0x05, 0xC8, 0x00, 0xFC, + 0xC6, 0xC5, 0x60, 0x04, 0x66, 0xA6, 0x07, 0x02, + 0x02, 0xFC, 0xE0, 0xA1, 0x2C, 0x09, 0xE0, 0xCD, + 0xEE, 0x05, 0xE0, 0xC5, 0x04, 0xFC, 0x20, 0xC8, + 0x2C, 0x09, 0x04, 0xFC, 0xE2, 0x10, 0xC5, 0xCD, + 0xC6, 0xC5, 0x60, 0x04, 0x66, 0xA6, 0x60, 0x04, + 0xB6, 0xA8, 0x06, 0xC8, 0x6C, 0x01, 0x85, 0x81, + 0x1A, 0x13, 0xE0, 0xC2, 0x04, 0xFC, 0x17, 0x15, + 0x86, 0xC2, 0x8A, 0xA2, 0xAA, 0xC1, 0x32, 0x0C, + 0x06, 0xC8, 0x6C, 0x01, 0x0B, 0xA8, 0x04, 0xFC, + 0x1A, 0x09, 0x0A, 0xC8, 0x6C, 0x01, 0xE0, 0xC2, + 0x02, 0xFC, 0xE0, 0x04, 0x00, 0xFC, 0x06, 0xC8, + 0x6C, 0x01, 0x0B, 0xC8, 0x02, 0xFC, 0xA0, 0x06, + 0x3E, 0xB4, 0x06, 0xC8, 0x6C, 0x01, 0xE0, 0x04, + 0x00, 0xFC, 0xA0, 0x01, 0x02, 0xFC, 0x02, 0x00, + 0x87, 0x07, 0x30, 0x06, 0xE7, 0x01, 0x04, 0x00, + 0x40, 0x00, 0xD7, 0x04, 0x27, 0x02, 0x0C, 0x00, + 0x05, 0xC2, 0x60, 0x01, 0x6A, 0x09, 0x04, 0x00, + 0x03, 0x16, 0xE0, 0x01, 0x02, 0xFC, 0x20, 0x00, + 0xA0, 0x06, 0xFC, 0xB4, 0xC0, 0x01, 0x20, 0x00, + 0x60, 0x04, 0x66, 0xA6, 0x48, 0x01, 0x00, 0x18, + 0x03, 0x13, 0x48, 0x01, 0x00, 0x10, 0x02, 0x16, + 0xA0, 0x05, 0x32, 0x09, 0x86, 0x02, 0x43, 0x00, + 0x03, 0x13, 0x40, 0x01, 0x80, 0x40, 0x98, 0x13, + 0x06, 0xC8, 0x6C, 0x01, 0xE0, 0x04, 0x00, 0xFC, + 0x85, 0xC2, 0xA0, 0x06, 0x3E, 0xB4, 0x20, 0x06, + 0x62, 0x09, 0xE6, 0x16, 0xA0, 0x06, 0xD0, 0xD5, + 0xE3, 0x10, 0xA0, 0xC2, 0xF6, 0x05, 0x56, 0x16, + 0x19, 0xC8, 0xF0, 0x05, 0xA9, 0xC2, 0x0A, 0x00, + 0x0D, 0x11, 0xA0, 0xF2, 0x2E, 0x09, 0x0A, 0xD8, + 0x80, 0x01, 0x29, 0xC8, 0x06, 0x00, 0x8C, 0x01, + 0xA0, 0x07, 0x16, 0x09, 0x04, 0x00, 0x09, 0xC8, + 0xF4, 0x05, 0x46, 0x10, 0x29, 0xC8, 0x06, 0x00, + 0x6C, 0x01, 0x20, 0xC8, 0x0E, 0xFC, 0xBC, 0x01, + 0x20, 0xC8, 0x10, 0xFC, 0xB0, 0x01, 0x20, 0xC8, + 0x12, 0xFC, 0xB2, 0x01, 0xA0, 0xF2, 0x2E, 0x09, + 0x8A, 0x01, 0x00, 0x10, 0xA0, 0x01, 0x80, 0x01, + 0x00, 0xC4, 0xE1, 0x10, 0x47, 0x01, 0x08, 0x00, + 0x06, 0x16, 0xA8, 0xC2, 0x06, 0x00, 0xA0, 0x06, + 0x3E, 0xB4, 0xE8, 0x04, 0x06, 0x00, 0x07, 0x01, + 0x20, 0x00, 0x31, 0x13, 0xE8, 0x04, 0x02, 0x00, + 0x3B, 0x10, 0xE0, 0x04, 0x00, 0xFC, 0xA0, 0x06, + 0x3E, 0xB4, 0x29, 0x10, 0x00, 0x03, 0x02, 0x00, + 0x20, 0xC2, 0x8C, 0x01, 0xE0, 0xC0, 0x6C, 0x01, + 0x20, 0xC2, 0xF4, 0x05, 0x28, 0xC8, 0x08, 0x00, + 0x6C, 0x01, 0xE8, 0xC1, 0x0A, 0x00, 0x20, 0xC3, + 0x02, 0xFC, 0x8C, 0x01, 0x20, 0x00, 0x0C, 0xC8, + 0x02, 0xFC, 0x0C, 0x01, 0x00, 0xFE, 0x3B, 0x16, + 0x47, 0x01, 0x40, 0x00, 0x50, 0x13, 0x60, 0xC2, + 0xF0, 0x05, 0xA7, 0x16, 0xE0, 0x04, 0xF4, 0x05, + 0x0C, 0xCA, 0x08, 0x00, 0x47, 0x01, 0x80, 0x00, + 0xC9, 0x16, 0x28, 0xC8, 0x06, 0x00, 0x6C, 0x01, + 0xA0, 0xC2, 0x00, 0xFC, 0xD2, 0x16, 0xE8, 0xC1, + 0x02, 0x00, 0xD7, 0xC2, 0x0F, 0x16, 0x27, 0x02, + 0x10, 0x00, 0xD8, 0x04, 0x57, 0xC2, 0x0E, 0x13, + 0xC7, 0x05, 0x57, 0xC2, 0x48, 0xC6, 0xC8, 0xC5, + 0x03, 0xC8, 0x6C, 0x01, 0x0D, 0x11, 0x90, 0x03, + 0xFF, 0x11, 0x80, 0x03, 0xD7, 0x04, 0xC3, 0x01, + 0x00, 0x80, 0xED, 0x10, 0xE7, 0x01, 0xF4, 0xFF, + 0x20, 0x00, 0xC8, 0xCD, 0xC8, 0xC5, 0xF0, 0x10, + 0x90, 0x03, 0xF8, 0x11, 0xE0, 0x02, 0xC0, 0x00, + 0x60, 0xC3, 0xFA, 0x00, 0xA0, 0xC3, 0xFC, 0x00, + 0xE0, 0xC3, 0xFE, 0x00, 0x54, 0x04, 0xE8, 0xC2, + 0x08, 0x00, 0xA8, 0xC2, 0x06, 0x00, 0x0C, 0xC3, + 0x33, 0x11, 0x20, 0x23, 0x0A, 0xE0, 0x45, 0x13, + 0x20, 0x23, 0x10, 0xE0, 0x46, 0x13, 0x20, 0x23, + 0x0E, 0xE0, 0x13, 0x13, 0xE0, 0x21, 0x16, 0xE0, + 0xB6, 0x16, 0x20, 0x23, 0x06, 0xE0, 0x03, 0x16, + 0x20, 0x27, 0xA8, 0xE4, 0x0A, 0x13, 0xE8, 0xC2, + 0x08, 0x00, 0xA8, 0xC2, 0x06, 0x00, 0x4C, 0x01, + 0x88, 0x00, 0xA9, 0x16, 0x0C, 0x01, 0x44, 0x00, + 0xA6, 0x16, 0x20, 0x06, 0x16, 0x09, 0xA3, 0x13, + 0x0A, 0xC8, 0x6C, 0x01, 0x20, 0xC8, 0x04, 0xE0, + 0x02, 0xFC, 0x0B, 0xC8, 0x6C, 0x01, 0xA0, 0x07, + 0x02, 0xFC, 0x00, 0x81, 0x20, 0xC3, 0x80, 0x01, + 0xA0, 0x01, 0x80, 0x01, 0x00, 0xC4, 0x0C, 0xC8, + 0x80, 0x01, 0x0A, 0xC8, 0x8C, 0x01, 0xAC, 0x10, + 0x0A, 0xC2, 0x0F, 0x13, 0x08, 0xC8, 0x6C, 0x01, + 0xA0, 0xC2, 0x00, 0xFC, 0x20, 0xC3, 0x02, 0xFC, + 0x20, 0x23, 0x12, 0xE0, 0xF5, 0x16, 0x0B, 0xC8, + 0x6C, 0x01, 0x0C, 0xC8, 0x02, 0xFC, 0x60, 0x04, + 0x72, 0xA9, 0x8A, 0x07, 0x00, 0x04, 0x60, 0x04, + 0x8A, 0xA3, 0x8A, 0x07, 0x20, 0x00, 0x60, 0x04, + 0x8A, 0xA3, 0x8A, 0x07, 0x00, 0x02, 0x20, 0x27, + 0x0E, 0xE0, 0x04, 0x16, 0xA0, 0x06, 0x32, 0xA5, + 0xC3, 0x01, 0x00, 0x80, 0xA8, 0xC2, 0x06, 0x00, + 0x60, 0x04, 0x98, 0xA9, 0x00, 0x03, 0x02, 0x00, + 0xC0, 0x01, 0x10, 0x00, 0xE0, 0xC2, 0x2E, 0x06, + 0x08, 0x13, 0xE0, 0xC2, 0xF8, 0x05, 0x05, 0x13, + 0xE0, 0x01, 0x3A, 0x07, 0x00, 0x80, 0x80, 0x01, + 0x10, 0x00, 0x90, 0x03, 0xFF, 0x7F, 0x80, 0x03, + 0x00, 0x03, 0x02, 0x00, 0x20, 0xC2, 0xF6, 0x05, + 0x20, 0xE2, 0xF4, 0x05, 0x0E, 0x16, 0x20, 0xD8, + 0x2E, 0x09, 0x80, 0x01, 0x2B, 0xC8, 0x06, 0x00, + 0x8C, 0x01, 0xA0, 0x07, 0x16, 0x09, 0x04, 0x00, + 0x0B, 0xC8, 0xF4, 0x05, 0x90, 0x03, 0xFF, 0xFF, + 0x80, 0x03, 0x87, 0x07, 0xF0, 0x05, 0xDB, 0x04, + 0x57, 0xC2, 0x05, 0x16, 0xCB, 0xCD, 0xCB, 0xC5, + 0x90, 0x03, 0xFF, 0xFF, 0x80, 0x03, 0xC7, 0x05, + 0x57, 0xC2, 0x4B, 0xC6, 0xCB, 0xC5, 0x90, 0x03, + 0xFF, 0xFF, 0x80, 0x03, 0x00, 0x03, 0x02, 0x00, + 0x0B, 0xC2, 0x20, 0xC3, 0xF4, 0x05, 0x0F, 0x13, + 0xA8, 0xC2, 0x0A, 0x00, 0x4A, 0x01, 0x10, 0x00, + 0x16, 0x16, 0xA0, 0x22, 0x04, 0xE0, 0x1A, 0x16, + 0x08, 0xC3, 0xA0, 0x06, 0x36, 0xAC, 0x0C, 0xC2, + 0x20, 0xC3, 0xF4, 0x05, 0x13, 0x16, 0x68, 0x01, + 0x0A, 0x00, 0x10, 0x00, 0x03, 0x13, 0xE0, 0xC2, + 0xF6, 0x05, 0x05, 0x16, 0xA0, 0x06, 0x78, 0xAC, + 0x90, 0x03, 0xFF, 0xFF, 0x80, 0x03, 0x87, 0x07, + 0xF0, 0x05, 0xA0, 0x06, 0xE6, 0xB4, 0x90, 0x03, + 0xFF, 0xFF, 0x80, 0x03, 0x87, 0x07, 0xF0, 0x05, + 0xA0, 0x06, 0x2C, 0xB5, 0x80, 0x03, 0x00, 0x03, + 0x02, 0x00, 0x87, 0x07, 0xF0, 0x05, 0xCB, 0xC2, + 0x08, 0x16, 0xA0, 0x06, 0x36, 0xAC, 0x20, 0x07, + 0xF6, 0x05, 0x60, 0xCB, 0xF4, 0x05, 0x02, 0x00, + 0x80, 0x03, 0xE0, 0x04, 0xF6, 0x05, 0x20, 0xC2, + 0xF4, 0x05, 0x05, 0x16, 0x17, 0xC2, 0x03, 0x13, + 0xD8, 0xC5, 0xA0, 0x06, 0x78, 0xAC, 0x80, 0x03, + 0x00, 0x03, 0x02, 0x00, 0x0B, 0xC3, 0xA0, 0x06, + 0x36, 0xAC, 0x8C, 0xC2, 0xCC, 0xC1, 0x27, 0x02, + 0x10, 0x00, 0x88, 0x07, 0xF0, 0x05, 0x88, 0xC1, + 0x18, 0xC2, 0x26, 0x13, 0xA8, 0x82, 0x02, 0x00, + 0xFA, 0x16, 0xE8, 0xC2, 0x0A, 0x00, 0xE0, 0x22, + 0x1E, 0xE0, 0xF5, 0x16, 0x98, 0xC5, 0xE0, 0x22, + 0x1C, 0xE0, 0x0B, 0x16, 0x28, 0xC8, 0x06, 0x00, + 0xF4, 0x00, 0xE0, 0x02, 0xE0, 0x00, 0xA0, 0x06, + 0x3E, 0xB4, 0xE0, 0x02, 0xC0, 0x00, 0xE8, 0x04, + 0x06, 0x00, 0xE0, 0x22, 0x18, 0xE0, 0xE4, 0x13, + 0x20, 0xEA, 0x22, 0xE0, 0x0A, 0x00, 0xA0, 0xEA, + 0x18, 0xE0, 0x04, 0x00, 0xDA, 0x04, 0xA0, 0x06, + 0xE6, 0xB4, 0x47, 0x06, 0x06, 0xC2, 0xD8, 0x10, + 0x06, 0xC8, 0xF2, 0x05, 0x60, 0xCB, 0xF4, 0x05, + 0x02, 0x00, 0x54, 0x04, 0x20, 0xC2, 0xF4, 0x05, + 0x13, 0x13, 0xE0, 0x01, 0x9C, 0x01, 0x00, 0x40, + 0x8B, 0x0B, 0x8B, 0x0B, 0x60, 0x01, 0x9C, 0x01, + 0x00, 0x40, 0x0A, 0x16, 0x60, 0xC2, 0x6C, 0x01, + 0x28, 0xC8, 0x06, 0x00, 0x6C, 0x01, 0xA0, 0xC2, + 0x02, 0xFC, 0x03, 0x11, 0x09, 0xC8, 0x6C, 0x01, + 0x5B, 0x04, 0x09, 0xC8, 0x6C, 0x01, 0x4B, 0xC2, + 0x87, 0x07, 0xF0, 0x05, 0xA0, 0x06, 0x2C, 0xB5, + 0xE0, 0x04, 0xF4, 0x05, 0x59, 0x04, 0xA8, 0xC2, + 0x0A, 0x00, 0x0D, 0x11, 0xA0, 0xF2, 0x2E, 0x09, + 0x0A, 0xD8, 0x80, 0x01, 0x28, 0xC8, 0x06, 0x00, + 0x8C, 0x01, 0xA0, 0x07, 0x16, 0x09, 0x04, 0x00, + 0x08, 0xC8, 0xF4, 0x05, 0x5B, 0x04, 0x20, 0xC3, + 0x6C, 0x01, 0x28, 0xC8, 0x06, 0x00, 0x6C, 0x01, + 0x20, 0xC8, 0x0E, 0xFC, 0xBC, 0x01, 0x20, 0xC8, + 0x10, 0xFC, 0xB0, 0x01, 0x20, 0xC8, 0x12, 0xFC, + 0xB2, 0x01, 0x0C, 0xC8, 0x6C, 0x01, 0xA0, 0xF2, + 0x2E, 0x09, 0x8A, 0x01, 0x00, 0x10, 0xA0, 0x01, + 0x80, 0x01, 0x00, 0xC4, 0xDD, 0x10, 0x48, 0xC0, + 0x89, 0xC0, 0x81, 0x60, 0xC2, 0x05, 0x5B, 0x04, + 0x0B, 0xC3, 0xA0, 0x06, 0xC8, 0xAC, 0x41, 0xCC, + 0x42, 0x06, 0xFD, 0x16, 0xA0, 0x06, 0xC8, 0xAC, + 0x01, 0xC1, 0x44, 0x8C, 0x12, 0x16, 0xC4, 0x05, + 0x42, 0x06, 0xFB, 0x16, 0x04, 0x02, 0x0E, 0xAD, + 0x03, 0x02, 0x01, 0x01, 0x94, 0x06, 0x03, 0x02, + 0x5A, 0x5A, 0x94, 0x06, 0x43, 0x05, 0x94, 0x06, + 0x03, 0x07, 0x94, 0x06, 0xC3, 0x04, 0x94, 0x06, + 0xCC, 0x05, 0x5C, 0x04, 0xCB, 0xC1, 0xA0, 0x06, + 0xC8, 0xAC, 0x43, 0xCC, 0x42, 0x06, 0xFD, 0x16, + 0xA0, 0x06, 0xC8, 0xAC, 0x43, 0x8C, 0xF5, 0x16, + 0x42, 0x06, 0xFC, 0x16, 0x57, 0x04, 0x8B, 0xC2, + 0x08, 0xC0, 0x49, 0xC1, 0x85, 0x05, 0x80, 0x02, + 0x40, 0x00, 0x03, 0x11, 0x80, 0x02, 0x4F, 0x00, + 0x45, 0x12, 0x01, 0x02, 0xC8, 0xAC, 0xA1, 0x09, + 0x01, 0x80, 0x40, 0x13, 0x01, 0x02, 0xF8, 0xAD, + 0xA1, 0x09, 0x01, 0x80, 0x3B, 0x13, 0x60, 0xC0, + 0x06, 0x00, 0xA1, 0x09, 0x01, 0x80, 0x36, 0x13, + 0x81, 0x05, 0x01, 0x80, 0x33, 0x13, 0x4A, 0xC0, + 0xA1, 0x09, 0x01, 0x80, 0x2F, 0x13, 0x00, 0xC8, + 0x6A, 0x01, 0x80, 0x02, 0x80, 0x00, 0x17, 0x14, + 0x01, 0x02, 0x00, 0xF8, 0xA0, 0xC1, 0x40, 0x01, + 0xA0, 0x01, 0x40, 0x01, 0x00, 0x04, 0x02, 0x02, + 0x00, 0x10, 0x03, 0x02, 0x00, 0x04, 0xB1, 0xCC, + 0x43, 0x06, 0xFD, 0x16, 0xA0, 0x01, 0x40, 0x01, + 0x00, 0x40, 0x08, 0x02, 0x10, 0xF8, 0x06, 0xC8, + 0x40, 0x01, 0x00, 0xC0, 0x02, 0x13, 0x08, 0x02, + 0x00, 0xF8, 0x09, 0x02, 0xFE, 0xFB, 0xA0, 0x06, + 0xD2, 0xAC, 0x25, 0x10, 0x80, 0x02, 0x80, 0x00, + 0x09, 0x14, 0x01, 0x02, 0x00, 0xF8, 0x02, 0x02, + 0x00, 0x10, 0x03, 0x02, 0x00, 0x04, 0x72, 0xCC, + 0x43, 0x06, 0xFD, 0x16, 0x80, 0x05, 0x80, 0x02, + 0x80, 0x00, 0x04, 0x12, 0x60, 0x01, 0x04, 0x01, + 0x20, 0x00, 0x05, 0x13, 0x40, 0x81, 0xAB, 0x16, + 0x80, 0x02, 0x80, 0x00, 0x0B, 0x14, 0xA0, 0x07, + 0x6A, 0x01, 0x7E, 0x00, 0x02, 0x02, 0x00, 0x10, + 0x03, 0x02, 0x00, 0x04, 0xC1, 0x04, 0x81, 0xCC, + 0x43, 0x06, 0xFD, 0x16, 0xCA, 0x05, 0x5A, 0x04, + 0x00, 0x02, 0xEA, 0xAD, 0x01, 0x02, 0x1A, 0xAF, + 0x40, 0x02, 0x00, 0xFC, 0x41, 0x02, 0x00, 0xFC, + 0x40, 0x80, 0x04, 0x13, 0xA0, 0x07, 0x04, 0x01, + 0x3C, 0x00, 0x5B, 0x04, 0xC0, 0x04, 0x01, 0x02, + 0x08, 0x00, 0x02, 0x02, 0x00, 0x12, 0xE0, 0xC1, + 0x40, 0x01, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x04, + 0x03, 0x02, 0x00, 0x01, 0x00, 0xC8, 0x6A, 0x01, + 0xA0, 0xCC, 0x10, 0xF8, 0x80, 0x05, 0x03, 0x06, + 0xF9, 0x16, 0x22, 0x02, 0x00, 0x02, 0x01, 0x06, + 0xF3, 0x16, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x40, + 0x07, 0xC8, 0x40, 0x01, 0x00, 0x02, 0x00, 0x08, + 0x40, 0xC0, 0x01, 0x06, 0x01, 0xC8, 0x6A, 0x01, + 0x61, 0x02, 0x00, 0x80, 0x01, 0xC8, 0x10, 0xF8, + 0x00, 0x06, 0xF6, 0x16, 0xC0, 0x04, 0xC8, 0x04, + 0xC9, 0x04, 0x03, 0x02, 0x00, 0x08, 0x00, 0xC8, + 0x6A, 0x01, 0x80, 0xC1, 0x66, 0x02, 0x00, 0x80, + 0x20, 0xC1, 0x10, 0xF8, 0x06, 0x81, 0x15, 0x16, + 0x08, 0xC2, 0x06, 0x13, 0x80, 0x05, 0x03, 0x06, + 0xF2, 0x16, 0x08, 0xC2, 0x0D, 0x13, 0x19, 0x10, + 0xA0, 0x07, 0x10, 0xF8, 0x55, 0x55, 0x20, 0xC1, + 0x10, 0xF8, 0x84, 0x02, 0x55, 0x55, 0x02, 0x16, + 0x06, 0xC2, 0xF0, 0x10, 0x06, 0x81, 0xEE, 0x13, + 0x5B, 0x04, 0xA0, 0x07, 0x10, 0xF8, 0x55, 0x55, + 0x60, 0xC1, 0x10, 0xF8, 0x05, 0x81, 0x03, 0x13, + 0x85, 0x02, 0x55, 0x55, 0xF5, 0x16, 0x08, 0xC2, + 0xE1, 0x13, 0x40, 0xC2, 0x09, 0x06, 0x48, 0x02, + 0xFF, 0x07, 0xC0, 0x04, 0x01, 0x02, 0x08, 0x00, + 0x02, 0x02, 0x00, 0x12, 0x03, 0x02, 0x00, 0x01, + 0x00, 0xC8, 0x6A, 0x01, 0x32, 0xC8, 0x10, 0xF8, + 0x80, 0x05, 0x03, 0x06, 0xF9, 0x16, 0x22, 0x02, + 0x00, 0x02, 0x01, 0x06, 0xF3, 0x16, 0x88, 0x02, + 0x40, 0x00, 0x13, 0x15, 0x89, 0x02, 0x4F, 0x00, + 0x10, 0x11, 0xC0, 0x04, 0x02, 0x02, 0x00, 0x12, + 0x01, 0x02, 0x08, 0x00, 0x03, 0x02, 0x00, 0x01, + 0x80, 0xCC, 0x03, 0x06, 0xFD, 0x16, 0x22, 0x02, + 0x00, 0x02, 0x01, 0x06, 0xF7, 0x16, 0xCB, 0x05, + 0x5B, 0x04, 0xA0, 0x07, 0x04, 0x01, 0x37, 0x00, + 0x5B, 0x04, 0x33, 0x07, 0x33, 0x07, 0x0C, 0x10, + 0x13, 0x07, 0x23, 0x07, 0x02, 0x00, 0xCB, 0xC8, + 0x06, 0x00, 0x23, 0x02, 0x18, 0x00, 0xE0, 0xCC, + 0x6C, 0x01, 0xCD, 0xCC, 0xCE, 0xCC, 0xCF, 0xCC, + 0x83, 0x07, 0x30, 0x06, 0xD3, 0xC1, 0x0A, 0x13, + 0x83, 0x07, 0x36, 0x07, 0xD3, 0xC1, 0x06, 0x13, + 0x83, 0x07, 0xA0, 0x00, 0x93, 0x00, 0x0C, 0xC8, + 0x6C, 0x01, 0x80, 0x03, 0x63, 0x07, 0x02, 0x00, + 0x2A, 0x15, 0x63, 0xC2, 0x04, 0x00, 0x63, 0x42, + 0x06, 0x00, 0xDB, 0x13, 0x63, 0xC3, 0x1A, 0x00, + 0x49, 0xD2, 0x0C, 0x13, 0xC9, 0x06, 0x49, 0x72, + 0x69, 0xD2, 0xC0, 0xE1, 0xC9, 0x06, 0x49, 0x72, + 0xE9, 0x48, 0x04, 0xE0, 0x04, 0x00, 0x49, 0xCB, + 0x02, 0x00, 0x52, 0x04, 0x69, 0xC2, 0xC0, 0xE1, + 0x49, 0x72, 0x29, 0x02, 0x10, 0x00, 0xC3, 0xC2, + 0xE9, 0xA2, 0xA8, 0xE1, 0x1B, 0xC3, 0x89, 0x02, + 0x12, 0x00, 0x0F, 0x13, 0xDC, 0xC6, 0x03, 0x16, + 0xE9, 0x48, 0x04, 0xE0, 0x04, 0x00, 0x49, 0xCB, + 0x02, 0x00, 0x4C, 0xCB, 0x04, 0x00, 0x90, 0x03, + 0xFF, 0x01, 0x93, 0x00, 0x0C, 0xC8, 0x6C, 0x01, + 0x80, 0x03, 0x0C, 0xC8, 0x6C, 0x01, 0xE0, 0xC6, + 0x00, 0xFC, 0xF1, 0x16, 0xE9, 0x48, 0x04, 0xE0, + 0x04, 0x00, 0x49, 0xCB, 0x02, 0x00, 0x4C, 0xCB, + 0x04, 0x00, 0xED, 0x10, 0x00, 0x03, 0x02, 0x00, + 0xDB, 0xC2, 0x63, 0xC2, 0x04, 0x00, 0x4B, 0x42, + 0x9F, 0x13, 0x49, 0xD2, 0x0E, 0x13, 0xC9, 0x06, + 0x49, 0x72, 0x69, 0xD2, 0xC0, 0xE1, 0xC9, 0x06, + 0x49, 0x72, 0xE9, 0x48, 0x04, 0xE0, 0x04, 0x00, + 0x49, 0xCB, 0x02, 0x00, 0x90, 0x03, 0xFF, 0xFF, + 0x80, 0x03, 0x69, 0xC2, 0xC0, 0xE1, 0x49, 0x72, + 0x29, 0x02, 0x10, 0x00, 0xC3, 0xC2, 0xE9, 0xA2, + 0xA8, 0xE1, 0x1B, 0xC3, 0x89, 0x02, 0x12, 0x00, + 0x0C, 0x13, 0xDC, 0xC6, 0x03, 0x16, 0xE9, 0x48, + 0x04, 0xE0, 0x04, 0x00, 0x49, 0xCB, 0x02, 0x00, + 0x4C, 0xCB, 0x04, 0x00, 0x90, 0x03, 0xFF, 0xFF, + 0x80, 0x03, 0x0C, 0xC8, 0x6C, 0x01, 0xE0, 0xC6, + 0x00, 0xFC, 0xF4, 0x16, 0xF0, 0x10, 0x00, 0x03, + 0x02, 0x00, 0xBB, 0xC2, 0xBB, 0xC1, 0x86, 0xD1, + 0x03, 0x13, 0x86, 0xEA, 0x04, 0x00, 0x13, 0x10, + 0xA6, 0xD1, 0xC0, 0xE1, 0xC6, 0x06, 0x86, 0x71, + 0xCA, 0xC1, 0xE6, 0xA1, 0xB8, 0xE1, 0xA6, 0xEA, + 0x14, 0xE0, 0x04, 0x00, 0x1B, 0xC2, 0x86, 0x02, + 0x02, 0x00, 0x03, 0x16, 0xA0, 0x06, 0x0C, 0xB5, + 0x02, 0x10, 0xA0, 0x06, 0xE6, 0xB4, 0xDA, 0x04, + 0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 0xAB, 0xC2, + 0x06, 0x00, 0x8C, 0x07, 0xE8, 0x05, 0x5C, 0xC2, + 0x16, 0x13, 0xA0, 0xC1, 0xEC, 0x05, 0x8A, 0x81, + 0x1A, 0x1A, 0xC6, 0xC1, 0x09, 0xC2, 0x59, 0xC2, + 0x20, 0x13, 0xE9, 0xA1, 0x08, 0x00, 0x87, 0x82, + 0xF9, 0x12, 0xA9, 0xA2, 0x08, 0x00, 0x87, 0x62, + 0xCA, 0xCA, 0x08, 0x00, 0x4A, 0x6A, 0x08, 0x00, + 0xC9, 0xC6, 0x0B, 0xC6, 0x80, 0x03, 0xCA, 0xCA, + 0x08, 0x00, 0x0A, 0xC8, 0xEC, 0x05, 0xDB, 0x04, + 0x0B, 0xCF, 0x0B, 0xC7, 0x80, 0x03, 0x8A, 0x61, + 0x46, 0xCA, 0x08, 0x00, 0xCA, 0xCA, 0x08, 0x00, + 0x0A, 0xC8, 0xEC, 0x05, 0xC9, 0xC6, 0x0B, 0xC7, + 0x80, 0x03, 0x87, 0x62, 0xCA, 0xCA, 0x08, 0x00, + 0xDB, 0x04, 0x0B, 0xC6, 0x0B, 0xCB, 0x02, 0x00, + 0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 0xBB, 0xC1, + 0xDB, 0xC2, 0x8C, 0x07, 0xE8, 0x05, 0x4C, 0xC2, + 0xED, 0x04, 0x02, 0x00, 0x09, 0xC2, 0x59, 0xC2, + 0x18, 0x13, 0xA9, 0x81, 0x02, 0x00, 0xFA, 0x16, + 0xE9, 0x82, 0x04, 0x00, 0xF7, 0x16, 0x49, 0xCB, + 0x04, 0x00, 0x99, 0xC2, 0x0A, 0xC6, 0x0A, 0x13, + 0x08, 0x83, 0x04, 0x13, 0xA9, 0xAA, 0x08, 0x00, + 0x08, 0x00, 0x80, 0x03, 0x2A, 0xA8, 0x08, 0x00, + 0xEC, 0x05, 0x80, 0x03, 0x08, 0xCB, 0x02, 0x00, + 0x80, 0x03, 0x2D, 0x07, 0x02, 0x00, 0x8C, 0x07, + 0x08, 0x00, 0x06, 0xA3, 0x4C, 0xC2, 0x09, 0xC2, + 0x59, 0xC2, 0x13, 0x13, 0xE9, 0x82, 0x04, 0x00, + 0xFA, 0x16, 0xAD, 0x07, 0x02, 0x00, 0x01, 0x00, + 0x49, 0xCB, 0x04, 0x00, 0x19, 0xC6, 0x01, 0x13, + 0x80, 0x03, 0x08, 0x83, 0x04, 0x16, 0xA0, 0x49, + 0x14, 0xE0, 0x04, 0x00, 0x80, 0x03, 0x08, 0xCB, + 0x02, 0x00, 0x80, 0x03, 0x00, 0x03, 0x02, 0x00, + 0x0B, 0x06, 0x1F, 0x11, 0x4D, 0x13, 0x8B, 0x07, + 0x00, 0x4E, 0x60, 0x01, 0x42, 0x01, 0x80, 0x00, + 0x09, 0x13, 0x8B, 0x07, 0x00, 0x3A, 0x20, 0xC1, + 0x4E, 0x01, 0x84, 0x02, 0x41, 0x0F, 0x02, 0x11, + 0x8B, 0x07, 0x00, 0x4E, 0x0B, 0xC8, 0x44, 0x01, + 0xA0, 0x07, 0x62, 0x09, 0xE8, 0x03, 0xE0, 0x01, + 0x40, 0x01, 0x00, 0x02, 0xE0, 0x01, 0x40, 0x01, + 0x00, 0x20, 0x84, 0x07, 0x34, 0xAF, 0x60, 0x04, + 0x42, 0xAF, 0x20, 0xC8, 0x16, 0xE0, 0xE0, 0x00, + 0xE0, 0xC2, 0x6A, 0x09, 0xE0, 0x22, 0x10, 0xE0, + 0x03, 0x13, 0x20, 0xE8, 0x14, 0xE0, 0xE0, 0x00, + 0x20, 0xC8, 0x04, 0xE0, 0x82, 0x01, 0x20, 0xC8, + 0xE2, 0x00, 0x8A, 0x01, 0xE0, 0x04, 0x18, 0x09, + 0xE0, 0x04, 0xF4, 0x05, 0xE0, 0x04, 0xF8, 0x05, + 0xE0, 0x04, 0xF0, 0x05, 0xE0, 0x04, 0x42, 0x07, + 0xA0, 0x07, 0x88, 0x01, 0x20, 0x00, 0xE0, 0xC2, + 0x30, 0x09, 0x09, 0x13, 0xA0, 0x07, 0x88, 0x01, + 0x80, 0x00, 0x20, 0xE8, 0x16, 0xE0, 0x80, 0x01, + 0xE0, 0x01, 0x82, 0x01, 0x00, 0x03, 0x8B, 0x07, + 0x00, 0xA0, 0x0B, 0xE8, 0x86, 0x01, 0x80, 0x03, + 0xE0, 0x04, 0x86, 0x01, 0xE0, 0x01, 0x9C, 0x01, + 0x40, 0x00, 0xE0, 0x01, 0x9C, 0x01, 0x00, 0x40, + 0xCB, 0x04, 0xB0, 0x03, 0x0B, 0x06, 0x04, 0x13, + 0x60, 0x01, 0x9C, 0x01, 0x00, 0x40, 0xF9, 0x16, + 0xE0, 0x04, 0x82, 0x01, 0x20, 0xE8, 0x08, 0xE0, + 0x6A, 0x09, 0x8B, 0x07, 0x00, 0x80, 0x0B, 0xC8, + 0x98, 0x07, 0x0B, 0xC8, 0x78, 0x07, 0x20, 0xC8, + 0x04, 0xE0, 0x82, 0x01, 0x8B, 0x07, 0x6F, 0x87, + 0x0B, 0x48, 0x3A, 0x07, 0xE0, 0xC2, 0x50, 0x07, + 0x8B, 0x02, 0x58, 0x07, 0x10, 0x13, 0x20, 0xE8, + 0x0A, 0xE0, 0x00, 0x01, 0xE0, 0xC2, 0x00, 0x01, + 0xE0, 0x22, 0x06, 0xE0, 0xF8, 0x13, 0x8B, 0x07, + 0x58, 0x07, 0x0B, 0xC8, 0x50, 0x07, 0x8B, 0x07, + 0x0C, 0xB8, 0x0B, 0xC8, 0x52, 0x07, 0x80, 0x03, + 0x00, 0x03, 0x02, 0x00, 0xE0, 0xC2, 0x1A, 0x09, + 0x0C, 0x13, 0x20, 0x06, 0x1C, 0x09, 0x0B, 0xC8, + 0x6C, 0x01, 0x20, 0xC8, 0x00, 0xFC, 0x1A, 0x09, + 0x4B, 0xCB, 0x02, 0x00, 0x90, 0x03, 0xFF, 0xFF, + 0x80, 0x03, 0x41, 0xC0, 0x0F, 0x13, 0x81, 0x80, + 0x0D, 0x13, 0x82, 0xA0, 0xE2, 0xC2, 0x32, 0x0C, + 0x12, 0x09, 0x0B, 0xC8, 0x6C, 0x01, 0xE0, 0x04, + 0x00, 0xFC, 0x20, 0xC3, 0x02, 0xFC, 0x07, 0x11, + 0x02, 0xC8, 0x00, 0xFC, 0xED, 0x04, 0x02, 0x00, + 0xE0, 0x04, 0x6C, 0x01, 0x80, 0x03, 0x42, 0xCB, + 0x02, 0x00, 0x02, 0xC8, 0x6C, 0x01, 0x8B, 0xC0, + 0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 0x83, 0x07, + 0x00, 0x80, 0x60, 0xC2, 0x7E, 0x09, 0x09, 0xC1, + 0x24, 0x02, 0xF8, 0xFF, 0xA9, 0x08, 0x01, 0x02, + 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x0B, 0x02, + 0x00, 0x00, 0x0C, 0x02, 0x00, 0x00, 0x07, 0x02, + 0x00, 0x00, 0x2C, 0xCB, 0x32, 0x0C, 0x32, 0x0C, + 0x06, 0x13, 0x8B, 0x05, 0xCC, 0x05, 0x0B, 0x88, + 0x46, 0x04, 0x27, 0x1B, 0xF6, 0x10, 0x09, 0xC2, + 0x8B, 0xC2, 0x08, 0x06, 0x0A, 0x13, 0x8B, 0x05, + 0xCC, 0x05, 0x0B, 0x88, 0x46, 0x04, 0x1D, 0x1B, + 0x2C, 0xCB, 0x32, 0x0C, 0x32, 0x0C, 0xED, 0x16, + 0xF4, 0x10, 0x82, 0xC0, 0x14, 0x13, 0x02, 0xC8, + 0x6C, 0x01, 0x0A, 0xC8, 0x00, 0xFC, 0x0A, 0xC8, + 0x6C, 0x01, 0xE0, 0x04, 0x00, 0xFC, 0xA0, 0x07, + 0x02, 0xFC, 0x00, 0x80, 0x04, 0xC8, 0x04, 0xFC, + 0x0A, 0xC2, 0x08, 0xA2, 0x02, 0xCA, 0x32, 0x0C, + 0x8A, 0xC0, 0x87, 0x05, 0xD6, 0x10, 0x4A, 0xC0, + 0xEE, 0x10, 0x47, 0xCB, 0x02, 0x00, 0xE0, 0x04, + 0x6C, 0x01, 0x8B, 0x07, 0x43, 0x00, 0xE0, 0x04, + 0x00, 0x0C, 0x00, 0x03, 0x02, 0x00, 0x0B, 0xC8, + 0x6C, 0x01, 0x8B, 0x02, 0x43, 0x00, 0x04, 0x13, + 0x60, 0x01, 0x02, 0xFC, 0x20, 0x00, 0x06, 0x13, + 0x8B, 0xC2, 0xA0, 0x06, 0x42, 0xB4, 0x90, 0x03, + 0x7F, 0x00, 0x80, 0x03, 0xA0, 0x01, 0x02, 0xFC, + 0x20, 0x00, 0x60, 0x01, 0x6A, 0x09, 0x01, 0x00, + 0x0B, 0x16, 0x0A, 0x02, 0x02, 0xFC, 0xA0, 0xA2, + 0x2C, 0x09, 0xA0, 0xCE, 0xEE, 0x05, 0xA0, 0xC6, + 0x04, 0xFC, 0x20, 0xC8, 0x2C, 0x09, 0x04, 0xFC, + 0x8A, 0x07, 0xF8, 0x05, 0x5A, 0xC2, 0x08, 0x13, + 0xCA, 0x05, 0x5A, 0xC2, 0x09, 0xC8, 0x6C, 0x01, + 0x0B, 0xC8, 0x00, 0xFC, 0x8B, 0xC6, 0x02, 0x10, + 0x8B, 0xCE, 0x8B, 0xC6, 0x20, 0x20, 0x1A, 0xE0, + 0x05, 0x16, 0x20, 0xE8, 0x04, 0xE0, 0x3A, 0x07, + 0xE0, 0x04, 0x36, 0x07, 0x90, 0x03, 0x7F, 0x00, + 0x80, 0x03, 0x00, 0x03, 0x02, 0x00, 0x0B, 0xC8, + 0x6C, 0x01, 0xCC, 0x04, 0xE0, 0x04, 0x00, 0xFC, + 0x8B, 0xC2, 0xA0, 0x06, 0x50, 0xB4, 0x90, 0x03, + 0x7F, 0x00, 0x80, 0x03, 0xA0, 0x07, 0x02, 0xFC, + 0x00, 0x80, 0x20, 0xC8, 0x8C, 0xE1, 0x04, 0xFC, + 0x41, 0xC0, 0x0F, 0x16, 0x20, 0xD8, 0x00, 0xE2, + 0x83, 0x01, 0x8B, 0x0B, 0x8B, 0x0B, 0x8B, 0x0B, + 0x8B, 0x0B, 0x8B, 0x0B, 0x8B, 0x0B, 0x8B, 0x0B, + 0x8B, 0x0B, 0x8B, 0x0B, 0x8B, 0x0B, 0x0A, 0xC8, + 0x8A, 0x01, 0x5B, 0x04, 0x0A, 0xC8, 0x6C, 0x01, + 0x20, 0xC3, 0x00, 0xFC, 0xE0, 0x04, 0x00, 0xFC, + 0x8A, 0x02, 0x43, 0x00, 0xDF, 0x13, 0xA0, 0x07, + 0x02, 0xFC, 0x00, 0x80, 0x04, 0xC8, 0x04, 0xFC, + 0x20, 0x98, 0x84, 0x09, 0x1D, 0x09, 0x0A, 0x13, + 0x20, 0xC8, 0x1A, 0x09, 0x00, 0xFC, 0x0A, 0xC8, + 0x1A, 0x09, 0xA0, 0x05, 0x1C, 0x09, 0x8C, 0xC2, + 0xE5, 0x16, 0x5B, 0x04, 0x41, 0xC0, 0x10, 0x13, + 0x8A, 0xA2, 0x82, 0xCA, 0x32, 0x0C, 0x1A, 0x09, + 0x02, 0xC8, 0x6C, 0x01, 0x0A, 0xC8, 0x00, 0xFC, + 0x8A, 0xC0, 0x20, 0x98, 0x83, 0x01, 0x00, 0xE2, + 0x09, 0x13, 0x8C, 0xC2, 0xD3, 0x16, 0x5B, 0x04, + 0x4A, 0xC0, 0x8A, 0xC0, 0x20, 0x98, 0x83, 0x01, + 0x00, 0xE2, 0x1B, 0x16, 0xE0, 0x01, 0x9C, 0x01, + 0x40, 0x00, 0xA0, 0x07, 0x64, 0x09, 0x00, 0x70, + 0x60, 0x01, 0x9C, 0x01, 0x40, 0x00, 0x07, 0x13, + 0x20, 0x06, 0x64, 0x09, 0xF9, 0x16, 0x0A, 0x02, + 0x00, 0x01, 0x60, 0x04, 0x8A, 0xA3, 0x60, 0x01, + 0x02, 0x0C, 0x00, 0x01, 0xE2, 0x13, 0x20, 0xD8, + 0x2F, 0x09, 0x83, 0x01, 0xA0, 0x07, 0x02, 0x0C, + 0x00, 0x80, 0x0A, 0xC8, 0x8A, 0x01, 0x0A, 0xC8, + 0x18, 0x09, 0xD7, 0x10, 0xD8, 0x04, 0x57, 0xC2, + 0x03, 0x16, 0xC8, 0xCD, 0xC8, 0xC5, 0x5B, 0x04, + 0xC7, 0x05, 0x57, 0xC2, 0x48, 0xC6, 0xC8, 0xC5, + 0x5B, 0x04, 0x08, 0xC8, 0x6C, 0x01, 0x08, 0xA2, + 0x20, 0xCA, 0x00, 0xFC, 0x32, 0x0C, 0x18, 0x09, + 0x02, 0x10, 0x08, 0xC8, 0x6C, 0x01, 0xE0, 0x04, + 0x00, 0xFC, 0x57, 0xC2, 0x03, 0x16, 0xC8, 0xCD, + 0xC8, 0xC5, 0x5B, 0x04, 0xC7, 0x05, 0x17, 0xC8, + 0x6C, 0x01, 0x08, 0xC8, 0x00, 0xFC, 0xC8, 0xC5, + 0x5B, 0x04, 0x17, 0xC6, 0x02, 0x16, 0xC8, 0xC9, + 0x02, 0x00, 0xC8, 0xC5, 0x5B, 0x04, 0x17, 0xC2, + 0x08, 0xC8, 0x6C, 0x01, 0x07, 0x13, 0xE0, 0xC5, + 0x00, 0xFC, 0x08, 0xA2, 0x28, 0xC8, 0x32, 0x0C, + 0x00, 0xFC, 0x18, 0x09, 0x5B, 0x04, 0x60, 0x01, + 0x82, 0x01, 0x00, 0x20, 0x0A, 0x16, 0x60, 0xC2, + 0x84, 0x01, 0xA0, 0x01, 0x82, 0x01, 0x00, 0x20, + 0xE0, 0x01, 0x82, 0x01, 0x00, 0x20, 0x09, 0xC8, + 0x84, 0x01, 0xC9, 0x04, 0x5B, 0x04, 0xA0, 0x06, + 0xBE, 0xB7, 0xD3, 0x04, 0xE0, 0x04, 0x02, 0x01, + 0x20, 0xE8, 0x14, 0xE0, 0x00, 0x01, 0x20, 0xC8, + 0x16, 0xE0, 0x04, 0x01, 0x05, 0x2C, 0x20, 0x48, + 0x14, 0xE0, 0x00, 0x01, 0x8C, 0x07, 0x00, 0x0A, + 0x8D, 0x07, 0xD8, 0x07, 0x8E, 0x07, 0x18, 0x00, + 0x7C, 0xCF, 0x4E, 0x06, 0xFD, 0x16, 0xE0, 0x02, + 0xD8, 0x07, 0x8F, 0x07, 0x11, 0xFF, 0x8B, 0x02, + 0x3B, 0x59, 0x21, 0x16, 0x8A, 0x02, 0x3B, 0x59, + 0x1E, 0x13, 0x8F, 0x05, 0x20, 0x20, 0x16, 0xE0, + 0x01, 0x16, 0x19, 0x10, 0x20, 0x20, 0x04, 0xE0, + 0x16, 0x16, 0x00, 0x01, 0xBF, 0x00, 0x13, 0x16, + 0x8B, 0x07, 0xC0, 0x40, 0x00, 0x01, 0x00, 0x60, + 0x10, 0x13, 0x40, 0x01, 0x00, 0x60, 0x0B, 0x16, + 0x8B, 0x07, 0xC4, 0x44, 0xA0, 0xC3, 0x02, 0x01, + 0x0E, 0x48, 0x02, 0x01, 0x4E, 0x01, 0x00, 0x10, + 0x04, 0x16, 0x8F, 0x07, 0x18, 0xFF, 0x60, 0x04, + 0x94, 0xB7, 0x0B, 0xC3, 0x4B, 0xC3, 0x20, 0x20, + 0x0A, 0xE0, 0x02, 0x16, 0x6B, 0x02, 0x20, 0x20, + 0x20, 0x20, 0x0C, 0xE0, 0x02, 0x16, 0x6C, 0x02, + 0x00, 0x20, 0x20, 0x20, 0x0E, 0xE0, 0x02, 0x16, + 0x6C, 0x02, 0x20, 0x00, 0x8F, 0x05, 0x20, 0x20, + 0x10, 0xE0, 0x07, 0x16, 0x6D, 0x02, 0x20, 0x00, + 0x20, 0x21, 0x22, 0xE0, 0xE4, 0x13, 0x04, 0xC1, + 0x02, 0x16, 0x84, 0x07, 0xFE, 0x7F, 0x8F, 0x05, + 0x20, 0x20, 0x12, 0xE0, 0x02, 0x16, 0x6D, 0x02, + 0x00, 0x20, 0x60, 0x21, 0x22, 0xE0, 0xD7, 0x13, + 0x45, 0xC1, 0x02, 0x16, 0x85, 0x07, 0xFE, 0x7F, + 0x8F, 0x05, 0x86, 0xD1, 0x0B, 0x13, 0xA0, 0x25, + 0x26, 0xE0, 0x08, 0x13, 0x8F, 0x05, 0x20, 0x26, + 0x22, 0xE0, 0x04, 0x16, 0x8F, 0x05, 0xA0, 0x26, + 0x22, 0xE0, 0x02, 0x13, 0x60, 0x04, 0x94, 0xB7, + 0x01, 0xD8, 0xEC, 0x08, 0x20, 0xD8, 0xDB, 0x07, + 0x00, 0x09, 0x02, 0xD8, 0xF6, 0x08, 0x20, 0xD8, + 0xDD, 0x07, 0xE2, 0x08, 0xE0, 0x02, 0x58, 0x07, + 0x20, 0xD8, 0xEF, 0x07, 0xF4, 0x07, 0x20, 0xD8, + 0xF1, 0x07, 0xF6, 0x07, 0x20, 0xD8, 0xF3, 0x07, + 0xF8, 0x07, 0x09, 0x02, 0x06, 0x00, 0xCB, 0x04, + 0x0F, 0x02, 0xEE, 0x07, 0x8F, 0x05, 0xCB, 0xDF, + 0x09, 0x06, 0xFC, 0x16, 0xA0, 0x06, 0xBE, 0xB7, + 0x89, 0x07, 0x5C, 0xE3, 0xE0, 0x04, 0x1A, 0x01, + 0x20, 0xC8, 0xE4, 0x07, 0x18, 0x01, 0x19, 0xC8, + 0x0C, 0x01, 0x39, 0xC8, 0x0A, 0x01, 0x39, 0xC8, + 0x12, 0x01, 0x09, 0x16, 0x79, 0xC3, 0x0F, 0x02, + 0x00, 0xE0, 0x4F, 0x63, 0x2D, 0x02, 0x00, 0x90, + 0x0D, 0xC8, 0x14, 0x01, 0x02, 0x10, 0x39, 0xC8, + 0x14, 0x01, 0xF9, 0xC3, 0x3F, 0xC8, 0x0E, 0x01, + 0x1F, 0xC8, 0x10, 0x01, 0xE0, 0x04, 0x14, 0x09, + 0xB9, 0xC2, 0x1A, 0xC8, 0x00, 0x01, 0x96, 0x06, + 0x89, 0x02, 0x84, 0xE3, 0xE0, 0x16, 0x8F, 0x07, + 0x1C, 0xFF, 0x8C, 0x07, 0x00, 0x0A, 0x8D, 0x07, + 0x84, 0xE3, 0x8E, 0x07, 0x10, 0x00, 0x7C, 0x8F, + 0x44, 0x16, 0x4E, 0x06, 0xFC, 0x16, 0xA0, 0xC3, + 0xE2, 0x07, 0xE0, 0xC3, 0xE0, 0x07, 0xCE, 0x83, + 0x01, 0x14, 0xCE, 0xC3, 0x0F, 0xC8, 0x1A, 0x01, + 0x8C, 0x07, 0x94, 0xE3, 0x8D, 0x07, 0x00, 0x0A, + 0x8E, 0x07, 0xA4, 0xE3, 0x8C, 0x63, 0x7C, 0xCF, + 0x4E, 0x06, 0xFD, 0x16, 0xE0, 0x04, 0x30, 0x09, + 0x20, 0x01, 0x42, 0x01, 0x00, 0x04, 0x02, 0x16, + 0x20, 0x07, 0x30, 0x09, 0x60, 0xC2, 0x62, 0x01, + 0xE0, 0x04, 0x62, 0x01, 0x8E, 0x07, 0x00, 0x80, + 0x8C, 0x07, 0x34, 0x09, 0x8D, 0x07, 0x06, 0x00, + 0x3E, 0xDF, 0x8E, 0x05, 0x0D, 0x06, 0xFC, 0x16, + 0xFE, 0xD3, 0xCF, 0x06, 0x8E, 0x05, 0xFE, 0xD3, + 0xCF, 0x06, 0x8C, 0x07, 0x34, 0x09, 0x09, 0xC8, + 0x62, 0x01, 0xC9, 0x04, 0x5C, 0xA3, 0x7C, 0xE2, + 0x5C, 0xA3, 0x7C, 0xE2, 0x5C, 0xA3, 0x7C, 0xE2, + 0x02, 0x13, 0xCD, 0x83, 0x09, 0x13, 0x20, 0x07, + 0x34, 0x09, 0x06, 0x10, 0x8F, 0x07, 0x19, 0xFF, + 0xCD, 0xA3, 0x0F, 0xC8, 0x04, 0x01, 0xFF, 0x10, + 0xA0, 0x01, 0x02, 0x01, 0x00, 0x10, 0xE0, 0xC3, + 0xEE, 0x07, 0xE0, 0x43, 0x06, 0xE0, 0x0F, 0xC8, + 0x00, 0x01, 0x20, 0xC0, 0x04, 0xE0, 0xE0, 0x04, + 0xFE, 0x06, 0xD3, 0x04, 0xE0, 0x04, 0x04, 0x01, + 0x60, 0x04, 0x0C, 0xB8, 0x8C, 0x07, 0x00, 0x0A, + 0x8D, 0x07, 0x18, 0x00, 0x8E, 0x07, 0x3B, 0x59, + 0x0E, 0xCF, 0x4D, 0x06, 0xFD, 0x16, 0x5B, 0x04, + 0x93, 0x01, 0x00, 0x80, 0x20, 0x04, 0xC0, 0xE2, + 0x60, 0xD0, 0x98, 0x07, 0x1C, 0x13, 0x00, 0x03, + 0x02, 0x00, 0xA0, 0xC0, 0x46, 0x07, 0x12, 0xC8, + 0x46, 0x07, 0x02, 0x16, 0x93, 0x01, 0x20, 0x00, + 0x00, 0x03, 0x0F, 0x00, 0x20, 0x04, 0xE8, 0xE2, + 0x93, 0x01, 0x00, 0x20, 0x80, 0x01, 0x00, 0x40, + 0x00, 0x01, 0xFE, 0x00, 0x49, 0x16, 0xC4, 0xC3, + 0x25, 0x16, 0xD3, 0xC3, 0xC5, 0x43, 0x0C, 0x16, + 0xE0, 0xC3, 0x98, 0x07, 0x03, 0x11, 0xE0, 0x02, + 0x98, 0x07, 0x51, 0x04, 0xE0, 0xC3, 0x78, 0x07, + 0x0A, 0x11, 0xE0, 0x02, 0x78, 0x07, 0x51, 0x04, + 0xD3, 0x11, 0x4F, 0x01, 0x00, 0x20, 0xE4, 0x13, + 0x4F, 0x01, 0x20, 0x00, 0xD1, 0x13, 0x05, 0x2C, + 0x41, 0xA0, 0x21, 0x04, 0xC0, 0xE2, 0x8B, 0x07, + 0x0C, 0xB8, 0x00, 0x01, 0x00, 0x40, 0x0F, 0x13, + 0xDD, 0xC3, 0x4F, 0x02, 0x0F, 0x00, 0x2F, 0xE1, + 0x14, 0xE0, 0x5B, 0x04, 0xE4, 0xC3, 0xC0, 0xE1, + 0xCF, 0x73, 0x2F, 0x41, 0x14, 0xE0, 0x6F, 0xC3, + 0xEC, 0xEA, 0x8B, 0x07, 0x0C, 0xB8, 0x4B, 0xC2, + 0xA0, 0xC2, 0xF4, 0x07, 0x8C, 0x07, 0x08, 0x00, + 0xBD, 0xC0, 0xA0, 0xC3, 0xEA, 0x07, 0xE0, 0xC3, + 0xEC, 0x07, 0xA0, 0x06, 0x00, 0xBA, 0xC0, 0x01, + 0x00, 0x40, 0x02, 0xD8, 0x17, 0x01, 0x62, 0x02, + 0x80, 0xFF, 0xA0, 0x06, 0x54, 0xBA, 0x02, 0xC8, + 0x04, 0x01, 0x90, 0x03, 0x3F, 0x60, 0x59, 0x04, + 0xC0, 0xC3, 0xCF, 0x73, 0xEF, 0xC3, 0xC0, 0xE1, + 0xCF, 0x73, 0xAF, 0xC3, 0xDE, 0xEA, 0x9E, 0xC3, + 0x4E, 0x02, 0x0F, 0x00, 0x2E, 0x21, 0x14, 0xE0, + 0x08, 0x13, 0x2F, 0x40, 0x14, 0xE0, 0xCF, 0xA3, + 0x2F, 0x04, 0xF0, 0xE2, 0x40, 0x01, 0x00, 0x40, + 0xA4, 0x13, 0xC4, 0xC3, 0xC7, 0x16, 0x00, 0x01, + 0xFE, 0x00, 0xE6, 0x16, 0x9E, 0x10, 0x40, 0x01, + 0x00, 0x40, 0x05, 0x16, 0x20, 0xE0, 0x14, 0xE0, + 0x65, 0x02, 0x00, 0x58, 0x96, 0x10, 0x20, 0xD8, + 0xDE, 0x07, 0x17, 0x01, 0x8F, 0x07, 0x86, 0xFF, + 0x0F, 0xC8, 0x04, 0x01, 0xC0, 0x01, 0x00, 0x40, + 0x45, 0x02, 0xFF, 0xA7, 0x8A, 0x10, 0x20, 0xC3, + 0xFE, 0x06, 0x20, 0x27, 0x38, 0xE3, 0x07, 0x13, + 0x20, 0x23, 0x22, 0xE0, 0x1A, 0x13, 0x65, 0x02, + 0xFF, 0xDF, 0x20, 0x40, 0x14, 0xE0, 0x20, 0xE0, + 0x16, 0xE0, 0x0C, 0xC8, 0xE6, 0x08, 0x8D, 0x07, + 0xE2, 0x08, 0x58, 0x04, 0x20, 0x48, 0x08, 0xE0, + 0xFE, 0x06, 0x20, 0xC3, 0xE6, 0x08, 0x20, 0x27, + 0x38, 0xE3, 0x19, 0x16, 0x80, 0x03, 0x02, 0xC3, + 0x6C, 0xC2, 0x0A, 0x00, 0x99, 0x06, 0x60, 0x04, + 0x0C, 0xB8, 0xA0, 0xC2, 0xF4, 0x07, 0x8C, 0x07, + 0x01, 0x00, 0x8D, 0x07, 0x06, 0x06, 0xCE, 0x04, + 0xE0, 0xC3, 0x08, 0x06, 0x01, 0x13, 0x97, 0x06, + 0x20, 0xD8, 0x07, 0x06, 0x17, 0x01, 0x8B, 0x07, + 0x82, 0xFF, 0x0B, 0xC8, 0x04, 0x01, 0xA0, 0x06, + 0xB4, 0xBE, 0x60, 0x04, 0x0C, 0xB8, 0xA0, 0xC2, + 0xEE, 0x07, 0x8C, 0x07, 0x06, 0x00, 0x8D, 0x07, + 0xEE, 0x08, 0xA0, 0xC3, 0xE6, 0x07, 0xE0, 0xC3, + 0xE8, 0x07, 0x97, 0x06, 0xA0, 0xC2, 0xF4, 0x07, + 0x8D, 0x07, 0xF4, 0x08, 0xDD, 0x04, 0x8C, 0x07, + 0x02, 0x00, 0x97, 0x06, 0x8D, 0x07, 0x00, 0x80, + 0xA0, 0xC2, 0xEE, 0x08, 0x0A, 0x88, 0x0C, 0x06, + 0x14, 0x1B, 0x82, 0x07, 0xD0, 0xB9, 0xA0, 0xC3, + 0xF0, 0x08, 0xE0, 0xC3, 0xF2, 0x08, 0x8B, 0x07, + 0x0C, 0xE3, 0x8A, 0x02, 0x14, 0x00, 0x04, 0x1A, + 0x8B, 0x07, 0xBA, 0xEA, 0x2A, 0x02, 0xEC, 0xFF, + 0x8A, 0xA2, 0xCA, 0xA2, 0xDB, 0xC2, 0x01, 0x13, + 0x9B, 0x06, 0x20, 0xC8, 0xEE, 0x08, 0xF2, 0x08, + 0x20, 0xC8, 0x20, 0xE0, 0xEE, 0x08, 0x0D, 0xC8, + 0xF0, 0x08, 0x8D, 0x07, 0xEC, 0x08, 0x20, 0xE0, + 0x18, 0xE0, 0x65, 0x02, 0x00, 0x58, 0x58, 0x04, + 0x45, 0x02, 0xFF, 0xA7, 0x80, 0x03, 0x60, 0xC0, + 0xEE, 0x05, 0x21, 0x02, 0xE8, 0x03, 0x20, 0x01, + 0x02, 0x01, 0x06, 0x00, 0x07, 0x16, 0x01, 0x88, + 0xEE, 0x05, 0xF9, 0x16, 0x39, 0x10, 0x60, 0xD0, + 0x03, 0x01, 0xF1, 0x13, 0x01, 0x02, 0x0A, 0x01, + 0x4C, 0xCC, 0x4C, 0xCC, 0x4E, 0xCC, 0x4F, 0xCC, + 0xB1, 0x07, 0x40, 0x00, 0x4D, 0xCC, 0x0A, 0xC8, + 0x00, 0x01, 0x5B, 0x04, 0x60, 0xC0, 0xEE, 0x05, + 0x21, 0x02, 0xE8, 0x03, 0x20, 0x01, 0x02, 0x01, + 0x06, 0x00, 0x07, 0x16, 0x01, 0x88, 0xEE, 0x05, + 0xF9, 0x16, 0x1E, 0x10, 0x60, 0xD0, 0x03, 0x01, + 0xF1, 0x13, 0x01, 0x02, 0x0A, 0x01, 0x4C, 0xCC, + 0x4C, 0xCC, 0x4E, 0xCC, 0x4F, 0xCC, 0xB1, 0x07, + 0x40, 0x00, 0x4D, 0xCC, 0x0A, 0xC8, 0x00, 0x01, + 0xA0, 0x03, 0x60, 0xD0, 0x03, 0x01, 0x01, 0x13, + 0x5B, 0x04, 0x60, 0xC0, 0xEE, 0x05, 0x21, 0x02, + 0xE8, 0x03, 0x20, 0x01, 0x02, 0x01, 0x06, 0x00, + 0xF7, 0x16, 0x01, 0x88, 0xEE, 0x05, 0xF9, 0x16, + 0xCD, 0x04, 0x8A, 0x07, 0x00, 0x40, 0x20, 0xC3, + 0x00, 0x01, 0x0C, 0x01, 0x00, 0x80, 0x02, 0x13, + 0x8A, 0x07, 0x00, 0x20, 0xA0, 0xC3, 0x0E, 0x01, + 0xE0, 0xC3, 0x10, 0x01, 0xB0, 0x03, 0x20, 0xC3, + 0x58, 0x07, 0x20, 0x23, 0x04, 0xE0, 0x02, 0x13, + 0x60, 0x04, 0x8E, 0xB7, 0x60, 0x04, 0x8A, 0xA3, + 0x8D, 0x07, 0x00, 0x20, 0x20, 0x20, 0x0A, 0xE0, + 0x01, 0x16, 0x5B, 0x04, 0x0D, 0x02, 0x32, 0x0C, + 0x5D, 0xC2, 0x01, 0x11, 0xDD, 0x04, 0xCD, 0x05, + 0x0D, 0x88, 0x30, 0x0C, 0xF9, 0x16, 0x60, 0xC2, + 0x0A, 0x06, 0x8D, 0x07, 0x6A, 0x09, 0xA0, 0x06, + 0xF4, 0xBE, 0x09, 0x02, 0x48, 0x00, 0xE0, 0xC3, + 0x30, 0x09, 0x03, 0x16, 0xE0, 0x01, 0x6A, 0x09, + 0x10, 0x00, 0xE0, 0xC2, 0x6A, 0x09, 0x0F, 0x02, + 0x00, 0x01, 0xC9, 0x26, 0x02, 0x13, 0x60, 0x04, + 0x86, 0xBD, 0x09, 0x02, 0x00, 0x12, 0x4B, 0x01, + 0x10, 0x00, 0x02, 0x13, 0x09, 0x02, 0x00, 0x13, + 0x09, 0xD8, 0x2E, 0x09, 0x8F, 0x07, 0x00, 0x40, + 0x89, 0x07, 0x6C, 0x09, 0xCB, 0x04, 0xF9, 0xE2, + 0xF9, 0xE2, 0xF9, 0xE2, 0x07, 0x16, 0x8B, 0x07, + 0x34, 0x09, 0x8C, 0x07, 0x6C, 0x09, 0x3B, 0xCF, + 0x3B, 0xCF, 0x1B, 0xC7, 0x20, 0xC3, 0x6C, 0x09, + 0x19, 0x11, 0x8F, 0x07, 0x00, 0x20, 0x89, 0x07, + 0x7A, 0x09, 0xA0, 0x06, 0x3A, 0xBB, 0xA0, 0x06, + 0x3A, 0xBB, 0x12, 0x10, 0x4C, 0xCE, 0x5B, 0x04, + 0x19, 0xC3, 0x02, 0x16, 0x8C, 0x07, 0x1A, 0x00, + 0x4C, 0xC3, 0x2D, 0x02, 0xF8, 0xFF, 0x0A, 0x02, + 0x09, 0x00, 0x2D, 0x02, 0xFA, 0xFF, 0xF2, 0x13, + 0x0A, 0x06, 0xFB, 0x16, 0x60, 0x04, 0x86, 0xBD, + 0x8F, 0x07, 0x00, 0x10, 0xD9, 0xC2, 0xFA, 0x11, + 0x02, 0x16, 0x8B, 0x07, 0x00, 0x04, 0x4B, 0xC3, + 0x8D, 0x02, 0x20, 0x00, 0x02, 0x14, 0x0D, 0x02, + 0x20, 0x00, 0x8D, 0x02, 0x00, 0x04, 0x02, 0x12, + 0x0D, 0x02, 0x00, 0x04, 0x2D, 0x02, 0xF8, 0xFF, + 0x0D, 0xC8, 0x2C, 0x09, 0x2B, 0x02, 0xFF, 0x03, + 0x8B, 0x01, 0xFF, 0x03, 0x4B, 0xCE, 0x60, 0xC3, + 0x6A, 0x09, 0x60, 0x23, 0x18, 0xE0, 0x0C, 0x16, + 0x49, 0xC3, 0xDD, 0xC2, 0x0F, 0x02, 0x01, 0x01, + 0x8B, 0x01, 0x80, 0xC0, 0xD7, 0x16, 0x8F, 0x05, + 0xED, 0xC2, 0x02, 0x00, 0xD3, 0x16, 0x02, 0x10, + 0x8D, 0x07, 0xBA, 0xEA, 0x3D, 0xC8, 0xA8, 0x09, + 0x1D, 0xC8, 0xAA, 0x09, 0xCB, 0x04, 0xE0, 0x04, + 0xF8, 0x05, 0xE0, 0x04, 0x66, 0x09, 0x20, 0xC8, + 0x30, 0x0C, 0x80, 0x09, 0xA0, 0x07, 0x82, 0x09, + 0xFE, 0xDF, 0x8D, 0x07, 0xFE, 0xDF, 0xE0, 0xC3, + 0xD8, 0x07, 0xE0, 0x23, 0x16, 0xE0, 0x24, 0x16, + 0xE0, 0xC3, 0x30, 0x0C, 0x4F, 0x63, 0xFF, 0x04, + 0xFF, 0x04, 0x4D, 0x06, 0xFD, 0x16, 0x8D, 0x07, + 0xFE, 0xDF, 0x20, 0x04, 0xA2, 0xEA, 0xA0, 0xC3, + 0xA2, 0xEA, 0xEE, 0xC3, 0x12, 0x00, 0xAA, 0x16, + 0x6E, 0xC3, 0x18, 0x00, 0xAD, 0x09, 0x8C, 0x07, + 0x00, 0xE0, 0xAC, 0x09, 0x0D, 0x63, 0x0C, 0x13, + 0x6E, 0xC3, 0x18, 0x00, 0xAD, 0x09, 0x2D, 0x02, + 0x40, 0x00, 0x1D, 0x0A, 0x2D, 0x02, 0x32, 0x0C, + 0xBD, 0x07, 0xFF, 0x7F, 0x0C, 0x06, 0xFC, 0x16, + 0x20, 0xC3, 0x46, 0x04, 0x8C, 0x02, 0x80, 0x00, + 0x13, 0x1A, 0xAC, 0x02, 0x0C, 0xC8, 0x9A, 0x00, + 0xE0, 0x02, 0x80, 0x00, 0x88, 0x07, 0x80, 0x00, + 0x60, 0xC2, 0x46, 0x04, 0xA0, 0x06, 0x28, 0xAD, + 0x02, 0x10, 0x9D, 0x00, 0x05, 0x10, 0x9D, 0x00, + 0x8F, 0x07, 0x00, 0x08, 0x60, 0x04, 0x86, 0xBD, + 0x4B, 0x2D, 0x81, 0xC3, 0xC9, 0x05, 0x8F, 0x07, + 0x00, 0x10, 0x8E, 0x02, 0x02, 0x00, 0xF6, 0x11, + 0x8F, 0x07, 0x00, 0x04, 0xC9, 0x05, 0xD9, 0xC2, + 0xE0, 0x26, 0x26, 0xE0, 0x02, 0x16, 0x2B, 0x02, + 0x06, 0x00, 0x4B, 0xC6, 0x4B, 0xC3, 0xCB, 0x72, + 0x2E, 0x02, 0xFE, 0xFF, 0x8B, 0x83, 0xE6, 0x1B, + 0xCD, 0x06, 0x4D, 0x73, 0xCD, 0x82, 0xE2, 0x1B, + 0xE0, 0x04, 0x1A, 0x09, 0xE0, 0x04, 0x1C, 0x09, + 0x4D, 0xC3, 0x02, 0x13, 0x60, 0x66, 0x12, 0xE0, + 0xC9, 0x05, 0xCF, 0x04, 0x81, 0x2D, 0x01, 0xC8, + 0x6C, 0x01, 0xD4, 0x13, 0x0F, 0xC8, 0x00, 0xFC, + 0xC1, 0xC3, 0x0D, 0x06, 0xF7, 0x15, 0x0D, 0x02, + 0x36, 0x07, 0x0E, 0x02, 0x98, 0x08, 0x0C, 0x02, + 0x03, 0x00, 0x8D, 0xCB, 0x02, 0x00, 0x81, 0x2D, + 0x81, 0xCB, 0x06, 0x00, 0xC3, 0x13, 0xEE, 0x04, + 0x0C, 0x00, 0x2E, 0x02, 0x18, 0x00, 0x0C, 0x06, + 0xF4, 0x16, 0xE0, 0x04, 0x96, 0x08, 0x1F, 0x2E, + 0xB9, 0xC3, 0xD9, 0xC3, 0x89, 0x07, 0x12, 0x00, + 0x8D, 0x07, 0x3A, 0x09, 0xA0, 0x06, 0xF4, 0xBE, + 0x60, 0xC3, 0xD8, 0x07, 0x60, 0x23, 0x16, 0xE0, + 0x09, 0x16, 0x20, 0xE8, 0x10, 0xE0, 0x6A, 0x09, + 0x20, 0xE8, 0x18, 0xE0, 0x98, 0x07, 0x20, 0xE8, + 0x12, 0xE0, 0x78, 0x07, 0x60, 0xC3, 0x6A, 0x09, + 0x60, 0x23, 0x1E, 0xE0, 0x03, 0x16, 0x20, 0x48, + 0xA4, 0xE3, 0x6A, 0x09, 0x60, 0x23, 0x22, 0xE0, + 0x06, 0x13, 0x60, 0x27, 0xA6, 0xE3, 0x03, 0x13, + 0x20, 0xE8, 0x10, 0xE0, 0x6A, 0x09, 0x20, 0x2D, + 0x00, 0x00, 0x8E, 0x07, 0x00, 0x00, 0xA0, 0x06, + 0xD4, 0xBE, 0x4E, 0x05, 0x0E, 0x2C, 0xA0, 0xC0, + 0x04, 0x08, 0xEF, 0xC3, 0x06, 0x00, 0x1B, 0x16, + 0xA0, 0xC3, 0x72, 0x09, 0xE0, 0xC3, 0x74, 0x09, + 0xA0, 0x06, 0xC2, 0xBD, 0xA0, 0xC3, 0x76, 0x09, + 0xE0, 0xC3, 0x78, 0x09, 0xA0, 0x06, 0xE0, 0xBD, + 0x20, 0xE0, 0x0A, 0xE0, 0x60, 0xC3, 0xD8, 0x07, + 0x60, 0x23, 0x16, 0xE0, 0x05, 0x16, 0xE0, 0x04, + 0x2E, 0x06, 0x60, 0x41, 0x04, 0xE0, 0x4D, 0x2E, + 0x8D, 0x07, 0x00, 0x80, 0x52, 0x04, 0xCF, 0x73, + 0x2F, 0x02, 0x00, 0x02, 0x4F, 0xC3, 0x52, 0x04, + 0x20, 0x20, 0x0A, 0xE0, 0x03, 0x13, 0x8D, 0x07, + 0x00, 0x10, 0x5B, 0x04, 0x20, 0x40, 0x0A, 0xE0, + 0x40, 0x02, 0xFF, 0xF0, 0x8E, 0x07, 0x02, 0x00, + 0xA0, 0x06, 0xD4, 0xBE, 0x4E, 0x05, 0x0E, 0x2C, + 0xA0, 0xC0, 0x04, 0x08, 0xA0, 0x06, 0xB4, 0xBE, + 0x60, 0xC3, 0xD8, 0x07, 0x60, 0x23, 0x16, 0xE0, + 0x66, 0x16, 0x20, 0x04, 0xB6, 0xEA, 0x63, 0x10, + 0x6E, 0x02, 0x00, 0x80, 0x8D, 0x07, 0x00, 0xC0, + 0x0D, 0xC8, 0xA6, 0x01, 0x0E, 0xC8, 0x72, 0x09, + 0x0F, 0xC8, 0x74, 0x09, 0x0E, 0xC8, 0xA8, 0x01, + 0x0F, 0xC8, 0xAA, 0x01, 0x12, 0x10, 0x8F, 0x01, + 0x01, 0x00, 0x8A, 0x07, 0x76, 0x09, 0xA0, 0xE3, + 0x4E, 0x09, 0x8E, 0xCE, 0x9A, 0x01, 0xFE, 0xFF, + 0xE0, 0xE3, 0x50, 0x09, 0x8F, 0xE6, 0x8A, 0x07, + 0xAC, 0x01, 0x8E, 0xCE, 0x9A, 0x01, 0xFE, 0xFF, + 0x8F, 0xE6, 0x20, 0x20, 0x0A, 0xE0, 0x3F, 0x13, + 0x8D, 0x07, 0x00, 0x10, 0x5B, 0x04, 0x20, 0x20, + 0x0A, 0xE0, 0x03, 0x13, 0x0D, 0x02, 0x00, 0x10, + 0x5B, 0x04, 0x8E, 0xC3, 0x04, 0x13, 0xE0, 0x01, + 0x50, 0x09, 0x00, 0x01, 0x06, 0x10, 0xA0, 0x01, + 0x50, 0x09, 0x00, 0x01, 0xA0, 0x01, 0x78, 0x09, + 0x00, 0x01, 0xA0, 0xC3, 0x76, 0x09, 0xE0, 0xC3, + 0x78, 0x09, 0xA0, 0xE3, 0x4E, 0x09, 0xE0, 0xE3, + 0x50, 0x09, 0x0E, 0xC8, 0xAC, 0x01, 0x0F, 0xC8, + 0xAE, 0x01, 0x0E, 0xC8, 0x76, 0x09, 0x0F, 0xC8, + 0x78, 0x09, 0x19, 0x10, 0x6E, 0x02, 0x00, 0x80, + 0x0E, 0xC8, 0xA6, 0x01, 0x20, 0x20, 0x0A, 0xE0, + 0x12, 0x13, 0x0D, 0x02, 0x00, 0x10, 0x5B, 0x04, + 0x8D, 0x07, 0x28, 0x07, 0x89, 0x07, 0x0E, 0x00, + 0xA0, 0x06, 0xFA, 0xBE, 0x8D, 0x07, 0x28, 0x07, + 0xFD, 0x04, 0x8D, 0x02, 0x36, 0x07, 0xFC, 0x16, + 0x20, 0x48, 0x14, 0xE0, 0xFE, 0x06, 0x8D, 0x07, + 0x00, 0x80, 0x52, 0x04, 0xA0, 0xC2, 0xEE, 0x07, + 0x8C, 0x07, 0x04, 0x00, 0x8D, 0x07, 0xF0, 0x08, + 0x97, 0x06, 0x7D, 0xC2, 0x5D, 0xC3, 0x60, 0x43, + 0x22, 0xE0, 0xA0, 0x06, 0xFA, 0xBE, 0xEF, 0x10, + 0x0E, 0xC8, 0x06, 0x06, 0x0F, 0xC8, 0x08, 0x06, + 0xEA, 0x10, 0xB0, 0x03, 0xA0, 0x01, 0x60, 0x07, + 0x26, 0x00, 0x40, 0x02, 0x00, 0xC0, 0xE0, 0x04, + 0x06, 0x06, 0x8C, 0x07, 0x10, 0x40, 0xCC, 0x44, + 0xE0, 0x04, 0xFE, 0x06, 0x85, 0x07, 0x40, 0x80, + 0x5B, 0x04, 0x02, 0xC8, 0x04, 0x08, 0x8F, 0x07, + 0xFA, 0x07, 0xCE, 0xCB, 0x02, 0x00, 0x8E, 0x07, + 0x36, 0x07, 0xCE, 0xCB, 0x04, 0x00, 0x8D, 0x07, + 0x30, 0x06, 0x8E, 0x07, 0x10, 0x00, 0x4D, 0x2C, + 0x5B, 0x04, 0xA0, 0xC2, 0xF2, 0x07, 0x02, 0x10, + 0xA0, 0xC2, 0xF8, 0x07, 0x0B, 0xC8, 0xEA, 0x08, + 0x09, 0xC3, 0x0A, 0x13, 0xA0, 0x06, 0x36, 0xBA, + 0xA0, 0xC2, 0x00, 0x01, 0xA0, 0xE2, 0x06, 0xE0, + 0x4C, 0xA3, 0xCC, 0xA3, 0x01, 0x17, 0x8E, 0x05, + 0x4C, 0x62, 0xE0, 0xC2, 0xEA, 0x08, 0x5B, 0x04, + 0x8D, 0x07, 0x00, 0x10, 0x20, 0x20, 0x0A, 0xE0, + 0x01, 0x13, 0x5B, 0x04, 0x0D, 0x02, 0x48, 0x00, + 0xE0, 0xC3, 0x30, 0x09, 0x02, 0x16, 0xCE, 0x01, + 0x10, 0x00, 0x8D, 0x27, 0x03, 0x13, 0x0D, 0x02, + 0x00, 0x01, 0x52, 0x04, 0x00, 0x03, 0x02, 0x00, + 0x60, 0xC3, 0x6A, 0x09, 0x4D, 0x02, 0x08, 0x80, + 0x4E, 0x02, 0xF7, 0x7F, 0x8D, 0xE3, 0xE0, 0xC3, + 0xD8, 0x07, 0xE0, 0x23, 0x16, 0xE0, 0x04, 0x13, + 0x8D, 0x07, 0x06, 0x00, 0x8D, 0x27, 0x02, 0x13, + 0xA0, 0xE3, 0x10, 0xE0, 0x0E, 0xC8, 0x6A, 0x09, + 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, 0x09, 0x13, + 0x0D, 0x02, 0x00, 0x12, 0x4E, 0x01, 0x10, 0x00, + 0x02, 0x13, 0x0D, 0x02, 0x00, 0x13, 0x0D, 0xD8, + 0x2E, 0x09, 0x60, 0xC3, 0x80, 0x01, 0x4E, 0x02, + 0x01, 0x00, 0x4D, 0x02, 0xFE, 0xFF, 0x4E, 0xE3, + 0x0D, 0xC8, 0x80, 0x01, 0x20, 0xD8, 0x40, 0xE2, + 0x2F, 0x09, 0x20, 0x01, 0x6A, 0x09, 0x06, 0x00, + 0x03, 0x13, 0x20, 0xD8, 0xD0, 0xE1, 0x2F, 0x09, + 0x20, 0x98, 0x83, 0x01, 0x00, 0xE2, 0x03, 0x13, + 0x20, 0xD8, 0x2F, 0x09, 0x83, 0x01, 0x00, 0x03, + 0x0F, 0x00, 0x60, 0x04, 0x88, 0xBE, 0x20, 0x20, + 0x0A, 0xE0, 0x03, 0x13, 0x0D, 0x02, 0x00, 0x10, + 0x5B, 0x04, 0x09, 0x02, 0x08, 0x00, 0x0D, 0x02, + 0x58, 0x09, 0xA0, 0x06, 0xF4, 0xBE, 0xA0, 0x07, + 0x02, 0x02, 0x00, 0x00, 0x0D, 0x02, 0x00, 0x04, + 0xE0, 0xC3, 0x58, 0x09, 0x0F, 0x01, 0x00, 0x7C, + 0x01, 0x13, 0x52, 0x04, 0x8F, 0xC3, 0x4E, 0x02, + 0x0F, 0x00, 0xFB, 0x13, 0x8E, 0x02, 0x0F, 0x00, + 0xF8, 0x13, 0x0D, 0x02, 0x00, 0x40, 0x4F, 0xC2, + 0x49, 0x09, 0x49, 0x02, 0x3F, 0x00, 0x09, 0x01, + 0x01, 0x00, 0xEF, 0x16, 0x89, 0x02, 0x06, 0x00, + 0xEC, 0x1A, 0x89, 0x02, 0x20, 0x00, 0xE9, 0x14, + 0xC9, 0x06, 0x1F, 0x09, 0x4F, 0x02, 0x00, 0x40, + 0x4F, 0xE2, 0x69, 0x02, 0x00, 0x80, 0x09, 0xC8, + 0x58, 0x09, 0x0F, 0x02, 0xFF, 0xFF, 0x4E, 0xC2, + 0x1F, 0x09, 0x09, 0x06, 0xFD, 0x16, 0x4F, 0x05, + 0x0D, 0x02, 0x00, 0x20, 0x60, 0xC2, 0x5A, 0x09, + 0xD4, 0x13, 0x4F, 0x26, 0xD2, 0x16, 0x0D, 0x02, + 0x00, 0x10, 0x60, 0xC2, 0x5C, 0x09, 0xCD, 0x13, + 0x4F, 0x26, 0xCB, 0x16, 0x0D, 0x02, 0x00, 0x30, + 0x20, 0x88, 0x5A, 0x09, 0x5C, 0x09, 0xC5, 0x13, + 0xE0, 0xC3, 0x5A, 0x09, 0x4E, 0xC2, 0x1F, 0x0A, + 0x09, 0x06, 0xFD, 0x16, 0xE0, 0xE3, 0x5E, 0x09, + 0x0F, 0xC8, 0x5A, 0x09, 0xE0, 0xC3, 0x5C, 0x09, + 0x4E, 0xC2, 0x1F, 0x0A, 0x09, 0x06, 0xFD, 0x16, + 0xE0, 0xE3, 0x5E, 0x09, 0x0F, 0xC8, 0x5C, 0x09, + 0x0F, 0x02, 0xFF, 0xFF, 0x4E, 0xC2, 0x1F, 0x0A, + 0x09, 0x06, 0xFD, 0x16, 0x0D, 0x02, 0x00, 0x08, + 0x60, 0xC2, 0x5E, 0x09, 0x4F, 0x26, 0xA5, 0x16, + 0x4F, 0x05, 0x0F, 0xC8, 0x5E, 0x09, 0x0F, 0x02, + 0x02, 0x02, 0x0E, 0x02, 0x03, 0x00, 0x60, 0xC3, + 0x40, 0x01, 0x0C, 0x02, 0xFE, 0xC0, 0xA0, 0x01, + 0x40, 0x01, 0x00, 0x04, 0xCF, 0x05, 0x09, 0x02, + 0x55, 0x55, 0x9C, 0x06, 0x49, 0x05, 0x9C, 0x06, + 0x09, 0x07, 0x9C, 0x06, 0x49, 0x05, 0x9C, 0x06, + 0x0E, 0x06, 0xF4, 0x16, 0xA0, 0x01, 0x40, 0x01, + 0x00, 0x40, 0x0D, 0xC8, 0x40, 0x01, 0x09, 0x02, + 0x08, 0x00, 0x0E, 0x02, 0x58, 0x09, 0x0F, 0x02, + 0x02, 0x02, 0xFE, 0xCF, 0x49, 0x06, 0xFD, 0x16, + 0x60, 0x04, 0x88, 0xBE, 0xC9, 0xC7, 0x5F, 0x82, + 0x01, 0x16, 0x5B, 0x04, 0xA0, 0x01, 0x40, 0x01, + 0x00, 0x40, 0x0D, 0xC8, 0x40, 0x01, 0x0D, 0x02, + 0x00, 0x01, 0x52, 0x04, 0x8D, 0x07, 0x00, 0x10, + 0x20, 0x20, 0x0A, 0xE0, 0x0A, 0x16, 0x8D, 0x07, + 0x00, 0x08, 0x20, 0x20, 0x10, 0xE0, 0x05, 0x13, + 0x8D, 0x07, 0x00, 0x40, 0x4F, 0x01, 0x01, 0x00, + 0x01, 0x16, 0x5B, 0x04, 0x20, 0xE0, 0x10, 0xE0, + 0x20, 0x07, 0x9C, 0x08, 0x20, 0x07, 0xB4, 0x08, + 0x20, 0x07, 0xCC, 0x08, 0xA0, 0x07, 0xA2, 0x08, + 0x84, 0x02, 0xA0, 0x07, 0xBA, 0x08, 0x84, 0x02, + 0xA0, 0x07, 0xD2, 0x08, 0x84, 0x02, 0xA0, 0x07, + 0x04, 0x09, 0x00, 0x40, 0xE0, 0x04, 0x06, 0x09, + 0xE0, 0x04, 0x08, 0x09, 0x0E, 0xC8, 0x4C, 0x08, + 0x0F, 0xC8, 0x4E, 0x08, 0x0E, 0xC8, 0x8E, 0x08, + 0x0F, 0xC8, 0x90, 0x08, 0xE0, 0x04, 0x5A, 0x08, + 0xE0, 0x04, 0x60, 0x08, 0xE0, 0x02, 0x78, 0x07, + 0xE0, 0x04, 0x94, 0x08, 0x20, 0x40, 0x40, 0xE3, + 0x20, 0xE0, 0x0C, 0xE0, 0x60, 0x04, 0xBC, 0xC6, + 0x80, 0x01, 0x00, 0xF0, 0xC0, 0x01, 0x00, 0x40, + 0x10, 0x10, 0x80, 0x01, 0x00, 0xF0, 0x0D, 0x10, + 0xC0, 0x01, 0x00, 0xF0, 0x20, 0x40, 0x06, 0xE0, + 0x08, 0x10, 0xC0, 0x01, 0x00, 0xF0, 0x80, 0x01, + 0x00, 0x20, 0xE0, 0xC3, 0x94, 0x08, 0x01, 0x16, + 0x5B, 0x04, 0x4B, 0xC0, 0x20, 0x04, 0xDA, 0xEA, + 0x40, 0x01, 0x00, 0x20, 0xFB, 0x16, 0x51, 0x04, + 0xA0, 0xC2, 0xD8, 0x07, 0x4A, 0x01, 0x40, 0x00, + 0x01, 0x16, 0x5B, 0x04, 0xE0, 0x02, 0x78, 0x07, + 0x20, 0x20, 0x0C, 0xE0, 0xEF, 0x16, 0x43, 0xC2, + 0x02, 0x13, 0xA0, 0x06, 0x1A, 0xC3, 0x20, 0x2F, + 0x36, 0x07, 0x20, 0x40, 0x0C, 0xE0, 0xA0, 0x06, + 0xAC, 0xC1, 0xA0, 0xC3, 0x94, 0x08, 0xFB, 0x16, + 0xA0, 0x06, 0x3A, 0xC2, 0x8E, 0x07, 0x04, 0x09, + 0x9E, 0x07, 0x00, 0x80, 0x20, 0x20, 0x10, 0xE0, + 0x05, 0x16, 0x8F, 0x07, 0x4C, 0x08, 0xBF, 0xCF, + 0xBF, 0xCF, 0x9F, 0xC7, 0xA0, 0x06, 0x5A, 0xC2, + 0x20, 0xE8, 0x3C, 0xE3, 0x62, 0x07, 0xA0, 0x06, + 0x3A, 0xC2, 0x20, 0x48, 0x3C, 0xE3, 0x62, 0x07, + 0x20, 0x40, 0x40, 0xE3, 0x20, 0xE0, 0x04, 0xE0, + 0x20, 0x48, 0x10, 0xE0, 0x58, 0x07, 0x5B, 0x04, + 0x80, 0x01, 0x00, 0xF0, 0x20, 0xE0, 0x04, 0xE0, + 0x60, 0x01, 0x60, 0x07, 0x02, 0x00, 0x02, 0x13, + 0x9B, 0x06, 0xB8, 0x10, 0x20, 0xE8, 0x1E, 0xE0, + 0x58, 0x07, 0xB4, 0x10, 0x9B, 0x06, 0x80, 0x03, + 0xE0, 0x02, 0x58, 0x07, 0x00, 0x01, 0x00, 0x40, + 0x07, 0x16, 0x8D, 0x07, 0x00, 0x09, 0xA0, 0x06, + 0x68, 0xB8, 0xE0, 0x02, 0x78, 0x07, 0x5B, 0x04, + 0xC4, 0x01, 0x02, 0x00, 0xE0, 0x02, 0x78, 0x07, + 0x5B, 0x04, 0x0E, 0x68, 0x96, 0x08, 0xE9, 0x04, + 0x0C, 0x00, 0x11, 0x10, 0x0E, 0x02, 0x00, 0x23, + 0x4E, 0xDB, 0x01, 0x00, 0xCC, 0x01, 0x00, 0x04, + 0x4C, 0xD7, 0x1C, 0x10, 0x60, 0xC2, 0x5C, 0x07, + 0x20, 0x06, 0x94, 0x08, 0xA9, 0xC2, 0x08, 0x00, + 0xA9, 0xC3, 0x0C, 0x00, 0xEA, 0x16, 0x29, 0x07, + 0x04, 0x00, 0x69, 0x01, 0x0A, 0x00, 0x01, 0x00, + 0x2D, 0x13, 0x49, 0xC3, 0x2D, 0x02, 0x0E, 0x00, + 0x0A, 0xC3, 0x1D, 0xD3, 0x8C, 0x01, 0x00, 0x84, + 0xCC, 0x01, 0x00, 0x40, 0x0A, 0x01, 0x00, 0x5E, + 0xDD, 0x16, 0x4C, 0xC7, 0xA9, 0xC3, 0x10, 0x00, + 0xE9, 0xC3, 0x12, 0x00, 0x41, 0xCA, 0x10, 0x00, + 0x2F, 0x02, 0x04, 0x00, 0x01, 0x17, 0x8E, 0x05, + 0x8C, 0x07, 0x02, 0x00, 0xA0, 0xC2, 0xF6, 0x07, + 0xA0, 0x06, 0x00, 0xBA, 0x69, 0xC0, 0x10, 0x00, + 0x29, 0xC8, 0x14, 0x00, 0x06, 0x09, 0x29, 0xC8, + 0x16, 0x00, 0x08, 0x09, 0x69, 0x01, 0x0E, 0x00, + 0x00, 0x08, 0x04, 0x16, 0x90, 0x03, 0x7F, 0x00, + 0xA0, 0x06, 0x5A, 0xC2, 0x40, 0x01, 0x00, 0x40, + 0x01, 0x16, 0x51, 0x04, 0x60, 0x04, 0xBE, 0xC1, + 0xA9, 0xC3, 0x0C, 0x00, 0x0B, 0x13, 0x0E, 0x68, + 0x96, 0x08, 0xE9, 0x04, 0x0C, 0x00, 0x29, 0xC8, + 0x06, 0x00, 0x6C, 0x01, 0xA0, 0xC3, 0x00, 0xFC, + 0x01, 0x13, 0x1E, 0x2E, 0x29, 0x07, 0x04, 0x00, + 0x5B, 0x04, 0x81, 0x07, 0x20, 0x20, 0x89, 0x07, + 0x4C, 0x08, 0x41, 0xCE, 0x63, 0xCE, 0x10, 0x00, + 0x63, 0xC6, 0x12, 0x00, 0xA0, 0x06, 0x54, 0xBA, + 0x43, 0xC2, 0x02, 0x13, 0xA0, 0x06, 0x1A, 0xC3, + 0x20, 0xE0, 0x10, 0xE0, 0x60, 0x04, 0xEC, 0xC1, + 0x40, 0x01, 0x00, 0x04, 0xEA, 0x16, 0xA0, 0x06, + 0xAC, 0xC1, 0xA0, 0xC2, 0xF0, 0x07, 0x8C, 0x07, + 0x04, 0x00, 0x8D, 0x07, 0x4C, 0x08, 0xA0, 0xC3, + 0x8E, 0x08, 0xE0, 0xC3, 0x90, 0x08, 0xA0, 0x06, + 0x36, 0xBA, 0xE0, 0xC3, 0x4E, 0x08, 0x4F, 0x01, + 0x01, 0x00, 0x13, 0x16, 0xE0, 0xC2, 0x94, 0x08, + 0xEA, 0x16, 0x60, 0x04, 0xEC, 0xC1, 0xE0, 0xC3, + 0x4E, 0x08, 0x4F, 0x01, 0x01, 0x00, 0x09, 0x16, + 0x60, 0x04, 0xEC, 0xC1, 0xA0, 0x06, 0x54, 0xBA, + 0xE0, 0xC3, 0x4E, 0x08, 0x4F, 0x01, 0x01, 0x00, + 0xD7, 0x13, 0xA0, 0xC2, 0xF0, 0x07, 0x20, 0xC3, + 0x7C, 0x09, 0x8D, 0x07, 0x4C, 0x08, 0x9D, 0xC3, + 0xA0, 0x06, 0x36, 0xBA, 0xC0, 0x06, 0x20, 0xD0, + 0x50, 0x08, 0xC0, 0x06, 0x40, 0x01, 0x00, 0x04, + 0x0A, 0x16, 0x40, 0x01, 0x80, 0x00, 0x07, 0x13, + 0x0E, 0xC8, 0x4C, 0x08, 0x0F, 0xC8, 0x4E, 0x08, + 0xA0, 0x06, 0xA2, 0xC1, 0xD8, 0x10, 0x0E, 0xC8, + 0x8E, 0x08, 0x0F, 0xC8, 0x90, 0x08, 0x40, 0x01, + 0x00, 0x04, 0x0C, 0x13, 0x40, 0x01, 0x20, 0x00, + 0x58, 0x16, 0x81, 0x07, 0x10, 0x20, 0x9F, 0x10, + 0xA0, 0x06, 0xAC, 0xC1, 0xA0, 0xC3, 0x8E, 0x08, + 0xE0, 0xC3, 0x90, 0x08, 0x83, 0x07, 0x98, 0x08, + 0x63, 0x07, 0x04, 0x00, 0x2D, 0x11, 0x83, 0x07, + 0xB0, 0x08, 0x63, 0x07, 0x04, 0x00, 0x28, 0x11, + 0x83, 0x07, 0xC8, 0x08, 0x63, 0x07, 0x04, 0x00, + 0x23, 0x11, 0xC3, 0x60, 0x60, 0xC2, 0x46, 0x07, + 0xE7, 0x13, 0x69, 0x01, 0x0E, 0x00, 0x00, 0x08, + 0xE3, 0x13, 0x00, 0x03, 0x02, 0x00, 0x19, 0xC8, + 0x46, 0x07, 0x03, 0x16, 0xA0, 0x01, 0x3A, 0x07, + 0x20, 0x00, 0x00, 0x03, 0x0F, 0x00, 0xC0, 0x01, + 0x00, 0xF0, 0x80, 0x01, 0x00, 0x20, 0x01, 0x02, + 0x06, 0xC4, 0x60, 0x04, 0x9A, 0xC2, 0x81, 0x07, + 0x80, 0x20, 0xE0, 0xC8, 0x8E, 0x08, 0x14, 0x00, + 0xE0, 0xC8, 0x90, 0x08, 0x16, 0x00, 0xC7, 0x10, + 0xE0, 0xC8, 0x50, 0x08, 0x0E, 0x00, 0xCE, 0xC8, + 0x10, 0x00, 0xCF, 0xC8, 0x12, 0x00, 0x40, 0x01, + 0x20, 0x00, 0xBB, 0x16, 0xE3, 0xC1, 0x06, 0x00, + 0xC7, 0xC8, 0x08, 0x00, 0x07, 0xC8, 0x6C, 0x01, + 0x07, 0xC8, 0xE0, 0x08, 0x08, 0x02, 0x02, 0xFC, + 0xB8, 0x07, 0x00, 0x81, 0xE0, 0xC1, 0xE8, 0x00, + 0x07, 0xCE, 0x20, 0xC8, 0x52, 0x08, 0x92, 0x08, + 0xDA, 0x13, 0xCE, 0xC8, 0x14, 0x00, 0xCF, 0xC8, + 0x16, 0x00, 0x80, 0x01, 0x00, 0x04, 0x82, 0x07, + 0x54, 0x08, 0x32, 0xC1, 0x08, 0x11, 0x72, 0xC1, + 0x92, 0xC1, 0x82, 0x07, 0x8A, 0x08, 0x04, 0xC1, + 0x07, 0x16, 0x60, 0x04, 0x8E, 0xC5, 0x72, 0xC1, + 0xB2, 0xC1, 0x84, 0x01, 0x00, 0x80, 0xF9, 0x13, + 0x04, 0x68, 0x92, 0x08, 0xC7, 0xC1, 0x37, 0x16, + 0x20, 0x98, 0x97, 0x08, 0x85, 0x09, 0x16, 0x16, + 0x81, 0x07, 0x40, 0x20, 0xE0, 0xC1, 0x94, 0x08, + 0x57, 0x13, 0xA0, 0x06, 0xAC, 0xC1, 0xF4, 0x10, + 0xE0, 0xC2, 0x3A, 0x07, 0xE0, 0x42, 0x62, 0x07, + 0xE0, 0x26, 0x3A, 0xE3, 0x02, 0x13, 0xA0, 0x06, + 0x92, 0xC1, 0xA0, 0x06, 0x54, 0xBA, 0x22, 0x10, + 0xA0, 0x06, 0x9C, 0xC1, 0x81, 0x2D, 0x01, 0xC2, + 0xFB, 0x13, 0xA0, 0x05, 0x96, 0x08, 0x23, 0xC8, + 0x08, 0x00, 0x6C, 0x01, 0xA0, 0x07, 0x02, 0xFC, + 0x00, 0x80, 0xC3, 0xC1, 0x27, 0x02, 0x06, 0x00, + 0xA0, 0x06, 0x0C, 0xB5, 0xA3, 0x05, 0x0C, 0x00, + 0x08, 0xC8, 0x6C, 0x01, 0x08, 0xC8, 0xE0, 0x08, + 0x08, 0x02, 0x02, 0xFC, 0xB8, 0x07, 0x00, 0x81, + 0xF8, 0xC1, 0x04, 0xC1, 0x37, 0x13, 0xE0, 0xD2, + 0x03, 0x01, 0xD2, 0x13, 0x0B, 0x02, 0x0A, 0x01, + 0xC4, 0xCE, 0xC7, 0xCE, 0xC5, 0xCE, 0xC6, 0xCE, + 0xFB, 0x04, 0x09, 0x02, 0x00, 0x04, 0x48, 0xA2, + 0xC9, 0xC6, 0x20, 0xA8, 0xE0, 0x08, 0x12, 0x01, + 0x20, 0xC8, 0xF2, 0x07, 0x00, 0x01, 0x47, 0xC2, + 0xC4, 0x81, 0x01, 0x14, 0x44, 0xC2, 0xC9, 0x61, + 0x09, 0xA2, 0x89, 0xA1, 0x01, 0x17, 0x85, 0x05, + 0x09, 0x61, 0xA8, 0x16, 0x82, 0x02, 0x8A, 0x08, + 0x05, 0x16, 0x40, 0x01, 0x10, 0x00, 0x12, 0x13, + 0x60, 0x04, 0xA6, 0xC3, 0x60, 0x04, 0xBC, 0xC4, + 0x60, 0x04, 0x40, 0xC3, 0x81, 0x07, 0x80, 0x20, + 0xFB, 0x10, 0x81, 0x07, 0x80, 0x20, 0xF8, 0x10, + 0x81, 0x07, 0x02, 0x20, 0xF5, 0x10, 0x81, 0x07, + 0x04, 0x20, 0xF2, 0x10, 0x23, 0xC8, 0x08, 0x00, + 0x6C, 0x01, 0x07, 0x05, 0xE0, 0xA1, 0xE8, 0x00, + 0x0C, 0x02, 0x04, 0xFC, 0x07, 0xCF, 0xE0, 0xC2, + 0x92, 0x08, 0xE8, 0x16, 0xE0, 0xD2, 0x03, 0x01, + 0x10, 0x16, 0xE0, 0xC2, 0x3A, 0x07, 0xE0, 0x42, + 0x62, 0x07, 0xE0, 0x26, 0x3A, 0xE3, 0x07, 0x13, + 0x90, 0x03, 0xC8, 0x2F, 0xA0, 0x06, 0x92, 0xC1, + 0xE0, 0xD2, 0x03, 0x01, 0x02, 0x16, 0xA0, 0x06, + 0x54, 0xBA, 0x23, 0xC8, 0x06, 0x00, 0x6C, 0x01, + 0xA3, 0xC2, 0x0E, 0x00, 0x4A, 0x01, 0x00, 0x01, + 0x0B, 0x13, 0x0C, 0x02, 0x0E, 0xFC, 0x5C, 0xC2, + 0x49, 0x02, 0x00, 0x80, 0x0D, 0x02, 0x6C, 0x09, + 0x7D, 0xE2, 0x09, 0xCF, 0x3D, 0xCF, 0x3D, 0xCF, + 0x0C, 0x02, 0x00, 0xFC, 0x6C, 0xC3, 0x06, 0x00, + 0x4D, 0x02, 0xFF, 0xE0, 0x4A, 0x02, 0x00, 0x02, + 0x8A, 0xA2, 0x8A, 0xA2, 0x4A, 0xE3, 0x60, 0xE3, + 0x9E, 0x09, 0x0D, 0xCB, 0x06, 0x00, 0xCD, 0x06, + 0x0B, 0x02, 0x0F, 0x00, 0xEC, 0x82, 0x04, 0x00, + 0xAD, 0x11, 0xEC, 0xC3, 0x0E, 0x00, 0x11, 0x15, + 0x10, 0x13, 0x6C, 0xC2, 0x14, 0x00, 0x49, 0x02, + 0x00, 0x1F, 0xA7, 0x13, 0xC9, 0x06, 0x89, 0x02, + 0x12, 0x00, 0xA3, 0x1B, 0x49, 0x01, 0x01, 0x00, + 0xA0, 0x13, 0xC9, 0xA2, 0xEC, 0x82, 0x04, 0x00, + 0x9C, 0x11, 0x4D, 0xA3, 0x9D, 0x18, 0x14, 0x11, + 0x60, 0x01, 0x6A, 0x09, 0x00, 0x80, 0x18, 0x13, + 0x1D, 0x09, 0xCC, 0xA2, 0xEB, 0xC2, 0x08, 0x00, + 0x7B, 0x09, 0x4B, 0x02, 0x1E, 0x00, 0xA0, 0xC3, + 0xF0, 0x06, 0xAB, 0x23, 0x04, 0xE0, 0x8F, 0x16, + 0x60, 0x27, 0x3E, 0xE3, 0x8C, 0x16, 0x4D, 0xA3, + 0x4D, 0xA3, 0x4D, 0xA3, 0xCD, 0x06, 0x4D, 0x02, + 0x07, 0x00, 0x0D, 0x88, 0xEE, 0x06, 0x0A, 0x15, + 0x90, 0x03, 0xFF, 0x6F, 0x53, 0x2F, 0xA0, 0x05, + 0x94, 0x08, 0xC3, 0x04, 0xC0, 0x01, 0x00, 0x04, + 0x60, 0x04, 0xAA, 0xC3, 0x60, 0x01, 0x6A, 0x09, + 0x00, 0x80, 0xF2, 0x13, 0x01, 0x02, 0x08, 0x20, + 0x60, 0x04, 0xA2, 0xC5, 0x8D, 0x07, 0x00, 0x10, + 0x20, 0x20, 0x0A, 0xE0, 0x0A, 0x16, 0x8D, 0x07, + 0x00, 0x08, 0x20, 0x20, 0x0E, 0xE0, 0x05, 0x13, + 0x8D, 0x07, 0x00, 0x40, 0x4F, 0x01, 0x01, 0x00, + 0x01, 0x16, 0x5B, 0x04, 0x20, 0xE0, 0x0E, 0xE0, + 0xA0, 0x07, 0xFA, 0x08, 0x00, 0x80, 0x0E, 0xC8, + 0xFA, 0x07, 0x0F, 0xC8, 0xFC, 0x07, 0x0E, 0xC8, + 0x3C, 0x08, 0x0F, 0xC8, 0x3E, 0x08, 0xE0, 0x04, + 0x08, 0x08, 0xE0, 0x04, 0x0E, 0x08, 0xE0, 0x02, + 0x98, 0x07, 0x20, 0x40, 0x4C, 0xE3, 0x20, 0x07, + 0x2E, 0x06, 0x60, 0x04, 0x12, 0xCA, 0x00, 0x70, + 0x4B, 0xC0, 0xE0, 0x04, 0x2E, 0x06, 0x0B, 0x10, + 0x20, 0xF0, 0x4B, 0xE3, 0x02, 0x10, 0x20, 0xF0, + 0x4A, 0xE3, 0x4B, 0xC0, 0xE0, 0x04, 0x2E, 0x06, + 0xE0, 0x01, 0x62, 0x07, 0x40, 0x00, 0x20, 0xE8, + 0x46, 0xE3, 0x62, 0x07, 0x20, 0x04, 0xDA, 0xEA, + 0x40, 0x01, 0x00, 0x20, 0x04, 0x13, 0xFA, 0x10, + 0x40, 0x01, 0x00, 0x40, 0xF7, 0x16, 0x20, 0x07, + 0x2E, 0x06, 0x20, 0x50, 0x50, 0xE3, 0x51, 0x04, + 0xF1, 0x10, 0xE0, 0x02, 0x58, 0x07, 0x00, 0x01, + 0x00, 0x40, 0x07, 0x16, 0x8D, 0x07, 0xF6, 0x08, + 0xA0, 0x06, 0x68, 0xB8, 0xE0, 0x02, 0x98, 0x07, + 0x5B, 0x04, 0xC4, 0x01, 0x04, 0x00, 0xE0, 0x02, + 0x98, 0x07, 0x5B, 0x04, 0x60, 0x01, 0x60, 0x07, + 0x04, 0x00, 0x06, 0x16, 0x20, 0xE8, 0x1C, 0xE0, + 0x58, 0x07, 0x80, 0x03, 0xE0, 0x02, 0x98, 0x07, + 0x20, 0xD8, 0xDC, 0x07, 0x17, 0x01, 0x8F, 0x07, + 0x8E, 0xFF, 0x0F, 0xC8, 0x04, 0x01, 0x20, 0xE8, + 0x06, 0xE0, 0x58, 0x07, 0x80, 0x01, 0x00, 0x80, + 0x5B, 0x04, 0xE0, 0xC2, 0x4A, 0x08, 0xC3, 0x82, + 0x03, 0x13, 0xDB, 0x2D, 0x03, 0xC8, 0x4A, 0x08, + 0x49, 0x01, 0x00, 0x01, 0x02, 0x16, 0x60, 0x04, + 0x52, 0xC9, 0xE0, 0xC0, 0xF8, 0x05, 0xFD, 0x13, + 0x03, 0xC8, 0x6C, 0x01, 0x20, 0xC8, 0x00, 0xFC, + 0xF8, 0x05, 0x88, 0x07, 0x02, 0xFC, 0x78, 0xC2, + 0xF8, 0xC1, 0x28, 0x02, 0x00, 0x04, 0x49, 0x01, + 0x00, 0x01, 0x4D, 0x16, 0x09, 0x01, 0x00, 0x5E, + 0x29, 0x16, 0x49, 0x01, 0x02, 0x00, 0x0B, 0x16, + 0x60, 0x01, 0x46, 0x08, 0x00, 0x02, 0x0A, 0x16, + 0x27, 0x02, 0x04, 0x00, 0x07, 0x88, 0x7E, 0x09, + 0x05, 0x12, 0x27, 0x02, 0xFC, 0xFF, 0xA0, 0x01, + 0x46, 0x08, 0x00, 0x02, 0xC7, 0xC1, 0x37, 0x15, + 0xD3, 0x2D, 0xE0, 0xC0, 0x4A, 0x08, 0x07, 0xA8, + 0x48, 0x08, 0x07, 0xA8, 0x44, 0x08, 0x0C, 0x15, + 0x20, 0xC8, 0x3C, 0x08, 0xFA, 0x07, 0x20, 0xC8, + 0x3E, 0x08, 0xFC, 0x07, 0x20, 0xC8, 0x40, 0x08, + 0x3C, 0x08, 0x20, 0xC8, 0x42, 0x08, 0x3E, 0x08, + 0x60, 0x04, 0x52, 0xC9, 0xA0, 0x06, 0x54, 0xBA, + 0xD3, 0x2D, 0xE0, 0xC2, 0x4A, 0x08, 0xC3, 0x82, + 0x01, 0x13, 0xDB, 0x2D, 0x20, 0x88, 0x3E, 0x08, + 0x3A, 0x08, 0x0D, 0x16, 0x20, 0x88, 0x3C, 0x08, + 0x38, 0x08, 0x09, 0x16, 0xE0, 0x04, 0x44, 0x08, + 0x82, 0x07, 0x02, 0x08, 0x04, 0x61, 0xE0, 0x04, + 0x48, 0x08, 0x60, 0x04, 0x1E, 0xCA, 0x20, 0xC8, + 0x38, 0x08, 0xFA, 0x07, 0x20, 0xC8, 0x3A, 0x08, + 0xFC, 0x07, 0x60, 0x04, 0x12, 0xCA, 0x07, 0xA8, + 0x48, 0x08, 0x04, 0xC1, 0x1B, 0x16, 0x82, 0x02, + 0x38, 0x08, 0x0A, 0x16, 0x60, 0x01, 0xFC, 0x07, + 0x01, 0x00, 0x02, 0x16, 0xA0, 0x06, 0x6E, 0xCB, + 0xA0, 0x06, 0xFC, 0xCA, 0x80, 0x01, 0x10, 0x00, + 0x32, 0xC1, 0x07, 0x11, 0x72, 0xC1, 0x92, 0xC1, + 0x82, 0x07, 0x38, 0x08, 0x04, 0xC1, 0x06, 0x16, + 0xEA, 0x10, 0x72, 0xC1, 0xB2, 0xC1, 0x84, 0x01, + 0x00, 0x80, 0xE5, 0x13, 0xE0, 0xD2, 0x03, 0x01, + 0x34, 0x13, 0x0B, 0x02, 0x0A, 0x01, 0xC4, 0xCE, + 0xC7, 0xCE, 0xC5, 0xCE, 0xC6, 0xCE, 0xFB, 0x04, + 0xC8, 0xC6, 0x03, 0xA8, 0x12, 0x01, 0x20, 0xC8, + 0xF8, 0x07, 0x00, 0x01, 0xC7, 0xC2, 0xC4, 0x81, + 0x01, 0x14, 0xC4, 0xC2, 0x0B, 0xA8, 0x44, 0x08, + 0x0B, 0x61, 0x0B, 0xA2, 0x8B, 0xA1, 0x01, 0x17, + 0x85, 0x05, 0xCB, 0x61, 0xC6, 0x16, 0x40, 0x01, + 0x40, 0x00, 0x15, 0x16, 0x87, 0x07, 0x20, 0x00, + 0xE0, 0x61, 0x44, 0x08, 0xC4, 0x81, 0x08, 0x1A, + 0x07, 0xA8, 0x48, 0x08, 0x07, 0xA8, 0x44, 0x08, + 0x07, 0x61, 0x87, 0xA1, 0x01, 0x17, 0x85, 0x05, + 0x80, 0x01, 0x40, 0x00, 0x03, 0xC8, 0x6C, 0x01, + 0xE0, 0xC1, 0x04, 0xFC, 0xAC, 0x10, 0x60, 0x04, + 0xBC, 0xC7, 0x20, 0x01, 0x3A, 0x07, 0x00, 0x70, + 0x04, 0x13, 0xA0, 0x06, 0x28, 0xC7, 0x20, 0x07, + 0x2E, 0x06, 0xA0, 0x06, 0x54, 0xBA, 0xC1, 0x10, + 0xE0, 0xD2, 0x03, 0x01, 0x0A, 0x16, 0x20, 0x01, + 0x3A, 0x07, 0x00, 0x70, 0x04, 0x13, 0xA0, 0x06, + 0x28, 0xC7, 0x20, 0x07, 0x2E, 0x06, 0xA0, 0x06, + 0x54, 0xBA, 0x90, 0x03, 0xBF, 0x4F, 0xD3, 0x2D, + 0x60, 0x01, 0xFC, 0x07, 0x01, 0x00, 0x02, 0x16, + 0xA0, 0x06, 0x6E, 0xCB, 0x60, 0xD2, 0x46, 0x08, + 0x89, 0x01, 0x00, 0xF1, 0xC9, 0x01, 0x00, 0x70, + 0x40, 0x01, 0x10, 0x00, 0x1C, 0x13, 0x20, 0x88, + 0x3E, 0x08, 0x3A, 0x08, 0x04, 0x16, 0x20, 0x88, + 0x3C, 0x08, 0x38, 0x08, 0x14, 0x13, 0x89, 0x01, + 0x00, 0x10, 0x8D, 0x07, 0x44, 0x08, 0x9D, 0x07, + 0x00, 0x50, 0xA0, 0xC2, 0xF6, 0x07, 0x8C, 0x07, + 0x02, 0x00, 0xA0, 0xC3, 0x3C, 0x08, 0xE0, 0xC3, + 0x3E, 0x08, 0x2F, 0x02, 0x04, 0x00, 0x01, 0x17, + 0x8E, 0x05, 0xA0, 0x06, 0x00, 0xBA, 0x8D, 0x07, + 0x46, 0x08, 0x49, 0xC7, 0xA0, 0xC2, 0xF6, 0x07, + 0x8C, 0x07, 0x04, 0x00, 0xA0, 0xC3, 0x38, 0x08, + 0xE0, 0xC3, 0x3A, 0x08, 0xCC, 0xA3, 0x01, 0x17, + 0x8E, 0x05, 0xA0, 0x06, 0x00, 0xBA, 0x20, 0xC8, + 0x3C, 0x08, 0xFC, 0x08, 0x20, 0xC8, 0x3E, 0x08, + 0xFE, 0x08, 0x09, 0x01, 0x00, 0x0C, 0x0C, 0x13, + 0x49, 0x01, 0x00, 0x04, 0x05, 0x16, 0xA0, 0x06, + 0x6C, 0xC7, 0xA0, 0x06, 0x38, 0xC7, 0x04, 0x10, + 0x90, 0x03, 0x7F, 0x40, 0xA0, 0x06, 0x6C, 0xC7, + 0xC0, 0x01, 0x90, 0x00, 0xA0, 0x06, 0xFC, 0xCA, + 0x0B, 0xC8, 0x46, 0x08, 0xE0, 0xC2, 0x42, 0x07, + 0x2D, 0x13, 0xE0, 0xC2, 0x2E, 0x06, 0x2A, 0x13, + 0xE0, 0x02, 0x58, 0x07, 0x8F, 0x07, 0xBF, 0xFF, + 0x0F, 0x2C, 0xE0, 0x02, 0x98, 0x07, 0xE0, 0xC0, + 0x5C, 0x07, 0x03, 0xC8, 0x4A, 0x08, 0x03, 0xC8, + 0x6C, 0x01, 0xC3, 0xC2, 0xCB, 0xA2, 0xEB, 0xC2, + 0x32, 0x0C, 0x32, 0x13, 0x0B, 0xC8, 0x00, 0xFC, + 0x0B, 0xC3, 0x4B, 0xC3, 0x0B, 0xC8, 0x6C, 0x01, + 0xE0, 0xC2, 0x00, 0xFC, 0xFA, 0x16, 0x00, 0x03, + 0x02, 0x00, 0x20, 0xC8, 0xF8, 0x05, 0x00, 0xFC, + 0x02, 0x16, 0x0D, 0xC8, 0xFA, 0x05, 0x0C, 0xC8, + 0xF8, 0x05, 0x00, 0x03, 0x0F, 0x00, 0x03, 0xC8, + 0x6C, 0x01, 0x1A, 0x10, 0xA0, 0xC3, 0x2E, 0x06, + 0x03, 0x13, 0xE0, 0xC0, 0xF8, 0x05, 0x0D, 0x16, + 0x4F, 0x2E, 0xC0, 0x01, 0x00, 0x80, 0xA0, 0x01, + 0x62, 0x07, 0x00, 0x80, 0x8E, 0xC3, 0x03, 0x13, + 0xA0, 0x01, 0x62, 0x07, 0x40, 0x00, 0x60, 0x04, + 0x4E, 0xC7, 0x03, 0xC8, 0x6C, 0x01, 0x20, 0xC8, + 0x00, 0xFC, 0xF8, 0x05, 0x03, 0xC8, 0x4A, 0x08, + 0x60, 0x01, 0x6A, 0x09, 0x00, 0x04, 0x02, 0x13, + 0x60, 0x04, 0xE4, 0xC7, 0x8C, 0x07, 0x0E, 0x00, + 0x20, 0xC2, 0x0E, 0xFC, 0x0A, 0x15, 0x09, 0x13, + 0x20, 0xC2, 0x14, 0xFC, 0x48, 0x02, 0x00, 0x1F, + 0xC8, 0x06, 0x88, 0x02, 0x12, 0x00, 0xF0, 0x1B, + 0x08, 0xA3, 0x88, 0x07, 0x02, 0xFC, 0x78, 0xC2, + 0xF8, 0xC1, 0x28, 0x02, 0x00, 0x04, 0x07, 0x83, + 0xE7, 0x1A, 0xCC, 0x61, 0x07, 0xC8, 0x04, 0xFC, + 0xCC, 0xC1, 0xC0, 0x01, 0x40, 0x00, 0x60, 0x04, + 0xF0, 0xC7, 0x4B, 0xC1, 0xA0, 0xC2, 0xF0, 0x07, + 0x20, 0xC3, 0x7A, 0x09, 0x8D, 0x07, 0xFA, 0x07, + 0x9D, 0xC3, 0xE0, 0xC3, 0xFC, 0x07, 0xA0, 0x06, + 0x00, 0xBA, 0x20, 0xC8, 0x3C, 0x08, 0x40, 0x08, + 0x20, 0xC8, 0x3E, 0x08, 0x42, 0x08, 0x0E, 0xC8, + 0x3C, 0x08, 0x0F, 0xC8, 0x3E, 0x08, 0xC4, 0x04, + 0x82, 0x07, 0x02, 0x08, 0xE0, 0x04, 0x44, 0x08, + 0x40, 0x01, 0x80, 0x00, 0x06, 0x16, 0x0E, 0xC8, + 0x38, 0x08, 0x0F, 0xC8, 0x3A, 0x08, 0xE0, 0x04, + 0x48, 0x08, 0xA0, 0x06, 0x54, 0xBA, 0xE0, 0xC2, + 0xFE, 0x07, 0x0D, 0x11, 0x0E, 0xC8, 0xFA, 0x07, + 0x0F, 0xC8, 0xFC, 0x07, 0x20, 0xC8, 0x40, 0x08, + 0x3C, 0x08, 0x20, 0xC8, 0x42, 0x08, 0x3E, 0x08, + 0xA0, 0x06, 0x32, 0xC7, 0xCB, 0x10, 0x80, 0x01, + 0x80, 0x00, 0x55, 0x04, 0x8B, 0xC0, 0xA0, 0xC2, + 0xF0, 0x07, 0x8C, 0x07, 0x04, 0x00, 0x8D, 0x07, + 0xFA, 0x07, 0xA0, 0xC3, 0x3C, 0x08, 0xE0, 0xC3, + 0x3E, 0x08, 0xA0, 0x06, 0x36, 0xBA, 0x60, 0x01, + 0xFC, 0x07, 0x01, 0x00, 0x04, 0x13, 0xA0, 0x07, + 0xFA, 0x08, 0x00, 0x80, 0x52, 0x04, 0x60, 0x01, + 0x60, 0x07, 0x04, 0x00, 0x07, 0x16, 0x20, 0xD0, + 0x04, 0xE0, 0x20, 0xE8, 0x1A, 0xE0, 0x58, 0x07, + 0x60, 0x04, 0x3E, 0xC7, 0xA0, 0x07, 0xFA, 0x08, + 0x00, 0x40, 0x20, 0xC8, 0x3C, 0x08, 0xFC, 0x08, + 0x20, 0xC8, 0x3E, 0x08, 0xFE, 0x08, 0xA0, 0x06, + 0x6C, 0xC7, 0xA0, 0x06, 0x38, 0xC7, 0xD3, 0x10, + 0xAD, 0xC2, 0x02, 0x00, 0x6D, 0xC2, 0x00, 0x00, + 0x05, 0x16, 0xAA, 0x07, 0x02, 0x00, 0x36, 0x07, + 0x9A, 0x2C, 0x80, 0x03, 0xEA, 0x2C, 0x02, 0x00, + 0x41, 0xCB, 0x00, 0x00, 0x80, 0x03, 0x2D, 0xC3, + 0x18, 0x00, 0xAC, 0x07, 0x02, 0x00, 0x36, 0x07, + 0x20, 0x4B, 0x06, 0xEB, 0x0A, 0x00, 0x20, 0xEB, + 0x00, 0xEB, 0x0A, 0x00, 0x9C, 0x2E, 0x80, 0x03, + 0xA0, 0xC2, 0x22, 0xE0, 0x60, 0x04, 0x8A, 0xA3, + 0xED, 0xC0, 0x18, 0x00, 0xA0, 0x06, 0x3A, 0xCC, + 0x80, 0x03, 0x44, 0xC2, 0xC3, 0xC0, 0x02, 0x13, + 0xA0, 0x06, 0x3A, 0xCC, 0x19, 0xC3, 0x09, 0xCB, + 0x18, 0x00, 0xC9, 0x05, 0x19, 0xCB, 0x16, 0x00, + 0x4C, 0xC2, 0x2C, 0x02, 0x1A, 0x00, 0x0D, 0xCF, + 0x0E, 0xCF, 0x0F, 0xC7, 0x99, 0x00, 0x5B, 0x04, + 0x8C, 0x07, 0x0A, 0x09, 0x9C, 0xC2, 0xA0, 0x22, + 0x14, 0xE0, 0x06, 0x13, 0xA0, 0xC2, 0x58, 0x07, + 0xA0, 0x22, 0x20, 0xE0, 0x01, 0x16, 0x80, 0x03, + 0x03, 0xC1, 0xC3, 0x04, 0x8A, 0x07, 0x04, 0x00, + 0x84, 0xA2, 0x3A, 0xCF, 0x3A, 0xCF, 0x3A, 0xCF, + 0x3A, 0xCF, 0x3A, 0xCF, 0xE0, 0x02, 0x58, 0x07, + 0x8D, 0x07, 0x0A, 0x09, 0x0B, 0xC8, 0xC2, 0x07, + 0xA0, 0x06, 0x44, 0xB8, 0xE0, 0xC2, 0xC2, 0x07, + 0x20, 0xE0, 0x20, 0xE0, 0xE0, 0x02, 0xB8, 0x07, + 0x5B, 0x04, 0x2D, 0xC3, 0x18, 0x00, 0x8C, 0xC2, + 0x60, 0xC2, 0x6C, 0x01, 0x0A, 0xC8, 0x6C, 0x01, + 0xE0, 0xC2, 0x00, 0xFC, 0x02, 0x13, 0x8B, 0xC2, + 0xF9, 0x10, 0x09, 0xC8, 0x6C, 0x01, 0x8B, 0x07, + 0xF8, 0x05, 0x5B, 0xC2, 0x0C, 0x13, 0xCB, 0x05, + 0x5B, 0xC2, 0xCA, 0xC6, 0xE0, 0xC2, 0x6C, 0x01, + 0x09, 0xC8, 0x6C, 0x01, 0x0C, 0xC8, 0x00, 0xFC, + 0x0B, 0xC8, 0x6C, 0x01, 0x02, 0x10, 0xCC, 0xCE, + 0xCA, 0xC6, 0xA0, 0xC2, 0xE0, 0x00, 0xA0, 0x22, + 0x1A, 0xE0, 0x06, 0x16, 0x20, 0xE8, 0x04, 0xE0, + 0x3A, 0x07, 0x20, 0x48, 0x1A, 0xE0, 0xE0, 0x00, + 0x80, 0x03, 0xE0, 0xD3, 0xAB, 0xE3, 0xE0, 0x04, + 0x8E, 0x09, 0xE0, 0xC1, 0xA8, 0x06, 0x05, 0x16, + 0x07, 0x02, 0xA2, 0x06, 0xA0, 0x06, 0x38, 0xB5, + 0x0B, 0x16, 0xE0, 0xC1, 0xBA, 0x06, 0x23, 0x16, + 0x07, 0x02, 0xB4, 0x06, 0xA0, 0x06, 0x38, 0xB5, + 0x1E, 0x13, 0x07, 0x02, 0xB8, 0x06, 0x02, 0x10, + 0x07, 0x02, 0xA6, 0x06, 0x60, 0xC1, 0x02, 0xFC, + 0x25, 0xC8, 0x0C, 0x00, 0x02, 0xFC, 0xC5, 0xC9, + 0x0C, 0x00, 0xF5, 0xCD, 0xF5, 0xCD, 0xF5, 0xCD, + 0xF5, 0xCD, 0xF5, 0xCD, 0xF5, 0xC5, 0xB7, 0x01, + 0x28, 0x00, 0x27, 0x02, 0xF4, 0xFF, 0xA7, 0x07, + 0x04, 0x00, 0x52, 0xCE, 0x20, 0xE8, 0x9E, 0x09, + 0x06, 0xFC, 0x97, 0x2E, 0xD2, 0x10, 0x00, 0x03, + 0x02, 0x00, 0xA0, 0x06, 0x50, 0xB5, 0x00, 0x03, + 0x0F, 0x00, 0x20, 0x2C, 0xF0, 0xED, 0xE0, 0x93, + 0xAB, 0xE3, 0x03, 0x16, 0x81, 0x02, 0x16, 0x00, + 0xC4, 0x16, 0x21, 0xC1, 0x10, 0xEB, 0x54, 0x04, + 0xE0, 0x93, 0x10, 0xE0, 0x03, 0x16, 0xA0, 0xD2, + 0xA8, 0xE3, 0x0B, 0x10, 0xCF, 0xD3, 0x09, 0x16, + 0xA0, 0x23, 0x08, 0xE0, 0x06, 0x16, 0x84, 0x07, + 0x20, 0x00, 0x04, 0xE8, 0xD2, 0x06, 0xA0, 0xD2, + 0x0C, 0xE0, 0x60, 0x04, 0xD2, 0xCE, 0x60, 0x04, + 0x70, 0xD1, 0x22, 0xC1, 0x04, 0x00, 0xE2, 0x04, + 0x02, 0x00, 0x54, 0x04, 0x02, 0xC8, 0x6C, 0x01, + 0x82, 0xA0, 0x22, 0xC8, 0x32, 0x0C, 0x00, 0xFC, + 0x02, 0x02, 0x00, 0xFC, 0xE0, 0x93, 0xAA, 0xE3, + 0x13, 0x16, 0xB0, 0x03, 0x20, 0x98, 0xAA, 0xE3, + 0x65, 0x06, 0x0D, 0x16, 0x8B, 0x07, 0x17, 0xFC, + 0xDB, 0xD2, 0x8B, 0x09, 0x8B, 0x02, 0x15, 0x00, + 0x7B, 0x1B, 0xEB, 0xD2, 0xC4, 0xEA, 0x06, 0x13, + 0x77, 0x15, 0x20, 0x07, 0xA0, 0x09, 0x74, 0x10, + 0xA0, 0x06, 0x02, 0xD0, 0xA0, 0x48, 0x04, 0xE0, + 0x0E, 0x00, 0x85, 0x02, 0x07, 0x00, 0x0E, 0x13, + 0x0E, 0x01, 0x03, 0x00, 0x0B, 0x13, 0xA0, 0x23, + 0x22, 0xE0, 0x03, 0x16, 0xA0, 0xD2, 0x0E, 0xE0, + 0x02, 0x10, 0xA0, 0xD2, 0xA8, 0xE3, 0x8E, 0x01, + 0x03, 0x00, 0x5E, 0x10, 0x05, 0xC8, 0xFC, 0x06, + 0xC3, 0xC0, 0x57, 0x16, 0xA0, 0x43, 0x10, 0xE0, + 0x22, 0x88, 0x0E, 0x00, 0x6C, 0x09, 0x0A, 0x16, + 0x22, 0x88, 0x10, 0x00, 0x6E, 0x09, 0x06, 0x16, + 0x22, 0x88, 0x12, 0x00, 0x70, 0x09, 0x02, 0x16, + 0xA0, 0xE3, 0x10, 0xE0, 0x85, 0x02, 0x09, 0x00, + 0x02, 0x13, 0xA0, 0x06, 0xB8, 0xD7, 0x45, 0xA1, + 0x65, 0xC1, 0xAC, 0xE3, 0x55, 0x04, 0x62, 0xC0, + 0x04, 0x00, 0x22, 0xC8, 0x06, 0x00, 0x6C, 0x01, + 0x82, 0x02, 0x48, 0x04, 0x02, 0x1B, 0xA0, 0x43, + 0x0C, 0xE0, 0x22, 0xC1, 0x0E, 0x00, 0x51, 0x04, + 0x42, 0xC0, 0xE1, 0x04, 0x02, 0x00, 0xA2, 0xC0, + 0x0C, 0x00, 0x22, 0xC1, 0x0A, 0x00, 0x20, 0x21, + 0x18, 0xE0, 0x07, 0x13, 0xA1, 0xC8, 0x0A, 0x00, + 0x0A, 0x00, 0xA1, 0xC8, 0x08, 0x00, 0x08, 0x00, + 0xE2, 0x10, 0x22, 0xC8, 0x06, 0x00, 0x6C, 0x01, + 0xA0, 0x06, 0x66, 0xD6, 0x60, 0x04, 0xB0, 0xCE, + 0x02, 0xC8, 0xD4, 0x06, 0x62, 0xC1, 0x02, 0x00, + 0x65, 0xC1, 0xD8, 0xE3, 0x55, 0x04, 0x0F, 0x10, + 0x0E, 0x10, 0x85, 0x07, 0xF4, 0x03, 0xF5, 0x04, + 0x60, 0xCD, 0xCE, 0xED, 0xA0, 0x06, 0xA2, 0xD8, + 0xA0, 0xE3, 0x0C, 0xE0, 0x20, 0xE8, 0x9E, 0x09, + 0x06, 0x04, 0xA0, 0x2E, 0xF4, 0x03, 0x60, 0x04, + 0xE4, 0xCC, 0xA0, 0x06, 0x26, 0xD5, 0x0C, 0x10, + 0xA0, 0x06, 0x66, 0xD6, 0x09, 0x10, 0xA0, 0x06, + 0x2A, 0xD8, 0x06, 0x10, 0xA0, 0x06, 0x66, 0xD6, + 0x03, 0xC8, 0x2A, 0x09, 0xA0, 0xD2, 0xAA, 0xE3, + 0xA0, 0x06, 0x6E, 0xCF, 0xA0, 0x92, 0x26, 0xE0, + 0x0C, 0x16, 0xE0, 0xD3, 0x26, 0xE0, 0xE0, 0x23, + 0x14, 0xE0, 0x0A, 0x13, 0x0A, 0xC1, 0xC4, 0x83, + 0x07, 0x13, 0xC4, 0xC3, 0x24, 0xC1, 0xDC, 0xE3, + 0x54, 0x04, 0xCA, 0x93, 0xDC, 0x13, 0xCA, 0xD3, + 0xB0, 0x03, 0x0F, 0xD8, 0x59, 0x06, 0x04, 0x71, + 0x24, 0xC1, 0xEC, 0xE3, 0x54, 0x04, 0xA0, 0x23, + 0x0C, 0xE0, 0xD1, 0x13, 0x4D, 0xC3, 0xCF, 0x13, + 0x4D, 0x01, 0x00, 0x04, 0x0B, 0x13, 0x86, 0x07, + 0x02, 0x00, 0x84, 0x07, 0x26, 0x00, 0x46, 0x23, + 0x03, 0x13, 0x44, 0x06, 0x86, 0xA1, 0xFB, 0x10, + 0x46, 0x43, 0xB3, 0x10, 0x84, 0x07, 0x18, 0x00, + 0x8D, 0x01, 0x00, 0x04, 0x85, 0x07, 0xF4, 0x03, + 0xF5, 0x04, 0x60, 0xCD, 0xCE, 0xED, 0xA0, 0x06, + 0xA2, 0xD8, 0x20, 0xE8, 0x9C, 0x09, 0xFE, 0x03, + 0x20, 0xE8, 0x9E, 0x09, 0x06, 0x04, 0xA8, 0x10, + 0x85, 0x07, 0x1C, 0x07, 0x86, 0x07, 0x1A, 0x04, + 0x76, 0x6D, 0x76, 0x6D, 0x76, 0x6D, 0xC6, 0x05, + 0x76, 0x6D, 0x76, 0x6D, 0x76, 0x6D, 0x83, 0x07, + 0x00, 0x90, 0xA9, 0x10, 0x0B, 0xC3, 0x86, 0x07, + 0x00, 0x01, 0x85, 0x07, 0x00, 0x80, 0x20, 0xC1, + 0xD2, 0x06, 0x37, 0x13, 0xC4, 0x04, 0x60, 0xC0, + 0xD2, 0x06, 0x45, 0x20, 0x04, 0x13, 0x84, 0x05, + 0x15, 0x09, 0xF9, 0x16, 0x2E, 0x10, 0xCF, 0xD3, + 0x06, 0x16, 0xE0, 0x23, 0x14, 0xE0, 0x03, 0x16, + 0x0E, 0x01, 0x03, 0x00, 0x03, 0x13, 0xE0, 0x04, + 0xD2, 0x06, 0x23, 0x10, 0x64, 0xD0, 0x1C, 0x07, + 0x46, 0xB0, 0x10, 0x18, 0x01, 0xD9, 0x1C, 0x07, + 0x60, 0x23, 0x20, 0xE0, 0x0B, 0x13, 0x81, 0x07, + 0x18, 0x00, 0x61, 0xC0, 0xFC, 0xE3, 0x11, 0x88, + 0xCE, 0xED, 0x04, 0x13, 0x08, 0x02, 0x18, 0x80, + 0xA0, 0x06, 0xDA, 0xD4, 0x64, 0xD0, 0x28, 0x07, + 0x46, 0xB0, 0x08, 0x18, 0x01, 0xD9, 0x28, 0x07, + 0x46, 0xB0, 0x04, 0x17, 0x83, 0x07, 0x40, 0x80, + 0xA0, 0x06, 0x2A, 0xD8, 0x05, 0x48, 0xD2, 0x06, + 0xCA, 0x16, 0x20, 0xC1, 0x32, 0x09, 0x01, 0x16, + 0x5C, 0x04, 0x04, 0x02, 0x07, 0x00, 0x20, 0x06, + 0x32, 0x09, 0x05, 0x02, 0x00, 0x01, 0xC7, 0x10, + 0x0B, 0xC3, 0xC5, 0x04, 0x42, 0xC0, 0xC7, 0x04, + 0x20, 0xC2, 0x6C, 0x01, 0xE1, 0xA1, 0x04, 0x00, + 0x11, 0xC8, 0x6C, 0x01, 0xFB, 0x16, 0x08, 0xC8, + 0x6C, 0x01, 0xC8, 0x04, 0xA0, 0x43, 0x1A, 0xE0, + 0x22, 0xC1, 0x0E, 0x00, 0x0D, 0x15, 0x0C, 0x13, + 0xA0, 0xE3, 0x1A, 0xE0, 0xA0, 0x06, 0x14, 0xD8, + 0x08, 0xC2, 0x48, 0x13, 0x88, 0x02, 0x12, 0x00, + 0x45, 0x1B, 0x20, 0x22, 0x22, 0xE0, 0x42, 0x13, + 0x02, 0xC1, 0x08, 0xA1, 0x08, 0x05, 0x28, 0x02, + 0xF2, 0xFF, 0x07, 0xA2, 0x83, 0x07, 0x01, 0x80, + 0x88, 0x02, 0x04, 0x00, 0x6E, 0x11, 0x64, 0xC2, + 0x16, 0x00, 0x49, 0xD2, 0x02, 0x16, 0x02, 0x81, + 0x31, 0x16, 0x09, 0x01, 0x00, 0xF0, 0x28, 0x16, + 0x49, 0xC1, 0x45, 0x71, 0xC3, 0x04, 0x85, 0x02, + 0x09, 0x00, 0x7C, 0x13, 0x83, 0x07, 0x02, 0x80, + 0xA4, 0xC1, 0x14, 0x00, 0x88, 0x81, 0x76, 0x16, + 0x83, 0x05, 0x85, 0x02, 0x15, 0x00, 0x13, 0x1B, + 0x83, 0x05, 0x49, 0x99, 0x30, 0xEB, 0x0A, 0x13, + 0x09, 0x98, 0x0E, 0xE0, 0x6B, 0x16, 0x25, 0x98, + 0x30, 0xEB, 0x0C, 0xE0, 0x67, 0x16, 0xE0, 0xC1, + 0xEC, 0x06, 0x64, 0x16, 0xC3, 0x04, 0x52, 0xC2, + 0x0F, 0x13, 0x83, 0x07, 0x09, 0x80, 0xE0, 0xC1, + 0x6A, 0x09, 0x47, 0x01, 0x00, 0x10, 0x5A, 0x16, + 0xA0, 0xC0, 0x6C, 0x01, 0xA0, 0x06, 0xBE, 0xD6, + 0x60, 0x04, 0xB0, 0xCE, 0x60, 0x04, 0xBA, 0xCE, + 0x89, 0x07, 0x0E, 0x07, 0xC7, 0x04, 0xE5, 0xD1, + 0x46, 0xEB, 0x05, 0x13, 0xC7, 0x06, 0x27, 0x02, + 0x5C, 0xEB, 0x77, 0xCE, 0xFE, 0x15, 0x44, 0xC0, + 0x21, 0x02, 0x18, 0x00, 0x28, 0x02, 0xFC, 0xFF, + 0x36, 0x13, 0x91, 0xC1, 0x86, 0xD1, 0x1F, 0x13, + 0xC6, 0x06, 0x87, 0x07, 0x0E, 0x07, 0xF7, 0xC0, + 0x46, 0x02, 0xFF, 0xBF, 0x43, 0x02, 0xFF, 0x3F, + 0xA0, 0x91, 0xF5, 0xED, 0x09, 0x16, 0xB0, 0x03, + 0x20, 0x98, 0x0E, 0xE0, 0x5D, 0x06, 0x0F, 0x16, + 0x21, 0xC8, 0x02, 0x00, 0x0C, 0x07, 0x17, 0x10, + 0x47, 0x82, 0x0C, 0x1B, 0xC6, 0x90, 0xEB, 0x16, + 0x47, 0x06, 0xF7, 0x04, 0xB0, 0x03, 0x20, 0x98, + 0x5D, 0x06, 0x57, 0x06, 0x0C, 0x13, 0x83, 0x07, + 0x05, 0x80, 0x1C, 0x10, 0xD1, 0xC0, 0xE0, 0x20, + 0x16, 0xE0, 0x03, 0x16, 0x83, 0x07, 0x08, 0x80, + 0x15, 0x10, 0x60, 0x44, 0x26, 0xE0, 0x86, 0x71, + 0x46, 0xA0, 0x06, 0x62, 0x83, 0x07, 0x05, 0x80, + 0x08, 0xC2, 0xCB, 0x15, 0x0B, 0x16, 0xC3, 0x04, + 0x87, 0x07, 0x0E, 0x07, 0x77, 0xC0, 0x47, 0x82, + 0x05, 0x1B, 0x60, 0x20, 0x06, 0xE0, 0xFA, 0x16, + 0x83, 0x07, 0x07, 0x80, 0x5C, 0x04, 0xA0, 0x92, + 0x0E, 0xE0, 0x11, 0x16, 0x20, 0xC8, 0x20, 0xE0, + 0x08, 0x07, 0xE0, 0x04, 0x84, 0x01, 0x60, 0x05, + 0x02, 0x07, 0x4B, 0x13, 0x20, 0x48, 0x06, 0xE0, + 0x82, 0x01, 0xA0, 0x06, 0xD0, 0xD4, 0x83, 0x07, + 0x00, 0xC0, 0xA0, 0x06, 0x2A, 0xD8, 0x20, 0xC8, + 0x1E, 0xE0, 0x02, 0x07, 0xA0, 0xE3, 0x04, 0xE0, + 0x08, 0x02, 0x24, 0x80, 0xA0, 0x06, 0xDA, 0xD4, + 0x42, 0x10, 0x20, 0xC1, 0x84, 0x01, 0x44, 0x02, + 0x00, 0x88, 0x2A, 0x13, 0x04, 0x48, 0x84, 0x01, + 0x20, 0x06, 0x02, 0x07, 0xF1, 0x16, 0x60, 0x01, + 0x8E, 0x09, 0x00, 0x80, 0x15, 0x13, 0xA0, 0x23, + 0x22, 0xE0, 0x05, 0x16, 0xA0, 0x43, 0x22, 0xE0, + 0xA0, 0xD2, 0x0E, 0xE0, 0xCF, 0x10, 0xE0, 0x23, + 0x14, 0xE0, 0x04, 0x13, 0x20, 0x98, 0xA9, 0xE3, + 0x65, 0x06, 0x0C, 0x16, 0xA0, 0x92, 0x0E, 0xE0, + 0xC5, 0x13, 0xA0, 0xD2, 0xA8, 0xE3, 0xD3, 0x10, + 0x20, 0xC8, 0x20, 0xE0, 0x08, 0x07, 0x83, 0x07, + 0x00, 0xC0, 0x04, 0x10, 0x83, 0x07, 0x02, 0x00, + 0x60, 0x04, 0xCA, 0xCE, 0x60, 0x04, 0xC0, 0xCE, + 0x20, 0xE8, 0x06, 0xE0, 0x82, 0x01, 0xA0, 0x06, + 0xD0, 0xD4, 0x20, 0x07, 0x02, 0x07, 0xA0, 0x43, + 0x04, 0xE0, 0x20, 0xC8, 0xAE, 0xE4, 0x86, 0x01, + 0x20, 0x88, 0x20, 0xE0, 0x08, 0x07, 0x03, 0x16, + 0x20, 0xC8, 0x78, 0xEB, 0x08, 0x07, 0x60, 0x04, + 0xD2, 0xCE, 0x0E, 0x01, 0x03, 0x00, 0x16, 0x13, + 0xCF, 0xD3, 0x08, 0x16, 0xA0, 0x23, 0x20, 0xE0, + 0x03, 0x16, 0xA0, 0xD2, 0xA8, 0xE3, 0x02, 0x10, + 0xA0, 0xD2, 0x0E, 0xE0, 0x8E, 0x01, 0x03, 0x00, + 0x09, 0x10, 0x60, 0xC1, 0x84, 0x01, 0x60, 0x21, + 0x0A, 0xE0, 0x04, 0x16, 0x83, 0x07, 0x00, 0x84, + 0x60, 0x04, 0xCA, 0xCE, 0x20, 0xC8, 0x2E, 0xE0, + 0x84, 0x01, 0x08, 0x02, 0x06, 0x80, 0xA0, 0x06, + 0xDA, 0xD4, 0x60, 0x04, 0xD2, 0xCE, 0x60, 0xE3, + 0x20, 0xE0, 0x60, 0x04, 0xD2, 0xCE, 0xE0, 0x93, + 0x26, 0xE0, 0x10, 0x16, 0xA0, 0x23, 0x08, 0xE0, + 0x0D, 0x16, 0xA0, 0x23, 0x06, 0xE0, 0x02, 0x13, + 0x60, 0xE3, 0x1C, 0xE0, 0x60, 0xE3, 0x18, 0xE0, + 0xA0, 0x43, 0x06, 0xE0, 0x08, 0x02, 0x3C, 0x80, + 0xA0, 0x06, 0xDA, 0xD4, 0x60, 0x04, 0xD2, 0xCE, + 0xA0, 0x92, 0xA8, 0xE3, 0x03, 0x13, 0xA0, 0x92, + 0xA9, 0xE3, 0x1E, 0x16, 0xE0, 0x23, 0x14, 0xE0, + 0x08, 0x13, 0x20, 0x98, 0xA9, 0xE3, 0x65, 0x06, + 0x04, 0x13, 0x83, 0x07, 0x07, 0x00, 0x60, 0x04, + 0xCA, 0xCE, 0xA0, 0xD2, 0x0E, 0xE0, 0x20, 0xC8, + 0x20, 0xE0, 0x08, 0x07, 0xA0, 0x27, 0x04, 0xE0, + 0x0B, 0x16, 0x20, 0xC8, 0x1E, 0xE0, 0x08, 0x07, + 0xE0, 0x93, 0xA8, 0xE3, 0x05, 0x16, 0xA0, 0x23, + 0x12, 0xE0, 0x02, 0x13, 0x20, 0x06, 0x08, 0x07, + 0x60, 0x04, 0xD2, 0xCE, 0xE0, 0x23, 0x14, 0xE0, + 0x3E, 0x13, 0xB0, 0x03, 0x20, 0x98, 0x0E, 0xE0, + 0x6F, 0x06, 0x0F, 0x16, 0xCF, 0xD3, 0x37, 0x16, + 0xA0, 0xD2, 0xA8, 0xE3, 0x60, 0x04, 0xD2, 0xCE, + 0xA0, 0x92, 0x0C, 0xE0, 0x30, 0x16, 0xE0, 0x23, + 0x14, 0xE0, 0xF6, 0x13, 0x83, 0x07, 0x06, 0x00, + 0x07, 0x10, 0x83, 0x07, 0x05, 0x00, 0xE0, 0x93, + 0x0E, 0xE0, 0x02, 0x16, 0x83, 0x07, 0x07, 0x00, + 0x60, 0x04, 0xCA, 0xCE, 0x60, 0xE3, 0x12, 0xE0, + 0xE0, 0x23, 0x14, 0xE0, 0x11, 0x13, 0x20, 0x98, + 0x0C, 0xE0, 0x65, 0x06, 0x03, 0x16, 0x20, 0xD8, + 0xA9, 0xE3, 0x65, 0x06, 0x14, 0x10, 0x60, 0x01, + 0x8E, 0x09, 0x00, 0x80, 0x10, 0x13, 0x20, 0xC1, + 0x84, 0x01, 0x20, 0x21, 0x06, 0xE0, 0xD2, 0x16, + 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, 0x07, 0x13, + 0x20, 0x48, 0x06, 0xE0, 0x84, 0x01, 0x08, 0x02, + 0x30, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x60, 0x04, + 0xD2, 0xCE, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x20, + 0xFA, 0x16, 0x08, 0x02, 0x78, 0x80, 0xA0, 0x06, + 0xDA, 0xD4, 0x20, 0xC2, 0xA2, 0x09, 0x03, 0x13, + 0x20, 0x06, 0xA2, 0x09, 0x21, 0x13, 0x20, 0xC2, + 0xA4, 0x09, 0xED, 0x13, 0x20, 0x06, 0xA4, 0x09, + 0xEA, 0x16, 0xA0, 0x07, 0xA4, 0x09, 0x05, 0x00, + 0xCD, 0x01, 0x00, 0x04, 0xE4, 0x10, 0x60, 0x01, + 0x8E, 0x09, 0x80, 0x00, 0x3E, 0x13, 0x60, 0x01, + 0x8E, 0x09, 0x00, 0x10, 0x02, 0x16, 0xA0, 0x06, + 0xE6, 0xD5, 0xA0, 0x01, 0x8E, 0x09, 0x00, 0x10, + 0xE0, 0x01, 0x8E, 0x09, 0x80, 0x00, 0x83, 0x07, + 0x00, 0xA8, 0xA0, 0x06, 0x2A, 0xD8, 0x16, 0x10, + 0x60, 0x01, 0x8E, 0x09, 0x00, 0x04, 0x21, 0x13, + 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x10, 0xA0, 0x07, + 0x08, 0x07, 0x05, 0x00, 0x83, 0x07, 0x08, 0xA8, + 0xA0, 0x23, 0x04, 0xE0, 0x05, 0x16, 0x20, 0xC8, + 0x20, 0xE0, 0x08, 0x07, 0x83, 0x07, 0x08, 0xE8, + 0xA0, 0x06, 0x2A, 0xD8, 0xA0, 0x01, 0x8E, 0x09, + 0x00, 0x20, 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x01, + 0xE0, 0x01, 0x82, 0x01, 0x00, 0x08, 0xA0, 0xD2, + 0x0E, 0xE0, 0x83, 0x07, 0x10, 0x80, 0x60, 0x04, + 0xC0, 0xCE, 0x08, 0x02, 0x78, 0x00, 0xA0, 0x06, + 0xDA, 0xD4, 0x83, 0x07, 0x00, 0x82, 0x60, 0x04, + 0xCA, 0xCE, 0x60, 0x04, 0xD2, 0xCE, 0x20, 0x06, + 0x90, 0x09, 0x07, 0x15, 0xA0, 0xD2, 0x10, 0xE0, + 0xCA, 0x06, 0xA0, 0xD2, 0x26, 0xE0, 0xCF, 0x04, + 0xF4, 0x10, 0x08, 0x02, 0x7E, 0x80, 0xA0, 0x06, + 0xDA, 0xD4, 0x20, 0xC2, 0x90, 0x09, 0x88, 0x02, + 0x96, 0x00, 0x0D, 0x1B, 0xEA, 0x16, 0x20, 0x48, + 0x08, 0xE0, 0x82, 0x01, 0xA0, 0x01, 0x8E, 0x09, + 0x00, 0x10, 0xA0, 0x06, 0xE6, 0xD5, 0x83, 0x07, + 0x00, 0x28, 0x60, 0x04, 0xC0, 0xCE, 0x60, 0x01, + 0x8E, 0x09, 0x00, 0x10, 0xDA, 0x16, 0x84, 0x07, + 0x04, 0x00, 0x85, 0x07, 0xF4, 0x03, 0xF5, 0x04, + 0xB5, 0x07, 0x30, 0x06, 0xA0, 0x06, 0xA2, 0xD8, + 0xA0, 0x07, 0xF8, 0x03, 0x34, 0xD4, 0x60, 0x04, + 0xC0, 0xDB, 0xA0, 0x07, 0x90, 0x09, 0xF4, 0x01, + 0x08, 0x02, 0x7E, 0x80, 0xA0, 0x06, 0xDA, 0xD4, + 0x08, 0x02, 0x36, 0x00, 0xA0, 0x06, 0xDA, 0xD4, + 0x20, 0xE8, 0x0C, 0xE0, 0x82, 0x01, 0xA0, 0x23, + 0x18, 0xE0, 0x06, 0x13, 0xA0, 0xE3, 0x18, 0xE0, + 0xE0, 0x2E, 0x00, 0x00, 0x41, 0xC0, 0xFA, 0x16, + 0xA0, 0x06, 0xE6, 0xD5, 0xB2, 0x10, 0x04, 0x02, + 0x64, 0x00, 0x04, 0x06, 0xFE, 0x16, 0x5B, 0x04, + 0xA0, 0xE3, 0x0A, 0xE0, 0x08, 0xC2, 0x02, 0x11, + 0xA0, 0x43, 0x0A, 0xE0, 0x20, 0x42, 0x04, 0xE0, + 0x28, 0x02, 0xFC, 0xE3, 0x58, 0xC0, 0x02, 0xC0, + 0x11, 0x88, 0xCE, 0xED, 0x03, 0x16, 0xD1, 0x2C, + 0x58, 0xC0, 0xD1, 0x04, 0x80, 0xC0, 0x0E, 0x01, + 0x00, 0x10, 0x0F, 0x13, 0x60, 0xCC, 0xCE, 0xED, + 0xC8, 0x05, 0x78, 0xCC, 0x03, 0x16, 0x41, 0x06, + 0x60, 0xCC, 0xD6, 0x06, 0x58, 0xC4, 0x02, 0x16, + 0x60, 0xC4, 0x00, 0x07, 0x21, 0x02, 0xFA, 0xFF, + 0x91, 0x2C, 0x5B, 0x04, 0x0B, 0xC3, 0xA0, 0x06, + 0xC2, 0xD5, 0xA0, 0x06, 0x9C, 0xD5, 0x08, 0xC2, + 0x05, 0x16, 0x62, 0xC2, 0x02, 0x00, 0x60, 0x26, + 0xA8, 0xE4, 0x0D, 0x16, 0x42, 0xC2, 0xC9, 0x05, + 0x60, 0xCE, 0xF2, 0xED, 0x60, 0xC6, 0x7C, 0xEB, + 0xA0, 0x06, 0x10, 0xD6, 0x18, 0xCA, 0x0A, 0x00, + 0x20, 0x46, 0x26, 0xE0, 0x04, 0x16, 0xA0, 0xC0, + 0x6C, 0x01, 0x12, 0x2E, 0x1D, 0x10, 0x12, 0xC1, + 0x05, 0x13, 0x60, 0xC1, 0x6C, 0x01, 0x14, 0x2E, + 0x05, 0xC8, 0x6C, 0x01, 0xD2, 0x04, 0x48, 0x06, + 0x84, 0x07, 0x02, 0x00, 0x48, 0xC1, 0xA0, 0xC0, + 0x6C, 0x01, 0x02, 0xC0, 0xA0, 0x06, 0xA2, 0xD8, + 0x60, 0xC5, 0x02, 0xFC, 0x07, 0x02, 0xA2, 0x06, + 0x25, 0x02, 0xF4, 0xFF, 0x05, 0xC8, 0x02, 0xFC, + 0x20, 0xC2, 0x6C, 0x01, 0xA0, 0x06, 0xFC, 0xB4, + 0x5C, 0x04, 0x42, 0xC2, 0x29, 0x02, 0x08, 0x00, + 0x39, 0xC2, 0x48, 0x02, 0x00, 0xC0, 0x88, 0x02, + 0x00, 0xC0, 0x08, 0x16, 0x60, 0x8E, 0x2E, 0xE0, + 0x05, 0x16, 0x60, 0x86, 0x2E, 0xE0, 0x02, 0x16, + 0xC8, 0x04, 0x5B, 0x04, 0x08, 0x07, 0x5B, 0x04, + 0x20, 0x88, 0x8E, 0xE1, 0x6C, 0x01, 0x02, 0x16, + 0x60, 0x04, 0xBA, 0xCE, 0x5B, 0x04, 0x88, 0x07, + 0xAE, 0x01, 0x20, 0xE8, 0x0E, 0xE0, 0x80, 0x01, + 0x08, 0x06, 0xFE, 0x16, 0x20, 0x48, 0x0E, 0xE0, + 0x80, 0x01, 0x5B, 0x04, 0xC2, 0x04, 0xA0, 0x23, + 0x0C, 0xE0, 0x10, 0x16, 0x20, 0x2F, 0x30, 0x06, + 0x82, 0x07, 0xDF, 0xFF, 0x02, 0x2C, 0x82, 0x02, + 0xF4, 0x03, 0x06, 0x13, 0xE2, 0x04, 0x02, 0x00, + 0xA2, 0xC0, 0x06, 0x00, 0x12, 0x2E, 0xF4, 0x10, + 0xA0, 0x43, 0x0C, 0xE0, 0x5B, 0x04, 0x42, 0xC2, + 0x88, 0x07, 0x0E, 0x00, 0x09, 0xA2, 0x29, 0x02, + 0x08, 0x00, 0x78, 0xCE, 0x78, 0xCE, 0x78, 0xCE, + 0x60, 0xCE, 0x6C, 0x09, 0x60, 0xCE, 0x6E, 0x09, + 0x60, 0xCE, 0x70, 0x09, 0xA0, 0x23, 0x1A, 0xE0, + 0x0F, 0x16, 0x58, 0xC2, 0x49, 0x02, 0x80, 0x1F, + 0x60, 0x2A, 0x14, 0xE0, 0xA0, 0xE8, 0x04, 0xE0, + 0x0E, 0x00, 0x09, 0xC6, 0x49, 0x02, 0x00, 0x1F, + 0xC9, 0x06, 0x09, 0xA2, 0x89, 0xA8, 0x04, 0x00, + 0x28, 0x02, 0x02, 0x00, 0x58, 0xC2, 0x49, 0x0A, + 0x49, 0x02, 0x00, 0xF0, 0x09, 0xD6, 0xE2, 0x04, + 0x06, 0x00, 0x5B, 0x04, 0x00, 0x07, 0x82, 0xC0, + 0x53, 0x13, 0xA0, 0xC0, 0x6C, 0x01, 0xA0, 0xC1, + 0x06, 0xFC, 0x46, 0x02, 0x0F, 0x00, 0x86, 0x02, + 0x01, 0x00, 0x3D, 0x12, 0x06, 0x88, 0xF2, 0x06, + 0x12, 0x16, 0x01, 0x02, 0x0E, 0xFC, 0x31, 0x88, + 0xF4, 0x06, 0x0D, 0x16, 0x31, 0x88, 0xF6, 0x06, + 0x0A, 0x16, 0x31, 0x88, 0xF8, 0x06, 0x07, 0x16, + 0x86, 0x02, 0x02, 0x00, 0x2C, 0x16, 0x20, 0x88, + 0x0A, 0x07, 0xFA, 0x06, 0x28, 0x13, 0x20, 0xC1, + 0x6A, 0x09, 0x44, 0x01, 0x00, 0x08, 0x06, 0x13, + 0x86, 0x02, 0x02, 0x00, 0x20, 0x16, 0x44, 0x01, + 0x80, 0x00, 0x1D, 0x16, 0x00, 0x07, 0xE0, 0x23, + 0x14, 0xE0, 0x19, 0x16, 0x82, 0x02, 0x43, 0x00, + 0x16, 0x13, 0x00, 0x02, 0x02, 0xFC, 0x40, 0xC0, + 0xB0, 0x01, 0x20, 0x00, 0x60, 0x01, 0x6A, 0x09, + 0x01, 0x00, 0x07, 0x16, 0x60, 0xA0, 0x2C, 0x09, + 0x60, 0xCC, 0xEE, 0x05, 0x50, 0xC4, 0x20, 0xC4, + 0x2C, 0x09, 0x80, 0x07, 0x36, 0x07, 0x81, 0x07, + 0x40, 0x00, 0x40, 0x2C, 0xC0, 0x04, 0x84, 0x07, + 0xF2, 0x06, 0x06, 0xCD, 0x01, 0x02, 0x0E, 0xFC, + 0x31, 0xCD, 0x31, 0xCD, 0x31, 0xCD, 0x20, 0xC5, + 0x0A, 0x07, 0x00, 0xC0, 0x01, 0x13, 0x12, 0x2E, + 0xE0, 0x04, 0x6C, 0x01, 0x5B, 0x04, 0x60, 0x01, + 0x8A, 0x09, 0x00, 0x80, 0x12, 0x13, 0x0B, 0xC8, + 0x22, 0x09, 0xA0, 0x06, 0x3E, 0xD7, 0x08, 0x02, + 0x42, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x08, 0x02, + 0x30, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0xE0, 0xC2, + 0x22, 0x09, 0x5B, 0x04, 0x20, 0x48, 0xAC, 0xE4, + 0x80, 0x01, 0x20, 0x48, 0x7E, 0xEB, 0x82, 0x01, + 0x20, 0x48, 0x22, 0xE0, 0xAE, 0x01, 0x20, 0x48, + 0x22, 0xE0, 0x78, 0x09, 0x60, 0x43, 0x18, 0xE0, + 0xA0, 0x43, 0x08, 0xE0, 0x60, 0x01, 0x8A, 0x09, + 0x00, 0x80, 0xEB, 0x13, 0x0B, 0xC3, 0x08, 0x02, + 0x42, 0x00, 0xA0, 0x06, 0xDA, 0xD4, 0x5C, 0x04, + 0x0B, 0xC3, 0x20, 0xE8, 0x0E, 0xE0, 0x82, 0x01, + 0x20, 0xE8, 0x22, 0xE0, 0xAE, 0x01, 0x20, 0xE8, + 0x22, 0xE0, 0x78, 0x09, 0xA0, 0xE3, 0x08, 0xE0, + 0x60, 0xE3, 0x18, 0xE0, 0xA0, 0x43, 0x06, 0xE0, + 0x08, 0x02, 0x3C, 0x80, 0xA0, 0x06, 0xDA, 0xD4, + 0x08, 0x02, 0x42, 0x80, 0xA0, 0x06, 0xDA, 0xD4, + 0x5C, 0x04, 0x0B, 0xC3, 0x83, 0x07, 0x00, 0x68, + 0xA0, 0x06, 0x2A, 0xD8, 0x83, 0x07, 0x10, 0x80, + 0xA0, 0x06, 0x2A, 0xD8, 0x5C, 0x04, 0x0B, 0xC3, + 0xA0, 0x06, 0x14, 0xD8, 0x02, 0xA2, 0x68, 0xC2, + 0x14, 0x00, 0x29, 0x02, 0xFC, 0xFF, 0x24, 0x13, + 0x28, 0x02, 0x18, 0x00, 0x87, 0x07, 0x0E, 0x00, + 0x81, 0x07, 0x0E, 0x07, 0xF1, 0x04, 0x47, 0x06, + 0xFD, 0x15, 0x58, 0xC0, 0xB0, 0x03, 0x01, 0x78, + 0x63, 0x06, 0x41, 0x02, 0x3F, 0x00, 0x0E, 0x13, + 0x81, 0x02, 0x1F, 0x00, 0x0B, 0x1B, 0x41, 0xA0, + 0x61, 0xC0, 0x86, 0xE4, 0xF8, 0xC1, 0xC7, 0x06, + 0xC7, 0x71, 0x47, 0x06, 0x78, 0xCC, 0x47, 0x06, + 0xFD, 0x15, 0x04, 0x10, 0x58, 0xC0, 0xC1, 0x06, + 0x41, 0x70, 0x01, 0xA2, 0x49, 0xC2, 0xE5, 0x15, + 0x5C, 0x04, 0xA0, 0x23, 0x1A, 0xE0, 0x02, 0x13, + 0xC8, 0x04, 0x5B, 0x04, 0x22, 0xC2, 0x14, 0x00, + 0x48, 0x02, 0x00, 0x1F, 0xC8, 0x06, 0x5B, 0x04, + 0x83, 0x02, 0x0F, 0x00, 0x17, 0x1B, 0xA0, 0xC1, + 0xD4, 0x06, 0x35, 0x13, 0x26, 0x02, 0x04, 0x00, + 0xA0, 0xCD, 0xCE, 0xED, 0x83, 0xC5, 0x04, 0x13, + 0x4A, 0xC2, 0x39, 0x0A, 0xC9, 0xE0, 0x83, 0xC5, + 0x86, 0x07, 0x36, 0x07, 0x87, 0x07, 0x10, 0x00, + 0x20, 0xC2, 0xD4, 0x06, 0xE0, 0x04, 0xD4, 0x06, + 0x46, 0x2C, 0x5B, 0x04, 0x60, 0xC0, 0xFE, 0x06, + 0x20, 0xC2, 0x6A, 0x09, 0x48, 0x02, 0x00, 0x60, + 0x20, 0x22, 0x06, 0xE0, 0x04, 0x16, 0x20, 0xE2, + 0x0A, 0xE0, 0x20, 0xE2, 0x18, 0xE0, 0x13, 0x0A, + 0x04, 0x18, 0x41, 0x05, 0x03, 0x48, 0xFE, 0x06, + 0x06, 0x10, 0x83, 0x02, 0x02, 0x00, 0x01, 0x16, + 0x13, 0x09, 0x03, 0xE8, 0xFE, 0x06, 0xC8, 0x40, + 0xC1, 0x40, 0x05, 0x13, 0x88, 0x07, 0x36, 0x07, + 0x89, 0x07, 0x00, 0x40, 0x48, 0x2C, 0x5B, 0x04, + 0xC9, 0x04, 0x24, 0xC1, 0x94, 0xEB, 0x84, 0xC1, + 0x86, 0x71, 0x86, 0xA1, 0x26, 0x02, 0x56, 0xEC, + 0xC4, 0x06, 0x04, 0x71, 0x24, 0x02, 0xC2, 0xEB, + 0x14, 0xD2, 0xC8, 0x09, 0x08, 0xA2, 0xB0, 0x03, + 0x34, 0xD8, 0x5F, 0x06, 0x47, 0x02, 0x0F, 0x00, + 0xC7, 0xA1, 0x28, 0xC2, 0x82, 0xEB, 0x58, 0x04, + 0x76, 0xCD, 0x47, 0x06, 0xFD, 0x16, 0x32, 0x10, + 0x36, 0xC2, 0x26, 0x10, 0x17, 0x09, 0x47, 0xA1, + 0x2D, 0x10, 0x17, 0x09, 0x47, 0x61, 0x2A, 0x10, + 0xA0, 0x43, 0x16, 0xE0, 0x5B, 0x04, 0xA0, 0x43, + 0x16, 0xE0, 0x49, 0xC2, 0x03, 0x16, 0x44, 0xC2, + 0x06, 0xC8, 0x22, 0x09, 0x27, 0xC1, 0x8E, 0xED, + 0x84, 0xC1, 0x86, 0x71, 0x26, 0x02, 0xC4, 0xED, + 0xC4, 0x06, 0x04, 0x71, 0x24, 0x02, 0xAA, 0xED, + 0xD3, 0x10, 0x09, 0xC1, 0xA0, 0xC1, 0x22, 0x09, + 0xC9, 0x04, 0x10, 0x10, 0x36, 0xC2, 0x78, 0xD5, + 0x60, 0x41, 0x22, 0xE0, 0xC5, 0x05, 0x0A, 0x10, + 0x78, 0xCD, 0x47, 0x06, 0xFD, 0x15, 0x06, 0x10, + 0xA0, 0x23, 0x16, 0xE0, 0xCD, 0x16, 0x49, 0xC2, + 0xEC, 0x16, 0xD6, 0x10, 0xA0, 0xE3, 0x16, 0xE0, + 0xBB, 0x10, 0x08, 0x02, 0x5A, 0x80, 0xA0, 0x06, + 0xDA, 0xD4, 0x44, 0x10, 0xA0, 0x92, 0x0C, 0xE0, + 0x15, 0x16, 0x44, 0x02, 0x00, 0x5E, 0x14, 0x16, + 0x20, 0x48, 0xAC, 0xE4, 0x80, 0x01, 0xA0, 0x06, + 0x72, 0xD7, 0x20, 0xC8, 0x9E, 0x01, 0x9E, 0x01, + 0xE0, 0x2E, 0x01, 0x00, 0xA0, 0x43, 0x18, 0xE0, + 0xA0, 0xD2, 0x26, 0xE0, 0x83, 0x07, 0x10, 0x00, + 0xA0, 0x06, 0x2A, 0xD8, 0x60, 0x04, 0xD2, 0xCE, + 0x84, 0x07, 0x08, 0x00, 0x60, 0x04, 0x94, 0xCE, + 0x85, 0x07, 0x03, 0x02, 0x05, 0xC8, 0xCE, 0x06, + 0xA0, 0x43, 0x12, 0xE0, 0xE0, 0x04, 0xFA, 0x06, + 0xA0, 0x06, 0xA4, 0xD7, 0x08, 0x02, 0x48, 0x80, + 0xA0, 0x06, 0xDA, 0xD4, 0x17, 0x10, 0x60, 0x01, + 0x8E, 0x09, 0x00, 0x80, 0x02, 0x16, 0x60, 0x04, + 0x9C, 0xD4, 0xA0, 0x27, 0x2C, 0xE0, 0x04, 0x16, + 0x08, 0x02, 0x54, 0x80, 0xA0, 0x06, 0xDA, 0xD4, + 0x83, 0x07, 0x00, 0xA8, 0x20, 0x88, 0x08, 0x07, + 0x20, 0xE0, 0x02, 0x16, 0x83, 0x07, 0x00, 0xE8, + 0xA0, 0x06, 0x2A, 0xD8, 0x08, 0x02, 0x36, 0x00, + 0xA0, 0x06, 0xDA, 0xD4, 0x20, 0xE8, 0x0C, 0xE0, + 0x82, 0x01, 0xA0, 0x23, 0x18, 0xE0, 0x06, 0x13, + 0xA0, 0xE3, 0x18, 0xE0, 0xE0, 0x2E, 0x00, 0x00, + 0x41, 0xC0, 0xFA, 0x16, 0xA0, 0x06, 0xE6, 0xD5, + 0x82, 0xC0, 0x02, 0x13, 0x4F, 0x02, 0x80, 0xFF, + 0xC4, 0x04, 0x0F, 0xD1, 0xC4, 0x06, 0x60, 0x04, + 0x94, 0xCE, 0xA0, 0x06, 0x32, 0xDA, 0x08, 0x02, + 0x36, 0x80, 0xA0, 0x07, 0xD6, 0x06, 0x20, 0xDA, + 0xA0, 0x06, 0xDA, 0xD4, 0x10, 0x10, 0xA0, 0x06, + 0x32, 0xDA, 0x20, 0xD1, 0xCE, 0x06, 0xE6, 0x13, + 0x20, 0x78, 0x12, 0xE0, 0xCE, 0x06, 0xE2, 0x10, + 0x20, 0xC1, 0x16, 0x04, 0x14, 0x0A, 0xC4, 0x06, + 0x0A, 0x91, 0x01, 0x16, 0x5B, 0x04, 0x60, 0x04, + 0xD2, 0xCE, 0xB0, 0x03, 0x20, 0x98, 0xAB, 0xE3, + 0x65, 0x06, 0x02, 0x13, 0x60, 0x04, 0xBA, 0xCE, + 0x60, 0xC1, 0x94, 0x09, 0x02, 0x13, 0x60, 0x04, + 0x22, 0xDE, 0x60, 0xD1, 0x0E, 0xE0, 0x3D, 0x10, + 0x85, 0x07, 0xBE, 0xEA, 0x35, 0xC8, 0x8A, 0x09, + 0x15, 0xC8, 0x8C, 0x09, 0x0B, 0x10, 0xE0, 0x04, + 0xA0, 0x09, 0x20, 0xD8, 0x2E, 0x09, 0xA6, 0x09, + 0x20, 0xC8, 0xA8, 0x09, 0x8A, 0x09, 0x20, 0xC8, + 0xAA, 0x09, 0x8C, 0x09, 0xE0, 0x04, 0x8E, 0x09, + 0xCA, 0x04, 0xCD, 0x04, 0xCE, 0x04, 0xCF, 0x04, + 0xE0, 0x04, 0xA8, 0x06, 0xE0, 0x04, 0xBA, 0x06, + 0x84, 0x07, 0xA0, 0x01, 0x85, 0x07, 0x10, 0x00, + 0xF4, 0x04, 0x45, 0x06, 0xFD, 0x15, 0x84, 0x07, + 0xD8, 0x06, 0x85, 0x07, 0x34, 0x07, 0x44, 0x61, + 0xF4, 0x04, 0x45, 0x06, 0xFD, 0x15, 0x84, 0x07, + 0xC8, 0x00, 0x04, 0xC8, 0x00, 0x07, 0x84, 0x07, + 0xFF, 0x7F, 0x04, 0xC8, 0xF0, 0x06, 0x84, 0x07, + 0x06, 0x00, 0x04, 0xC8, 0xEE, 0x06, 0x85, 0x07, + 0x02, 0x0C, 0x20, 0xC1, 0x8A, 0x09, 0x01, 0x11, + 0xC5, 0x06, 0xB0, 0x03, 0x05, 0xD8, 0x65, 0x06, + 0x60, 0x04, 0xD2, 0xCE, 0xB0, 0x03, 0x20, 0x98, + 0xAA, 0xE3, 0x65, 0x06, 0x79, 0x16, 0x60, 0xD1, + 0x10, 0xE0, 0xF3, 0x10, 0x60, 0xD1, 0xAB, 0xE3, + 0xA0, 0x01, 0x8E, 0x09, 0x00, 0x02, 0xE0, 0x01, + 0x80, 0x01, 0x00, 0x20, 0xC8, 0x04, 0x20, 0xD2, + 0x80, 0x01, 0x08, 0xC8, 0x9C, 0x09, 0x08, 0xD8, + 0x2E, 0x09, 0xE3, 0x10, 0x20, 0xF8, 0x19, 0xEE, + 0x82, 0x01, 0x20, 0xC8, 0x10, 0xE0, 0xC6, 0x06, + 0x20, 0xC8, 0x20, 0xE0, 0xC8, 0x06, 0x20, 0xC8, + 0xC2, 0xEA, 0x90, 0x09, 0xE0, 0x2E, 0x00, 0x00, + 0xA0, 0x06, 0xE6, 0xD5, 0x20, 0xC8, 0x6C, 0x09, + 0xA0, 0x01, 0x20, 0xC8, 0x6E, 0x09, 0xA2, 0x01, + 0x20, 0xC8, 0x70, 0x09, 0xA4, 0x01, 0x20, 0xC8, + 0x6E, 0x09, 0xB0, 0x01, 0x20, 0xC8, 0x70, 0x09, + 0xB2, 0x01, 0x20, 0xC8, 0x70, 0x09, 0xCC, 0x06, + 0x20, 0xF8, 0x18, 0xEE, 0x80, 0x01, 0xB0, 0x03, + 0xA0, 0x01, 0x8E, 0x09, 0x00, 0x02, 0x20, 0x98, + 0xAA, 0xE3, 0x65, 0x06, 0x3A, 0x13, 0xE0, 0x01, + 0x8E, 0x09, 0x00, 0x02, 0x88, 0x07, 0x56, 0xDF, + 0xE0, 0xC2, 0x8A, 0x09, 0x05, 0x11, 0xA0, 0x01, + 0x8E, 0x09, 0x00, 0x02, 0x88, 0x07, 0x9A, 0xDF, + 0x98, 0x06, 0x08, 0x02, 0x12, 0x80, 0xA0, 0x06, + 0xDA, 0xD4, 0x84, 0x07, 0x0A, 0x00, 0x85, 0x07, + 0xF4, 0x03, 0x20, 0x88, 0xC6, 0x06, 0x20, 0xE0, + 0x08, 0x1B, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, + 0xA5, 0x13, 0x84, 0x07, 0x1C, 0x00, 0x85, 0x07, + 0xF8, 0x03, 0xA0, 0x06, 0xA2, 0xD8, 0x85, 0x07, + 0x42, 0xDC, 0x05, 0xC8, 0xF8, 0x03, 0x20, 0xC8, + 0xA0, 0x09, 0xA0, 0x09, 0x6C, 0x16, 0x20, 0xE8, + 0x9C, 0x09, 0xFE, 0x03, 0x20, 0xE8, 0x9E, 0x09, + 0x06, 0x04, 0xA0, 0x23, 0x0C, 0xE0, 0x32, 0x13, + 0xA0, 0xE3, 0x0C, 0xE0, 0xA0, 0x2E, 0xF4, 0x03, + 0x2D, 0x10, 0xA0, 0x06, 0x56, 0xDF, 0x60, 0x01, + 0x8E, 0x09, 0x00, 0x40, 0x08, 0x13, 0x08, 0x02, + 0x6C, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x22, 0x10, + 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x40, 0x08, 0x02, + 0x60, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x84, 0x07, + 0x2A, 0x00, 0x85, 0x07, 0xF4, 0x03, 0xA0, 0x06, + 0xA2, 0xD8, 0xD5, 0x10, 0xB0, 0x03, 0x20, 0x98, + 0xAA, 0xE3, 0x65, 0x06, 0x0F, 0x16, 0x20, 0x06, + 0x90, 0x09, 0x9A, 0x16, 0x60, 0x01, 0x8A, 0x09, + 0x00, 0x40, 0x39, 0x13, 0xE0, 0x04, 0x8A, 0x09, + 0xE0, 0x04, 0x8C, 0x09, 0xE0, 0x04, 0x8E, 0x09, + 0x60, 0x04, 0x62, 0xDA, 0x60, 0x04, 0xB0, 0xCE, + 0xB0, 0x03, 0x20, 0x98, 0x10, 0xE0, 0x65, 0x06, + 0xF9, 0x16, 0x44, 0x02, 0x00, 0x5E, 0x04, 0x16, + 0x20, 0x06, 0xC6, 0x06, 0x9A, 0x16, 0x0A, 0x10, + 0xB0, 0x03, 0x20, 0x98, 0x10, 0xE0, 0x65, 0x06, + 0xED, 0x16, 0x20, 0x06, 0xC8, 0x06, 0x02, 0x13, + 0x60, 0x04, 0x5A, 0xDB, 0x60, 0x01, 0x8E, 0x09, + 0x00, 0x01, 0x02, 0x16, 0xCE, 0x01, 0x03, 0x00, + 0x0E, 0x01, 0x03, 0x00, 0x03, 0x13, 0x83, 0x07, + 0x00, 0x82, 0x07, 0x10, 0x83, 0x07, 0x01, 0x00, + 0xE0, 0x04, 0x8E, 0x09, 0x20, 0xE8, 0x0C, 0xE0, + 0x82, 0x01, 0x60, 0x04, 0xCA, 0xCE, 0x60, 0x01, + 0x8A, 0x09, 0x00, 0x40, 0xC7, 0x16, 0x83, 0x07, + 0x0D, 0x00, 0xF2, 0x10, 0xB0, 0x03, 0x20, 0x98, + 0xAA, 0xE3, 0x65, 0x06, 0xC7, 0x16, 0x20, 0x88, + 0x98, 0x09, 0x20, 0xE0, 0xF0, 0x16, 0x22, 0xC8, + 0x0E, 0x00, 0xDC, 0x06, 0x22, 0xC8, 0x10, 0x00, + 0xDE, 0x06, 0x22, 0xC8, 0x12, 0x00, 0xE0, 0x06, + 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x80, 0x08, 0x02, + 0x66, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0xB2, 0x10, + 0xA0, 0x07, 0x9A, 0x09, 0x5A, 0x00, 0xA0, 0x07, + 0xA2, 0x09, 0x19, 0x00, 0xA0, 0x07, 0xA4, 0x09, + 0x05, 0x00, 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x20, + 0xE0, 0x01, 0x8E, 0x09, 0x00, 0x04, 0x08, 0x02, + 0x78, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0xB0, 0x03, + 0x20, 0x98, 0xAB, 0xE3, 0x65, 0x06, 0x9A, 0x16, + 0x08, 0x02, 0x72, 0x80, 0xA0, 0x06, 0xDA, 0xD4, + 0x20, 0xE8, 0x0C, 0xE0, 0x82, 0x01, 0xA0, 0x06, + 0xD0, 0xD5, 0x20, 0x06, 0x9A, 0x09, 0xBF, 0x13, + 0x84, 0x07, 0x2C, 0x00, 0x85, 0x07, 0xF4, 0x03, + 0xA0, 0x06, 0xA2, 0xD8, 0x60, 0x04, 0xC0, 0xDB, + 0x20, 0x48, 0x0C, 0xE0, 0x82, 0x01, 0x82, 0x10, + 0x0E, 0x01, 0x03, 0x00, 0x0A, 0x13, 0x08, 0x02, + 0x0C, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0xE0, 0xE3, + 0x14, 0xE0, 0x20, 0xC8, 0xAE, 0xE4, 0x86, 0x01, + 0x26, 0x10, 0x20, 0x48, 0x0C, 0xE0, 0x82, 0x01, + 0xE0, 0x2E, 0x01, 0x00, 0x60, 0xC1, 0x1E, 0x09, + 0x35, 0x0A, 0x05, 0xE8, 0x82, 0x01, 0x20, 0xC1, + 0x6A, 0x09, 0x04, 0x01, 0x06, 0x00, 0x06, 0x13, + 0x20, 0xD8, 0xD0, 0xE1, 0x2F, 0x09, 0x20, 0xD8, + 0xD0, 0xE1, 0x83, 0x01, 0x20, 0x21, 0x22, 0xE0, + 0x03, 0x16, 0x20, 0xE8, 0x22, 0xE0, 0x80, 0x01, + 0x20, 0x21, 0x04, 0xE0, 0x04, 0x16, 0xA0, 0xE3, + 0x14, 0xE0, 0x60, 0x04, 0x0A, 0xD3, 0x08, 0x02, + 0x00, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x20, 0xE8, + 0x08, 0xE0, 0x82, 0x01, 0xE0, 0xC2, 0x8A, 0x09, + 0x02, 0x11, 0x60, 0x04, 0xB0, 0xCE, 0xA0, 0x01, + 0x8E, 0x09, 0x00, 0x04, 0x6B, 0x10, 0x20, 0xC8, + 0xAE, 0xE4, 0x86, 0x01, 0x08, 0x02, 0x00, 0x80, + 0xA0, 0x06, 0xDA, 0xD4, 0x20, 0xC2, 0x1E, 0x09, + 0x08, 0xA2, 0x08, 0x05, 0x28, 0xC8, 0x22, 0xE0, + 0xCA, 0x06, 0x20, 0xC8, 0x20, 0xE0, 0xC6, 0x06, + 0x20, 0xC8, 0x20, 0xE0, 0xC8, 0x06, 0x60, 0xE3, + 0x16, 0xE0, 0x60, 0x04, 0xD2, 0xCE, 0x44, 0xC1, + 0x44, 0x02, 0x00, 0x5E, 0xF8, 0x16, 0x60, 0x25, + 0xA8, 0xE4, 0x0F, 0x16, 0x20, 0x06, 0xC6, 0x06, + 0xF2, 0x16, 0x20, 0x06, 0xCA, 0x06, 0x03, 0x13, + 0xA0, 0x05, 0xCC, 0x06, 0xE6, 0x10, 0xB0, 0x03, + 0x20, 0xD8, 0x0C, 0xE0, 0x65, 0x06, 0x60, 0x04, + 0xD2, 0xCE, 0x20, 0x06, 0xC8, 0x06, 0xE3, 0x16, + 0x20, 0x88, 0x70, 0x09, 0xCC, 0x06, 0x03, 0x16, + 0x83, 0x07, 0x08, 0x00, 0x02, 0x10, 0x83, 0x07, + 0x0C, 0x00, 0x60, 0x04, 0x8A, 0xDC, 0x60, 0x04, + 0xD2, 0xCE, 0xA0, 0x23, 0x08, 0xE0, 0x03, 0x13, + 0x60, 0x23, 0x12, 0xE0, 0x06, 0x16, 0xB0, 0x03, + 0x20, 0xD8, 0xA9, 0xE3, 0x65, 0x06, 0x60, 0x04, + 0xD2, 0xCE, 0x08, 0x02, 0x00, 0x80, 0xA0, 0x06, + 0xDA, 0xD4, 0x60, 0x04, 0xB0, 0xCE, 0x08, 0x02, + 0x00, 0x80, 0xA0, 0x06, 0xDA, 0xD4, 0x20, 0xC8, + 0x1E, 0xE0, 0xC6, 0x06, 0x20, 0xC8, 0x1E, 0xE0, + 0xC8, 0x06, 0x60, 0xE3, 0x10, 0xE0, 0x60, 0x04, + 0xD2, 0xCE, 0xE0, 0x23, 0x14, 0xE0, 0x30, 0x13, + 0x44, 0xC1, 0x44, 0x02, 0x00, 0x1E, 0xF5, 0x16, + 0x60, 0x25, 0xA8, 0xE4, 0x1D, 0x16, 0x20, 0x06, + 0xC8, 0x06, 0xEF, 0x16, 0x60, 0x01, 0x8E, 0x09, + 0x00, 0x80, 0x13, 0x16, 0x60, 0x01, 0x8E, 0x09, + 0x00, 0x01, 0x0C, 0x16, 0xA0, 0x01, 0x8E, 0x09, + 0x00, 0x01, 0xA0, 0x01, 0x8E, 0x09, 0x80, 0x00, + 0xA0, 0x43, 0x04, 0xE0, 0x83, 0x07, 0x18, 0x68, + 0xA0, 0x06, 0x2A, 0xD8, 0x20, 0xC8, 0xAE, 0xE4, + 0x86, 0x01, 0xC2, 0x04, 0x60, 0x04, 0x2C, 0xE4, + 0x08, 0x02, 0x1E, 0x80, 0xA0, 0x06, 0xDA, 0xD4, + 0x07, 0x10, 0x20, 0x06, 0xC6, 0x06, 0xCD, 0x16, + 0x83, 0x07, 0x09, 0x00, 0xA0, 0x06, 0x8A, 0xDC, + 0x60, 0x04, 0xB0, 0xCE, 0xCE, 0x04, 0xE0, 0x04, + 0x2A, 0x09, 0xE0, 0xD3, 0xAA, 0xE3, 0x8F, 0xC2, + 0x20, 0xC8, 0xB0, 0xE4, 0x86, 0x01, 0x20, 0x48, + 0x08, 0xE0, 0x82, 0x01, 0x86, 0x07, 0x05, 0x00, + 0x84, 0x07, 0x72, 0x06, 0x54, 0xC1, 0x01, 0x13, + 0xD4, 0x2C, 0x24, 0x02, 0x0A, 0x00, 0x06, 0x06, + 0xF9, 0x16, 0x08, 0x02, 0x2A, 0x80, 0xA0, 0x06, + 0xDA, 0xD4, 0x20, 0x2C, 0x1A, 0xE0, 0x60, 0x04, + 0x50, 0xCD, 0xA0, 0x06, 0x3E, 0xD7, 0xCD, 0x04, + 0xA0, 0x23, 0x1C, 0xE0, 0x0D, 0x13, 0x0E, 0x01, + 0x03, 0x00, 0x0A, 0x13, 0xA0, 0xE3, 0x1C, 0xE0, + 0xB0, 0x03, 0x20, 0xD8, 0x10, 0xE0, 0x65, 0x06, + 0xA0, 0xD2, 0x26, 0xE0, 0xCF, 0x04, 0x08, 0x10, + 0x20, 0x2D, 0x01, 0x00, 0xE0, 0xC0, 0x2A, 0x09, + 0xA0, 0x06, 0x2A, 0xD8, 0xA0, 0xD2, 0xAB, 0xE3, + 0x60, 0x04, 0xD2, 0xCE, 0xA0, 0x01, 0x80, 0x01, + 0x00, 0x01, 0xE0, 0x01, 0x80, 0x01, 0x00, 0xAC, + 0xA0, 0x01, 0x82, 0x01, 0x00, 0x03, 0xE0, 0x01, + 0x82, 0x01, 0x00, 0x08, 0x88, 0x07, 0xAE, 0x01, + 0x08, 0x06, 0xFE, 0x16, 0x60, 0x01, 0x8E, 0x09, + 0x00, 0x02, 0x03, 0x16, 0xA0, 0x01, 0x80, 0x01, + 0x00, 0x20, 0xC8, 0x04, 0x20, 0xD2, 0x80, 0x01, + 0x08, 0xC8, 0x9C, 0x09, 0x08, 0xD8, 0x2E, 0x09, + 0xA0, 0x07, 0x9E, 0x09, 0x00, 0x10, 0x5B, 0x04, + 0x20, 0xD8, 0xA6, 0x09, 0x2E, 0x09, 0xE0, 0x01, + 0x80, 0x01, 0x00, 0x04, 0xE0, 0x01, 0x82, 0x01, + 0x00, 0x08, 0xA0, 0x01, 0x82, 0x01, 0x00, 0x03, + 0x20, 0xC2, 0x30, 0x09, 0x03, 0x13, 0xE0, 0x01, + 0x82, 0x01, 0x00, 0x03, 0xA0, 0x01, 0x80, 0x01, + 0x00, 0xA1, 0x20, 0xF8, 0x2E, 0x09, 0x80, 0x01, + 0x88, 0x07, 0xAE, 0x01, 0x08, 0x06, 0xFE, 0x16, + 0xA0, 0x01, 0x80, 0x01, 0x00, 0x0C, 0xE0, 0x04, + 0x9E, 0x01, 0xE0, 0x04, 0x9C, 0x09, 0xE0, 0x04, + 0x9E, 0x09, 0x5B, 0x04, 0x20, 0x01, 0xA8, 0x09, + 0x00, 0x80, 0x11, 0x13, 0xE0, 0x93, 0x26, 0xE0, + 0x0E, 0x16, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, + 0x0A, 0x13, 0x08, 0x02, 0x84, 0x80, 0x00, 0x00, + 0x00, 0xE0, 0xDC, 0x0F, 0xA0, 0x06, 0xDA, 0xD4, + 0x20, 0x48, 0x08, 0xE0, 0x82, 0x01, 0x02, 0x10, + 0x60, 0x04, 0x70, 0xDA, 0x60, 0x04, 0xBA, 0xCE, + 0xA0, 0x06, 0x9C, 0xD5, 0x08, 0xC2, 0x19, 0x13, + 0x83, 0x07, 0x80, 0x80, 0xE0, 0x23, 0x14, 0xE0, + 0x02, 0x13, 0x83, 0x07, 0x0A, 0x00, 0x60, 0x04, + 0xC6, 0xCE, 0x20, 0xC1, 0x06, 0x06, 0x0D, 0x13, + 0xA0, 0x06, 0x9C, 0xD5, 0x08, 0xC2, 0x09, 0x13, + 0x83, 0x07, 0x0B, 0x00, 0xE0, 0x23, 0x14, 0xE0, + 0x02, 0x16, 0x83, 0x07, 0x01, 0x80, 0x60, 0x04, + 0xC6, 0xCE, 0x83, 0x07, 0x0A, 0x80, 0x60, 0x04, + 0xB4, 0xCE, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, + 0x06, 0x16, 0xA0, 0x06, 0xA8, 0xE5, 0x47, 0x10, + 0xD0, 0x03, 0x60, 0x04, 0xB0, 0xD3, 0xE0, 0x93, + 0x0E, 0xE0, 0x5E, 0x13, 0xE0, 0x93, 0x10, 0xE0, + 0x17, 0x13, 0xE0, 0x23, 0x14, 0xE0, 0x04, 0x13, + 0x83, 0x07, 0x07, 0x00, 0x60, 0x04, 0xC6, 0xCE, + 0x83, 0x07, 0x00, 0xA0, 0xA0, 0x06, 0x2A, 0xD8, + 0x83, 0x07, 0x00, 0x48, 0xA0, 0x06, 0x2A, 0xD8, + 0xA0, 0xD2, 0x10, 0xE0, 0x20, 0xC8, 0x1C, 0xE0, + 0xCA, 0x06, 0x20, 0xC8, 0x20, 0xE0, 0xCC, 0x06, + 0xA0, 0x06, 0x3E, 0xD7, 0x08, 0x02, 0x4E, 0x80, + 0xA0, 0x06, 0xDA, 0xD4, 0xA0, 0x23, 0x1C, 0xE0, + 0x20, 0x13, 0x20, 0x88, 0x6C, 0x09, 0x0E, 0x07, + 0x1C, 0x16, 0x20, 0x88, 0x6E, 0x09, 0x10, 0x07, + 0x18, 0x16, 0x20, 0x88, 0x70, 0x09, 0x12, 0x07, + 0x14, 0x16, 0x20, 0x88, 0x0A, 0x07, 0x22, 0xE0, + 0x10, 0x13, 0x20, 0x06, 0xCA, 0x06, 0x38, 0x16, + 0xA0, 0xE3, 0x20, 0xE0, 0x06, 0x10, 0xE0, 0x23, + 0x14, 0xE0, 0xCA, 0x16, 0xA0, 0xE3, 0x22, 0xE0, + 0xC2, 0x04, 0xA0, 0xD2, 0xAA, 0xE3, 0x60, 0x04, + 0xBA, 0xCE, 0x20, 0xC8, 0x1C, 0xE0, 0xCA, 0x06, + 0xA0, 0x88, 0xDC, 0x06, 0x0E, 0x00, 0x10, 0x16, + 0xA0, 0x88, 0xDE, 0x06, 0x10, 0x00, 0x0C, 0x16, + 0xA0, 0x88, 0xE0, 0x06, 0x12, 0x00, 0x08, 0x16, + 0x20, 0x06, 0xCC, 0x06, 0x19, 0x16, 0x20, 0xE8, + 0x0E, 0xE0, 0x82, 0x01, 0xA0, 0xE3, 0x1E, 0xE0, + 0x20, 0xC8, 0x20, 0xE0, 0xCC, 0x06, 0x10, 0x10, + 0xA0, 0x23, 0x10, 0xE0, 0x08, 0x16, 0x64, 0xC1, + 0x06, 0x00, 0x60, 0x21, 0x0C, 0xE0, 0x08, 0x13, + 0xA0, 0xD2, 0xA8, 0xE3, 0x05, 0x10, 0x20, 0x88, + 0x0A, 0x07, 0x08, 0x07, 0x96, 0x12, 0x00, 0x10, + 0x60, 0x04, 0xBA, 0xCE, 0x60, 0x01, 0x8E, 0x09, + 0x00, 0x80, 0x06, 0x16, 0x83, 0x07, 0x00, 0x82, + 0xA0, 0x06, 0x2A, 0xD8, 0x60, 0x04, 0xCA, 0xCE, + 0xE0, 0x93, 0x0E, 0xE0, 0x50, 0x13, 0xE0, 0x93, + 0xA9, 0xE3, 0x4D, 0x13, 0xE0, 0x93, 0xA8, 0xE3, + 0x1C, 0x13, 0xA0, 0x06, 0xA4, 0xD7, 0xA0, 0x23, + 0x10, 0xE0, 0x45, 0x13, 0xA0, 0x23, 0x08, 0xE0, + 0x06, 0x16, 0x60, 0xE3, 0x1E, 0xE0, 0x20, 0xC8, + 0x22, 0xE0, 0x06, 0x07, 0x34, 0x10, 0xE0, 0x23, + 0x14, 0xE0, 0x31, 0x16, 0x60, 0xC1, 0x6A, 0x09, + 0x60, 0x21, 0x12, 0xE0, 0x2C, 0x16, 0xA0, 0x06, + 0x0E, 0xE2, 0x31, 0x10, 0xA0, 0xD2, 0xA8, 0xE3, + 0x2E, 0x10, 0xA0, 0xE3, 0x12, 0xE0, 0xA0, 0x06, + 0x0E, 0xE2, 0x64, 0xC1, 0x06, 0x00, 0x60, 0x21, + 0x0C, 0xE0, 0x25, 0x13, 0x20, 0x88, 0x0E, 0x07, + 0xDC, 0x06, 0x14, 0x16, 0x20, 0x88, 0x10, 0x07, + 0xDE, 0x06, 0x10, 0x16, 0x20, 0x88, 0x12, 0x07, + 0xE0, 0x06, 0x0C, 0x16, 0x20, 0x98, 0xCE, 0x06, + 0xCF, 0x06, 0x15, 0x13, 0x20, 0x06, 0xCE, 0x06, + 0x12, 0x16, 0x60, 0xE3, 0x1A, 0xE0, 0xA0, 0xD2, + 0x0C, 0xE0, 0x0D, 0x10, 0x60, 0xE3, 0x1E, 0xE0, + 0x20, 0xC8, 0x32, 0xE0, 0x06, 0x07, 0xA0, 0x06, + 0x3E, 0xD7, 0x08, 0x02, 0x48, 0x80, 0xA0, 0x06, + 0xDA, 0xD4, 0xA0, 0xD2, 0xA9, 0xE3, 0x60, 0x04, + 0xBA, 0xCE, 0x22, 0x88, 0x0E, 0x00, 0x6C, 0x09, + 0xC9, 0x1A, 0x0B, 0x1B, 0x22, 0x88, 0x10, 0x00, + 0x6E, 0x09, 0xC4, 0x1A, 0x06, 0x1B, 0x22, 0x88, + 0x12, 0x00, 0x70, 0x09, 0xBF, 0x1A, 0x01, 0x1B, + 0x5B, 0x04, 0x60, 0xC1, 0x6C, 0x01, 0x85, 0x02, + 0x43, 0x00, 0xE1, 0x13, 0xE0, 0x93, 0xA8, 0xE3, + 0xDE, 0x16, 0xA0, 0xC8, 0x00, 0xEE, 0x02, 0x00, + 0x84, 0x07, 0x0E, 0x00, 0x42, 0xC1, 0xA0, 0xC0, + 0x6C, 0x01, 0x02, 0xC0, 0x25, 0x02, 0x48, 0x00, + 0x81, 0x07, 0x60, 0xE2, 0x83, 0x07, 0x14, 0xAE, + 0x60, 0x04, 0x9E, 0xE5, 0x02, 0x02, 0x00, 0xFC, + 0xCA, 0x10, 0x60, 0x01, 0x8E, 0x09, 0x00, 0x80, + 0x06, 0x16, 0x83, 0x07, 0x00, 0x82, 0xA0, 0x06, + 0x2A, 0xD8, 0x60, 0x04, 0xCA, 0xCE, 0x20, 0x98, + 0x0E, 0xE0, 0x65, 0x06, 0x03, 0x16, 0x20, 0xD8, + 0xA8, 0xE3, 0x65, 0x06, 0xE0, 0x93, 0xA9, 0xE3, + 0x0D, 0x13, 0xA0, 0x23, 0x08, 0xE0, 0x19, 0x16, + 0xA0, 0x23, 0x10, 0xE0, 0x16, 0x13, 0x60, 0xE3, + 0x1E, 0xE0, 0x20, 0xC8, 0x20, 0xE0, 0x06, 0x07, + 0xA0, 0x06, 0x3E, 0xD7, 0xA0, 0x43, 0x18, 0xE0, + 0xE0, 0x2E, 0x01, 0x00, 0xA0, 0xD2, 0x26, 0xE0, + 0x83, 0x07, 0x10, 0x00, 0xA0, 0x06, 0x2A, 0xD8, + 0xE0, 0x23, 0x14, 0xE0, 0x02, 0x16, 0xA0, 0x06, + 0x18, 0xD7, 0xA0, 0x43, 0x2C, 0xE0, 0x20, 0xC8, + 0x20, 0xE0, 0x24, 0x09, 0x60, 0x04, 0xBA, 0xCE, + 0xA0, 0x06, 0xA8, 0xE5, 0x01, 0x10, 0x03, 0x10, + 0x20, 0x07, 0xA0, 0x09, 0x03, 0x10, 0xA0, 0x07, + 0xA2, 0x09, 0x19, 0x00, 0x60, 0x04, 0xBA, 0xCE, + 0xA0, 0x43, 0x0E, 0xE0, 0xA0, 0xC1, 0x24, 0x09, + 0x02, 0x13, 0x20, 0x06, 0x24, 0x09, 0xE0, 0x23, + 0x14, 0xE0, 0x03, 0x13, 0xA0, 0x23, 0x08, 0xE0, + 0x29, 0x16, 0x20, 0xC2, 0x8A, 0x09, 0xE4, 0x11, + 0x08, 0x02, 0x42, 0x80, 0xA0, 0x06, 0xDA, 0xD4, + 0xA0, 0x23, 0x08, 0xE0, 0x1F, 0x16, 0xA0, 0x23, + 0x10, 0xE0, 0x0A, 0x16, 0x22, 0xC1, 0x02, 0x00, + 0x20, 0x25, 0xA8, 0xE4, 0x23, 0x16, 0x83, 0x07, + 0x20, 0x80, 0xA0, 0x06, 0x2A, 0xD8, 0x12, 0x10, + 0xA0, 0x06, 0x3E, 0xD7, 0xE0, 0x23, 0x14, 0xE0, + 0x02, 0x16, 0xA0, 0x06, 0x18, 0xD7, 0x60, 0xE3, + 0x1E, 0xE0, 0x20, 0xC8, 0x20, 0xE0, 0x06, 0x07, + 0xA0, 0x23, 0x08, 0xE0, 0x03, 0x16, 0xA0, 0x23, + 0x06, 0xE0, 0x51, 0x13, 0x20, 0x98, 0x0E, 0xE0, + 0x65, 0x06, 0x03, 0x16, 0x20, 0xD8, 0xA8, 0xE3, + 0x65, 0x06, 0x22, 0xC1, 0x02, 0x00, 0x20, 0x25, + 0xA8, 0xE4, 0x0E, 0x13, 0x83, 0x07, 0x20, 0x00, + 0xA0, 0x06, 0x2A, 0xD8, 0x22, 0xC8, 0x0E, 0x00, + 0xE6, 0x06, 0x22, 0xC8, 0x10, 0x00, 0xE8, 0x06, + 0x22, 0xC8, 0x12, 0x00, 0xEA, 0x06, 0x37, 0x10, + 0x22, 0x88, 0x0E, 0x00, 0xDC, 0x06, 0x08, 0x16, + 0x22, 0x88, 0x10, 0x00, 0xDE, 0x06, 0x04, 0x16, + 0x22, 0x88, 0x12, 0x00, 0xE0, 0x06, 0x0B, 0x13, + 0x22, 0xC8, 0x0E, 0x00, 0xDC, 0x06, 0x22, 0xC8, + 0x10, 0x00, 0xDE, 0x06, 0x22, 0xC8, 0x12, 0x00, + 0xE0, 0x06, 0x60, 0xE3, 0x14, 0xE0, 0xA0, 0x23, + 0x0E, 0xE0, 0x08, 0x16, 0xA0, 0xC1, 0x24, 0x09, + 0x1A, 0x16, 0x86, 0x07, 0x00, 0x10, 0x06, 0xE8, + 0xD2, 0x06, 0x15, 0x10, 0xA0, 0xE3, 0x0E, 0xE0, + 0xA0, 0x23, 0x08, 0xE0, 0x09, 0x16, 0xA0, 0xE3, + 0x06, 0xE0, 0xE0, 0x04, 0xE6, 0x06, 0xE0, 0x04, + 0xE8, 0x06, 0xE0, 0x04, 0xEA, 0x06, 0x07, 0x10, + 0x08, 0x02, 0x36, 0x80, 0xA0, 0x07, 0xD6, 0x06, + 0x36, 0xD3, 0xA0, 0x06, 0xDA, 0xD4, 0x60, 0x04, + 0xBA, 0xCE, 0x20, 0x98, 0x65, 0x06, 0x10, 0xE0, + 0x03, 0x16, 0x20, 0xD8, 0x0E, 0xE0, 0x65, 0x06, + 0x60, 0x04, 0xBA, 0xCE, 0xE0, 0x23, 0x14, 0xE0, + 0x02, 0x13, 0x60, 0x04, 0xBA, 0xCE, 0x2E, 0x10, + 0xB0, 0x03, 0x20, 0x98, 0xA9, 0xE3, 0x6F, 0x06, + 0x19, 0x16, 0x24, 0xC2, 0x08, 0x00, 0x16, 0x11, + 0xE0, 0xE3, 0x14, 0xE0, 0x83, 0x07, 0x00, 0x00, + 0xA0, 0x06, 0x2A, 0xD8, 0xA0, 0x23, 0x14, 0xE0, + 0x04, 0x13, 0x08, 0x02, 0x06, 0x80, 0xA0, 0x06, + 0xDA, 0xD4, 0x08, 0x02, 0x1E, 0x00, 0xA0, 0x06, + 0xDA, 0xD4, 0xA0, 0x23, 0x08, 0xE0, 0x02, 0x13, + 0xA0, 0x06, 0x18, 0xD7, 0x82, 0xC0, 0x02, 0x16, + 0x60, 0x04, 0xD2, 0xCE, 0x20, 0xE8, 0x1C, 0xEE, + 0xF0, 0x06, 0x20, 0x99, 0x0E, 0xE0, 0x16, 0x00, + 0x05, 0x16, 0xE0, 0x04, 0xEC, 0x06, 0x20, 0x48, + 0x14, 0xE0, 0xF0, 0x06, 0x83, 0x07, 0x01, 0x00, + 0x60, 0x04, 0xB4, 0xCE, 0x64, 0xC2, 0x14, 0x00, + 0x24, 0x02, 0x18, 0x00, 0xC4, 0xC1, 0xC2, 0x61, + 0x27, 0x02, 0xFC, 0xFF, 0x74, 0xC1, 0x85, 0xC1, + 0x45, 0x71, 0x85, 0x02, 0x27, 0x00, 0x46, 0x16, + 0x54, 0xC1, 0x45, 0x02, 0xCF, 0xFF, 0x42, 0x16, + 0xC8, 0x04, 0x64, 0xC1, 0x08, 0x00, 0x06, 0x15, + 0x05, 0x13, 0x24, 0xC2, 0x0E, 0x00, 0x48, 0x02, + 0x00, 0x1F, 0xC8, 0x06, 0x28, 0x02, 0x11, 0x00, + 0x04, 0xA2, 0x18, 0x98, 0x21, 0xEE, 0x32, 0x16, + 0x42, 0xC1, 0x25, 0x02, 0x04, 0x00, 0x47, 0x65, + 0x35, 0xC2, 0x74, 0xCD, 0x48, 0x06, 0xFD, 0x15, + 0xA0, 0xC0, 0x6C, 0x01, 0x02, 0xC1, 0x04, 0xC8, + 0x6C, 0x01, 0xA0, 0xC1, 0x00, 0xFC, 0x05, 0x13, + 0x20, 0xC8, 0x80, 0xEB, 0x02, 0xFC, 0x06, 0xC1, + 0xF6, 0x10, 0x20, 0xC8, 0x00, 0xEE, 0x02, 0xFC, + 0x02, 0xC8, 0x6C, 0x01, 0x81, 0x07, 0x08, 0xE5, + 0x04, 0xC0, 0x83, 0x07, 0x10, 0x02, 0x84, 0x07, + 0x0E, 0x00, 0x3B, 0x10, 0x84, 0x07, 0x0C, 0x00, + 0xE2, 0xC0, 0x08, 0x00, 0x05, 0x02, 0x00, 0xFC, + 0xA0, 0xC0, 0x6C, 0x01, 0x02, 0xC0, 0x95, 0xC1, + 0x30, 0x13, 0xD5, 0x04, 0x16, 0x2E, 0x02, 0xC8, + 0x6C, 0x01, 0x2B, 0x10, 0xA0, 0xC8, 0x22, 0xEE, + 0x0E, 0x00, 0xA0, 0xC8, 0x24, 0xEE, 0x10, 0x00, + 0xA0, 0xC8, 0x26, 0xEE, 0x12, 0x00, 0x83, 0x07, + 0x06, 0x80, 0x60, 0x04, 0xB4, 0xCE, 0x60, 0x04, + 0xD2, 0xCE, 0x84, 0x07, 0x10, 0x00, 0x85, 0x07, + 0x34, 0x00, 0x09, 0x10, 0x84, 0x07, 0x12, 0x00, + 0x85, 0x07, 0x32, 0x00, 0x04, 0x10, 0x84, 0x07, + 0x14, 0x00, 0x85, 0x07, 0x38, 0x00, 0xA0, 0x06, + 0xC2, 0xD5, 0x85, 0xC8, 0x04, 0x00, 0xA0, 0x06, + 0x10, 0xD6, 0xA0, 0xC8, 0x00, 0xEE, 0x02, 0x00, + 0xA0, 0xC0, 0x6C, 0x01, 0x02, 0xC0, 0x48, 0x06, + 0x48, 0xC1, 0xA0, 0x06, 0xA2, 0xD8, 0x07, 0x02, + 0xA2, 0x06, 0x60, 0xC5, 0x02, 0xFC, 0x25, 0x02, + 0xF4, 0xFF, 0x05, 0xC8, 0x02, 0xFC, 0x20, 0xC2, + 0x6C, 0x01, 0xA0, 0x06, 0xFC, 0xB4, 0x60, 0x04, + 0xB0, 0xCE, 0xA0, 0x06, 0xA2, 0xD8, 0x07, 0x02, + 0xB4, 0x06, 0xEF, 0x10, 0x22, 0x88, 0x12, 0x00, + 0x70, 0x09, 0x08, 0x16, 0x22, 0x88, 0x10, 0x00, + 0x6E, 0x09, 0x04, 0x16, 0x22, 0x88, 0x0E, 0x00, + 0x6C, 0x09, 0x0E, 0x13, 0x22, 0x88, 0x12, 0x00, + 0xE0, 0x06, 0x08, 0x16, 0x22, 0x88, 0x10, 0x00, + 0xDE, 0x06, 0x04, 0x16, 0x22, 0x88, 0x0E, 0x00, + 0xDC, 0x06, 0x01, 0x13, 0xCB, 0x05, 0xCB, 0x05, + 0x5B, 0x04, 0x0B, 0xC3, 0x00, 0x03, 0x02, 0x00, + 0x82, 0x07, 0xC0, 0x00, 0x20, 0xC8, 0x0C, 0x00, + 0xC0, 0x00, 0x20, 0xC8, 0x0E, 0x00, 0xC2, 0x00, + 0x20, 0xC8, 0x10, 0x00, 0xC4, 0x00, 0x20, 0xC8, + 0x12, 0x00, 0xC6, 0x00, 0x20, 0xC8, 0x14, 0x00, + 0xC8, 0x00, 0x20, 0xC8, 0x16, 0x00, 0xCA, 0x00, + 0x20, 0xC8, 0x04, 0x00, 0xCC, 0x00, 0x20, 0xC8, + 0x06, 0x00, 0xCE, 0x00, 0x02, 0xC8, 0x0C, 0x00, + 0xA0, 0x07, 0x0E, 0x00, 0x7E, 0xE6, 0x02, 0xC8, + 0x10, 0x00, 0xA0, 0x07, 0x12, 0x00, 0x88, 0xE6, + 0x02, 0xC8, 0x14, 0x00, 0xA0, 0x07, 0x16, 0x00, + 0xB8, 0xE6, 0x02, 0xC8, 0x04, 0x00, 0xA0, 0x07, + 0x06, 0x00, 0xCE, 0xE6, 0x60, 0x01, 0x1C, 0x01, + 0x04, 0x00, 0x09, 0x16, 0xE0, 0x01, 0x40, 0x01, + 0x00, 0x08, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x40, + 0xE0, 0x01, 0x40, 0x01, 0x00, 0x04, 0xA0, 0x06, + 0x8E, 0xE9, 0x05, 0x02, 0x00, 0x80, 0x05, 0xD8, + 0x80, 0x04, 0xC7, 0x04, 0x00, 0x03, 0x0F, 0x00, + 0x88, 0x07, 0x00, 0x10, 0x09, 0x02, 0x00, 0x20, + 0x8A, 0x07, 0xE6, 0xE6, 0x03, 0x02, 0x3E, 0xE6, + 0x5A, 0x04, 0x00, 0x03, 0x00, 0x00, 0x20, 0xD2, + 0x87, 0x01, 0x06, 0x10, 0x00, 0x03, 0x00, 0x00, + 0x20, 0xC2, 0x8A, 0x01, 0x08, 0x02, 0x00, 0x1A, + 0x60, 0xC2, 0xAE, 0x00, 0x48, 0xDA, 0x80, 0x04, + 0x89, 0x05, 0x89, 0x02, 0x06, 0x00, 0x07, 0x15, + 0x88, 0x07, 0x00, 0x80, 0x48, 0xDA, 0x80, 0x04, + 0x09, 0xC8, 0xAE, 0x00, 0x80, 0x03, 0xE0, 0x02, + 0xA0, 0x00, 0x5C, 0x04, 0x00, 0x03, 0x00, 0x00, + 0x60, 0x01, 0x9C, 0x01, 0x20, 0x00, 0xE2, 0x13, + 0x20, 0xC2, 0x8C, 0x01, 0x08, 0x02, 0x00, 0x1C, + 0xE3, 0x10, 0x00, 0x03, 0x00, 0x00, 0x60, 0x01, + 0x40, 0x01, 0x00, 0x40, 0xEC, 0x16, 0xA0, 0x01, + 0x40, 0x01, 0x00, 0x40, 0x08, 0x02, 0x00, 0x02, + 0xD7, 0x10, 0xB3, 0xC0, 0x92, 0x06, 0xFD, 0x10, + 0xB3, 0xC0, 0x48, 0xC0, 0x72, 0xCC, 0x72, 0xCC, + 0x32, 0xC1, 0x44, 0xCC, 0x72, 0xDC, 0x04, 0x06, + 0xFD, 0x16, 0x5B, 0x04, 0x48, 0xC0, 0x02, 0x02, + 0xD0, 0xE9, 0x84, 0x07, 0x06, 0x00, 0xF6, 0x10, + 0x02, 0x02, 0x1E, 0xE6, 0x49, 0xC0, 0x84, 0x07, + 0x06, 0x00, 0xF0, 0x10, 0xB3, 0xC0, 0x32, 0xC1, + 0x01, 0x02, 0x01, 0x00, 0x44, 0xD0, 0xC1, 0x06, + 0x44, 0x02, 0xFF, 0x00, 0xE7, 0x10, 0x33, 0xC1, + 0x73, 0xC0, 0x44, 0xD1, 0x44, 0x02, 0xFF, 0x00, + 0x45, 0xDC, 0x04, 0x06, 0xFD, 0x16, 0x5A, 0x04, + 0xA0, 0x06, 0x0E, 0xE9, 0x33, 0xC8, 0x9E, 0x01, + 0x5A, 0x04, 0xA0, 0x06, 0x0C, 0xE7, 0x89, 0xC1, + 0xA6, 0x09, 0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, + 0x8A, 0x01, 0x88, 0xC1, 0xA6, 0x09, 0x66, 0x02, + 0x40, 0x00, 0x06, 0xC8, 0x8C, 0x01, 0xC2, 0x04, + 0xC7, 0xC1, 0x03, 0x16, 0x02, 0x06, 0xFC, 0x16, + 0x4D, 0x10, 0x5A, 0x04, 0xA0, 0x06, 0x58, 0xE8, + 0x89, 0xC1, 0xA6, 0x09, 0x66, 0x02, 0x40, 0x00, + 0x06, 0xC8, 0x8A, 0x01, 0x88, 0xC1, 0xA6, 0x09, + 0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, 0x8C, 0x01, + 0x33, 0xC8, 0x9E, 0x01, 0xE8, 0x10, 0x33, 0x8A, + 0x02, 0x00, 0x38, 0x16, 0x73, 0x8A, 0x02, 0x00, + 0x35, 0x16, 0x5A, 0x04, 0x20, 0x8A, 0xCA, 0xE9, + 0x02, 0x00, 0x30, 0x16, 0x60, 0x8A, 0xCE, 0xE9, + 0x02, 0x00, 0x2C, 0x16, 0x82, 0x07, 0x74, 0xEA, + 0x01, 0x10, 0xB3, 0xC0, 0x04, 0x02, 0x80, 0x04, + 0x52, 0xD1, 0x03, 0x13, 0x32, 0x9D, 0x22, 0x16, + 0xFB, 0x10, 0x85, 0x07, 0x00, 0x80, 0x05, 0xD8, + 0x80, 0x04, 0xC7, 0x04, 0x5A, 0x04, 0x20, 0xC8, + 0xC0, 0x00, 0x0C, 0x00, 0x20, 0xC8, 0xC2, 0x00, + 0x0E, 0x00, 0x20, 0xC8, 0xC4, 0x00, 0x10, 0x00, + 0x20, 0xC8, 0xC6, 0x00, 0x12, 0x00, 0x20, 0xC8, + 0xC8, 0x00, 0x14, 0x00, 0x20, 0xC8, 0xCA, 0x00, + 0x16, 0x00, 0x20, 0xC8, 0xCC, 0x00, 0x04, 0x00, + 0x20, 0xC8, 0xCE, 0x00, 0x06, 0x00, 0x00, 0x03, + 0x0F, 0x00, 0xCC, 0x05, 0x5C, 0x04, 0xE0, 0x04, + 0x82, 0x01, 0x02, 0x02, 0x18, 0xE6, 0x32, 0xC8, + 0x82, 0x01, 0x32, 0xC8, 0x80, 0x01, 0xA0, 0x06, + 0x24, 0xE8, 0x12, 0xC8, 0x82, 0x01, 0xCA, 0xC2, + 0x84, 0x07, 0xD0, 0x07, 0xE0, 0x04, 0x84, 0x01, + 0x04, 0x06, 0xFC, 0x16, 0x20, 0xC1, 0x84, 0x01, + 0xE9, 0x16, 0x04, 0x02, 0x32, 0x00, 0x85, 0x07, + 0x00, 0x80, 0x05, 0xD8, 0x80, 0x04, 0xC7, 0x04, + 0x60, 0xC1, 0x86, 0x01, 0x04, 0x06, 0xFC, 0x16, + 0x20, 0xC1, 0x84, 0x01, 0x5B, 0x04, 0xB3, 0xC0, + 0xB3, 0xC4, 0x5B, 0x04, 0x48, 0xC0, 0xB3, 0xC0, + 0x73, 0xA0, 0x42, 0xC4, 0x5B, 0x04, 0x33, 0x88, + 0x84, 0x01, 0xE6, 0x16, 0x5A, 0x04, 0x89, 0xC1, + 0xA6, 0x09, 0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, + 0x8A, 0x01, 0x5B, 0x04, 0xC5, 0x04, 0xA0, 0x07, + 0x9C, 0x01, 0x40, 0x00, 0x60, 0x01, 0x9C, 0x01, + 0x40, 0x00, 0x03, 0x13, 0x05, 0x06, 0xF7, 0x16, + 0x5C, 0x04, 0x5B, 0x04, 0xA0, 0x06, 0xAC, 0xE8, + 0x60, 0xC0, 0x40, 0x01, 0x05, 0xC8, 0x40, 0x01, + 0x02, 0xC5, 0x01, 0xC8, 0x40, 0x01, 0x5A, 0x04, + 0xA0, 0x06, 0xAC, 0xE8, 0x08, 0xA1, 0xF4, 0x10, + 0xB3, 0xC0, 0x33, 0xC1, 0x60, 0xC1, 0x40, 0x01, + 0x85, 0x01, 0x00, 0x04, 0xC5, 0x01, 0x00, 0x10, + 0x5B, 0x04, 0x08, 0xC1, 0x09, 0xC2, 0x44, 0xC2, + 0x5B, 0x04, 0x05, 0x02, 0xC8, 0x00, 0x05, 0x06, + 0xFE, 0x16, 0x5B, 0x04, 0x33, 0xC1, 0x03, 0xC0, + 0xC4, 0xC0, 0x5B, 0x04, 0xC0, 0xC0, 0x5B, 0x04, + 0xE0, 0x94, 0x9E, 0x01, 0xC2, 0x16, 0xC3, 0x05, + 0x5B, 0x04, 0x73, 0xC0, 0xA0, 0x06, 0x26, 0xE9, + 0x2D, 0x02, 0x08, 0x00, 0x85, 0x07, 0x08, 0x00, + 0x71, 0x9F, 0xB7, 0x16, 0x05, 0x06, 0xFC, 0x16, + 0x5A, 0x04, 0x02, 0x02, 0x24, 0xE6, 0x60, 0x04, + 0x10, 0xE7, 0xE9, 0x8C, 0x04, 0x00, 0xAD, 0x16, + 0x5B, 0x04, 0x20, 0xC1, 0x80, 0x01, 0x85, 0x07, + 0xD0, 0x07, 0xE0, 0x01, 0x80, 0x01, 0x00, 0x04, + 0x45, 0x06, 0xFE, 0x16, 0x04, 0xC8, 0x80, 0x01, + 0x5B, 0x04, 0x33, 0xC1, 0x48, 0xC3, 0x04, 0xC1, + 0x04, 0x13, 0x2D, 0x02, 0x00, 0x04, 0x04, 0x06, + 0xFC, 0x16, 0x5B, 0x04, 0x8D, 0xC3, 0xA0, 0x06, + 0x26, 0xE9, 0x8D, 0xC1, 0xA6, 0x09, 0x66, 0x02, + 0x40, 0x00, 0x86, 0xC7, 0x5A, 0x04, 0x8D, 0xC1, + 0xA6, 0x09, 0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, + 0x8A, 0x01, 0x5B, 0x04, 0x8D, 0xC1, 0xA6, 0x09, + 0x66, 0x02, 0x40, 0x00, 0x06, 0xC8, 0x8C, 0x01, + 0x5B, 0x04, 0x4D, 0xC0, 0x04, 0x02, 0x28, 0x00, + 0x85, 0x07, 0x00, 0x55, 0x60, 0x04, 0x34, 0xE7, + 0x4D, 0xC0, 0xB3, 0xC0, 0x32, 0xC1, 0x60, 0x04, + 0xF8, 0xE6, 0x33, 0xC1, 0x60, 0x01, 0x1C, 0x01, + 0x04, 0x00, 0x01, 0x16, 0x5B, 0x04, 0xC4, 0xC0, + 0x5B, 0x04, 0x89, 0x07, 0x66, 0xE5, 0x39, 0xC2, + 0x07, 0x13, 0x39, 0xC6, 0x39, 0x86, 0x25, 0x16, + 0x39, 0xC6, 0x39, 0x86, 0x22, 0x16, 0xF7, 0x10, + 0x02, 0x02, 0xAC, 0xE9, 0xC4, 0x04, 0xC5, 0x04, + 0x39, 0xC2, 0x02, 0x13, 0x60, 0x04, 0xE8, 0xE9, + 0x02, 0x02, 0xBA, 0xE9, 0xC4, 0x04, 0x39, 0xC2, + 0x03, 0x13, 0x79, 0xC1, 0x60, 0x04, 0xE8, 0xE9, + 0x02, 0x02, 0xCA, 0xE9, 0xC5, 0x04, 0x39, 0xC2, + 0x03, 0x13, 0x39, 0xC1, 0x60, 0x04, 0xE8, 0xE9, + 0x79, 0xC0, 0xB9, 0xC0, 0x81, 0x60, 0xC2, 0x05, + 0x12, 0x09, 0xF1, 0x04, 0x02, 0x06, 0xFD, 0x16, + 0x5B, 0x04, 0x5C, 0x04, 0x01, 0x02, 0xAA, 0xAA, + 0x01, 0xC6, 0x44, 0xE0, 0x45, 0x40, 0x58, 0x80, + 0xF8, 0x16, 0x01, 0x02, 0x14, 0x00, 0x01, 0x06, + 0xFE, 0x16, 0x01, 0x02, 0x55, 0x55, 0x01, 0xC6, + 0x44, 0xE0, 0x45, 0x40, 0x58, 0x80, 0xED, 0x16, + 0x52, 0x04, 0xE0, 0x02, 0xA0, 0x00, 0x88, 0x07, + 0xC0, 0x00, 0x09, 0x02, 0x62, 0xEA, 0x84, 0x07, + 0x2A, 0xE6, 0x05, 0x02, 0x01, 0x00, 0x8B, 0xC2, + 0xCC, 0x04, 0xA0, 0x06, 0x6C, 0xEA, 0x60, 0x2C, + 0x01, 0x00, 0x99, 0x06, 0xA0, 0x2C, 0x02, 0x00, + 0x99, 0x06, 0x20, 0x2D, 0x04, 0x00, 0x99, 0x06, + 0x20, 0x2E, 0x08, 0x00, 0x99, 0x06, 0xA0, 0x2F, + 0x10, 0x00, 0x8C, 0x05, 0x09, 0x16, 0x80, 0xCC, + 0x81, 0xC4, 0x83, 0x07, 0xB0, 0xEA, 0x88, 0xC0, + 0x02, 0x04, 0x8C, 0x05, 0x01, 0x16, 0x33, 0x10, + 0xE0, 0x02, 0xA0, 0x00, 0x5A, 0x04, 0x8C, 0x05, + 0xFB, 0x16, 0x80, 0xCC, 0x81, 0xC4, 0x15, 0x0A, + 0xB4, 0xC0, 0x12, 0xC0, 0x88, 0xCC, 0x52, 0xC0, + 0xB4, 0xC4, 0x42, 0x06, 0x5B, 0x04, 0x2D, 0x07, + 0x18, 0x00, 0x41, 0x8B, 0x0A, 0x00, 0xEC, 0x16, + 0xC1, 0x82, 0xEA, 0x16, 0xC2, 0x02, 0x42, 0x02, + 0x00, 0x02, 0xE6, 0x16, 0x80, 0x03, 0x81, 0x07, + 0x01, 0x00, 0xF1, 0x10, 0x01, 0x02, 0x02, 0x00, + 0xEE, 0x10, 0x01, 0x02, 0x04, 0x00, 0xEB, 0x10, + 0x01, 0x02, 0x08, 0x00, 0xE8, 0x10, 0x01, 0x02, + 0x10, 0x00, 0xE5, 0x10, 0xA1, 0x02, 0x41, 0x8B, + 0x10, 0x00, 0x02, 0x13, 0x60, 0x04, 0x5C, 0xEA, + 0x2D, 0x07, 0x18, 0x00, 0x80, 0x03, 0x09, 0x02, + 0x00, 0x08, 0x03, 0x02, 0x04, 0x00, 0xC7, 0x04, + 0xA0, 0x06, 0xDC, 0xEB, 0x60, 0x01, 0x1C, 0x01, + 0x04, 0x00, 0x1C, 0x16, 0xA0, 0x01, 0x40, 0x01, + 0x00, 0x08, 0xE0, 0x01, 0x40, 0x01, 0x00, 0x10, + 0x04, 0x02, 0x01, 0x00, 0x44, 0xCE, 0xC4, 0x06, + 0x44, 0xC6, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x10, + 0x49, 0x06, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x40, + 0xE0, 0x01, 0x40, 0x01, 0x00, 0x04, 0xE0, 0x01, + 0x40, 0x01, 0x00, 0x08, 0xA0, 0x06, 0x7A, 0xEC, + 0xA0, 0x06, 0x7A, 0xEC, 0xC7, 0x05, 0x04, 0x02, + 0xE4, 0xE4, 0xE0, 0x04, 0xD0, 0x03, 0x74, 0xC1, + 0xB4, 0xC1, 0x86, 0x05, 0x1C, 0x13, 0xE0, 0x02, + 0xC0, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, 0xC0, + 0x80, 0xC0, 0xC0, 0xC0, 0x00, 0xC1, 0x40, 0xC1, + 0x80, 0xC1, 0xC0, 0xC1, 0x00, 0xC2, 0x40, 0xC2, + 0x80, 0xC2, 0xC0, 0xC2, 0x00, 0xC3, 0x40, 0xC3, + 0x80, 0xC3, 0xC0, 0xC3, 0xA0, 0x04, 0xAA, 0x00, + 0xD0, 0x03, 0xD0, 0x03, 0x3F, 0x10, 0x85, 0x05, + 0x85, 0x81, 0xE1, 0x13, 0xE4, 0x10, 0xC7, 0x05, + 0x05, 0x02, 0xFF, 0x7F, 0x45, 0xA1, 0xD0, 0x03, + 0xD0, 0x03, 0x34, 0x10, 0xC0, 0xCC, 0xC1, 0xC4, + 0x03, 0x02, 0x28, 0x00, 0xA0, 0x06, 0xDC, 0xEB, + 0xE0, 0x01, 0x42, 0x01, 0x00, 0x10, 0xC7, 0x05, + 0xD0, 0x03, 0xD0, 0x03, 0x27, 0x10, 0xC7, 0x05, + 0xA0, 0xC1, 0x4A, 0x01, 0xA0, 0x07, 0x4A, 0x01, + 0x00, 0x0E, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x02, + 0x20, 0x07, 0x44, 0x01, 0x60, 0xC1, 0x44, 0x01, + 0x85, 0x02, 0x00, 0xFF, 0x17, 0x16, 0xE0, 0x01, + 0x40, 0x01, 0x00, 0x22, 0x05, 0x02, 0xC0, 0x00, + 0x05, 0x06, 0xD0, 0x03, 0xFD, 0x16, 0x60, 0xC1, + 0x46, 0x01, 0x85, 0x02, 0x00, 0xFF, 0x0A, 0x13, + 0x05, 0x02, 0x93, 0x33, 0x05, 0x06, 0x00, 0x10, + 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, + 0xD0, 0x03, 0xF8, 0x16, 0x51, 0x10, 0x06, 0xC8, + 0x4A, 0x01, 0xC0, 0xCC, 0xC1, 0xC4, 0x4B, 0x10, + 0x13, 0xC0, 0xC8, 0xCC, 0x53, 0xC0, 0x02, 0x02, + 0xEC, 0xEB, 0xC2, 0xC4, 0x43, 0x06, 0x5B, 0x04, + 0x60, 0xC0, 0xAE, 0x00, 0xC4, 0x02, 0x44, 0x02, + 0x0F, 0x00, 0x44, 0x88, 0xCA, 0xE4, 0x3C, 0x16, + 0x81, 0x02, 0x08, 0x00, 0x27, 0x13, 0x21, 0xC1, + 0xDC, 0xE4, 0x14, 0xC1, 0x21, 0x21, 0xBA, 0xE4, + 0x33, 0x16, 0x21, 0xC1, 0xC2, 0xE4, 0x81, 0x02, + 0x00, 0x00, 0x0B, 0x13, 0x0D, 0x02, 0xA0, 0x00, + 0x84, 0x83, 0x09, 0x13, 0xC4, 0x05, 0x84, 0x83, + 0x06, 0x13, 0xC4, 0x05, 0x84, 0x83, 0x03, 0x13, + 0x23, 0x10, 0x0E, 0x81, 0x21, 0x16, 0x21, 0xC1, + 0xDC, 0xE4, 0x21, 0x45, 0xBA, 0xE4, 0xE0, 0x01, + 0x42, 0x01, 0x00, 0x10, 0xA0, 0x01, 0x42, 0x01, + 0x00, 0x10, 0xA1, 0xC3, 0xD4, 0xE4, 0x0F, 0x02, + 0x2F, 0x00, 0x80, 0x03, 0xA0, 0x01, 0x40, 0x01, + 0x00, 0x02, 0xA0, 0x01, 0x40, 0x01, 0x00, 0x80, + 0x6D, 0xC0, 0x0A, 0x00, 0x09, 0x13, 0x81, 0x02, + 0x5C, 0x12, 0x06, 0x1B, 0x0E, 0x02, 0xD2, 0xEB, + 0x0F, 0x02, 0x0F, 0x00, 0x80, 0x03, 0xCA, 0x05, + 0xE0, 0x02, 0xA0, 0x00, 0x5A, 0x04, 0x59, 0xCE, + 0x20, 0x88, 0xE4, 0xE4, 0xE4, 0xE4, 0xF8, 0x10, + 0xC1, 0x04, 0x48, 0x62, 0x89, 0x05, 0xA0, 0xC0, + 0x6C, 0x01, 0x08, 0xC8, 0x6C, 0x01, 0x03, 0x02, + 0x00, 0xFC, 0x04, 0x02, 0x00, 0x02, 0x73, 0xA0, + 0x04, 0x06, 0xFD, 0x16, 0x88, 0x05, 0x09, 0x06, + 0xF4, 0x16, 0x02, 0xC8, 0x6C, 0x01, 0x81, 0x86, + 0x02, 0x16, 0xD0, 0x03, 0xCB, 0x05, 0x5B, 0x04, + 0x43, 0x28, 0x31, 0x29, 0x38, 0x39, 0x2D, 0x33, + 0x38, 0x38, 0x42, 0x20, 0x20, 0x59, 0x49, 0x54, + 0x4B, 0xC2, 0xA8, 0x02, 0x98, 0x00, 0x83, 0x07, + 0x02, 0x00, 0x28, 0x02, 0x08, 0x00, 0x23, 0xC6, + 0x36, 0xE5, 0x48, 0x06, 0xC4, 0xC0, 0x73, 0x0A, + 0x65, 0x17, 0xA0, 0x06, 0xAA, 0xED, 0xC8, 0xC1, + 0xC7, 0x05, 0x03, 0x02, 0xA5, 0x00, 0xB0, 0x03, + 0xF8, 0xCD, 0xF8, 0xCD, 0xA6, 0x02, 0x06, 0x62, + 0x88, 0x02, 0x0A, 0x00, 0x57, 0x16, 0x03, 0x29, + 0x55, 0x16, 0x05, 0x29, 0xC4, 0x80, 0x52, 0x16, + 0x15, 0x09, 0x50, 0x17, 0x15, 0x09, 0x4E, 0x18, + 0x85, 0x02, 0x29, 0x00, 0x4B, 0x16, 0xC6, 0x05, + 0x96, 0x00, 0x03, 0x07, 0xC4, 0x04, 0x45, 0x06, + 0x95, 0x00, 0x44, 0x05, 0x43, 0x16, 0x44, 0x81, + 0x41, 0x16, 0x00, 0x03, 0x05, 0x00, 0xC4, 0x02, + 0x00, 0x03, 0x0A, 0x00, 0x44, 0x02, 0x0F, 0x00, + 0x84, 0x02, 0x05, 0x00, 0x37, 0x16, 0xC4, 0x02, + 0x00, 0x03, 0x0F, 0x00, 0x44, 0x02, 0x0F, 0x00, + 0x84, 0x02, 0x0A, 0x00, 0x2F, 0x16, 0x04, 0x02, + 0xFE, 0xFF, 0x2C, 0x13, 0x2B, 0x15, 0x2A, 0x1A, + 0x84, 0x05, 0x28, 0x12, 0x27, 0x15, 0x26, 0x1A, + 0x25, 0x18, 0x84, 0x05, 0x23, 0x16, 0x22, 0x1B, + 0x21, 0x17, 0x84, 0x05, 0x1F, 0x13, 0x1E, 0x1A, + 0x1D, 0x11, 0x04, 0x06, 0x1B, 0x16, 0xA5, 0x02, + 0xC5, 0xC1, 0x25, 0x02, 0x06, 0x00, 0x03, 0x02, + 0xA5, 0xA5, 0x83, 0xC1, 0x95, 0x00, 0x03, 0x38, + 0x94, 0x00, 0x83, 0x02, 0x2E, 0x6B, 0x0E, 0x16, + 0x84, 0x02, 0x59, 0x1C, 0x0B, 0x16, 0x24, 0x02, + 0x69, 0x00, 0x95, 0x00, 0x03, 0x3C, 0x94, 0x00, + 0x83, 0x81, 0x04, 0x16, 0x84, 0x02, 0x69, 0x00, + 0x01, 0x16, 0xC9, 0x05, 0x59, 0x04, 0xC3, 0xD0, + 0xFD, 0x13, 0x01, 0x1C, 0xFB, 0x10, 0xE0, 0x90, + 0x3D, 0xE5, 0xF8, 0x16, 0xC3, 0x06, 0xC3, 0xD0, + 0xF5, 0x1C, 0xF4, 0x16, 0xE0, 0x90, 0x3A, 0xE5, + 0xF1, 0x16, 0x5B, 0x04, 0x0B, 0xC3, 0x09, 0x02, + 0x3E, 0xE5, 0xA0, 0x06, 0x92, 0xE9, 0xCC, 0x05, + 0x5C, 0x04, 0x88, 0x07, 0x00, 0xA0, 0x89, 0x07, + 0xFE, 0xFF, 0xA8, 0x09, 0xA9, 0x09, 0x8A, 0x07, + 0x02, 0xE0, 0xA0, 0x06, 0x84, 0xEC, 0x00, 0x00, + 0x88, 0x07, 0x00, 0x90, 0x89, 0x07, 0xFE, 0x9F, + 0xA8, 0x09, 0xA9, 0x09, 0x8A, 0x07, 0x78, 0xE0, + 0xA0, 0x06, 0x84, 0xEC, 0x00, 0x00, 0xA0, 0x06, + 0xC4, 0xEC, 0x00, 0x00, 0xE6, 0x10, 0xE5, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, + 0x00, 0x08, 0x11, 0xE3, 0x6C, 0xCC, 0x00, 0x80, + 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, + 0x00, 0x04, 0x00, 0x02, 0x00, 0x01, 0x80, 0x00, + 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 0x00, + 0x04, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0xFF, + 0xFF, 0x00, 0xF0, 0xFF, 0x00, 0xF0, 0x0F, 0x00, + 0xFF, 0xFF, 0xFF, 0x7F, 0x03, 0x00, 0x00, 0x00, + 0xC3, 0x00, 0xE7, 0xE7, 0xF3, 0xE7, 0xF1, 0xF1, + 0x43, 0x28, 0x20, 0x29, 0x4F, 0x43, 0x59, 0x50, + 0x49, 0x52, 0x48, 0x47, 0x20, 0x54, 0x42, 0x49, + 0x20, 0x4D, 0x39, 0x31, 0x33, 0x38, 0x34, 0x2C, + 0x35, 0x2C, 0x36, 0x2C, 0x43, 0x28, 0x20, 0x29, + 0x4F, 0x43, 0x59, 0x50, 0x49, 0x52, 0x48, 0x47, + 0x20, 0x54, 0x49, 0x54, 0x31, 0x20, 0x38, 0x39, + 0x2D, 0x33, 0x39, 0x38, 0x39, 0x2C, 0x2D, 0x30, + 0x38, 0x39, 0x00, 0x00, 0x61, 0x9B, 0xC4, 0xEC, + 0x0E, 0xEA, 0xDE, 0xE5, 0xC8, 0xED, 0x00, 0x00, + 0xC4, 0x00, 0xB8, 0xAF, 0x4A, 0x06, 0x50, 0x06, + 0x4C, 0x06, 0xDC, 0xCC, 0x4E, 0x06, 0x0F, 0x00, + 0x32, 0x06, 0x01, 0x00, 0x50, 0x07, 0x58, 0x07, + 0x52, 0x07, 0x70, 0xB5, 0x54, 0x07, 0x0F, 0x00, + 0x38, 0x07, 0x01, 0x00, 0xBA, 0x00, 0xA0, 0x00, + 0xBC, 0x00, 0xD6, 0xED, 0xBE, 0x00, 0x0F, 0x00, + 0x5E, 0x07, 0x3A, 0x07, 0x62, 0x07, 0x40, 0x80, + 0x64, 0x07, 0x54, 0xBA, 0x66, 0x07, 0x36, 0xBA, + 0x68, 0x07, 0x40, 0xB8, 0x98, 0x07, 0x00, 0x80, + 0x78, 0x07, 0x00, 0x80, 0xE2, 0x08, 0x04, 0x00, + 0xE4, 0x08, 0x01, 0x00, 0xEC, 0x08, 0x08, 0x00, + 0xF6, 0x08, 0x0A, 0x00, 0xF8, 0x08, 0x06, 0x00, + 0x00, 0x09, 0x0C, 0x00, 0x02, 0x09, 0x04, 0x00, + 0xAE, 0x01, 0x00, 0x00, 0x1E, 0x09, 0x00, 0x00, + 0x66, 0x09, 0x00, 0x00, 0x0C, 0x06, 0x13, 0x00, + 0x0A, 0x06, 0x20, 0x00, 0x00, 0x00, 0xE0, 0x00, + 0x86, 0xA3, 0xE0, 0x00, 0xE6, 0xA2, 0xE0, 0x00, + 0x86, 0xA3, 0xE0, 0x00, 0x02, 0xA5, 0xE0, 0x00, + 0x5E, 0xA6, 0xE0, 0x00, 0x66, 0xA9, 0xE0, 0x00, + 0x12, 0xA4, 0xC0, 0x00, 0x22, 0xA4, 0xE0, 0x00, + 0x86, 0xA3, 0xE0, 0x00, 0x86, 0xA3, 0xC0, 0x00, + 0x74, 0xA4, 0xE0, 0x00, 0x86, 0xA3, 0xE0, 0x00, + 0x86, 0xA3, 0xE0, 0x00, 0x86, 0xA3, 0xE0, 0x00, + 0x86, 0xA3, 0xE0, 0x00, 0x86, 0xA3, 0xC0, 0x00, + 0xDE, 0xAF, 0xC0, 0x00, 0x48, 0xB0, 0xC0, 0x00, + 0x84, 0xB0, 0xC0, 0x00, 0xF4, 0xB0, 0xC0, 0x00, + 0x76, 0xB1, 0xE0, 0x00, 0xE4, 0xB2, 0xE0, 0x00, + 0x8A, 0xB2, 0xE0, 0x00, 0xF4, 0xB3, 0xE0, 0x00, + 0x7C, 0xB3, 0xE0, 0x00, 0xC6, 0xAA, 0xC0, 0x00, + 0x36, 0xAB, 0xC0, 0x00, 0x90, 0xAB, 0xC0, 0x00, + 0xC2, 0xAB, 0xC0, 0x00, 0xEA, 0xAA, 0xC0, 0x00, + 0x80, 0xA3, 0xC0, 0x00, 0x80, 0xA3, 0x00, 0x3F, + 0x00, 0x7F, 0x00, 0x5E, 0x30, 0x00, 0x28, 0x00, + 0x43, 0x00, 0xB6, 0xA6, 0xB6, 0xA6, 0x1C, 0xA5, + 0x14, 0xA5, 0x46, 0xA5, 0x46, 0xA5, 0x62, 0xA5, + 0xB6, 0xA6, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x20, 0x00, 0x08, + 0x00, 0x80, 0x00, 0x08, 0x00, 0x01, 0x00, 0x10, + 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, + 0x14, 0x00, 0x0E, 0x10, 0x0C, 0x0C, 0x0A, 0x0A, + 0x0A, 0x0A, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x98, 0x07, 0x7E, 0xCA, 0x58, 0x07, + 0xF8, 0xB8, 0x58, 0x07, 0xFE, 0xB7, 0x58, 0x07, + 0x68, 0xB9, 0x58, 0x07, 0xD0, 0xB8, 0x98, 0x07, + 0x5A, 0xC7, 0x98, 0x07, 0x52, 0xC7, 0x78, 0x07, + 0xC2, 0xC1, 0x58, 0x07, 0x30, 0xB9, 0x98, 0x07, + 0x38, 0xCA, 0x78, 0x07, 0x96, 0xC2, 0x58, 0x07, + 0x6A, 0xC7, 0x58, 0x07, 0xE0, 0xB8, 0x58, 0x07, + 0x1E, 0xB9, 0x58, 0x07, 0xE2, 0xB9, 0x98, 0x07, + 0xAE, 0xCB, 0x98, 0x07, 0x8E, 0xC7, 0x78, 0x07, + 0x56, 0xC2, 0xB8, 0x07, 0x14, 0xCC, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xA2, 0xBA, 0x16, 0xC1, + 0xCA, 0xC1, 0xD6, 0xC6, 0x8A, 0xBD, 0xC2, 0xBD, + 0xE0, 0xBD, 0x6A, 0xBE, 0x8E, 0xBE, 0xAA, 0xBE, + 0x22, 0xBF, 0x22, 0xBF, 0x56, 0xBE, 0xC8, 0xBF, + 0x10, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, + 0x00, 0x0C, 0x01, 0x0F, 0xFF, 0xFE, 0x00, 0x58, + 0x00, 0x0E, 0xFF, 0xFE, 0x0E, 0x00, 0x00, 0x70, + 0x40, 0x80, 0x00, 0x5E, 0xA0, 0xC0, 0xDF, 0xFF, + 0x00, 0x18, 0x00, 0xE0, 0x00, 0x78, 0x00, 0x50, + 0x00, 0x60, 0x00, 0x70, 0x00, 0x0C, 0x06, 0x00, + 0x00, 0x00, 0x84, 0xE3, 0xE6, 0x07, 0xF4, 0x07, + 0x08, 0x00, 0x00, 0x00, 0x8A, 0xE3, 0xEA, 0x07, + 0xF4, 0x07, 0x06, 0x00, 0x40, 0x00, 0x00, 0x0A, + 0xE6, 0x07, 0xEE, 0x07, 0x08, 0x00, 0x40, 0x00, + 0x06, 0x0A, 0xEA, 0x07, 0xEE, 0x07, 0x00, 0x00, + 0xE2, 0xC1, 0x8B, 0xD4, 0xFF, 0xFF, 0xD7, 0xD1, + 0xD9, 0xC5, 0xD4, 0xC3, 0x3B, 0x59, 0x34, 0x09, + 0xFC, 0x05, 0x6C, 0x09, 0xD8, 0x06, 0x06, 0x04, + 0xBA, 0xEA, 0x30, 0x09, 0x48, 0x04, 0x80, 0x08, + 0x06, 0x00, 0x0A, 0x06, 0x0E, 0x0C, 0xBA, 0xCE, + 0x2E, 0xE0, 0x56, 0xE0, 0x50, 0xE1, 0x66, 0xE2, + 0xEC, 0xE2, 0x4C, 0xE3, 0xFE, 0xE3, 0xBA, 0xCE, + 0x80, 0xE4, 0x10, 0xE4, 0x14, 0xE0, 0x1C, 0xE4, + 0x1C, 0xE4, 0x46, 0xE5, 0x50, 0xE5, 0x5A, 0xE5, + 0xBA, 0xCE, 0xA6, 0xDC, 0xBA, 0xCE, 0x44, 0xDA, + 0xE6, 0xDF, 0x70, 0xDA, 0xDE, 0xDE, 0xB0, 0xCE, + 0x16, 0xDB, 0x3A, 0xDD, 0xB8, 0xDD, 0x34, 0xDE, + 0x58, 0xDE, 0x16, 0xDB, 0xDA, 0xDC, 0x08, 0xCF, + 0xB0, 0xCE, 0xA8, 0xD9, 0x8A, 0xD9, 0x44, 0xD9, + 0xB0, 0xCE, 0xEA, 0xDE, 0xB0, 0xCE, 0x72, 0x06, + 0xF6, 0xD2, 0x08, 0x07, 0x72, 0x06, 0x54, 0xD2, + 0xF4, 0x01, 0x72, 0x06, 0x34, 0xD2, 0x08, 0x07, + 0x7C, 0x06, 0x5A, 0xDC, 0x04, 0x00, 0x7C, 0x06, + 0x78, 0xD2, 0x00, 0x00, 0x7C, 0x06, 0xCC, 0xDE, + 0xFA, 0x00, 0x86, 0x06, 0xAC, 0xD1, 0x05, 0x00, + 0x90, 0x06, 0x1C, 0xDF, 0x28, 0x00, 0x90, 0x06, + 0x50, 0xD3, 0x04, 0x01, 0x90, 0x06, 0x00, 0x00, + 0x02, 0x00, 0x90, 0x06, 0x80, 0xD2, 0xBC, 0x02, + 0x9A, 0x06, 0x06, 0xD3, 0xDC, 0x05, 0x9A, 0x06, + 0xAA, 0xD2, 0x64, 0x00, 0x9A, 0x06, 0x0A, 0xD3, + 0x14, 0x00, 0x9A, 0x06, 0xE2, 0xE0, 0x40, 0x06, + 0x9A, 0x06, 0x12, 0xD3, 0x64, 0x00, 0x7C, 0x06, + 0x16, 0xDC, 0x04, 0x00, 0x7C, 0x06, 0xE6, 0xDA, + 0x16, 0x00, 0x7C, 0x06, 0xFA, 0xDB, 0x05, 0x00, + 0x7C, 0x06, 0x00, 0xDD, 0x14, 0x00, 0x9A, 0x06, + 0x7C, 0xD3, 0x14, 0x00, 0x9A, 0x06, 0x38, 0xD4, + 0x02, 0x00, 0x7C, 0x06, 0x0C, 0xE0, 0x19, 0x00, + 0x00, 0x00, 0x0A, 0x07, 0x0E, 0x07, 0x04, 0x07, + 0xD8, 0x06, 0x00, 0x07, 0xF0, 0x06, 0xEE, 0x06, + 0xEC, 0x06, 0x0C, 0x07, 0xE6, 0x06, 0x18, 0x07, + 0x92, 0x09, 0x94, 0x09, 0x96, 0x09, 0x98, 0x09, + 0x00, 0x50, 0xCC, 0x00, 0x03, 0x00, 0x00, 0x84, + 0x00, 0xA8, 0x00, 0xA0, 0x00, 0x20, 0x00, 0x80, + 0x00, 0x40, 0x00, 0x08, 0x00, 0x40, 0x00, 0x80, + 0x00, 0x40, 0x00, 0x10, 0x82, 0xEC, 0x48, 0xEB, + 0x62, 0xEB, 0x7C, 0xEB, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x09, 0x00, 0x09, 0x00, 0xEA, 0xEB, + 0x52, 0xEB, 0x68, 0xEB, 0x82, 0xEB, 0x40, 0x01, + 0x42, 0x01, 0x42, 0x01, 0x42, 0x01, 0x00, 0x00, + 0x7F, 0x00, 0xA0, 0x00, 0xFF, 0x00, 0x10, 0x02, + 0x1F, 0x02, 0x30, 0x02, 0x3F, 0x02, 0x50, 0x02, + 0x5F, 0x02, 0x70, 0x02, 0x7F, 0x02, 0x90, 0x02, + 0x9F, 0x02, 0xB0, 0x02, 0xBF, 0x02, 0xD0, 0x02, + 0xDF, 0x02, 0xE1, 0x02, 0xFF, 0x02, 0x01, 0x03, + 0x7F, 0x03, 0x81, 0x03, 0x8F, 0x03, 0x91, 0x03, + 0x9F, 0x03, 0xA1, 0x03, 0xAF, 0x03, 0xB1, 0x03, + 0xBF, 0x03, 0xC1, 0x03, 0xCF, 0x03, 0xE1, 0x03, + 0xFF, 0x03, 0xC0, 0x07, 0xFF, 0x07, 0x00, 0x0C, + 0xFF, 0x0F, 0x00, 0x30, 0xFF, 0x37, 0xFF, 0xFF, + 0xFF, 0xFF, 0xBC, 0xFE, 0x07, 0x00, 0x5E, 0x02, + 0x00, 0x01, 0xFF, 0xBA, 0x80, 0xBA, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0C, 0x01, 0x0A, 0x01, + 0x0E, 0x01, 0x10, 0x01, 0x14, 0x01, 0x00, 0x00, + 0x12, 0x01, 0x00, 0xF8, 0x16, 0x01, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x1C, 0x01, + 0x82, 0x01, 0x66, 0x96, 0x66, 0x96, 0x55, 0x55, + 0x00, 0x00, 0x82, 0x01, 0x2A, 0x8A, 0x2A, 0x8A, + 0x18, 0xC9, 0x18, 0xC9, 0x86, 0x01, 0xAA, 0xA2, + 0x1E, 0xA0, 0x55, 0x55, 0x1E, 0x54, 0x8A, 0x01, + 0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, + 0x8C, 0x01, 0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, + 0x00, 0x00, 0x8E, 0x01, 0x00, 0x50, 0x00, 0x00, + 0x00, 0xA8, 0x00, 0x00, 0x90, 0x01, 0x00, 0x50, + 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x92, 0x01, + 0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, + 0x94, 0x01, 0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, + 0x00, 0x00, 0x96, 0x01, 0x00, 0x50, 0x00, 0x00, + 0x00, 0xA8, 0x00, 0x00, 0x98, 0x01, 0x00, 0x50, + 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x9A, 0x01, + 0x00, 0x50, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, + 0x9C, 0x01, 0x55, 0x55, 0xC0, 0x7F, 0xAA, 0xAA, + 0xC0, 0x7F, 0x00, 0x00, 0xA2, 0x01, 0xA4, 0x01, + 0xA8, 0x01, 0xAA, 0x01, 0xAE, 0x01, 0xB0, 0x01, + 0xB2, 0x01, 0x80, 0x01, 0x00, 0x00, 0x88, 0x01, + 0x00, 0xFF, 0x9E, 0x01, 0xFF, 0x00, 0xA0, 0x01, + 0x00, 0x80, 0xAC, 0x01, 0x00, 0x80, 0x00, 0x00, + 0xA6, 0x01, 0x00, 0x80, 0x00, 0x00, 0x80, 0x01, + 0xBC, 0x01, 0x00, 0x88, 0x00, 0x06, 0x00, 0xC8, + 0x00, 0x00, 0x00, 0x80, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x02, 0x00, 0x44, 0x00, 0x92, 0xEA, + 0x48, 0x00, 0x98, 0xEA, 0x50, 0x00, 0x9E, 0xEA, + 0x60, 0x00, 0xA4, 0xEA, 0x78, 0x00, 0xAA, 0xEA, + 0x0A, 0xE8, 0x18, 0xE7, 0x3C, 0xEA, 0x2A, 0xE7, + 0x14, 0x55, 0xA0, 0x01, 0xEC, 0xE6, 0xD0, 0xE9, + 0x46, 0xE7, 0xA0, 0xE7, 0x00, 0xE7, 0x58, 0xE8, + 0x00, 0x00, 0x1E, 0x00, 0x46, 0xE7, 0x92, 0xE7, + 0x00, 0x41, 0x01, 0x41, 0xB6, 0xE7, 0x73, 0xEA, + 0x18, 0xE7, 0x48, 0xEA, 0xEC, 0xE6, 0x04, 0xEA, + 0x56, 0xE7, 0x62, 0xE7, 0xB6, 0xE7, 0x6E, 0xEA, + 0x62, 0xE8, 0x00, 0x00, 0x36, 0xE8, 0xEC, 0xE6, + 0xFA, 0xE9, 0x56, 0xE7, 0x62, 0xE7, 0x36, 0xE8, + 0x62, 0xE8, 0x00, 0x00, 0xEC, 0xE6, 0xF0, 0xE9, + 0x0C, 0xE7, 0x4A, 0xE7, 0x62, 0xE7, 0x36, 0xE8, + 0xEC, 0xE6, 0xFA, 0xE9, 0x56, 0xE7, 0x62, 0xE7, + 0x36, 0xE8, 0x62, 0xE8, 0x00, 0x20, 0x2A, 0xE7, + 0x14, 0x55, 0xA0, 0x01, 0x18, 0xE7, 0x50, 0xEA, + 0xEC, 0xE6, 0xD0, 0xE9, 0x58, 0xE8, 0x50, 0x55, + 0x0C, 0x00, 0x46, 0xE7, 0x92, 0xE7, 0x00, 0x01, + 0x00, 0x00, 0xB6, 0xE7, 0x75, 0xEA, 0x00, 0xE7, + 0x58, 0xE8, 0x55, 0x55, 0x0C, 0x00, 0x56, 0xE7, + 0xA0, 0xE7, 0x00, 0xE7, 0x58, 0xE8, 0xFF, 0xFF, + 0x08, 0x00, 0x58, 0xE8, 0x02, 0x10, 0x06, 0x00, + 0x46, 0xE7, 0x92, 0xE7, 0x00, 0x01, 0x01, 0x01, + 0xB6, 0xE7, 0x80, 0xEA, 0x00, 0xE7, 0x58, 0xE8, + 0x00, 0xC0, 0x08, 0x00, 0x58, 0xE8, 0xFF, 0xFF, + 0x0A, 0x00, 0x58, 0xE8, 0xFF, 0xFF, 0x0C, 0x00, + 0x58, 0xE8, 0x0D, 0x10, 0x06, 0x00, 0x46, 0xE7, + 0x92, 0xE7, 0x00, 0x01, 0x01, 0x01, 0xB6, 0xE7, + 0x74, 0xEA, 0x62, 0xE8, 0x08, 0x20, 0x00, 0xE7, + 0x52, 0xE8, 0x82, 0x01, 0x02, 0xC9, 0x46, 0xE7, + 0xB6, 0xE7, 0x80, 0xEA, 0x62, 0xE8, 0x34, 0x20, + 0x00, 0xE7, 0x58, 0xE8, 0x00, 0x10, 0x06, 0x00, + 0x46, 0xE7, 0xC6, 0xE8, 0xB6, 0xE7, 0x78, 0xEA, + 0x52, 0xE8, 0x9C, 0x01, 0x40, 0x00, 0x18, 0xE7, + 0x50, 0xEA, 0x2A, 0xE7, 0xFF, 0x00, 0x80, 0x07, + 0x26, 0xE9, 0x03, 0x00, 0x66, 0xE9, 0x74, 0xE9, + 0x12, 0xEA, 0x38, 0xE9, 0x00, 0x00, 0x74, 0xE9, + 0x1C, 0xEA, 0x38, 0xE9, 0x04, 0x00, 0x74, 0xE9, + 0x24, 0xEA, 0x38, 0xE9, 0x07, 0x00, 0x74, 0xE9, + 0x2C, 0xEA, 0x26, 0xE9, 0x01, 0x00, 0x74, 0xE9, + 0x34, 0xEA, 0x38, 0xE9, 0x02, 0x00, 0x74, 0xE9, + 0x34, 0xEA, 0x38, 0xE9, 0x06, 0x00, 0x74, 0xE9, + 0x34, 0xEA, 0x38, 0xE9, 0x05, 0x00, 0x74, 0xE9, + 0x34, 0xEA, 0x26, 0xE9, 0x01, 0x00, 0x4A, 0xE9, + 0x26, 0xE9, 0x03, 0x00, 0x58, 0xE9, 0x62, 0xE7, + 0xE6, 0xE8, 0xD8, 0xE9, 0x01, 0x00, 0xE6, 0xE8, + 0x25, 0xEA, 0x02, 0x00, 0xE6, 0xE8, 0x2F, 0xEA, + 0x06, 0x00, 0xE6, 0xE8, 0x3A, 0xEA, 0x05, 0x00, + 0xB6, 0xE7, 0x74, 0xEA, 0x36, 0xE8, 0xEC, 0xE6, + 0xD0, 0xE9, 0x56, 0xE7, 0xC6, 0xE8, 0x0C, 0xE7, + 0x92, 0xE7, 0x00, 0x01, 0x00, 0x80, 0xB6, 0xE7, + 0x78, 0xEA, 0x00, 0xE7, 0xFE, 0xE8, 0x52, 0xE8, + 0x80, 0x01, 0x41, 0x8E, 0x4A, 0xE7, 0x92, 0xE7, + 0x00, 0x01, 0x01, 0x1B, 0x06, 0xE9, 0xE4, 0xFF, + 0xB6, 0xE7, 0x7C, 0xEA, 0xBE, 0xE8, 0x18, 0xE7, + 0x56, 0xEA, 0x0C, 0xE7, 0x6A, 0xE8, 0x3C, 0xE7, + 0x00, 0xE0, 0xC6, 0xE8, 0xB6, 0xE7, 0x86, 0xEA, + 0x3C, 0xE7, 0x00, 0xE8, 0x62, 0xE7, 0xB6, 0xE7, + 0x85, 0xEA, 0x3C, 0xE7, 0x00, 0x08, 0xC6, 0xE8, + 0xB6, 0xE7, 0x86, 0xEA, 0x3C, 0xE7, 0x00, 0xF8, + 0x62, 0xE7, 0xB6, 0xE7, 0x85, 0xEA, 0x52, 0xE8, + 0x80, 0x01, 0x00, 0x02, 0x3C, 0xE7, 0x00, 0xE0, + 0x62, 0xE7, 0xB6, 0xE7, 0x85, 0xEA, 0x52, 0xE8, + 0x84, 0x01, 0x00, 0x00, 0x62, 0xE8, 0x34, 0x00, + 0x3C, 0xE7, 0x00, 0x00, 0xC6, 0xE8, 0x62, 0xE8, + 0x34, 0x60, 0x0E, 0xE9, 0x52, 0xE8, 0x84, 0x01, + 0x00, 0x00, 0xB6, 0xE7, 0x86, 0xEA, 0x52, 0xE8, + 0x82, 0x01, 0x00, 0xC8, 0x3C, 0xE7, 0x00, 0xE0, + 0xC6, 0xE8, 0x3C, 0xE7, 0x00, 0x10, 0xC6, 0xE8, + 0x62, 0xE8, 0x34, 0x60, 0x52, 0xE8, 0x80, 0x01, + 0x00, 0x06, 0x3C, 0xE7, 0x10, 0x00, 0x78, 0xE8, + 0x36, 0xE8, 0x52, 0xE8, 0x84, 0x01, 0x00, 0x00, + 0x62, 0xE8, 0x34, 0x00, 0xEC, 0xE6, 0xD0, 0xE9, + 0x18, 0xE7, 0x5C, 0xEA, 0xD0, 0xE8, 0x92, 0xE9, + 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0xF0, + 0x06, 0x00, 0x00, 0xC7, 0xA0, 0xE7, 0xDC, 0xE8, + 0x00, 0xE0, 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, + 0x40, 0xD0, 0x06, 0x00, 0x00, 0xE0, 0xA0, 0xE7, + 0xDC, 0xE8, 0x00, 0xC0, 0x00, 0xE7, 0x0C, 0xE7, + 0x70, 0xE7, 0x40, 0x90, 0x06, 0x00, 0x00, 0xA0, + 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x80, 0x00, 0xE7, + 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0x50, 0x06, 0x00, + 0x00, 0x60, 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x40, + 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0x10, + 0x06, 0x00, 0x00, 0x20, 0xA0, 0xE7, 0xDC, 0xE8, + 0x00, 0x00, 0xD0, 0xE8, 0x92, 0xE9, 0x00, 0xE7, + 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0xD0, 0x06, 0x00, + 0x00, 0xA6, 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0xC0, + 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0x90, + 0x06, 0x00, 0x00, 0xC0, 0xA0, 0xE7, 0xDC, 0xE8, + 0x00, 0x80, 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, + 0x40, 0x50, 0x06, 0x00, 0x00, 0x40, 0xA0, 0xE7, + 0xDC, 0xE8, 0x00, 0x40, 0x00, 0xE7, 0x0C, 0xE7, + 0x70, 0xE7, 0x40, 0x70, 0x06, 0x00, 0x00, 0x60, + 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x60, 0x7E, 0xE9, + 0x90, 0xE9, 0x18, 0xE7, 0x62, 0xEA, 0xEC, 0xE6, + 0xD0, 0xE9, 0xA4, 0xE8, 0x55, 0x55, 0x16, 0x00, + 0x46, 0xE7, 0x92, 0xE7, 0x00, 0x00, 0x00, 0x00, + 0xB6, 0xE7, 0x8B, 0xEA, 0x0A, 0xE8, 0x18, 0xE7, + 0x62, 0xEA, 0x58, 0xE8, 0x55, 0x55, 0x16, 0x00, + 0x00, 0xE7, 0x46, 0xE7, 0xA0, 0xE7, 0x2A, 0xE7, + 0xFF, 0x00, 0x00, 0x08, 0x2A, 0xE7, 0xFF, 0x00, + 0x00, 0x0C, 0x2A, 0xE7, 0xFF, 0x00, 0x00, 0x10, + 0x2A, 0xE7, 0xFF, 0x00, 0x00, 0x14, 0x2A, 0xE7, + 0xFF, 0x00, 0x00, 0x18, 0x2A, 0xE7, 0xFF, 0x00, + 0x00, 0x1C, 0x2A, 0xE7, 0xFF, 0x00, 0x00, 0x20, + 0x2A, 0xE7, 0xFF, 0x00, 0x00, 0x24, 0x2A, 0xE7, + 0xFF, 0x00, 0x00, 0x28, 0x2A, 0xE7, 0xFF, 0x00, + 0x00, 0x2C, 0xD2, 0xE7, 0x00, 0xE7, 0x0C, 0xE7, + 0x70, 0xE7, 0x40, 0x30, 0x06, 0x00, 0x00, 0x01, + 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x20, 0x00, 0xE7, + 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0x70, 0x06, 0x00, + 0x00, 0x43, 0xA0, 0xE7, 0xDC, 0xE8, 0x00, 0x60, + 0x00, 0xE7, 0x0C, 0xE7, 0x70, 0xE7, 0x40, 0xB0, + 0x06, 0x00, 0x00, 0x85, 0xA0, 0xE7, 0xDC, 0xE8, + 0x00, 0xA0, 0xD8, 0xE8, 0x00, 0x01, 0x03, 0x01, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x81, 0x1A, 0x00, + 0x40, 0x10, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x72, 0x82, + 0x4A, 0xA9, 0xA5, 0x5A, 0xDA, 0xE7, 0x03, 0x09, + 0x11, 0x9D, 0x00, 0x00, 0x00, 0x81, 0x04, 0x00, + 0xD8, 0x90, 0x00, 0x10, 0x00, 0x00, 0x00, 0x81, + 0x04, 0x00, 0xD8, 0x90, 0xD8, 0xB4, 0x00, 0x00, + 0x00, 0x81, 0x08, 0x00, 0xD8, 0x90, 0x46, 0x16, + 0x00, 0x40, 0xD8, 0xB4, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x13, 0x00, 0x40, 0x10, 0x16, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x10, 0x00, 0x15, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x15, 0x00, + 0x00, 0x00, 0x00, 0x81, 0x0F, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x12, 0x00, 0x0A, 0x80, + 0x40, 0x9E, 0x00, 0xC8, 0x00, 0x00, 0x5E, 0x80, + 0x0F, 0x00, 0x06, 0x80, 0x40, 0xFE, 0x00, 0xCC, + 0x00, 0x00, 0x04, 0x80, 0x40, 0x8E, 0x00, 0xC9, + 0x04, 0x80, 0x00, 0x06, 0x00, 0xCC, 0x04, 0x80, + 0x40, 0x0A, 0x00, 0xC8, 0x0A, 0x80, 0x40, 0x8A, + 0x00, 0xC8, 0x00, 0x00, 0x5E, 0x80, 0x0F, 0x00, + 0x0A, 0x08, 0x80, 0x1C, 0x0A, 0x00, 0x1C, 0x1A, + 0x00, 0x80, 0x1C, 0x0C, 0x00, 0x80, 0x1C, 0x1A, + 0x00, 0x80, 0x1A, 0x0E, 0x80, 0x1C, 0x04, 0x00, + 0x00, 0x80, 0x80, 0x02, 0x02, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x58, 0x07, 0x0C, 0xB8, + 0x16, 0xE0, 0xE2, 0x08, 0xEC, 0x08, 0xF6, 0x08, + 0x16, 0xE0, 0x00, 0x09, 0x0A, 0x09, 0x00, 0x00, + 0x00, 0x00, 0xE2, 0x08, 0x00, 0x00, 0xEC, 0x08, + 0xF6, 0x08, 0x00, 0x09, 0x00, 0x00, 0xB8, 0x07, + 0xCA, 0xCB, 0x80, 0x02, 0xB8, 0x07, 0xE8, 0xCB, + 0x84, 0xFF, 0xB8, 0x07, 0x0A, 0xCC, 0xB8, 0x07, + 0x84, 0xCC, 0x6E, 0xCD, 0x62, 0xCD, 0x88, 0xCD, + 0x90, 0xCE, 0x84, 0xCD, 0x92, 0xCE, 0x92, 0xCE, + 0x92, 0xCE, 0x8C, 0xCD, 0x96, 0xCD, 0x38, 0xCE, + 0x82, 0xCE, 0x92, 0xCE, 0x92, 0xCE, 0x92, 0xCE, + 0x92, 0xCE, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x08, 0x01, 0x05, 0x08, + 0x08, 0x08, 0x03, 0x08, 0x03, 0x03, 0x03, 0x03, + 0x00, 0x00, 0x04, 0x02, 0x04, 0x04, 0x00, 0x04, + 0x0A, 0x08, 0x00, 0x00, 0x10, 0x0C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x1A, 0x00, 0x00, + 0x04, 0x41, 0x06, 0x0B, 0x08, 0xC2, 0x00, 0xE6, + 0x00, 0xE7, 0x04, 0x06, 0x04, 0x07, 0x04, 0x03, + 0x06, 0x04, 0x04, 0x05, 0x04, 0x88, 0x04, 0xCF, + 0x04, 0xCD, 0x03, 0x00, 0x05, 0x00, 0x1C, 0x00, + 0x00, 0x0C, 0x00, 0x80, 0xD2, 0xD8, 0xDA, 0xD8, + 0x1E, 0xD9, 0xDE, 0xD8, 0xEA, 0xD8, 0xF0, 0xD8, + 0x14, 0xD9, 0xE4, 0xD8, 0x32, 0xD9, 0x00, 0x06, + 0x00, 0x00, 0x03, 0x07, 0x0A, 0x0E, 0x0F, 0x14, + 0x26, 0x2A, 0x52, 0x42, 0x50, 0x48, 0x5D, 0x4D, + 0x62, 0x62, 0x6D, 0x57, 0x46, 0x39, 0x1A, 0x1D, + 0x7C, 0x76, 0x1F, 0x23, 0x15, 0x1D, 0x74, 0x6F, + 0x84, 0x7C, 0x8B, 0x82, 0x92, 0x89, 0x00, 0x00, + 0x32, 0x2F, 0x3F, 0x34, 0x32, 0x01, 0x01, 0x57, + 0x32, 0x11, 0x81, 0x51, 0x02, 0x56, 0x03, 0x55, + 0x54, 0x11, 0x56, 0x81, 0x55, 0x02, 0x54, 0x02, + 0x56, 0x81, 0x01, 0x76, 0x02, 0x34, 0x02, 0x55, + 0x81, 0x54, 0x02, 0x58, 0x02, 0x55, 0x81, 0x54, + 0x02, 0x58, 0x11, 0x12, 0x02, 0x52, 0x58, 0x83, + 0x52, 0x05, 0x83, 0x04, 0x02, 0x58, 0x08, 0x55, + 0x58, 0x83, 0x55, 0x02, 0x81, 0x02, 0x05, 0x58, + 0x03, 0x52, 0x5C, 0x15, 0x53, 0x5B, 0x52, 0x87, + 0x11, 0x03, 0x41, 0x51, 0x78, 0x51, 0x34, 0x11, + 0x81, 0x11, 0x20, 0x31, 0x54, 0x57, 0x01, 0x53, + 0x5A, 0x12, 0x81, 0x51, 0x20, 0x31, 0x5B, 0x57, + 0x01, 0x5A, 0x01, 0x11, 0x51, 0x11, 0x31, 0x81, + 0x57, 0x20, 0x15, 0x01, 0x13, 0x01, 0x11, 0x01, + 0x11, 0x11, 0x81, 0x51, 0x05, 0x58, 0x02, 0x52, + 0x5B, 0x54, 0x5D, 0x81, 0x52, 0x05, 0x54, 0x02, + 0x58, 0x81, 0x50, 0x02, 0x13, 0x03, 0x58, 0x81, + 0x50, 0x02, 0x11, 0x03, 0x81, 0x54, 0x72, 0x5D, + 0x50, 0x03, 0x13, 0x03, 0x13, 0x01, 0x40, 0x54, + 0x0E, 0x00, 0x20, 0x06, 0x56, 0x06, 0x0C, 0xDA, + 0x24, 0x00, 0x02, 0x10, 0x16, 0x00, 0x02, 0x00, + 0x01, 0x04, 0x08, 0x07, 0x0C, 0xDA, 0x20, 0x00, + 0x03, 0x10, 0x12, 0x00, 0x03, 0x00, 0x4E, 0xD9, + 0x14, 0x8E, 0x20, 0x00, 0x04, 0x10, 0x12, 0x00, + 0x04, 0x00, 0xD2, 0xCE, 0x20, 0x00, 0x05, 0xE0, + 0x12, 0x00, 0x05, 0x00, 0xD2, 0xCE, 0x20, 0x00, + 0x06, 0xE0, 0x12, 0x00, 0x06, 0x00, 0xE8, 0xDD, + 0x12, 0x00, 0x01, 0xE0, 0x6C, 0x09, 0xCC, 0x06, + 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x30, 0x06, + 0x42, 0xDC, 0xF0, 0x05, 0x00, 0xE0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xE2, 0x05, 0x08, 0x00, + 0x26, 0xFF, 0xDC, 0x05, 0x00, 0x00, 0x30, 0x06, + 0xF8, 0xDB, 0x1E, 0x00, 0x01, 0xE0, 0x10, 0x00, + 0x11, 0x30, 0x0C, 0x04, 0x01, 0x00, 0x0E, 0x04, + 0x02, 0x00, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x06, 0x32, 0xDD, 0x12, 0x00, 0x01, 0xE0, + 0x04, 0x00, 0x13, 0x30, 0x74, 0xDE, 0x3E, 0x00, + 0x00, 0xE0, 0x00, 0xC0, 0x00, 0x00, 0x02, 0x00, + 0x30, 0x00, 0x20, 0x50, 0x23, 0x0C, 0xFC, 0x05, + 0x52, 0x06, 0x56, 0x06, 0x00, 0x00, 0x00, 0x81, + 0x16, 0x00, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0x00, + 0x10, 0x00, 0x08, 0x00, 0x2A, 0x40, 0x2A, 0x04, + 0x56, 0x06, 0x26, 0x00, 0x19, 0xED, 0x2B, 0x06, + 0x72, 0x09, 0x22, 0x00, 0x24, 0x00, 0x2F, 0xED, + 0x23, 0x0C, 0xFC, 0x05, 0x28, 0x08, 0x34, 0x09, + 0x29, 0x08, 0x58, 0x07, 0x78, 0x07, 0x98, 0x07, + 0x23, 0x00, 0x2A, 0x00, 0x3D, 0xED, 0x06, 0x04, + 0xF0, 0x06, 0x07, 0x04, 0xEE, 0x06, 0x24, 0x00, + 0xD2, 0xCE, 0x34, 0x00, 0x00, 0xE0, 0x00, 0xC0, + 0x00, 0x00, 0x10, 0x00, 0x26, 0x00, 0x25, 0x40, + 0xD2, 0xCE, 0x20, 0x00, 0x00, 0xE0, 0x00, 0xC0, + 0x00, 0x00, 0x10, 0x00, 0x12, 0x00, 0x26, 0x40, + 0xD2, 0xCE, 0x1A, 0x00, 0x00, 0xE0, 0x0C, 0x00, + 0x27, 0x60, 0x0A, 0x08, 0xE6, 0x06, 0xD2, 0xCE, + 0x24, 0x00, 0x00, 0xE0, 0x16, 0x00, 0x28, 0x60, + 0x30, 0x04, 0x06, 0x07, 0x52, 0xCF, 0x00, 0x81, + 0x30, 0x00, 0x00, 0xE0, 0x22, 0x00, 0x29, 0x60, + 0x2D, 0x08, 0x1C, 0x07, 0x2E, 0x08, 0x22, 0x07, + 0x00, 0x00, 0x08, 0x02, 0x06, 0x01, 0x14, 0x06, + 0x18, 0x08, 0x20, 0x0C, 0x26, 0x0E, 0x30, 0x0F, + 0x34, 0x11, 0x3E, 0x12, 0x42, 0x14, 0x46, 0x16, + 0x1C, 0x0A, 0x4A, 0x18, 0x13, 0x03, 0x11, 0x83, + 0x01, 0x11, 0x11, 0x81, 0x12, 0x81, 0x13, 0x01, + 0x52, 0x83, 0x81, 0x85, 0x85, 0x11, 0x12, 0x81, + 0x12, 0x81, 0x19, 0x81, 0x60, 0x85, 0x00, 0xC0, + 0x00, 0x00, 0x08, 0x00, 0x6C, 0x09, 0x00, 0x00, + 0x30, 0x06, 0x08, 0xE5, 0x54, 0x06, 0x50, 0x06, + 0x38, 0x02, 0x21, 0x04, 0x1E, 0x09, 0x0B, 0x06, + 0xD8, 0x06, 0x02, 0x08, 0xDC, 0x06, 0x00, 0xC0, + 0xFF, 0xFF, 0xFF, 0xFF, 0x41, 0x00, 0x41, 0x00, + 0x14, 0xAE, 0x00, 0x00, 0x00, 0x81, 0x09, 0x04, + 0x0C, 0x07, 0x41, 0x00, 0x41, 0x00, 0x14, 0x02, + 0x00, 0x00, 0x00, 0x81, 0x0B, 0x06, 0xD8, 0x06, + 0x2C, 0x06, 0x76, 0x09, 0x22, 0x14, 0x3A, 0x09, + 0x41, 0x00, 0x41, 0x00, 0x54, 0x02, 0x00, 0x00, + 0x00, 0x81, 0xD8, 0x06, 0x00, 0x84, 0x00, 0x48, + 0xFC, 0xFF, 0x09, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xB8, 0xFF, 0x20, 0x00, + 0x43, 0x28, 0x31, 0x29, 0x38, 0x39, 0x2D, 0x33, + 0x39, 0x38, 0x39, 0x2C, 0x2D, 0x30, 0x38, 0x39, + 0x54, 0x20, 0x78, 0x65, 0x73, 0x61, 0x49, 0x20, + 0x73, 0x6E, 0x72, 0x74, 0x6D, 0x75, 0x6E, 0x65, + 0x73, 0x74, 0x28, 0x0A, 0x29, 0x43, 0x39, 0x31, + 0x33, 0x38, 0x34, 0x2C, 0x35, 0x2C, 0x36, 0x2C, + 0x49, 0x20, 0x4D, 0x42, 0x43, 0x20, 0x72, 0x6F, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xF8, 0xFF, 0x01, 0x00, 0x34, 0x90, + 0x00, 0x00, 0xFA, 0xFF, 0x01, 0x00, 0xB8, 0xFF, + 0x00, 0x00, 0xFC, 0xFF, 0x02, 0x00, 0x80, 0x00, + 0x3E, 0xA0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +#endif /* CONFIG_SKTR */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/Config.in linux/drivers/net/wan/Config.in --- v2.3.20/linux/drivers/net/wan/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/Config.in Mon Oct 11 10:13:25 1999 @@ -0,0 +1,64 @@ +# +# wan devices configuration +# + +mainmenu_option next_comment +comment 'Wan interfaces' + +bool 'Wan interfaces support' CONFIG_WAN +if [ "$CONFIG_WAN" = "y" ]; then + + # There is no way to detect a comtrol sv11 - force it modular for now. + + dep_tristate 'Comtrol Hostess SV-11 support' CONFIG_HOSTESS_SV11 m + + # The COSA/SRP driver has not been tested as non-modular yet. + + dep_tristate 'COSA/SRP sync serial boards support' CONFIG_COSA m + + # There is no way to detect a Sealevel board. Force it modular + + dep_tristate 'Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m + + tristate 'Frame relay DLCI support' CONFIG_DLCI + if [ "$CONFIG_DLCI" != "n" ]; then + int 'Max open DLCI' CONFIG_DLCI_COUNT 24 + int 'Max DLCI per device' CONFIG_DLCI_MAX 8 + dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI + fi + + # Wan router core. + + if [ "$CONFIG_WAN_ROUTER" != "n" ]; then + bool 'WAN router drivers' CONFIG_WAN_ROUTER_DRIVERS + if [ "$CONFIG_WAN_ROUTER_DRIVERS" = "y" ]; then + dep_tristate ' Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_ROUTER_DRIVERS + if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then + int 'Maximum number of cards' CONFIG_WANPIPE_CARDS 1 + bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25 + bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR + bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP + fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' Cyclom 2X(tm) cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_ROUTER_DRIVERS + if [ "$CONFIG_CYCLADES_SYNC" != "n" ]; then + bool ' Cyclom 2X X.25 support' CONFIG_CYCLOMX_X25 + fi + fi + fi + fi + + # X.25 network drivers + + if [ "$CONFIG_X25" != "n" ]; then + if [ "$CONFIG_LAPB" != "n" ]; then + dep_tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER $CONFIG_LAPB + dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB + fi + fi + + tristate 'SBNI12-xx support' CONFIG_SBNI +fi + +endmenu + diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/Makefile linux/drivers/net/wan/Makefile --- v2.3.20/linux/drivers/net/wan/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/Makefile Mon Oct 11 10:13:25 1999 @@ -0,0 +1,181 @@ +# File: drivers/net/wan/Makefile +# +# Makefile for the Linux network (wan) device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now inherited from the +# parent makefile. +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +L_TARGET := wan.a +L_OBJS := +M_OBJS := + +# Need these to keep track of whether the 82530 or SYNCPPP +# modules should really go in the kernel or a module. +CONFIG_85230_BUILTIN := +CONFIG_85230_MODULE := +CONFIG_SYNCPPP_BUILTIN := +CONFIG_SYNCPPP_MODULE := + +ifeq ($(CONFIG_HOSTESS_SV11),y) +L_OBJS += hostess_sv11.o +CONFIG_85230_BUILTIN = y +CONFIG_SYNCPPP_BUILTIN = y +else + ifeq ($(CONFIG_HOSTESS_SV11),m) + CONFIG_85230_MODULE = y + CONFIG_SYNCPPP_MODULE = y + M_OBJS += hostess_sv11.o + endif +endif + +ifeq ($(CONFIG_SEALEVEL_4021),y) +L_OBJS += sealevel.o +CONFIG_85230_BUILTIN = y +CONFIG_SYNCPPP_BUILTIN = y +else + ifeq ($(CONFIG_SEALEVEL_4021),m) + CONFIG_85230_MODULE = y + CONFIG_SYNCPPP_MODULE = y + M_OBJS += sealevel.o + endif +endif + +ifeq ($(CONFIG_COSA),y) +L_OBJS += cosa.o +CONFIG_SYNCPPP_BUILTIN = y +else + ifeq ($(CONFIG_COSA),m) + CONFIG_SYNCPPP_MODULE = y + M_OBJS += cosa.o + endif +endif + +# If anything built-in uses syncppp, then build it into the kernel also. +# If not, but a module uses it, build as a module. + +ifdef CONFIG_SYNCPPP_BUILTIN +LX_OBJS += syncppp.o +else + ifdef CONFIG_SYNCPPP_MODULE + MX_OBJS += syncppp.o + endif +endif + +# If anything built-in uses Z85230, then build it into the kernel also. +# If not, but a module uses it, build as a module. + +ifdef CONFIG_85230_BUILTIN +LX_OBJS += z85230.o +else + ifdef CONFIG_85230_MODULE + MX_OBJS += z85230.o + endif +endif + +ifeq ($(CONFIG_DLCI),y) +L_OBJS += dlci.o +else + ifeq ($(CONFIG_DLCI),m) + M_OBJS += dlci.o + endif +endif + +ifeq ($(CONFIG_SDLA),y) + L_OBJS += sdla.o +else + ifeq ($(CONFIG_SDLA),m) + M_OBJS += sdla.o +endif + +ifeq ($(CONFIG_VENDOR_SANGOMA),y) + LX_OBJS += sdladrv.o + L_OBJS += sdlamain.o + ifeq ($(CONFIG_WANPIPE_X25),y) + L_OBJS += sdla_x25.o + endif + ifeq ($(CONFIG_WANPIPE_FR),y) + L_OBJS += sdla_fr.o + endif + ifeq ($(CONFIG_WANPIPE_PPP),y) + L_OBJS += sdla_ppp.o + endif +endif + +endif + +ifeq ($(CONFIG_VENDOR_SANGOMA),m) + MX_OBJS += sdladrv.o + M_OBJS += wanpipe.o + WANPIPE_OBJS = sdlamain.o + ifeq ($(CONFIG_WANPIPE_X25),y) + WANPIPE_OBJS += sdla_x25.o + endif + ifeq ($(CONFIG_WANPIPE_FR),y) + WANPIPE_OBJS += sdla_fr.o + endif + ifeq ($(CONFIG_WANPIPE_PPP),y) + WANPIPE_OBJS += sdla_ppp.o + endif +endif + +ifeq ($(CONFIG_CYCLADES_SYNC),y) + LX_OBJS += cycx_drv.o + L_OBJS += cycx_main.o + ifeq ($(CONFIG_CYCLOMX_X25),y) + L_OBJS += cycx_x25.o + endif +endif + +ifeq ($(CONFIG_CYCLADES_SYNC),m) + MX_OBJS += cycx_drv.o + M_OBJS += cyclomx.o + CYCLOMX_OBJS = cycx_main.o + ifeq ($(CONFIG_CYCLOMX_X25),y) + CYCLOMX_OBJS += cycx_x25.o + endif +endif + +ifeq ($(CONFIG_X25_ASY),y) +L_OBJS += x25_asy.o +else + ifeq ($(CONFIG_X25_ASY),m) + M_OBJS += x25_asy.o + endif +endif + +ifeq ($(CONFIG_LAPBETHER),y) +L_OBJS += lapbether.o +else + ifeq ($(CONFIG_LAPBETHER),m) + M_OBJS += lapbether.o + endif +endif + +ifeq ($(CONFIG_SBNI),y) +L_OBJS += sbni.o +else + ifeq ($(CONFIG_SBNI),m) + M_OBJS += sbni.o + endif +endif + +include $(TOPDIR)/Rules.make + +clean: + rm -f core *.o *.a *.s + +wanpipe.o: $(WANPIPE_OBJS) + ld -r -o $@ $(WANPIPE_OBJS) + +cyclomx.o: $(CYCLOMX_OBJS) + ld -r -o $@ $(CYCLOMX_OBJS) + diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/cosa.c linux/drivers/net/wan/cosa.c --- v2.3.20/linux/drivers/net/wan/cosa.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/cosa.c Mon Oct 11 10:13:25 1999 @@ -0,0 +1,2038 @@ +/* $Id: cosa.c,v 1.26 1999/07/09 15:02:37 kas Exp $ */ + +/* + * Copyright (C) 1995-1997 Jan "Yenya" Kasprzak + * + * 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 . 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 . + * + * 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 + * fixed a deadlock in cosa_sppp_open + */ + +/* ---------- Headers, macros, data structures ---------- */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef COSA_SLOW_IO /* for testing purposes only */ +#undef REALLY_SLOW_IO + +#include +#include +#include + +#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, "); +MODULE_DESCRIPTION("Modular driver for the COSA or SRP synchronous card"); +#endif + +/* I use this mainly for testing purposes */ +#ifdef COSA_SLOW_IO +#define cosa_outb outb_p +#define cosa_outw outw_p +#define cosa_inb inb_p +#define cosa_inw inw_p +#else +#define cosa_outb outb +#define cosa_outw outw +#define cosa_inb inb +#define cosa_inw inw +#endif + +#define is_8bit(cosa) (!(cosa->datareg & 0x08)) + +#define cosa_getstatus(cosa) (cosa_inb(cosa->statusreg)) +#define cosa_putstatus(cosa, stat) (cosa_outb(stat, cosa->statusreg)) +#define cosa_getdata16(cosa) (cosa_inw(cosa->datareg)) +#define cosa_getdata8(cosa) (cosa_inb(cosa->datareg)) +#define cosa_putdata16(cosa, dt) (cosa_outw(dt, cosa->datareg)) +#define cosa_putdata8(cosa, dt) (cosa_outb(dt, cosa->datareg)) + +/* Initialization stuff */ +static int cosa_probe(int ioaddr, int irq, int dma); + +/* HW interface */ +static void cosa_enable_rx(struct channel_data *chan); +static void cosa_disable_rx(struct channel_data *chan); +static int cosa_start_tx(struct channel_data *channel, char *buf, int size); +static void cosa_kick(struct cosa_data *cosa); +static int cosa_dma_able(struct channel_data *chan, char *buf, int data); + +/* SPPP/HDLC stuff */ +static void sppp_channel_init(struct channel_data *chan); +static void sppp_channel_delete(struct channel_data *chan); +static int cosa_sppp_open(struct net_device *d); +static int cosa_sppp_close(struct net_device *d); +static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *d); +static char *sppp_setup_rx(struct channel_data *channel, int size); +static int sppp_rx_done(struct channel_data *channel); +static int sppp_tx_done(struct channel_data *channel, int size); +static int cosa_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); +static struct net_device_stats *cosa_net_stats(struct net_device *dev); + +/* Character device */ +static void chardev_channel_init(struct channel_data *chan); +static char *chrdev_setup_rx(struct channel_data *channel, int size); +static int chrdev_rx_done(struct channel_data *channel); +static int chrdev_tx_done(struct channel_data *channel, int size); +static long long cosa_lseek(struct file *file, + long long offset, int origin); +static ssize_t cosa_read(struct file *file, + char *buf, size_t count, loff_t *ppos); +static ssize_t cosa_write(struct file *file, + const char *buf, size_t count, loff_t *ppos); +static unsigned int cosa_poll(struct file *file, poll_table *poll); +static int cosa_open(struct inode *inode, struct file *file); +static int cosa_release(struct inode *inode, struct file *file); +static int cosa_chardev_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +#ifdef COSA_FASYNC_WORKING +static int cosa_fasync(struct inode *inode, struct file *file, int on); +#endif + +static struct file_operations cosa_fops = { + cosa_lseek, + cosa_read, + cosa_write, + NULL, /* readdir */ + cosa_poll, + cosa_chardev_ioctl, + NULL, /* mmap */ + cosa_open, + NULL, /* flush */ + cosa_release, + NULL, /* fsync */ +#ifdef COSA_FASYNC_WORKING + cosa_fasync, +#else + NULL, +#endif + NULL, /* check media change */ + NULL, /* revalidate */ + NULL /* lock */ +}; + +/* Ioctls */ +static int cosa_start(struct cosa_data *cosa, int address); +static int cosa_reset(struct cosa_data *cosa); +static int cosa_download(struct cosa_data *cosa, struct cosa_download *d); +static int cosa_readmem(struct cosa_data *cosa, struct cosa_download *d); + +/* COSA/SRP ROM monitor */ +static int download(struct cosa_data *cosa, char *data, int addr, int len); +static int startmicrocode(struct cosa_data *cosa, int address); +static int readmem(struct cosa_data *cosa, char *data, int addr, int len); +static int cosa_reset_and_read_id(struct cosa_data *cosa, char *id); + +/* Auxilliary functions */ +static int get_wait_data(struct cosa_data *cosa); +static int put_wait_data(struct cosa_data *cosa, int data); +static int puthexnumber(struct cosa_data *cosa, int number); +static void put_driver_status(struct cosa_data *cosa); +static void put_driver_status_nolock(struct cosa_data *cosa); + +/* Interrupt handling */ +static void cosa_interrupt(int irq, void *cosa, struct pt_regs *regs); + +/* I/O ops debugging */ +#ifdef DEBUG_IO +static void debug_data_in(struct cosa_data *cosa, int data); +static void debug_data_out(struct cosa_data *cosa, int data); +static void debug_data_cmd(struct cosa_data *cosa, int data); +static void debug_status_in(struct cosa_data *cosa, int status); +static void debug_status_out(struct cosa_data *cosa, int status); +#endif + + +/* ---------- Initialization stuff ---------- */ + +#ifdef MODULE +int init_module(void) +#else +static int __init cosa_init(void) +#endif +{ + int i; + printk(KERN_INFO "cosa v1.06 (c) 1997-8 Jan Kasprzak \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; inchannels; 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; inchannels; i++) { + cosa->chan[i].cosa = cosa; + cosa->chan[i].num = i; + channel_init(cosa->chan+i); + } + + printk (KERN_INFO "cosa%d: %s (%s at 0x%x irq %d dma %d), %d channels\n", + cosa->num, cosa->id_string, cosa->type, + cosa->datareg, cosa->irq, cosa->dma, cosa->nchannels); + + return nr_cards++; +} + + +/*---------- SPPP/HDLC netdevice ---------- */ + +static void sppp_channel_init(struct channel_data *chan) +{ + struct net_device *d; + sppp_attach(&chan->pppdev); + d=&chan->pppdev.dev; + d->name = chan->name; + d->base_addr = chan->cosa->datareg; + d->irq = chan->cosa->irq; + d->dma = chan->cosa->dma; + d->priv = chan; + d->init = NULL; + d->open = cosa_sppp_open; + d->stop = cosa_sppp_close; + d->hard_start_xmit = cosa_sppp_tx; + d->do_ioctl = cosa_sppp_ioctl; + d->get_stats = cosa_net_stats; + dev_init_buffers(d); + if (register_netdev(d) == -1) { + printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); + sppp_detach(&chan->pppdev.dev); + return; + } +} + +static void sppp_channel_delete(struct channel_data *chan) +{ + sppp_detach(&chan->pppdev.dev); + unregister_netdev(&chan->pppdev.dev); +} + + +static int cosa_sppp_open(struct net_device *d) +{ + struct channel_data *chan = d->priv; + int err, flags; + + spin_lock_irqsave(&chan->cosa->lock, flags); + if (chan->usage != 0) { + printk(KERN_WARNING "%s: sppp_open called with usage count %d\n", + chan->name, chan->usage); + spin_unlock_irqrestore(&chan->cosa->lock, flags); + return -EBUSY; + } + chan->setup_rx = sppp_setup_rx; + chan->tx_done = sppp_tx_done; + chan->rx_done = sppp_rx_done; + chan->usage=-1; + chan->cosa->usage++; + MOD_INC_USE_COUNT; + spin_unlock_irqrestore(&chan->cosa->lock, flags); + + err = sppp_open(d); + if (err) { + spin_lock_irqsave(&chan->cosa->lock, flags); + chan->usage=0; + chan->cosa->usage--; + MOD_DEC_USE_COUNT; + + spin_unlock_irqrestore(&chan->cosa->lock, flags); + return err; + } + + d->tbusy = 0; + cosa_enable_rx(chan); + return 0; +} + +static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct channel_data *chan = dev->priv; + + if (dev->tbusy) { + if (time_before(jiffies, dev->trans_start+2*HZ)) + return 1; /* Two seconds timeout */ + if (test_bit(RXBIT, &chan->cosa->rxtx)) { + chan->stats.rx_errors++; + chan->stats.rx_missed_errors++; + } else { + chan->stats.tx_errors++; + chan->stats.tx_aborted_errors++; + } + cosa_kick(chan->cosa); + if (chan->tx_skb) { + dev_kfree_skb(chan->tx_skb); + chan->tx_skb = 0; + } + dev->tbusy = 0; + } + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { + printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); + return 1; + } + + chan->tx_skb = skb; + dev->trans_start = jiffies; + cosa_start_tx(chan, skb->data, skb->len); + return 0; +} + +static int cosa_sppp_close(struct net_device *d) +{ + struct channel_data *chan = d->priv; + int flags; + + sppp_close(d); + d->tbusy = 1; + cosa_disable_rx(chan); + spin_lock_irqsave(&chan->cosa->lock, flags); + if (chan->rx_skb) { + kfree_skb(chan->rx_skb); + chan->rx_skb = 0; + } + if (chan->tx_skb) { + kfree_skb(chan->tx_skb); + chan->tx_skb = 0; + } + chan->usage=0; + chan->cosa->usage--; + MOD_DEC_USE_COUNT; + spin_unlock_irqrestore(&chan->cosa->lock, flags); + return 0; +} + +static char *sppp_setup_rx(struct channel_data *chan, int size) +{ + /* + * We can safely fall back to non-dma-able memory, because we have + * the cosa->bouncebuf pre-allocated. + */ + if (chan->rx_skb) + kfree_skb(chan->rx_skb); + chan->rx_skb = dev_alloc_skb(size); + if (chan->rx_skb == NULL) { + printk(KERN_NOTICE "%s: Memory squeeze, dropping packet\n", + chan->name); + chan->stats.rx_dropped++; + return NULL; + } + chan->pppdev.dev.trans_start = jiffies; + return skb_put(chan->rx_skb, size); +} + +static int sppp_rx_done(struct channel_data *chan) +{ + if (!chan->rx_skb) { + printk(KERN_WARNING "%s: rx_done with empty skb!\n", + chan->name); + chan->stats.rx_errors++; + chan->stats.rx_frame_errors++; + return 0; + } + chan->rx_skb->protocol = htons(ETH_P_WAN_PPP); + chan->rx_skb->dev = &chan->pppdev.dev; + chan->rx_skb->mac.raw = chan->rx_skb->data; + chan->stats.rx_packets++; + chan->stats.rx_bytes += chan->cosa->rxsize; + netif_rx(chan->rx_skb); + chan->rx_skb = 0; + chan->pppdev.dev.trans_start = jiffies; + return 0; +} + +/* ARGSUSED */ +static int sppp_tx_done(struct channel_data *chan, int size) +{ + if (!chan->tx_skb) { + printk(KERN_WARNING "%s: tx_done with empty skb!\n", + chan->name); + chan->stats.tx_errors++; + chan->stats.tx_aborted_errors++; + return 1; + } + dev_kfree_skb(chan->tx_skb); + chan->tx_skb = 0; + chan->stats.tx_packets++; + chan->stats.tx_bytes += size; + chan->pppdev.dev.tbusy = 0; + mark_bh(NET_BH); + return 1; +} + +static struct net_device_stats *cosa_net_stats(struct net_device *dev) +{ + struct channel_data *chan = dev->priv; + return &chan->stats; +} + + +/*---------- Character device ---------- */ + +static void chardev_channel_init(struct channel_data *chan) +{ + init_MUTEX(&chan->rsem); + init_MUTEX(&chan->wsem); +} + +static long long cosa_lseek(struct file * file, + long long offset, int origin) +{ + return -ESPIPE; +} + +static ssize_t cosa_read(struct file *file, + char *buf, size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + int flags; + struct channel_data *chan = (struct channel_data *)file->private_data; + struct cosa_data *cosa = chan->cosa; + char *kbuf; + + if (down_interruptible(&chan->rsem)) + return -ERESTARTSYS; + + if ((chan->rxdata = kmalloc(COSA_MTU, GFP_DMA|GFP_KERNEL)) == NULL) { + printk(KERN_INFO "%s: cosa_read() - OOM\n", cosa->name); + up(&chan->rsem); + return -ENOMEM; + } + + chan->rx_status = 0; + cosa_enable_rx(chan); + spin_lock_irqsave(&cosa->lock, flags); + add_wait_queue(&chan->rxwaitq, &wait); + while(!chan->rx_status) { + current->state = TASK_INTERRUPTIBLE; + spin_unlock_irqrestore(&cosa->lock, flags); + schedule(); + spin_lock_irqsave(&cosa->lock, flags); + if (signal_pending(current) && chan->rx_status == 0) { + chan->rx_status = 1; + remove_wait_queue(&chan->rxwaitq, &wait); + current->state = TASK_RUNNING; + spin_unlock_irqrestore(&cosa->lock, flags); + up(&chan->rsem); + return -ERESTARTSYS; + } + } + remove_wait_queue(&chan->rxwaitq, &wait); + current->state = TASK_RUNNING; + kbuf = chan->rxdata; + count = chan->rxsize; + spin_unlock_irqrestore(&cosa->lock, flags); + up(&chan->rsem); + + if (copy_to_user(buf, kbuf, count)) { + kfree(buf); + return -EFAULT; + } + kfree(kbuf); + return count; +} + +static char *chrdev_setup_rx(struct channel_data *chan, int size) +{ + /* Expect size <= COSA_MTU */ + chan->rxsize = size; + return chan->rxdata; +} + +static int chrdev_rx_done(struct channel_data *chan) +{ + if (chan->rx_status) { /* Reader has died */ + kfree(chan->rxdata); + up(&chan->wsem); + } + chan->rx_status = 1; + wake_up_interruptible(&chan->rxwaitq); + return 1; +} + + +static ssize_t cosa_write(struct file *file, + const char *buf, size_t count, loff_t *ppos) +{ + struct channel_data *chan = (struct channel_data *)file->private_data; + DECLARE_WAITQUEUE(wait, current); + struct cosa_data *cosa = chan->cosa; + unsigned int flags; + char *kbuf; + + if (down_interruptible(&chan->wsem)) + return -ERESTARTSYS; + + if (count > COSA_MTU) + count = COSA_MTU; + + /* Allocate the buffer */ + if ((kbuf = kmalloc(count, GFP_KERNEL|GFP_DMA)) == NULL) { + printk(KERN_NOTICE "%s: cosa_write() OOM - dropping packet\n", + cosa->name); + up(&chan->wsem); + return -ENOMEM; + } + if (copy_from_user(kbuf, buf, count)) { + up(&chan->wsem); + kfree(kbuf); + return -EFAULT; + } + chan->tx_status=0; + cosa_start_tx(chan, kbuf, count); + + spin_lock_irqsave(&cosa->lock, flags); + add_wait_queue(&chan->txwaitq, &wait); + while(!chan->tx_status) { + current->state = TASK_INTERRUPTIBLE; + spin_unlock_irqrestore(&cosa->lock, flags); + schedule(); + spin_lock_irqsave(&cosa->lock, flags); + if (signal_pending(current) && chan->tx_status == 0) { + chan->tx_status = 1; + remove_wait_queue(&chan->txwaitq, &wait); + current->state = TASK_RUNNING; + chan->tx_status = 1; + spin_unlock_irqrestore(&cosa->lock, flags); + return -ERESTARTSYS; + } + } + remove_wait_queue(&chan->txwaitq, &wait); + current->state = TASK_RUNNING; + up(&chan->wsem); + spin_unlock_irqrestore(&cosa->lock, flags); + kfree(kbuf); + return count; +} + +static int chrdev_tx_done(struct channel_data *chan, int size) +{ + if (chan->tx_status) { /* Writer was interrupted */ + kfree(chan->txbuf); + up(&chan->wsem); + } + chan->tx_status = 1; + wake_up_interruptible(&chan->txwaitq); + return 1; +} + +static unsigned int cosa_poll(struct file *file, poll_table *poll) +{ + printk(KERN_INFO "cosa_poll is here\n"); + return 0; +} + +static int cosa_open(struct inode *inode, struct file *file) +{ + struct cosa_data *cosa; + struct channel_data *chan; + unsigned long flags; + int n; + + if ((n=MINOR(file->f_dentry->d_inode->i_rdev)>>CARD_MINOR_BITS) + >= nr_cards) + return -ENODEV; + cosa = cosa_cards+n; + + if ((n=MINOR(file->f_dentry->d_inode->i_rdev) + & ((1<= cosa->nchannels) + return -ENODEV; + chan = cosa->chan + n; + + file->private_data = chan; + + spin_lock_irqsave(&cosa->lock, flags); + + if (chan->usage < 0) { /* in netdev mode */ + spin_unlock_irqrestore(&cosa->lock, flags); + return -EBUSY; + } + cosa->usage++; + chan->usage++; + + chan->tx_done = chrdev_tx_done; + chan->setup_rx = chrdev_setup_rx; + chan->rx_done = chrdev_rx_done; +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + spin_unlock_irqrestore(&cosa->lock, flags); + return 0; +} + +static int cosa_release(struct inode *inode, struct file *file) +{ + struct channel_data *channel = (struct channel_data *)file->private_data; + struct cosa_data *cosa = channel->cosa; + unsigned long flags; + + spin_lock_irqsave(&cosa->lock, flags); + cosa->usage--; + channel->usage--; +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + spin_unlock_irqrestore(&cosa->lock, flags); + return 0; +} + +#ifdef COSA_FASYNC_WORKING +static struct fasync_struct *fasync[256] = { NULL, }; + +/* To be done ... */ +static int cosa_fasync(struct inode *inode, struct file *file, int on) +{ + int port = MINOR(inode->i_rdev); + int rv = fasync_helper(inode, file, on, &fasync[port]); + return rv < 0 ? rv : 0; +} +#endif + + +/* ---------- Ioctls ---------- */ + +/* + * Ioctl subroutines can safely be made inline, because they are called + * only from cosa_ioctl(). + */ +static inline int cosa_reset(struct cosa_data *cosa) +{ + char idstring[COSA_MAX_ID_STRING]; + if (cosa->usage > 1) + printk(KERN_INFO "cosa%d: WARNING: reset requested with cosa->usage > 1 (%d). Odd things may happen.\n", + cosa->num, cosa->usage); + if (cosa_reset_and_read_id(cosa, idstring) < 0) { + printk(KERN_NOTICE "cosa%d: reset failed\n", cosa->num); + return -EIO; + } + printk(KERN_INFO "cosa%d: resetting device: %s\n", cosa->num, + idstring); + return 0; +} + +/* High-level function to download data into COSA memory. Calls download() */ +static inline int cosa_download(struct cosa_data *cosa, struct cosa_download *d) +{ + int i; + int addr, len; + char *code; + + if (cosa->usage > 1) + printk(KERN_INFO "cosa%d: WARNING: download of microcode requested with cosa->usage > 1 (%d). Odd things may happen.\n", + cosa->num, cosa->usage); +#if 0 + if (cosa->status != CARD_STATUS_RESETED && cosa->status != CARD_STATUS_DOWNLOADED) { + printk(KERN_NOTICE "cosa%d: reset the card first (status %d).\n", + cosa->num, cosa->status); + return -EPERM; + } +#endif + get_user_ret(addr, &(d->addr), -EFAULT); + get_user_ret(len, &(d->len), -EFAULT); + get_user_ret(code, &(d->code), -EFAULT); + + if (d->addr < 0 || d->addr > COSA_MAX_FIRMWARE_SIZE) + return -EINVAL; + if (d->len < 0 || d->len > COSA_MAX_FIRMWARE_SIZE) + return -EINVAL; + + if ((i=download(cosa, d->code, len, addr)) < 0) { + printk(KERN_NOTICE "cosa%d: microcode download failed: %d\n", + cosa->num, i); + return -EIO; + } + printk(KERN_INFO "cosa%d: downloading microcode - 0x%04x bytes at 0x%04x\n", + cosa->num, len, addr); + return 0; +} + +/* High-level function to read COSA memory. Calls readmem() */ +static inline int cosa_readmem(struct cosa_data *cosa, struct cosa_download *d) +{ + int i; + int addr, len; + char *code; + + if (cosa->usage > 1) + printk(KERN_INFO "cosa%d: WARNING: readmem requested with " + "cosa->usage > 1 (%d). Odd things may happen.\n", + cosa->num, cosa->usage); +#if 0 + if (cosa->status != CARD_STATUS_RESETED && + cosa->status != CARD_STATUS_DOWNLOADED) { + printk(KERN_NOTICE "cosa%d: reset the card first (status %d).\n", + cosa->num, cosa->status); + return -EPERM; + } +#endif + get_user_ret(addr, &(d->addr), -EFAULT); + get_user_ret(len, &(d->len), -EFAULT); + get_user_ret(code, &(d->code), -EFAULT); + + if ((i=readmem(cosa, d->code, len, addr)) < 0) { + printk(KERN_NOTICE "cosa%d: reading memory failed: %d\n", + cosa->num, i); + return -EIO; + } + printk(KERN_INFO "cosa%d: reading card memory - 0x%04x bytes at 0x%04x\n", + cosa->num, len, addr); + return 0; +} + +/* High-level function to start microcode. Calls startmicrocode(). */ +static inline int cosa_start(struct cosa_data *cosa, int address) +{ + int i; + + if (cosa->usage > 1) + printk(KERN_INFO "cosa%d: WARNING: start microcode requested with cosa->usage > 1 (%d). Odd things may happen.\n", + cosa->num, cosa->usage); +#if 0 + if (cosa->status != CARD_STATUS_DOWNLOADED) { + printk(KERN_NOTICE "cosa%d: download the microcode first (status %d).\n", + cosa->num, cosa->status); + return -EPERM; + } +#endif + if ((i=startmicrocode(cosa, address)) < 0) { + printk(KERN_NOTICE "cosa%d: start microcode at 0x%04x failed: %d\n", + cosa->num, address, i); + return -EIO; + } + printk(KERN_INFO "cosa%d: starting microcode at 0x%04x\n", + cosa->num, address); + cosa->startaddr = address; + return 0; +} + +/* Buffer of size at least COSA_MAX_ID_STRING is expected */ +static inline int cosa_getidstr(struct cosa_data *cosa, char *string) +{ + int l = strlen(cosa->id_string)+1; + copy_to_user_ret(string, cosa->id_string, l, -EFAULT); + return l; +} + +/* Buffer of size at least COSA_MAX_ID_STRING is expected */ +static inline int cosa_gettype(struct cosa_data *cosa, char *string) +{ + int l = strlen(cosa->type)+1; + copy_to_user_ret(string, cosa->type, l, -EFAULT); + return l; +} + +static int cosa_ioctl_common(struct cosa_data *cosa, + struct channel_data *channel, unsigned int cmd, unsigned long arg) +{ + switch(cmd) { + case COSAIORSET: /* Reset the device */ + if (!suser()) + return -EACCES; + return cosa_reset(cosa); + case COSAIOSTRT: /* Start the firmware */ + if (!suser()) + return -EACCES; + return cosa_start(cosa, arg); + case COSAIODOWNLD: /* Download the firmware */ + if (!suser()) + return -EACCES; + return cosa_download(cosa, (struct cosa_download *)arg); + case COSAIORMEM: + if (!suser()) + return -EACCES; + return cosa_readmem(cosa, (struct cosa_download *)arg); + case COSAIORTYPE: + return cosa_gettype(cosa, (char *)arg); + case COSAIORIDSTR: + return cosa_getidstr(cosa, (char *)arg); +/* + * These two are _very_ugly_hack_(tm). Don't even look at this. + * Implementing this saved me few reboots after some process segfaulted + * inside this module. + */ +#ifdef MODULE +#if 0 + case COSAIOMINC: + MOD_INC_USE_COUNT; + return 0; + case COSAIOMDEC: + MOD_DEC_USE_COUNT; + return 0; +#endif +#endif + case COSAIONRCARDS: + return nr_cards; + case COSAIONRCHANS: + return cosa->nchannels; + case COSAIOBMSET: + if (!suser()) + return -EACCES; + if (is_8bit(cosa)) + return -EINVAL; + if (arg != COSA_BM_OFF && arg != COSA_BM_ON) + return -EINVAL; + cosa->busmaster = arg; + return 0; + case COSAIOBMGET: + return cosa->busmaster; + } + return -ENOIOCTLCMD; +} + +static int cosa_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, + int cmd) +{ + int rv; + struct channel_data *chan = (struct channel_data *)dev->priv; + rv = cosa_ioctl_common(chan->cosa, chan, cmd, (int)ifr->ifr_data); + if (rv == -ENOIOCTLCMD) { + return sppp_do_ioctl(dev, ifr, cmd); + } + return rv; +} + +static int cosa_chardev_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct channel_data *channel = (struct channel_data *)file->private_data; + struct cosa_data *cosa = channel->cosa; + return cosa_ioctl_common(cosa, channel, cmd, arg); +} + + +/*---------- HW layer interface ---------- */ + +/* + * The higher layer can bind itself to the HW layer by setting the callbacks + * in the channel_data structure and by using these routines. + */ +static void cosa_enable_rx(struct channel_data *chan) +{ + struct cosa_data *cosa = chan->cosa; + + if (!test_and_set_bit(chan->num, &cosa->rxbitmap)) + put_driver_status(cosa); +} + +static void cosa_disable_rx(struct channel_data *chan) +{ + struct cosa_data *cosa = chan->cosa; + + if (test_and_clear_bit(chan->num, &cosa->rxbitmap)) + put_driver_status(cosa); +} + +/* + * FIXME: This routine probably should check for cosa_start_tx() called when + * the previous transmit is still unfinished. In this case the non-zero + * return value should indicate to the caller that the queuing(sp?) up + * the transmit has failed. + */ +static int cosa_start_tx(struct channel_data *chan, char *buf, int len) +{ + struct cosa_data *cosa = chan->cosa; + int flags; +#ifdef DEBUG_DATA + int i; + + printk(KERN_INFO "cosa%dc%d: starting tx(0x%x)", chan->cosa->num, + chan->num, len); + for (i=0; ilock, 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<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<rxbitmap|cosa->txbitmap) { + cosa_putstatus(cosa, SR_RX_INT_ENA); +#ifdef DEBUG_IO + debug_status_out(cosa, SR_RX_INT_ENA); +#endif + cosa->enabled = 1; + } else { + cosa_putstatus(cosa, 0); +#ifdef DEBUG_IO + debug_status_out(cosa, 0); +#endif + cosa->enabled = 0; + } + cosa_putdata8(cosa, status); +#ifdef DEBUG_IO + debug_data_cmd(cosa, status); +#endif +} + +/* + * The "kickme" function: When the DMA times out, this is called to + * clean up the driver status. + * FIXME: Preliminary support, the interface is probably wrong. + */ +static void cosa_kick(struct cosa_data *cosa) +{ + unsigned flags, flags1; + char *s = "Unknown"; + + if (test_bit(RXBIT, &cosa->rxtx)) + s = "RX"; + if (test_bit(TXBIT, &cosa->rxtx)) + s = "TX"; + + printk(KERN_INFO "%s: %s DMA timeout - restarting.\n", cosa->name, s); + spin_lock_irqsave(&cosa->lock, flags); + cosa->rxtx = 0; + + flags1 = claim_dma_lock(); + disable_dma(cosa->dma); + clear_dma_ff(cosa->dma); + release_dma_lock(flags1); + + /* FIXME: Anything else? */ + udelay(100); + cosa_putstatus(cosa, 0); + udelay(100); + (void) cosa_getdata8(cosa); + udelay(100); + cosa_putdata8(cosa, 0); + udelay(100); + put_driver_status_nolock(cosa); + spin_unlock_irqrestore(&cosa->lock, flags); +} + +/* + * Check if the whole buffer is DMA-able. It means it is below the 16M of + * physical memory and doesn't span the 64k boundary. For now it seems + * SKB's never do this, but we'll check this anyway. + */ +static int cosa_dma_able(struct channel_data *chan, char *buf, int len) +{ + static int count = 0; + unsigned long b = (unsigned long)buf; + if (b+len >= MAX_DMA_ADDRESS) + return 0; + if ((b^ (b+len)) & 0x10000) { + if (count++ < 5) + printk(KERN_INFO "%s: packet spanning a 64k boundary\n", + chan->name); + return 0; + } + return 1; +} + + +/* ---------- The SRP/COSA ROM monitor functions ---------- */ + +/* + * Downloading SRP microcode: say "w" to SRP monitor, it answers by "w=", + * drivers need to say 4-digit hex number meaning start address of the microcode + * separated by a single space. Monitor replies by saying " =". Now driver + * has to write 4-digit hex number meaning the last byte address ended + * by a single space. Monitor has to reply with a space. Now the download + * begins. After the download monitor replies with "\r\n." (CR LF dot). + */ +static int download(struct cosa_data *cosa, char *microcode, int length, int address) +{ + int i; + + if (put_wait_data(cosa, 'w') == -1) return -1; + if ((i=get_wait_data(cosa)) != 'w') { printk("dnld: 0x%04x\n",i); return -2;} + if (get_wait_data(cosa) != '=') return -3; + + if (puthexnumber(cosa, address) < 0) return -4; + if (put_wait_data(cosa, ' ') == -1) return -10; + if (get_wait_data(cosa) != ' ') return -11; + if (get_wait_data(cosa) != '=') return -12; + + if (puthexnumber(cosa, address+length-1) < 0) return -13; + if (put_wait_data(cosa, ' ') == -1) return -18; + if (get_wait_data(cosa) != ' ') return -19; + + while (length--) { + char c; +#ifndef SRP_DOWNLOAD_AT_BOOT + get_user_ret(c,microcode, -23); +#else + c = *microcode; +#endif + if (put_wait_data(cosa, c) == -1) + return -20; + microcode++; + } + + if (get_wait_data(cosa) != '\r') return -21; + if (get_wait_data(cosa) != '\n') return -22; + if (get_wait_data(cosa) != '.') return -23; +#if 0 + printk(KERN_DEBUG "cosa%d: download completed.\n", cosa->num); +#endif + return 0; +} + + +/* + * Starting microcode is done via the "g" command of the SRP monitor. + * The chat should be the following: "g" "g=" "" + * "". + */ +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=" " " " =" " " " " + * Then driver can read the data and the conversation is finished + * by SRP monitor sending "." (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; istate = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + printk(KERN_INFO "cosa: timeout in get_wait_data (status 0x%x)\n", + cosa_getstatus(cosa)); + return -1; +} + +/* + * This routine puts the data byte to the card waiting for the SR_TX_RDY + * bit to be set in a loop. It should be used in the exceptional cases + * only (for example when resetting the card or downloading the firmware). + */ +static int put_wait_data(struct cosa_data *cosa, int data) +{ + int retries = 1000; + while (--retries) { + /* read data and return them */ + if (cosa_getstatus(cosa) & SR_TX_RDY) { + cosa_putdata8(cosa, data); +#if 0 + printk(KERN_INFO "Putdata: %d retries\n", 999-retries); +#endif + return 0; + } +#if 0 + /* sleep if not ready to read */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); +#endif + } + printk(KERN_INFO "cosa%d: timeout in put_wait_data (status 0x%x)\n", + cosa->num, cosa_getstatus(cosa)); + return -1; +} + +/* + * The following routine puts the hexadecimal number into the SRP monitor + * and verifies the proper echo of the sent bytes. Returns 0 on success, + * negative number on failure (-1,-3,-5,-7) means that put_wait_data() failed, + * (-2,-4,-6,-8) means that reading echo failed. + */ +static int puthexnumber(struct cosa_data *cosa, int number) +{ + char temp[5]; + int i; + + /* Well, I should probably replace this by something faster. */ + sprintf(temp, "%04X", number); + for (i=0; i<4; i++) { + if (put_wait_data(cosa, temp[i]) == -1) { + printk(KERN_NOTICE "cosa%d: puthexnumber failed to write byte %d\n", + cosa->num, i); + return -1-2*i; + } + if (get_wait_data(cosa) != temp[i]) { + printk(KERN_NOTICE "cosa%d: puthexhumber failed to read echo of byte %d\n", + cosa->num, i); + return -2-2*i; + } + } + return 0; +} + + +/* ---------- Interrupt routines ---------- */ + +/* + * There are three types of interrupt: + * At the beginning of transmit - this handled is in tx_interrupt(), + * at the beginning of receive - it is in rx_interrupt() and + * at the end of transmit/receive - it is the eot_interrupt() function. + * These functions are multiplexed by cosa_interrupt() according to the + * COSA status byte. I have moved the rx/tx/eot interrupt handling into + * separate functions to make it more readable. These functions are inline, + * so there should be no overhead of function call. + * + * In the COSA bus-master mode, we need to tell the card the address of a + * buffer. Unfortunately, COSA may be too slow for us, so we must busy-wait. + * It's time to use the bottom half :-( + */ + +/* + * Transmit interrupt routine - called when COSA is willing to obtain + * data from the OS. The most tricky part of the routine is selection + * of channel we (OS) want to send packet for. For SRP we should probably + * use the round-robin approach. The newer COSA firmwares have a simple + * flow-control - in the status word has bits 2 and 3 set to 1 means that the + * channel 0 or 1 doesn't want to receive data. + * + * It seems there is a bug in COSA firmware (need to trace it further): + * When the driver status says that the kernel has no more data for transmit + * (e.g. at the end of TX DMA) and then the kernel changes its mind + * (e.g. new packet is queued to hard_start_xmit()), the card issues + * the TX interrupt but does not mark the channel as ready-to-transmit. + * The fix seems to be to push the packet to COSA despite its request. + * We first try to obey the card's opinion, and then fall back to forced TX. + */ +static inline void tx_interrupt(struct cosa_data *cosa, int status) +{ + unsigned long flags, flags1; +#ifdef DEBUG_IRQS + printk(KERN_INFO "cosa%d: SR_DOWN_REQUEST status=0x%04x\n", + cosa->num, status); +#endif + spin_lock_irqsave(&cosa->lock, flags); + set_bit(TXBIT, &cosa->rxtx); + if (!test_bit(IRQBIT, &cosa->rxtx)) { + /* flow control, see the comment above */ + int i=0; + if (!cosa->txbitmap) { + printk(KERN_WARNING "%s: No channel wants data " + "in TX IRQ. Expect DMA timeout.", + cosa->name); + put_driver_status_nolock(cosa); + clear_bit(TXBIT, &cosa->rxtx); + spin_unlock_irqrestore(&cosa->lock, flags); + return; + } + while(1) { + cosa->txchan++; + i++; + if (cosa->txchan >= cosa->nchannels) + cosa->txchan = 0; + if (!(cosa->txbitmap & (1<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; irxsize; i++) + printk (" %02x", cosa->rxbuf[i]&0xff); + printk("\n"); + } +#endif + /* Packet for unknown channel? */ + if (cosa->rxbuf == cosa->bouncebuf) + goto out; + if (!cosa_dma_able(cosa->rxchan, cosa->rxbuf, cosa->rxsize)) + memcpy(cosa->rxbuf, cosa->bouncebuf, cosa->rxsize); + if (cosa->rxchan->rx_done) + if (cosa->rxchan->rx_done(cosa->rxchan)) + clear_bit(cosa->rxchan->num, &cosa->rxbitmap); + } else { + printk(KERN_NOTICE "cosa%d: unexpected EOT interrupt\n", + cosa->num); + } + /* + * Clear the RXBIT, TXBIT and IRQBIT (the latest should be + * cleared anyway). We should do it as soon as possible + * so that we can tell the COSA we are done and to give it a time + * for recovery. + */ +out: + cosa->rxtx = 0; + put_driver_status_nolock(cosa); + spin_unlock_irqrestore(&cosa->lock, flags); +} + +static void cosa_interrupt(int irq, void *cosa_, struct pt_regs *regs) +{ + unsigned status; + int count = 0; + struct cosa_data *cosa = cosa_; +again: + status = cosa_getstatus(cosa); +#ifdef DEBUG_IRQS + printk(KERN_INFO "cosa%d: got IRQ, status 0x%02x\n", cosa->num, + status & 0xff); +#endif +#ifdef DEBUG_IO + debug_status_in(cosa, status); +#endif + switch (status & SR_CMD_FROM_SRP_MASK) { + case SR_DOWN_REQUEST: + tx_interrupt(cosa, status); + break; + case SR_UP_REQUEST: + rx_interrupt(cosa, status); + break; + case SR_END_OF_TRANSFER: + eot_interrupt(cosa, status); + break; + default: + /* We may be too fast for SRP. Try to wait a bit more. */ + if (count++ < 100) { + udelay(100); + goto again; + } + printk(KERN_INFO "cosa%d: unknown status 0x%02x in IRQ after %d retries\n", + cosa->num, status & 0xff, count); + } +#ifdef DEBUG_IRQS + if (count) + printk(KERN_INFO "%s: %d-times got unknown status in IRQ\n", + cosa->name, count); + else + printk(KERN_INFO "%s: returning from IRQ\n", cosa->name); +#endif +} + + +/* ---------- I/O debugging routines ---------- */ +/* + * These routines can be used to monitor COSA/SRP I/O and to printk() + * the data being transfered on the data and status I/O port in a + * readable way. + */ + +#ifdef DEBUG_IO +static void debug_status_in(struct cosa_data *cosa, int status) +{ + char *s; + switch(status & SR_CMD_FROM_SRP_MASK) { + case SR_UP_REQUEST: + s = "RX_REQ"; + break; + case SR_DOWN_REQUEST: + s = "TX_REQ"; + break; + case SR_END_OF_TRANSFER: + s = "ET_REQ"; + break; + default: + s = "NO_REQ"; + break; + } + printk(KERN_INFO "%s: IO: status -> 0x%02x (%s%s%s%s)\n", + cosa->name, + status, + status & SR_USR_RQ ? "USR_RQ|":"", + status & SR_TX_RDY ? "TX_RDY|":"", + status & SR_RX_RDY ? "RX_RDY|":"", + s); +} + +static void debug_status_out(struct cosa_data *cosa, int status) +{ + printk(KERN_INFO "%s: IO: status <- 0x%02x (%s%s%s%s%s%s)\n", + cosa->name, + status, + status & SR_RX_DMA_ENA ? "RXDMA|":"!rxdma|", + status & SR_TX_DMA_ENA ? "TXDMA|":"!txdma|", + status & SR_RST ? "RESET|":"", + status & SR_USR_INT_ENA ? "USRINT|":"!usrint|", + status & SR_TX_INT_ENA ? "TXINT|":"!txint|", + status & SR_RX_INT_ENA ? "RXINT":"!rxint"); +} + +static void debug_data_in(struct cosa_data *cosa, int data) +{ + printk(KERN_INFO "%s: IO: data -> 0x%04x\n", cosa->name, data); +} + +static void debug_data_out(struct cosa_data *cosa, int data) +{ + printk(KERN_INFO "%s: IO: data <- 0x%04x\n", cosa->name, data); +} + +static void debug_data_cmd(struct cosa_data *cosa, int data) +{ + printk(KERN_INFO "%s: IO: data <- 0x%04x (%s|%s)\n", + cosa->name, data, + data & SR_RDY_RCV ? "RX_RDY" : "!rx_rdy", + data & SR_RDY_SND ? "TX_RDY" : "!tx_rdy"); +} +#endif + +/* EOF -- this file has not been truncated */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/cosa.h linux/drivers/net/wan/cosa.h --- v2.3.20/linux/drivers/net/wan/cosa.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/cosa.h Mon Oct 11 10:13:25 1999 @@ -0,0 +1,111 @@ +/* $Id: cosa.h,v 1.6 1999/01/06 14:02:44 kas Exp $ */ + +/* + * Copyright (C) 1995-1997 Jan "Yenya" Kasprzak + * + * 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 + +#ifdef __KERNEL__ +/* status register - output bits */ +#define SR_RX_DMA_ENA 0x04 /* receiver DMA enable bit */ +#define SR_TX_DMA_ENA 0x08 /* transmitter DMA enable bit */ +#define SR_RST 0x10 /* SRP reset */ +#define SR_USR_INT_ENA 0x20 /* user interrupt enable bit */ +#define SR_TX_INT_ENA 0x40 /* transmitter interrupt enable bit */ +#define SR_RX_INT_ENA 0x80 /* receiver interrupt enable bit */ + +/* status register - input bits */ +#define SR_USR_RQ 0x20 /* user interupt request pending */ +#define SR_TX_RDY 0x40 /* transmitter empty (ready) */ +#define SR_RX_RDY 0x80 /* receiver data ready */ + +#define SR_UP_REQUEST 0x02 /* request from SRP to transfer data + up to PC */ +#define SR_DOWN_REQUEST 0x01 /* SRP is able to transfer data down + from PC to SRP */ +#define SR_END_OF_TRANSFER 0x03 /* SRP signalize end of + transfer (up or down) */ + +#define SR_CMD_FROM_SRP_MASK 0x03 /* mask to get SRP command */ + +/* bits in driver status byte definitions : */ +#define SR_RDY_RCV 0x01 /* ready to receive packet */ +#define SR_RDY_SND 0x02 /* ready to send packet */ +#define SR_CMD_PND 0x04 /* command pending */ /* not currently used */ + +/* ???? */ +#define SR_PKT_UP 0x01 /* transfer of packet up in progress */ +#define SR_PKT_DOWN 0x02 /* transfer of packet down in progress */ + +#endif /* __KERNEL__ */ + +#define SR_LOAD_ADDR 0x4400 /* SRP microcode load address */ +#define SR_START_ADDR 0x4400 /* SRP microcode start address */ + +#define COSA_LOAD_ADDR 0x400 /* SRP microcode load address */ +#define COSA_MAX_FIRMWARE_SIZE 0x10000 + +/* ioctls */ +struct cosa_download { + int addr, len; + char *code; +}; + +/* Reset the device */ +#define COSAIORSET _IO('C',0xf0) + +/* Start microcode at given address */ +#define COSAIOSTRT _IOW('C',0xf1,sizeof(int)) + +/* Read the block from the device memory */ +#define COSAIORMEM _IOR('C',0xf2,sizeof(struct cosa_download *)) + +/* Write the block to the device memory (i.e. download the microcode) */ +#define COSAIODOWNLD _IOW('C',0xf2,sizeof(struct cosa_download *)) + +/* Read the device type (one of "srp", "cosa", and "cosa8" for now) */ +#define COSAIORTYPE _IOR('C',0xf3,sizeof(char *)) + +/* Read the device identification string */ +#define COSAIORIDSTR _IOR('C',0xf4,sizeof(char *)) +/* Maximum length of the identification string. */ +#define COSA_MAX_ID_STRING 128 + +/* Increment/decrement the module usage count :-) */ +/* #define COSAIOMINC _IO('C',0xf5) */ +/* #define COSAIOMDEC _IO('C',0xf6) */ + +/* Get the total number of cards installed */ +#define COSAIONRCARDS _IO('C',0xf7) + +/* Get the number of channels on this card */ +#define COSAIONRCHANS _IO('C',0xf8) + +/* Set the driver for the bus-master operations */ +#define COSAIOBMSET _IOW('C', 0xf9, sizeof(unsigned short)) + +#define COSA_BM_OFF 0 /* Bus-mastering off - use ISA DMA (default) */ +#define COSA_BM_ON 1 /* Bus-mastering on - faster but untested */ + +/* Gets the busmaster status */ +#define COSAIOBMGET _IO('C', 0xfa) + +#endif /* !COSA_H__ */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/cycx_drv.c linux/drivers/net/wan/cycx_drv.c --- v2.3.20/linux/drivers/net/wan/cycx_drv.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/cycx_drv.c Mon Oct 11 10:13:25 1999 @@ -0,0 +1,660 @@ +/* +* cycx_drv.c cycx Support Module. +* +* This module is a library of common hardware-specific +* functions used by all Cyclades sync and some async (8x & 16x) +* drivers. +* +* Copyright: (c) 1998, 1999 Arnaldo Carvalho de Melo +* +* Author: Arnaldo Carvalho de Melo +* +* Based on sdladrv.c by Gene Kozin +* +* 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 +#endif +#include +#else +#define EXPORT_SYMBOL(function) +#endif +#include /* printk(), and other useful stuff */ +#include /* offsetof(), etc. */ +#include /* return codes */ +#include /* for jiffies, HZ, etc. */ +#include /* API definitions */ +#include /* CYCX firmware module definitions */ +#include /* udelay */ +#include /* for inb(), outb(), etc. */ + +#define MOD_VERSION 0 +#define MOD_RELEASE 2 + +#ifdef MODULE +MODULE_AUTHOR("Arnaldo Carvalho de Melo"); +MODULE_DESCRIPTION("Cyclades Sync Cards Driver."); +#endif + +/* Function Prototypes */ +/* Module entry points. These are called by the OS and must be public. */ +int init_module (void); +void cleanup_module (void); + +/* Hardware-specific functions */ +static int cycx_detect (cycxhw_t *hw); +static int cycx_load (cycxhw_t *hw, cfm_t *cfm, u32 len); +static int cycx_init (cycxhw_t *hw); +static int cycx_reset (cycxhw_t *hw); +static void cycx_bootcfg (cycxhw_t *hw); + +static int init_cycx_2x (cycxhw_t *hw); +static int reset_cycx_2x (u32 addr); +static int detect_cycx_2x (u32 addr); + +/* Miscellaneous functions */ +static void delay_cycx (int sec); +static int get_option_index (u32 *optlist, u32 optval); +static u16 checksum (u8 *buf, u32 len); + +#define wait_cyc(addr) cycx_exec(addr + CMD_OFFSET) + +/* Global Data + * Note: All data must be explicitly initialized!!! */ + +/* private data */ +static char modname[] = "cycx_drv"; +static char fullname[] = "Cyclom X Support Module"; +static char copyright[] = "(c) 1998, 1999 Arnaldo Carvalho de Melo"; + +/* Hardware configuration options. + * These are arrays of configuration options used by verification routines. + * The first element of each array is its size (i.e. number of options). + */ +static u32 cycx_2x_dpmbase_options[] = +{ + 20, + 0xA0000, 0xA4000, 0xA8000, 0xAC000, 0xB0000, 0xB4000, 0xB8000, + 0xBC000, 0xC0000, 0xC4000, 0xC8000, 0xCC000, 0xD0000, 0xD4000, + 0xD8000, 0xDC000, 0xE0000, 0xE4000, 0xE8000, 0xEC000 +}; + +static u32 cycx_2x_irq_options[] = { 7, 3, 5, 9, 10, 11, 12, 15 }; + +/* Kernel Loadable Module Entry Points */ +/* Module 'insert' entry point. + * o print announcement + * o initialize static data + * + * Return: 0 Ok + * < 0 error. + * Context: process */ +#ifdef MODULE +int init_module (void) +{ + printk(KERN_INFO "%s v%u.%u %s\n", + fullname, MOD_VERSION, MOD_RELEASE, copyright); + return 0; +} +/* Module 'remove' entry point. + * o release all remaining system resources */ +void cleanup_module (void) +{ +} +#endif +/* Kernel APIs */ +/* Set up adapter. + * o detect adapter type + * o verify hardware configuration options + * o check for hardware conflicts + * o set up adapter shared memory + * o test adapter memory + * o load firmware + * Return: 0 ok. + * < 0 error */ +EXPORT_SYMBOL(cycx_setup); +int cycx_setup (cycxhw_t *hw, void *cfm, u32 len) +{ + u32 *irq_opt = NULL; /* IRQ options */ + u32 *dpmbase_opt = NULL;/* DPM window base options */ + int err = 0; + + if (cycx_detect(hw)) { + printk(KERN_ERR "%s: adapter Cyclom %uX not found at " + "address 0x%lX!\n", + modname, hw->type, (unsigned long) hw->dpmbase); + return -EINVAL; + } + + printk(KERN_INFO "%s: found Cyclom %uX card at address 0x%lx.\n", + modname, hw->type, (unsigned long) hw->dpmbase); + + switch (hw->type) { + case CYCX_2X: + irq_opt = cycx_2x_irq_options; + dpmbase_opt = cycx_2x_dpmbase_options; + break; + default: + printk(KERN_ERR "%s: unknown card.\n", modname); + return -EINVAL; + } + + /* Verify IRQ configuration options */ + if (!get_option_index(irq_opt, hw->irq)) { + printk (KERN_ERR "%s: IRQ %d is illegal!\n", modname, hw->irq); + return -EINVAL; + } + + /* Setup adapter dual-port memory window and test memory */ + if (!hw->dpmbase) { + printk(KERN_ERR "%s: you must specify the dpm address!\n", + modname); + return -EINVAL; + } + else if (!get_option_index(dpmbase_opt, hw->dpmbase)) { + printk(KERN_ERR "%s: memory address 0x%lX is illegal!\n", + modname, (unsigned long) hw->dpmbase); + return -EINVAL; + } + + hw->dpmsize = CYCX_WINDOWSIZE; + /* FIXME! Is this the only amount ever available? */ + hw->memory = 0x40000; + + cycx_init(hw); + + printk(KERN_INFO "%s: dual-port memory window is set at 0x%lX.\n", + modname, (unsigned long) hw->dpmbase); + printk(KERN_INFO "%s: found %luK bytes of on-board memory.\n", + modname, (unsigned long) hw->memory / 1024); + + /* Load firmware. If loader fails then shut down adapter */ + err = cycx_load(hw, cfm, len); + if (err) cycx_down(hw); /* shutdown adapter */ + return err; +} + +/* Shut down CYCX: disable shared memory access and interrupts, stop CPU,etc.*/ +EXPORT_SYMBOL(cycx_down); +int cycx_down (cycxhw_t *hw) +{ + return 0; /* FIXME: anything needed here? */ +} + +/* Enable interrupt generation. */ +EXPORT_SYMBOL(cycx_inten); +int cycx_inten (cycxhw_t *hw) +{ + switch (hw->type) { + case CYCX_2X: writeb (0, hw->dpmbase); break; + default: return -EINVAL; + } + + return 0; +} + +/* Generate an interrupt to adapter's CPU. */ +EXPORT_SYMBOL(cycx_intr); +int cycx_intr (cycxhw_t *hw) +{ + switch (hw->type) { + case CYCX_2X: + writew(0, hw->dpmbase + GEN_CYCX_INTR); + return 0; + default: return -EINVAL; + } + + return 0; +} + +/* Execute Adapter Command. + * o Set exec flag. + * o Busy-wait until flag is reset. */ +EXPORT_SYMBOL(cycx_exec); +int cycx_exec (u32 addr) +{ + u16 i = 0; + /* wait till addr content is zeroed */ + + while (readw(addr) != 0) { + udelay(1000); + if (++i > 50) return -1; + } + + return 0; +} + +/* Read absolute adapter memory. + * Transfer data from adapter's memory to data buffer. */ +EXPORT_SYMBOL(cycx_peek); +int cycx_peek (cycxhw_t *hw, u32 addr, void *buf, u32 len) +{ + if (len == 1) *(u8*)buf = readb (hw->dpmbase + addr); + else memcpy_fromio(buf, hw->dpmbase + addr, len); + + return 0; +} + +/* Write Absolute Adapter Memory. + * Transfer data from data buffer to adapter's memory. */ +EXPORT_SYMBOL(cycx_poke); +int cycx_poke (cycxhw_t *hw, u32 addr, void *buf, u32 len) +{ + if (len == 1) writeb (*(u8*)buf, hw->dpmbase + addr); + else memcpy_toio(hw->dpmbase + addr, buf, len); + + return 0; +} + +/* Hardware-Specific Functions */ +/* Detect adapter type. + * o if adapter type is specified then call detection routine for that adapter + * type. Otherwise call detection routines for every adapter types until + * adapter is detected. + * + * Notes: + * 1) Detection tests are destructive! Adapter will be left in shutdown state + * after the test. */ +static int cycx_detect (cycxhw_t *hw) +{ + int err = 0; + + if (!hw->dpmbase) return -EFAULT; + + switch (hw->type) { + case CYCX_2X: + if (!detect_cycx_2x(hw->dpmbase)) err = -ENODEV; + break; + default: + if (detect_cycx_2x(hw->dpmbase)) hw->type = CYCX_2X; + else err = -ENODEV; + } + + return err; +} + +/* Load Aux Routines */ +/* Reset board hardware. + return 1 if memory exists at addr and 0 if not. */ +static int memory_exists(u32 addr) +{ + int timeout = 0; + + for (; timeout < 3 ; timeout++) { + writew (TEST_PATTERN, addr + 0x10); + + if (readw (addr + 0x10) == TEST_PATTERN) + if (readw (addr + 0x10) == TEST_PATTERN) return 1; + + delay_cycx(1); + } + + return 0; +} + +/* Reset board hardware. */ +static int cycx_reset(cycxhw_t *hw) +{ + /* Reset board */ + switch (hw->type) { + case CYCX_2X: return reset_cycx_2x(hw->dpmbase); + } + + return -EINVAL; +} + +/* Load reset code. */ +static void reset_load(u32 addr, u8 *buffer, u32 cnt) +{ + u32 pt_code = addr + RESET_OFFSET; + u16 i, j; + + for ( i = 0 ; i < cnt ; i++) { + for (j = 0 ; j < 50 ; j++); /* Delay - FIXME busy waiting... */ + writeb(*buffer++, pt_code++); + } +} + +/* Load buffer using boot interface. + * o copy data from buffer to Cyclom-X memory + * o wait for reset code to copy it to right portion of memory */ +static int buffer_load(u32 addr, u8 *buffer, u32 cnt) +{ + memcpy_toio(addr + DATA_OFFSET, buffer, cnt); + writew(GEN_BOOT_DAT, addr + CMD_OFFSET); + return wait_cyc(addr); +} + +/* Set up entry point and kick start Cyclom-X CPU. */ +static void cycx_start (u32 addr) +{ + /* put in 0x30 offset the jump instruction to the code entry point */ + writeb(0xea, addr + 0x30); + writeb(0x00, addr + 0x31); + writeb(0xc4, addr + 0x32); + writeb(0x00, addr + 0x33); + writeb(0x00, addr + 0x34); + + /* cmd to start executing code */ + writew(GEN_START, addr + CMD_OFFSET); +} + +/* Load and boot reset code. */ +static void cycx_reset_boot(u32 addr, u8 *code, u32 len) +{ + u32 pt_start = addr + START_OFFSET; + + writeb(0xea, pt_start++); /* jmp to f000:3f00 */ + writeb(0x00, pt_start++); + writeb(0xfc, pt_start++); + writeb(0x00, pt_start++); + writeb(0xf0, pt_start); + reset_load(addr, code, len); + + /* 80186 was in hold, go */ + writeb(0, addr + START_CPU); + delay_cycx(1); +} + +/* Load data.bin file through boot (reset) interface. */ +static int cycx_data_boot(u32 addr, u8 *code, u32 len) +{ + u32 pt_boot_cmd = addr + CMD_OFFSET; + u32 i; + + /* boot buffer lenght */ + writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16)); + writew(GEN_DEFPAR, pt_boot_cmd); + + if (wait_cyc(addr) < 0) return 2; + + writew(0, pt_boot_cmd + sizeof(u16)); + writew(0x4000, pt_boot_cmd + 2 * sizeof(u16)); + writew(GEN_SET_SEG, pt_boot_cmd); + + if (wait_cyc(addr) < 0) return 2; + + for (i = 0 ; i < len ; i += CFM_LOAD_BUFSZ) + if (buffer_load(addr, code + i, + MIN(CFM_LOAD_BUFSZ, (len - i))) < 0) { + printk(KERN_ERR "%s: Error !!\n", modname); + return 4; + } + + return 0; +} + + +/* Load code.bin file through boot (reset) interface. */ +static int cycx_code_boot(u32 addr, u8 *code, u32 len) +{ + u32 pt_boot_cmd = addr + CMD_OFFSET; + u32 i; + + /* boot buffer lenght */ + writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16)); + writew(GEN_DEFPAR, pt_boot_cmd); + + if (wait_cyc(addr) == -1) return 2; + + writew(0x0000, pt_boot_cmd + sizeof(u16)); + writew(0xc400, pt_boot_cmd + 2 * sizeof(u16)); + writew(GEN_SET_SEG, pt_boot_cmd); + + if (wait_cyc(addr) == -1) return 1; + + for (i = 0 ; i < len ; i += CFM_LOAD_BUFSZ) + if (buffer_load(addr, code + i,MIN(CFM_LOAD_BUFSZ,(len - i)))) { + printk(KERN_ERR "%s: Error !!\n", modname); + return 4; + } + + return 0; +} + +/* Initialize CYCX hardware: setup memory window, IRQ, etc. */ +static int cycx_init (cycxhw_t *hw) +{ + switch (hw->type) { + case CYCX_2X: return init_cycx_2x(hw); + } + + return -EINVAL; +} + +/* Load adapter from the memory image of the CYCX firmware module. + * o verify firmware integrity and compatibility + * o start adapter up */ +static int cycx_load (cycxhw_t *hw, cfm_t *cfm, u32 len) +{ + int i, j, status; + cycx_header_t *img_hdr; + u8 *reset_image, + *data_image, + *code_image; + u32 pt_cycld = hw->dpmbase + 0x400; + u16 cksum; + + /* Announce */ + printk(KERN_INFO "%s: firmware signature=\"%s\"\n", + modname, cfm->signature); + + /* Verify firmware signature */ + if (strcmp(cfm->signature, CFM_SIGNATURE)) { + printk(KERN_ERR "%s:cycx_load: not Cyclom-2X firmware!\n", + modname); + return -EINVAL; + } + + printk(KERN_INFO "%s: firmware version=%u\n", modname, cfm->version); + + /* Verify firmware module format version */ + if (cfm->version != CFM_VERSION) { + printk(KERN_ERR "%s:cycx_load: firmware format %u rejected! " + "Expecting %u.\n", + modname, cfm->version, CFM_VERSION); + return -EINVAL; + } + + /* Verify firmware module length and checksum */ + cksum = checksum((u8*)&cfm->info, sizeof(cfm_info_t) + + cfm->info.codesize); +/* + FIXME cfm->info.codesize is off by 2 + if (((len - sizeof(cfm_t) - 1) != cfm->info.codesize) || +*/ + if (cksum != cfm->checksum) { + printk(KERN_ERR "%s:cycx_load: firmware corrupted!\n", modname); + printk(KERN_ERR " cdsize = 0x%x (expected 0x%lx)\n", + len - sizeof(cfm_t) - 1, cfm->info.codesize); + printk(KERN_ERR " chksum = 0x%x (expected 0x%x)\n", + cksum, cfm->checksum); + return -EINVAL; + } + + /* If everything is ok, set reset, data and code pointers */ + + img_hdr = (cycx_header_t*)(((u8*) cfm) + sizeof(cfm_t) - 1); +#ifdef FIRMWARE_DEBUG + printk(KERN_INFO "%s:cycx_load: image sizes\n", modname); + printk(KERN_INFO " reset=%lu\n", img_hdr->reset_size); + printk(KERN_INFO " data=%lu\n", img_hdr->data_size); + printk(KERN_INFO " code=%lu\n", img_hdr->code_size); +#endif + reset_image = ((u8 *) img_hdr) + sizeof(cycx_header_t); + data_image = reset_image + img_hdr->reset_size; + code_image = data_image + img_hdr->data_size; + + /*---- Start load ----*/ + /* Announce */ + printk(KERN_INFO "%s: loading firmware %s (ID=%u)...\n", modname, + (cfm->descr[0] != '\0') ? cfm->descr : "unknown firmware", + cfm->info.codeid); + + for (i = 0 ; i < 5 ; i++) { + /* Reset Cyclom hardware */ + if ((status = cycx_reset(hw)) != 0) { + printk(KERN_ERR "%s: dpm problem or board not " + "found (%d).\n", modname, status); + return -EINVAL; + } + + /* Load reset.bin */ + cycx_reset_boot(hw->dpmbase, reset_image, img_hdr->reset_size); + /* reset is waiting for boot */ + writew(GEN_POWER_ON, pt_cycld); + delay_cycx(1); + + for (j = 0 ; j < 3 ; j++) + if (!readw(pt_cycld)) goto reset_loaded; + else delay_cycx(1); + } + + printk(KERN_ERR "%s: reset not started.\n", modname); + return -EINVAL; +reset_loaded: + /* Load data.bin */ + if((status = cycx_data_boot(hw->dpmbase, data_image, + img_hdr->data_size)) != 0) { + printk(KERN_ERR "%s: cannot load data file (%d).\n", + modname, status); + return -EINVAL; + } + + /* Load code.bin */ + if((status = cycx_code_boot(hw->dpmbase, code_image, + img_hdr->code_size)) != 0) { + printk(KERN_ERR "%s: cannot load code file (%d).\n", + modname, status); + return -EINVAL; + } + + /* Prepare boot-time configuration data */ + cycx_bootcfg(hw); + + /* kick-off CPU */ + cycx_start(hw->dpmbase); + + /* Arthur Ganzert's tip: wait a while after the firmware loading... + seg abr 26 17:17:12 EST 1999 - acme */ + delay_cycx(7); + printk(KERN_INFO "%s: firmware loaded!\n", modname); + + /* enable interrupts */ + if (cycx_inten(hw)) { + printk(KERN_ERR "%s: adapter hardware failure!\n", modname); + return -EIO; + } + + return 0; +} + +/* Prepare boot-time firmware configuration data. + * o initialize configuration data area + From async.doc - V_3.4.0 - 07/18/1994 + - As of now, only static buffers are available to the user. + So, the bit VD_RXDIRC must be set in 'valid'. That means that user + wants to use the static transmission and reception buffers. */ +static void cycx_bootcfg (cycxhw_t *hw) +{ + /* use fixed buffers */ + writeb(FIXED_BUFFERS, hw->dpmbase + CONF_OFFSET); +} + +/* Initialize CYCX_2X adapter. */ +static int init_cycx_2x (cycxhw_t *hw) +{ + if (!detect_cycx_2x(hw->dpmbase)) return -ENODEV; + return 0; +} + +/* Detect Cyclom 2x adapter. + * Following tests are used to detect Cyclom 2x adapter: + * to be completed based on the tests done below + * Return 1 if detected o.k. or 0 if failed. + * Note: This test is destructive! Adapter will be left in shutdown + * state after the test. */ +static int detect_cycx_2x (u32 addr) +{ + printk(KERN_INFO "%s: looking for a cyclom 2x at 0x%lX...\n", + modname, (unsigned long) addr); + + reset_cycx_2x(addr); + return memory_exists(addr); +} + +/* Miscellaneous */ +/* Get option's index into the options list. + * Return option's index (1 .. N) or zero if option is invalid. */ +static int get_option_index (u32 *optlist, u32 optval) +{ + int i = 1; + for (; i <= optlist[0]; ++i) if (optlist[i] == optval) return i; + return 0; +} + +/* Reset adapter's CPU. */ +static int reset_cycx_2x (u32 addr) +{ + writeb (0, addr + RST_ENABLE); delay_cycx (2); + writeb (0, addr + RST_DISABLE); delay_cycx (2); + return memory_exists(addr) ? 0 : 1; +} + +/* Delay */ +static void delay_cycx (int sec) +{ +/* acme + Thu dez 31 21:45:16 EDT 1998 + FIXME I'll keep this comment here just in case, as of now I don't + know it all the contexts where this routine is used are interruptible... */ + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(sec*HZ); +} + +/* Calculate 16-bit CRC using CCITT polynomial. */ +static u16 checksum (u8 *buf, u32 len) +{ + u16 crc = 0; + u16 mask, flag; + + for (; len; --len, ++buf) + for (mask = 0x80; mask; mask >>= 1) { + flag = (crc & 0x8000); + crc <<= 1; + crc |= ((*buf & mask) ? 1 : 0); + if (flag) crc ^= 0x1021; + } + + return crc; +} +/* End */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/cycx_main.c linux/drivers/net/wan/cycx_main.c --- v2.3.20/linux/drivers/net/wan/cycx_main.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/cycx_main.c Mon Oct 11 10:13:25 1999 @@ -0,0 +1,379 @@ +/* +* cycx_main.c Cyclades Cyclom X Multiprotocol WAN Link Driver. Main module. +* +* Author: Arnaldo Carvalho de Melo +* +* Copyright: (c) 1998, 1999 Arnaldo Carvalho de Melo +* +* Based on sdlamain.c by Gene Kozin & +* Jaspreet Singh +* +* 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 /* OS configuration options */ +#include /* offsetof(), etc. */ +#include /* return codes */ +#include /* inline memset(), etc. */ +#include /* kmalloc(), kfree() */ +#include /* printk(), and other useful stuff */ +#include /* support for loadable modules */ +#include /* request_region(), release_region() */ +#include /* for kernel task queues */ +#include /* WAN router definitions */ +#include /* cyclomx common user API definitions */ +#include /* kernel <-> user copy */ +#include /* __init (when not using as a module) */ + +#ifdef MODULE +MODULE_AUTHOR("Arnaldo Carvalho de Melo"); +MODULE_DESCRIPTION("Cyclades Sync Cards Driver."); +#endif + +/* Defines & Macros */ + +#define DRV_VERSION 0 /* version number */ +#define DRV_RELEASE 4 /* release (minor version) number */ +#define MAX_CARDS 1 /* max number of adapters */ + +#ifndef CONFIG_CYCLOMX_CARDS /* configurable option */ +#define CONFIG_CYCLOMX_CARDS 1 +#endif + +/* Function Prototypes */ + +/* Module entry points */ +int init_module (void); +void cleanup_module (void); + +/* WAN link driver entry points */ +static int setup (wan_device_t *wandev, wandev_conf_t *conf); +static int shutdown (wan_device_t *wandev); +static int ioctl (wan_device_t *wandev, unsigned cmd, unsigned long arg); + +/* Miscellaneous functions */ +static void cycx_isr (int irq, void *dev_id, struct pt_regs *regs); + +/* Global Data + * Note: All data must be explicitly initialized!!! + */ + +/* private data */ +static char drvname[] = "cyclomx"; +static char fullname[] = "CYCLOM X(tm) Multiprotocol Driver"; +static char copyright[] = "(c) 1998, 1999 Arnaldo Carvalho de Melo"; +static int ncards = CONFIG_CYCLOMX_CARDS; +static cycx_t *card_array = NULL; /* adapter data space */ + +/* Kernel Loadable Module Entry Points */ + +/* + * Module 'insert' entry point. + * o print announcement + * o allocate adapter data space + * o initialize static data + * o register all cards with WAN router + * o calibrate CYCX shared memory access delay. + * + * Return: 0 Ok + * < 0 error. + * Context: process + */ +#ifdef MODULE +int init_module (void) +#else +int __init cyclomx_init (void) +#endif +{ + int cnt, err = 0; + + printk(KERN_INFO "%s v%u.%u %s\n", + fullname, DRV_VERSION, DRV_RELEASE, copyright); + + /* Verify number of cards and allocate adapter data space */ + ncards = min(ncards, MAX_CARDS); + ncards = max(ncards, 1); + card_array = kmalloc(sizeof(cycx_t) * ncards, GFP_KERNEL); + + if (card_array == NULL) return -ENOMEM; + + memset(card_array, 0, sizeof(cycx_t) * ncards); + + /* Register adapters with WAN router */ + for (cnt = 0; cnt < ncards; ++cnt) { + cycx_t *card = &card_array[cnt]; + wan_device_t *wandev = &card->wandev; + + sprintf(card->devname, "%s%d", drvname, cnt + 1); + wandev->magic = ROUTER_MAGIC; + wandev->name = card->devname; + wandev->private = card; + wandev->setup = &setup; + wandev->shutdown = &shutdown; + wandev->ioctl = &ioctl; + err = register_wan_device(wandev); + + if (err) { + printk(KERN_ERR + "%s: %s registration failed with error %d!\n", + drvname, card->devname, err); + break; + } + } + + if (cnt) ncards = cnt; /* adjust actual number of cards */ + else { + kfree(card_array); + err = -ENODEV; + } + + return err; +} + +/* + * Module 'remove' entry point. + * o unregister all adapters from the WAN router + * o release all remaining system resources + */ +#ifdef MODULE +void cleanup_module (void) +{ + int i = 0; + + for (; i < ncards; ++i) { + cycx_t *card = &card_array[i]; + unregister_wan_device(card->devname); + } + + kfree(card_array); +} +#endif +/* WAN Device Driver Entry Points */ +/* + * Setup/confugure WAN link driver. + * o check adapter state + * o make sure firmware is present in configuration + * o allocate interrupt vector + * o setup CYCLOM X hardware + * o call appropriate routine to perform protocol-specific initialization + * o mark I/O region as used + * + * This function is called when router handles ROUTER_SETUP IOCTL. The + * configuration structure is in kernel memory (including extended data, if + * any). + */ +static int setup (wan_device_t *wandev, wandev_conf_t *conf) +{ + cycx_t *card; + int err = 0; + int irq; + + /* Sanity checks */ + if (!wandev || !wandev->private || !conf) return -EFAULT; + + card = wandev->private; + + if (wandev->state != WAN_UNCONFIGURED) return -EBUSY; + + if (!conf->data_size || (conf->data == NULL)) { + printk(KERN_ERR "%s: firmware not found in configuration " + "data!\n", wandev->name); + return -EINVAL; + } + + if (conf->irq <= 0) { + printk(KERN_ERR "%s: can't configure without IRQ!\n", + wandev->name); + return -EINVAL; + } + + /* Allocate IRQ */ + irq = conf->irq == 2 ? 9 : conf->irq; /* IRQ2 -> IRQ9 */ + + if (request_irq(irq, cycx_isr, 0, wandev->name, card)) { + printk(KERN_ERR "%s: can't reserve IRQ %d!\n", + wandev->name, irq); + return -EINVAL; + } + + /* Configure hardware, load firmware, etc. */ + memset(&card->hw, 0, sizeof(cycxhw_t)); + card->hw.irq = (conf->irq == 9) ? 2 : conf->irq; + card->hw.dpmbase = conf->maddr; + card->hw.dpmsize = CYCX_WINDOWSIZE; + card->hw.type = conf->hw_opt[0]; + card->hw.fwid = CFID_X25_2X; + card->lock = SPIN_LOCK_UNLOCKED; +#if LINUX_VERSION_CODE >= 0x020300 + init_waitqueue_head(&card->wait_stats); +#else + card->wait_stats = NULL; +#endif + err = cycx_setup(&card->hw, conf->data, conf->data_size); + + if (err) { + free_irq(irq, card); + return err; + } + + /* Intialize WAN device data space */ + wandev->irq = irq; + wandev->dma = wandev->ioport = 0; + wandev->maddr = (unsigned long*)card->hw.dpmbase; + wandev->msize = card->hw.dpmsize; + wandev->hw_opt[0] = card->hw.type; + wandev->hw_opt[1] = card->hw.pclk; + wandev->hw_opt[2] = card->hw.memory; + wandev->hw_opt[3] = card->hw.fwid; + + /* Protocol-specific initialization */ + switch (card->hw.fwid) { +#ifdef CONFIG_CYCLOMX_X25 + case CFID_X25_2X: err = cyx_init(card, conf); break; +#endif + default: + printk(KERN_ERR "%s: this firmware is not supported!\n", + wandev->name); + err = -EINVAL; + } + + if (err) { + cycx_down(&card->hw); + free_irq(irq, card); + return err; + } + + return 0; +} + +/* + * Shut down WAN link driver. + * o shut down adapter hardware + * o release system resources. + * + * This function is called by the router when device is being unregistered or + * when it handles ROUTER_DOWN IOCTL. + */ +static int shutdown (wan_device_t *wandev) +{ + cycx_t *card; + + /* sanity checks */ + if (!wandev || !wandev->private) return -EFAULT; + + if (wandev->state == WAN_UNCONFIGURED) return 0; + + card = wandev->private; + wandev->state = WAN_UNCONFIGURED; + cycx_down(&card->hw); + printk(KERN_INFO "%s: irq %d being freed!\n", wandev->name,wandev->irq); + free_irq(wandev->irq, card); + return 0; +} + +/* + * Driver I/O control. + * o verify arguments + * o perform requested action + * + * This function is called when router handles one of the reserved user + * IOCTLs. Note that 'arg' stil points to user address space. + */ +static int ioctl (wan_device_t *wandev, unsigned cmd, unsigned long arg) +{ + return -EINVAL; +} + +/* Miscellaneous */ +/* + * CYCX Interrupt Service Routine. + * o acknowledge CYCX hardware interrupt. + * o call protocol-specific interrupt service routine, if any. + */ +static void cycx_isr (int irq, void *dev_id, struct pt_regs *regs) +{ +#define card ((cycx_t*)dev_id) + if (!card || card->wandev.state == WAN_UNCONFIGURED) + return; + + if (card->in_isr) { + printk(KERN_WARNING "%s: interrupt re-entrancy on IRQ %d!\n", + card->devname, card->wandev.irq); + return; + } + + if (card->isr) + card->isr(card); +#undef card +} + +/* + * This routine is called by the protocol-specific modules when network + * interface is being open. The only reason we need this, is because we + * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's + * defined more than once into the same kernel module. + */ +void cyclomx_open (cycx_t *card) +{ + ++card->open_cnt; + MOD_INC_USE_COUNT; +} + +/* + * This routine is called by the protocol-specific modules when network + * interface is being closed. The only reason we need this, is because we + * have to call MOD_DEC_USE_COUNT, but cannot include 'module.h' where it's + * defined more than once into the same kernel module. + */ +void cyclomx_close (cycx_t *card) +{ + --card->open_cnt; + MOD_DEC_USE_COUNT; +} + +/* Set WAN device state. */ +void cyclomx_set_state (cycx_t *card, int state) +{ + unsigned long host_cpu_flags; + + spin_lock_irqsave(&card->lock, host_cpu_flags); + + if (card->wandev.state != state) { + switch (state) { + case WAN_CONNECTED: + printk (KERN_INFO "%s: link connected!\n", + card->devname); + break; + + case WAN_CONNECTING: + printk (KERN_INFO "%s: link connecting...\n", + card->devname); + break; + + case WAN_DISCONNECTED: + printk (KERN_INFO "%s: link disconnected!\n", + card->devname); + break; + } + + card->wandev.state = state; + } + + card->state_tick = jiffies; + spin_unlock_irqrestore(&card->lock, host_cpu_flags); +} + +/* End */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/cycx_x25.c linux/drivers/net/wan/cycx_x25.c --- v2.3.20/linux/drivers/net/wan/cycx_x25.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/cycx_x25.c Mon Oct 11 10:13:25 1999 @@ -0,0 +1,1488 @@ +/* +* cycx_x25.c CYCLOM X Multiprotocol WAN Link Driver. X.25 module. +* +* Author: Arnaldo Carvalho de Melo +* Copyright: (c) 1998, 1999 Arnaldo Carvalho de Melo +* +* Based on sdla_x25.c by Gene Kozin +* +* 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 +#include /* printk(), and other useful stuff */ +#include /* offsetof(), etc. */ +#include /* return codes */ +#include /* inline memset(), etc. */ +#include /* kmalloc(), kfree() */ +#include /* WAN router definitions */ +#include /* htons(), etc. */ +#include /* ARPHRD_X25 */ +#include /* CYCLOM X common user API definitions */ +#include /* X.25 firmware API definitions */ + +/* Defines & Macros */ +#define MAX_CMD_RETRY 5 +#define X25_CHAN_MTU 2048 /* unfragmented logical channel MTU */ + +/* Data Structures */ +/* This is an extention of the 'struct net_device' we create for each network + interface to keep the rest of X.25 channel-specific data. */ +typedef struct x25_channel { + char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ + char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ + char *local_addr; /* local media address, ASCIIZ - + svc thru crossover cable */ + s16 lcn; /* logical channel number/conn.req.key*/ + u8 link; + struct timer_list timer; /* timer used for svc channel disc. */ + u16 protocol; /* ethertype, 0 - multiplexed */ + u8 svc; /* 0 - permanent, 1 - switched */ + u8 state; /* channel state */ + u8 drop_sequence; /* mark sequence for dropping */ + u32 idle_tmout; /* sec, before disconnecting */ + struct sk_buff *rx_skb; /* receive socket buffer */ + cycx_t *card; /* -> owner */ + struct enet_statistics ifstats; /* interface statistics */ +} x25_channel_t; + +/* Function Prototypes */ +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t *wandev), + new_if (wan_device_t *wandev, struct net_device *dev,wanif_conf_t *conf), + del_if (wan_device_t *wandev, struct net_device *dev); + +/* Network device interface */ +static int if_init (struct net_device *dev), + if_open (struct net_device *dev), + if_close (struct net_device *dev), + if_header (struct sk_buff *skb, struct net_device *dev, + u16 type, void *daddr, void *saddr, unsigned len), + if_rebuild_hdr (struct sk_buff *skb), + if_send (struct sk_buff *skb, struct net_device *dev); + +static struct net_device_stats * if_stats (struct net_device *dev); + +/* Interrupt handlers */ +static void cyx_isr (cycx_t *card), + tx_intr (cycx_t *card, TX25Cmd *cmd), + rx_intr (cycx_t *card, TX25Cmd *cmd), + log_intr (cycx_t *card, TX25Cmd *cmd), + stat_intr (cycx_t *card, TX25Cmd *cmd), + connect_confirm_intr (cycx_t *card, TX25Cmd *cmd), + disconnect_confirm_intr (cycx_t *card, TX25Cmd *cmd), + connect_intr (cycx_t *card, TX25Cmd *cmd), + disconnect_intr (cycx_t *card, TX25Cmd *cmd), + spur_intr (cycx_t *card, TX25Cmd *cmd); + +/* X.25 firmware interface functions */ +static int x25_configure (cycx_t *card, TX25Config *conf), + x25_get_stats (cycx_t *card), + x25_send (cycx_t *card, u8 link, u8 lcn, u8 bitm, int len,void *buf), + x25_connect_response (cycx_t *card, x25_channel_t *chan), + x25_disconnect_response (cycx_t *card, u8 link, u8 lcn); + +/* Miscellaneous functions */ +static int chan_connect (struct net_device *dev), + chan_send (struct net_device *dev, struct sk_buff *skb); + +static void set_chan_state (struct net_device *dev, u8 state), + nibble_to_byte (u8 *s, u8 *d, u8 len, u8 nibble), + reset_timer (struct net_device *dev), + chan_disc (struct net_device *dev), + chan_timer (unsigned long d); + +static u8 bps_to_speed_code (u32 bps); +static u8 log2 (u32 n); + +static unsigned dec_to_uint (u8 *str, int len); + +static struct net_device *get_dev_by_lcn (wan_device_t *wandev, s16 lcn); +static struct net_device *get_dev_by_dte_addr (wan_device_t *wandev, char *dte); + +#ifdef CYCLOMX_X25_DEBUG +static void hex_dump(char *msg, unsigned char *p, int len); +static void x25_dump_config(TX25Config *conf); +static void x25_dump_stats(TX25Stats *stats); +static void x25_dump_devs(wan_device_t *wandev); +#define dprintk(format, a...) printk(format, ##a) +#else +#define hex_dump(msg, p, len) +#define x25_dump_config(conf) +#define x25_dump_stats(stats) +#define x25_dump_devs(wandev) +#define dprintk(format, a...) +#endif +/* Public Functions */ + +/* X.25 Protocol Initialization routine. + * + * This routine is called by the main CYCLOM X module during setup. At this + * point adapter is completely initialized and X.25 firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. */ +int cyx_init (cycx_t *card, wandev_conf_t *conf) +{ + TX25Config cfg; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_X25) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + + /* Initialize protocol-specific fields */ + card->mbox = card->hw.dpmbase + X25_MBOX_OFFS; + card->u.x.connection_keys = 0; + card->u.x.lock = SPIN_LOCK_UNLOCKED; + + /* Configure adapter. Here we set resonable defaults, then parse + * device configuration structure and set configuration options. + * Most configuration options are verified and corrected (if + * necessary) since we can't rely on the adapter to do so and don't + * want it to fail either. */ + memset(&cfg, 0, sizeof(cfg)); + cfg.link = 0; + cfg.clock = conf->clocking == WANOPT_EXTERNAL ? 8 : 55; + cfg.speed = bps_to_speed_code(conf->bps); + cfg.n3win = 7; + cfg.n2win = 2; + cfg.n2 = 5; + cfg.nvc = 1; + cfg.npvc = 1; + cfg.flags = 0x02; /* default = V35 */ + cfg.t1 = 10; /* line carrier timeout */ + cfg.t2 = 29; /* tx timeout */ + cfg.t21 = 180; /* CALL timeout */ + cfg.t23 = 180; /* CLEAR timeout */ + + /* adjust MTU */ + if (!conf->mtu || conf->mtu >= 512) + card->wandev.mtu = 512; + else if (conf->mtu >= 256) + card->wandev.mtu = 256; + else if (conf->mtu >= 128) + card->wandev.mtu = 128; + else + card->wandev.mtu = 64; + + cfg.pktlen = log2(card->wandev.mtu); + + if (conf->station == WANOPT_DTE) { + cfg.locaddr = 3; /* DTE */ + cfg.remaddr = 1; /* DCE */ + } else { + cfg.locaddr = 1; /* DCE */ + cfg.remaddr = 3; /* DTE */ + } + + if (conf->interface == WANOPT_RS232) + cfg.flags = 0; /* FIXME just reset the 2nd bit */ + + if (conf->u.x25.hi_pvc) { + card->u.x.hi_pvc = min(conf->u.x25.hi_pvc, 4095); + card->u.x.lo_pvc = min(conf->u.x25.lo_pvc, card->u.x.hi_pvc); + } + + if (conf->u.x25.hi_svc) { + card->u.x.hi_svc = min(conf->u.x25.hi_svc, 4095); + card->u.x.lo_svc = min(conf->u.x25.lo_svc, card->u.x.hi_svc); + } + + if (card->u.x.lo_pvc == 255) + cfg.npvc = 0; + else + cfg.npvc = card->u.x.hi_pvc - card->u.x.lo_pvc + 1; + + cfg.nvc = card->u.x.hi_svc - card->u.x.lo_svc + 1 + cfg.npvc; + + if (conf->u.x25.hdlc_window) + cfg.n2win = min(conf->u.x25.hdlc_window, 7); + + if (conf->u.x25.pkt_window) + cfg.n3win = min(conf->u.x25.pkt_window, 7); + + if (conf->u.x25.t1) + cfg.t1 = min(conf->u.x25.t1, 30); + + if (conf->u.x25.t2) + cfg.t2 = min(conf->u.x25.t2, 30); + + if (conf->u.x25.t11_t21) + cfg.t21 = min(conf->u.x25.t11_t21, 30); + + if (conf->u.x25.t13_t23) + cfg.t23 = min(conf->u.x25.t13_t23, 30); + + if (conf->u.x25.n2) + cfg.n2 = min(conf->u.x25.n2, 30); + + /* initialize adapter */ + if (x25_configure(card, &cfg)) + return -EIO; + + /* Initialize protocol-specific fields of adapter data space */ + card->wandev.bps = conf->bps; + card->wandev.interface = conf->interface; + card->wandev.clocking = conf->clocking; + card->wandev.station = conf->station; + card->isr = &cyx_isr; + card->exec = NULL; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.state = WAN_DISCONNECTED; + return 0; +} + +/* WAN Device Driver Entry Points */ +/* Update device status & statistics. */ +static int update (wan_device_t *wandev) +{ + /* sanity checks */ + if (!wandev || !wandev->private) + return -EFAULT; + + if (wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + x25_get_stats(wandev->private); + return 0; +} + +/* Create new logical channel. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) */ +static int new_if (wan_device_t *wandev, struct net_device *dev, wanif_conf_t *conf) +{ + cycx_t *card = wandev->private; + x25_channel_t *chan; + int err = 0; + + if (conf->name[0] == '\0' || strlen(conf->name) > WAN_IFNAME_SZ) { + printk(KERN_INFO "%s: invalid interface name!\n",card->devname); + return -EINVAL; + } + + /* allocate and initialize private data */ + if ((chan = kmalloc(sizeof(x25_channel_t), GFP_KERNEL)) == NULL) + return -ENOMEM; + + memset(chan, 0, sizeof(x25_channel_t)); + strcpy(chan->name, conf->name); + chan->card = card; + chan->link = conf->port; + chan->protocol = ETH_P_IP; + chan->rx_skb = NULL; + /* only used in svc connected thru crossover cable */ + chan->local_addr = NULL; + + if (conf->addr[0] == '@') { /* SVC */ + int len = strlen(conf->local_addr); + + if (len) { + if (len > WAN_ADDRESS_SZ) { + printk(KERN_ERR "%s: %s local addr too long!\n", + wandev->name, chan->name); + kfree(chan); + return -EINVAL; + } else { + chan->local_addr = kmalloc(len + 1, GFP_KERNEL); + + if (!chan->local_addr) { + kfree(chan); + return ENOMEM; + } + } + + strncpy(chan->local_addr, conf->local_addr, + WAN_ADDRESS_SZ); + } + + chan->svc = 1; + strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ); + init_timer(&chan->timer); + chan->timer.function = chan_timer; + chan->timer.data = (unsigned long) dev; + + /* Set channel timeouts (default if not specified) */ + chan->idle_tmout = conf->idle_timeout ? conf->idle_timeout : 90; + } else if (is_digit(conf->addr[0])) { /* PVC */ + s16 lcn = dec_to_uint(conf->addr, 0); + + if (lcn >= card->u.x.lo_pvc && lcn <= card->u.x.hi_pvc) + chan->lcn = lcn; + else { + printk(KERN_ERR + "%s: PVC %u is out of range on interface %s!\n", + wandev->name, lcn, chan->name); + err = -EINVAL; + } + } else { + printk(KERN_ERR "%s: invalid media address on interface %s!\n", + wandev->name, chan->name); + err = -EINVAL; + } + + if (err) { + if (chan->local_addr) + kfree(chan->local_addr); + + kfree(chan); + return err; + } + + /* prepare network device data space for registration */ + dev->name = chan->name; + dev->init = &if_init; + dev->priv = chan; + return 0; +} + +/* Delete logical channel. */ +static int del_if (wan_device_t *wandev, struct net_device *dev) +{ + if (!dev) { + printk(KERN_ERR "cycx_x25:del_if:dev == NULL!\n"); + return 0; + } + + if (dev->priv) { + x25_channel_t *chan = dev->priv; + + if (chan->svc) { + if (chan->local_addr) + kfree(chan->local_addr); + + if (chan->state == WAN_CONNECTED) + del_timer(&chan->timer); + } + + kfree(chan); + dev->priv = NULL; + } + + return 0; +} + +/* Network Device Interface */ +/* Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. */ +static int if_init (struct net_device *dev) +{ + x25_channel_t *chan = dev->priv; + cycx_t *card = chan->card; + wan_device_t *wandev = &card->wandev; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = &if_header; + dev->rebuild_header = &if_rebuild_hdr; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + + /* Initialize media-specific parameters */ + dev->mtu = X25_CHAN_MTU; + dev->type = ARPHRD_X25; /* ARP h/w type */ + dev->hard_header_len = 0; /* media header length */ + dev->addr_len = 0; /* hardware address length */ + + if (!chan->svc) + *(u16*)dev->dev_addr = htons(chan->lcn); + + /* Initialize hardware parameters (just for reference) */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = (unsigned long)wandev->maddr; + dev->mem_end = (unsigned long)(wandev->maddr + wandev->msize - 1); + dev->flags |= IFF_NOARP; + + /* Set transmit buffer queue length */ + dev->tx_queue_len = 10; + + /* Initialize socket buffers */ + dev_init_buffers(dev); + set_chan_state(dev, WAN_DISCONNECTED); + return 0; +} + +/* Open network interface. + * o prevent module from unloading by incrementing use count + * o if link is disconnected then initiate connection + * + * Return 0 if O.k. or errno. */ +static int if_open (struct net_device *dev) +{ + x25_channel_t *chan = dev->priv; + cycx_t *card = chan->card; + + if (dev->start) + return -EBUSY; /* only one open is allowed */ + + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + cyclomx_open(card); + + return 0; +} + +/* Close network interface. + * o reset flags. + * o if there's no more open channels then disconnect physical link. */ +static int if_close (struct net_device *dev) +{ + x25_channel_t *chan = dev->priv; + cycx_t *card = chan->card; + + dev->start = 0; + + if (chan->state == WAN_CONNECTED || chan->state == WAN_CONNECTING) + chan_disc(dev); + + cyclomx_close(card); + return 0; +} + +/* Build media header. + * o encapsulate packet according to encapsulation type. + * + * The trick here is to put packet type (Ethertype) into 'protocol' field of + * the socket buffer, so that we don't forget it. If encapsulation fails, + * set skb->protocol to 0 and discard packet later. + * + * Return: media header length. */ +static int if_header (struct sk_buff *skb, struct net_device *dev, + u16 type, void *daddr, void *saddr, unsigned len) +{ + skb->protocol = type; + return dev->hard_header_len; +} + +/* * Re-build media header. + * Return: 1 physical address resolved. + * 0 physical address not resolved */ +static int if_rebuild_hdr (struct sk_buff *skb) +{ + return 1; +} + +/* Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission). + * o check link state. If link is not up, then drop the packet. + * o check channel status. If it's down then initiate a call. + * o pass a packet to corresponding WAN device. + * o free socket buffer + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. */ +static int if_send (struct sk_buff *skb, struct net_device *dev) +{ + x25_channel_t *chan = dev->priv; + cycx_t *card = chan->card; + + if (dev->tbusy) { + ++chan->ifstats.rx_dropped; + return -EBUSY; + } + + if (!chan->svc) + chan->protocol = skb->protocol; + + if (card->wandev.state != WAN_CONNECTED) + ++chan->ifstats.tx_dropped; + else if (chan->svc && chan->protocol && + chan->protocol != skb->protocol) { + printk(KERN_INFO + "%s: unsupported Ethertype 0x%04X on interface %s!\n", + card->devname, skb->protocol, dev->name); + ++chan->ifstats.tx_errors; + } else switch (chan->state) { + case WAN_DISCONNECTED: + if (chan_connect(dev)) { + dev->tbusy = 1; + return -EBUSY; + } + /* fall thru */ + case WAN_CONNECTED: + reset_timer(dev); + dev->trans_start = jiffies; + dev->tbusy = 1; + + if (chan_send(dev, skb)) { + return -EBUSY; + } + break; + default: + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + } + + dev_kfree_skb(skb); + return 0; +} + +/* Get Ethernet-style interface statistics. + * Return a pointer to struct net_device_stats */ +static struct net_device_stats *if_stats (struct net_device *dev) +{ + x25_channel_t *chan = dev->priv; + + return chan ? &chan->ifstats : NULL; +} + +/* Interrupt Handlers */ +/* X.25 Interrupt Service Routine. */ +static void cyx_isr (cycx_t *card) +{ + TX25Cmd cmd; + u16 z = 0; + + card->in_isr = 1; + card->buff_int_mode_unbusy = 0; + cycx_peek(&card->hw, X25_RXMBOX_OFFS, &cmd, sizeof(cmd)); + + switch (cmd.command) { + case X25_DATA_INDICATION: + rx_intr(card, &cmd); + break; + case X25_ACK_FROM_VC: + tx_intr(card, &cmd); + break; + case X25_LOG: + log_intr(card, &cmd); + break; + case X25_STATISTIC: + stat_intr(card, &cmd); + break; + case X25_CONNECT_CONFIRM: + connect_confirm_intr(card, &cmd); + break; + case X25_CONNECT_INDICATION: + connect_intr(card, &cmd); + break; + case X25_DISCONNECT_INDICATION: + disconnect_intr(card, &cmd); + break; + case X25_DISCONNECT_CONFIRM: + disconnect_confirm_intr(card, &cmd); + break; + case X25_LINE_ON: + cyclomx_set_state(card, WAN_CONNECTED); + break; + case X25_LINE_OFF: + cyclomx_set_state(card, WAN_DISCONNECTED); + break; + default: + spur_intr(card, &cmd); /* unwanted interrupt */ + } + + cycx_poke(&card->hw, 0, &z, sizeof(z)); + cycx_poke(&card->hw, X25_RXMBOX_OFFS, &z, sizeof(z)); + card->in_isr = 0; + + if (card->buff_int_mode_unbusy) + mark_bh(NET_BH); +} + +/* Transmit interrupt handler. + * o Release socket buffer + * o Clear 'tbusy' flag */ +static void tx_intr (cycx_t *card, TX25Cmd *cmd) +{ + struct net_device *dev; + wan_device_t *wandev = &card->wandev; + u8 lcn; + + cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn)); + + /* unbusy device and then dev_tint(); */ + if ((dev = get_dev_by_lcn (wandev, lcn)) != NULL) { + card->buff_int_mode_unbusy = 1; + dev->tbusy = 0; + } else + printk(KERN_ERR "%s:ackvc for inexistent lcn %d\n", + card->devname, lcn); +} + +/* Receive interrupt handler. + * This routine handles fragmented IP packets using M-bit according to the + * RFC1356. + * o map ligical channel number to network interface. + * o allocate socket buffer or append received packet to the existing one. + * o if M-bit is reset (i.e. it's the last packet in a sequence) then + * decapsulate packet and pass socket buffer to the protocol stack. + * + * Notes: + * 1. When allocating a socket buffer, if M-bit is set then more data is + * comming and we have to allocate buffer for the maximum IP packet size + * expected on this channel. + * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no + * socket buffers available) the whole packet sequence must be discarded. */ +static void rx_intr (cycx_t *card, TX25Cmd *cmd) +{ + wan_device_t *wandev = &card->wandev; + struct net_device *dev; + x25_channel_t *chan; + struct sk_buff *skb; + u8 bitm, lcn; + int pktlen = cmd->len - 5; + + cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn)); + cycx_peek(&card->hw, cmd->buf + 4, &bitm, sizeof(bitm)); + bitm &= 0x10; + + if ((dev = get_dev_by_lcn(wandev, lcn)) == NULL) { + /* Invalid channel, discard packet */ + printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n", + card->devname, lcn); + return; + } + + chan = dev->priv; + reset_timer(dev); + + if (chan->drop_sequence) { + if (!bitm) + chan->drop_sequence = 0; + else + return; + } + + if ((skb = chan->rx_skb) == NULL) { + /* Allocate new socket buffer */ + int bufsize = bitm ? dev->mtu : pktlen; + + if ((skb = dev_alloc_skb(bufsize + + dev->hard_header_len)) == NULL) { + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + chan->drop_sequence = 1; + ++chan->ifstats.rx_dropped; + return; + } + + skb->dev = dev; + skb->protocol = htons(chan->protocol); + chan->rx_skb = skb; + } + + if (skb_tailroom(skb) < pktlen) { + /* No room for the packet. Call off the whole thing! */ + dev_kfree_skb(skb); + chan->rx_skb = NULL; + + if (bitm) + chan->drop_sequence = 1; + + printk(KERN_INFO "%s: unexpectedly long packet sequence " + "on interface %s!\n", card->devname, dev->name); + ++chan->ifstats.rx_length_errors; + return; + } + + /* Append packet to the socket buffer */ + cycx_peek(&card->hw, cmd->buf + 5, skb_put(skb, pktlen), pktlen); + + if (bitm) + return; /* more data is coming */ + + dev->last_rx = jiffies; /* timestamp */ + chan->rx_skb = NULL; /* dequeue packet */ + + skb->protocol = htons(ETH_P_IP); + skb->dev = dev; + skb->mac.raw = skb->data; + netif_rx(skb); + ++chan->ifstats.rx_packets; + chan->ifstats.rx_bytes += skb->len; +} + +/* Connect interrupt handler. */ +static void connect_intr (cycx_t *card, TX25Cmd *cmd) +{ + wan_device_t *wandev = &card->wandev; + struct net_device *dev = NULL; + x25_channel_t *chan; + u8 d[32], + loc[24], + rem[24]; + u8 lcn, sizeloc, sizerem; + + cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn)); + cycx_peek(&card->hw, cmd->buf + 5, &sizeloc, sizeof(sizeloc)); + cycx_peek(&card->hw, cmd->buf + 6, d, cmd->len - 6); + + sizerem = sizeloc >> 4; + sizeloc &= 0x0F; + + loc[0] = rem[0] = '\0'; + + if (sizeloc) + nibble_to_byte(d, loc, sizeloc, 0); + + if (sizerem) + nibble_to_byte(d + (sizeloc >> 1), rem, sizerem, sizeloc & 1); + + dprintk(KERN_INFO "connect_intr:lcn=%d, local=%s, remote=%s\n", + lcn, loc, rem); + if ((dev = get_dev_by_dte_addr(wandev, rem)) == NULL) { + /* Invalid channel, discard packet */ + printk(KERN_INFO "%s: connect not expected: remote %s!\n", + card->devname, rem); + return; + } + + chan = dev->priv; + chan->lcn = lcn; + x25_connect_response(card, chan); + set_chan_state(dev, WAN_CONNECTED); +} + +/* Connect confirm interrupt handler. */ +static void connect_confirm_intr (cycx_t *card, TX25Cmd *cmd) +{ + wan_device_t *wandev = &card->wandev; + struct net_device *dev; + x25_channel_t *chan; + u8 lcn, key; + + cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn)); + cycx_peek(&card->hw, cmd->buf + 1, &key, sizeof(key)); + dprintk(KERN_INFO "%s: connect_confirm_intr:lcn=%d, key=%d\n", + card->devname, lcn, key); + if ((dev = get_dev_by_lcn(wandev, -key)) == NULL) { + /* Invalid channel, discard packet */ + clear_bit(--key, (void*)&card->u.x.connection_keys); + printk(KERN_INFO "%s: connect confirm not expected: lcn %d, " + "key=%d!\n", card->devname, lcn, key); + return; + } + + clear_bit(--key, (void*)&card->u.x.connection_keys); + chan = dev->priv; + chan->lcn = lcn; + set_chan_state(dev, WAN_CONNECTED); +} + +/* Disonnect confirm interrupt handler. */ +static void disconnect_confirm_intr (cycx_t *card, TX25Cmd *cmd) +{ + wan_device_t *wandev = &card->wandev; + struct net_device *dev; + u8 lcn; + + cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn)); + dprintk(KERN_INFO "%s: disconnect_confirm_intr:lcn=%d\n", + card->devname, lcn); + if ((dev = get_dev_by_lcn(wandev, lcn)) == NULL) { + /* Invalid channel, discard packet */ + printk(KERN_INFO "%s:disconnect confirm not expected!:lcn %d\n", + card->devname, lcn); + return; + } + + set_chan_state(dev, WAN_DISCONNECTED); +} + +/* disconnect interrupt handler. */ +static void disconnect_intr (cycx_t *card, TX25Cmd *cmd) +{ + wan_device_t *wandev = &card->wandev; + struct net_device *dev; + u8 lcn; + + cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn)); + dprintk(KERN_INFO "disconnect_intr:lcn=%d\n", lcn); + + if ((dev = get_dev_by_lcn(wandev, lcn)) != NULL) { + x25_channel_t *chan = dev->priv; + + x25_disconnect_response(card, chan->link, lcn); + set_chan_state(dev, WAN_DISCONNECTED); + } else + x25_disconnect_response(card, 0, lcn); +} + +/* LOG interrupt handler. */ +static void log_intr (cycx_t *card, TX25Cmd *cmd) +{ +#if CYCLOMX_X25_DEBUG + char bf[20]; + u16 size, toread, link, msg_code; + u8 code, routine; + + cycx_peek(&card->hw, cmd->buf, &msg_code, sizeof(msg_code)); + cycx_peek(&card->hw, cmd->buf + 2, &link, sizeof(link)); + cycx_peek(&card->hw, cmd->buf + 4, &size, sizeof(size)); + /* at most 20 bytes are available... thanx to Daniela :) */ + toread = size < 20 ? size : 20; + cycx_peek(&card->hw, cmd->buf + 10, &bf, toread); + cycx_peek(&card->hw, cmd->buf + 10 + toread, &code, 1); + cycx_peek(&card->hw, cmd->buf + 10 + toread + 1, &routine, 1); + + printk(KERN_INFO "cyx_isr: X25_LOG (0x4500) indic.:\n"); + printk(KERN_INFO "cmd->buf=0x%X\n", cmd->buf); + printk(KERN_INFO "Log message code=0x%X\n", msg_code); + printk(KERN_INFO "Link=%d\n", link); + printk(KERN_INFO "log code=0x%X\n", code); + printk(KERN_INFO "log routine=0x%X\n", routine); + printk(KERN_INFO "Message size=%d\n", size); + hex_dump("Message", bf, toread); +#endif +} + +/* STATISTIC interrupt handler. */ +static void stat_intr (cycx_t *card, TX25Cmd *cmd) +{ + cycx_peek(&card->hw, cmd->buf, &card->u.x.stats, + sizeof(card->u.x.stats)); + hex_dump("stat_intr", (unsigned char*)&card->u.x.stats, + sizeof(card->u.x.stats)); + x25_dump_stats(&card->u.x.stats); + wake_up_interruptible(&card->wait_stats); +} + +/* Spurious interrupt handler. + * o print a warning + * If number of spurious interrupts exceeded some limit, then ??? */ +static void spur_intr (cycx_t *card, TX25Cmd *cmd) +{ + printk(KERN_INFO "%s: spurious interrupt (0x%X)!\n", + card->devname, cmd->command); +} +#ifdef CYCLOMX_X25_DEBUG +static void hex_dump(char *msg, unsigned char *p, int len) +{ + unsigned char hex[1024], + * phex = hex; + + if (len >= (sizeof(hex) / 2)) + len = (sizeof(hex) / 2) - 1; + + while (len--) { + sprintf(phex, "%02x", *p++); + phex += 2; + } + + printk(KERN_INFO "%s: %s\n", msg, hex); +} +#endif +/* CYCLOM X Firmware-Specific Functions */ +/* Exec x25 command. */ +static int x25_exec (cycx_t *card, int command, int link, + void *d1, int len1, void *d2, int len2) +{ + TX25Cmd c; + unsigned long flags; + u32 addr = 0x1200 + 0x2E0 * link + 0x1E2; + u8 retry = MAX_CMD_RETRY; + int err = 0; + + c.command = command; + c.link = link; + c.len = len1 + len2; + + spin_lock_irqsave(&card->u.x.lock, flags); + + /* write command */ + cycx_poke(&card->hw, X25_MBOX_OFFS, &c, sizeof(c) - sizeof(c.buf)); + + /* write x25 data */ + if (d1) { + cycx_poke(&card->hw, addr, d1, len1); + + if (d2) { + if (len2 > 254) { + u32 addr1 = 0xA00 + 0x400 * link; + + cycx_poke(&card->hw, addr + len1, d2, 249); + cycx_poke(&card->hw, addr1, ((u8*) d2) + 249, + len2 - 249); + } else + cycx_poke(&card->hw, addr + len1, d2, len2); + } + } + + /* generate interruption, executing command */ + cycx_intr(&card->hw); + + /* wait till card->mbox == 0 */ + do { + err = cycx_exec(card->mbox); + } while (retry-- && err); + + spin_unlock_irqrestore(&card->u.x.lock, flags); + + return err; +} + +/* Configure adapter. */ +static int x25_configure (cycx_t *card, TX25Config *conf) +{ + struct { + u16 nlinks; + TX25Config conf[2]; + } x25_cmd_conf; + + memset (&x25_cmd_conf, 0, sizeof(x25_cmd_conf)); + x25_cmd_conf.nlinks = 2; + x25_cmd_conf.conf[0] = *conf; + /* FIXME: we need to find a way in the wanrouter framework + to configure the second link, for now lets use it + with the same config from the first link, fixing + the interface type to RS232, the speed in 38400 and + the clock to external */ + x25_cmd_conf.conf[1] = *conf; + x25_cmd_conf.conf[1].link = 1; + x25_cmd_conf.conf[1].speed = 5; /* 38400 */ + x25_cmd_conf.conf[1].clock = 8; + x25_cmd_conf.conf[1].flags = 0; /* default = RS232 */ + + x25_dump_config(&x25_cmd_conf.conf[0]); + x25_dump_config(&x25_cmd_conf.conf[1]); + + return x25_exec(card, X25_CONFIG, 0, + &x25_cmd_conf, sizeof(x25_cmd_conf), NULL, 0); +} + +/* Get protocol statistics. */ +static int x25_get_stats (cycx_t *card) +{ + /* the firmware expects 20 in the size field!!! + thanx to Daniela */ + int err = x25_exec(card, X25_STATISTIC, 0, NULL, 20, NULL, 0); + + if (err) + return err; + + interruptible_sleep_on(&card->wait_stats); + + if (signal_pending(current)) + return -EINTR; + + card->wandev.stats.rx_packets = card->u.x.stats.n2_rx_frames; + card->wandev.stats.rx_over_errors = card->u.x.stats.rx_over_errors; + card->wandev.stats.rx_crc_errors = card->u.x.stats.rx_crc_errors; + card->wandev.stats.rx_length_errors = 0; /* not available from fw */ + card->wandev.stats.rx_frame_errors = 0; /* not available from fw */ + card->wandev.stats.rx_missed_errors = card->u.x.stats.rx_aborts; + card->wandev.stats.rx_dropped = 0; /* not available from fw */ + card->wandev.stats.rx_errors = 0; /* not available from fw */ + card->wandev.stats.tx_packets = card->u.x.stats.n2_tx_frames; + card->wandev.stats.tx_aborted_errors = card->u.x.stats.tx_aborts; + card->wandev.stats.tx_dropped = 0; /* not available from fw */ + card->wandev.stats.collisions = 0; /* not available from fw */ + card->wandev.stats.tx_errors = 0; /* not available from fw */ + + x25_dump_devs(&card->wandev); + return 0; +} + +/* return the number of nibbles */ +static int byte_to_nibble(u8 *s, u8 *d, char *nibble) +{ + int i = 0; + + if (*nibble && *s) { + d[i] |= *s++ - '0'; + *nibble = 0; + ++i; + } + + while (*s) { + d[i] = (*s - '0') << 4; + if (*(s + 1)) + d[i] |= *(s + 1) - '0'; + else { + *nibble = 1; + break; + } + ++i; + s += 2; + } + + return i; +} + +static void nibble_to_byte(u8 *s, u8 *d, u8 len, u8 nibble) +{ + if (nibble) { + *d++ = '0' + (*s++ & 0x0F); + --len; + } + + while (len) { + *d++ = '0' + (*s >> 4); + + if (--len) { + *d++ = '0' + (*s & 0x0F); + --len; + } else break; + + ++s; + } + + *d = '\0'; +} + +/* Place X.25 call. */ +static int x25_place_call (cycx_t *card, x25_channel_t *chan) +{ + int err = 0, + len; + char d[64], + nibble = 0, + mylen = chan->local_addr ? strlen(chan->local_addr) : 0, + remotelen = strlen(chan->addr); + u8 key; + + if (card->u.x.connection_keys == ~0UL) { + printk(KERN_INFO "%s: too many simultaneous connection " + "requests!\n", card->devname); + return -EAGAIN; + } + + key = ffz(card->u.x.connection_keys); + set_bit(key, (void*)&card->u.x.connection_keys); + ++key; + dprintk(KERN_INFO "%s:x25_place_call:key=%d\n", card->devname, key); + memset(d, 0, sizeof(d)); + d[1] = key; /* user key */ + d[2] = 0x10; + d[4] = 0x0B; + + len = byte_to_nibble(chan->addr, d + 6, &nibble); + + if (chan->local_addr) + len += byte_to_nibble(chan->local_addr, d + 6 + len, &nibble); + + if (nibble) + ++len; + + d[5] = mylen << 4 | remotelen; + d[6 + len + 1] = 0xCC; /* TCP/IP over X.25, thanx to Daniela :) */ + + if ((err = x25_exec(card, X25_CONNECT_REQUEST, chan->link, + &d, 7 + len + 1, NULL, 0)) != 0) + clear_bit(--key, (void*)&card->u.x.connection_keys); + else { + chan->lcn = -key; + chan->protocol = ETH_P_IP; + } + + return err; +} + +/* Place X.25 CONNECT RESPONSE. */ +static int x25_connect_response (cycx_t *card, x25_channel_t *chan) +{ + u8 d[8]; + + memset(d, 0, sizeof(d)); + d[0] = d[3] = chan->lcn; + d[2] = 0x10; + d[4] = 0x0F; + d[7] = 0xCC; /* TCP/IP over X.25, thanx Daniela */ + + return x25_exec(card, X25_CONNECT_RESPONSE, chan->link, &d, 8, NULL, 0); +} + +/* Place X.25 DISCONNECT RESPONSE. */ +static int x25_disconnect_response (cycx_t *card, u8 link, u8 lcn) +{ + char d[5]; + + memset(d, 0, sizeof(d)); + d[0] = d[3] = lcn; + d[2] = 0x10; + d[4] = 0x17; + return x25_exec(card, X25_DISCONNECT_RESPONSE, link, &d, 5, NULL, 0); +} + +/* Clear X.25 call. */ +static int x25_clear_call (cycx_t *card, u8 link, u8 lcn, u8 cause, u8 diagn) +{ + u8 d[7]; + + memset(d, 0, sizeof(d)); + d[0] = d[3] = lcn; + d[2] = 0x10; + d[4] = 0x13; + d[5] = cause; + d[6] = diagn; + + return x25_exec(card, X25_DISCONNECT_REQUEST, link, d, 7, NULL, 0); +} + +/* Send X.25 data packet. */ +static int x25_send (cycx_t *card, u8 link, u8 lcn, u8 bitm, int len, void *buf) +{ + u8 d[] = "?\xFF\x10??"; + + d[0] = d[3] = lcn; + d[4] = bitm; + + return x25_exec(card, X25_DATA_REQUEST, link, &d, 5, buf, len); +} + +/* Miscellaneous */ +/* Find network device by its channel number. */ +static struct net_device *get_dev_by_lcn (wan_device_t *wandev, s16 lcn) +{ + struct net_device *dev = wandev->dev; + + for (; dev; dev = dev->slave) + if (((x25_channel_t*)dev->priv)->lcn == lcn) + break; + return dev; +} + +/* Find network device by its remote dte address. */ +static struct net_device *get_dev_by_dte_addr (wan_device_t *wandev, char *dte) +{ + struct net_device *dev = wandev->dev; + + for (; dev; dev = dev->slave) + if (!strcmp (((x25_channel_t*)dev->priv)->addr, dte)) + break; + return dev; +} + +/* Initiate connection on the logical channel. + * o for PVC we just get channel configuration + * o for SVCs place an X.25 call + * + * Return: 0 connected + * >0 connection in progress + * <0 failure */ +static int chan_connect (struct net_device *dev) +{ + x25_channel_t *chan = dev->priv; + cycx_t *card = chan->card; + + if (chan->svc) { + if (!chan->addr[0]) + return -EINVAL; /* no destination address */ + dprintk(KERN_INFO "%s: placing X.25 call to %s...\n", + card->devname, chan->addr); + if (x25_place_call(card, chan)) + return -EIO; + set_chan_state(dev, WAN_CONNECTING); + return 1; + } else + set_chan_state(dev, WAN_CONNECTED); + + return 0; +} + +/* Disconnect logical channel. + * o if SVC then clear X.25 call */ +static void chan_disc (struct net_device *dev) +{ + x25_channel_t *chan = dev->priv; + + if (chan->svc) { + x25_clear_call(chan->card, chan->link, chan->lcn, 0, 0); + set_chan_state(dev, WAN_DISCONNECTING); + } else + set_chan_state(dev, WAN_DISCONNECTED); +} + +/* Called by kernel timer */ +static void chan_timer (unsigned long d) +{ + struct net_device *dev = (struct net_device*) d; + x25_channel_t *chan = dev->priv; + + switch (chan->state) { + case WAN_CONNECTED: + chan_disc(dev); + break; + default: + printk (KERN_ERR "%s: chan_timer for svc (%s) not " + "connected!\n", + chan->card->devname, dev->name); + } +} + +/* Set logical channel state. */ +static void set_chan_state (struct net_device *dev, u8 state) +{ + x25_channel_t *chan = dev->priv; + cycx_t *card = chan->card; + u32 flags = 0; + + spin_lock_irqsave(&card->lock, flags); + + if (chan->state != state) { + if (chan->svc && chan->state == WAN_CONNECTED) + del_timer(&chan->timer); + + switch (state) { + case WAN_CONNECTED: + printk (KERN_INFO "%s: interface %s " + "connected!\n", + card->devname, dev->name); + *(u16*)dev->dev_addr = htons(chan->lcn); + dev->tbusy = 0; + reset_timer(dev); + break; + + case WAN_CONNECTING: + printk (KERN_INFO "%s: interface %s " + "connecting...\n", + card->devname, dev->name); + break; + + case WAN_DISCONNECTING: + printk (KERN_INFO "%s: interface %s " + "disconnecting...\n", + card->devname, dev->name); + break; + + case WAN_DISCONNECTED: + printk (KERN_INFO "%s: interface %s " + "disconnected!\n", + card->devname, dev->name); + if (chan->svc) { + *(unsigned short*)dev->dev_addr = 0; + chan->lcn = 0; + } + dev->tbusy = 0; + break; + } + + chan->state = state; + } + + spin_unlock_irqrestore(&card->lock, flags); +} + +/* Send packet on a logical channel. + * When this function is called, tx_skb field of the channel data space + * points to the transmit socket buffer. When transmission is complete, + * release socket buffer and reset 'tbusy' flag. + * + * Return: 0 - transmission complete + * 1 - busy + * + * Notes: + * 1. If packet length is greater than MTU for this channel, we'll fragment + * the packet into 'complete sequence' using M-bit. + * 2. When transmission is complete, an event notification should be issued + * to the router. */ +static int chan_send (struct net_device *dev, struct sk_buff *skb) +{ + x25_channel_t *chan = dev->priv; + cycx_t *card = chan->card; + int bitm = 0; /* final packet */ + unsigned len = skb->len; + + if (skb->len > card->wandev.mtu) { + len = card->wandev.mtu; + bitm = 0x10; /* set M-bit (more data) */ + } + + if (x25_send(card, chan->link, chan->lcn, bitm, len, skb->data)) + return 1; + + if (bitm) { + skb_pull(skb, len); + return 1; + } + + ++chan->ifstats.tx_packets; + chan->ifstats.tx_bytes += len; + return 0; +} + +/* Convert line speed in bps to a number used by cyclom 2x code. */ +static u8 bps_to_speed_code (u32 bps) +{ + u8 number = 0; /* defaults to the lowest (1200) speed ;> */ + + if (bps >= 512000) number = 8; + else if (bps >= 256000) number = 7; + else if (bps >= 64000) number = 6; + else if (bps >= 38400) number = 5; + else if (bps >= 19200) number = 4; + else if (bps >= 9600) number = 3; + else if (bps >= 4800) number = 2; + else if (bps >= 2400) number = 1; + + return number; +} + +/* log base 2 */ +static u8 log2 (u32 n) +{ + u8 log = 0; + + if (!n) + return 0; + + while (n > 1) { + n >>= 1; + ++log; + } + + return log; +} + +/* Convert decimal string to unsigned integer. + * If len != 0 then only 'len' characters of the string are converted. */ +static unsigned dec_to_uint (u8 *str, int len) +{ + unsigned val = 0; + + if (!len) + len = strlen(str); + + for (; len && is_digit(*str); ++str, --len) + val = (val * 10) + (*str - (unsigned)'0'); + + return val; +} + +static void reset_timer(struct net_device *dev) +{ + x25_channel_t *chan = dev->priv; + + if (!chan->svc) + return; + + del_timer(&chan->timer); + chan->timer.expires = jiffies + chan->idle_tmout * HZ; + add_timer(&chan->timer); +} +#ifdef CYCLOMX_X25_DEBUG +static void x25_dump_config(TX25Config *conf) +{ + printk (KERN_INFO "x25 configuration\n"); + printk (KERN_INFO "-----------------\n"); + printk (KERN_INFO "link number=%d\n", conf->link); + printk (KERN_INFO "line speed=%d\n", conf->speed); + printk (KERN_INFO "clock=%sternal\n", conf->clock == 8 ? "Ex" : "In"); + printk (KERN_INFO "# level 2 retransm.=%d\n", conf->n2); + printk (KERN_INFO "level 2 window=%d\n", conf->n2win); + printk (KERN_INFO "level 3 window=%d\n", conf->n3win); + printk (KERN_INFO "# logical channels=%d\n", conf->nvc); + printk (KERN_INFO "level 3 pkt len=%d\n", conf->pktlen); + printk (KERN_INFO "my address=%d\n", conf->locaddr); + printk (KERN_INFO "remote address=%d\n", conf->remaddr); + printk (KERN_INFO "t1=%d seconds\n", conf->t1); + printk (KERN_INFO "t2=%d seconds\n", conf->t2); + printk (KERN_INFO "t21=%d seconds\n", conf->t21); + printk (KERN_INFO "# PVCs=%d\n", conf->npvc); + printk (KERN_INFO "t23=%d seconds\n", conf->t23); + printk (KERN_INFO "flags=0x%x\n", conf->flags); +} + +static void x25_dump_stats(TX25Stats *stats) +{ + printk (KERN_INFO "x25 statistics\n"); + printk (KERN_INFO "--------------\n"); + printk (KERN_INFO "rx_crc_errors=%d\n", stats->rx_crc_errors); + printk (KERN_INFO "rx_over_errors=%d\n", stats->rx_over_errors); + printk (KERN_INFO "n2_tx_frames=%d\n", stats->n2_tx_frames); + printk (KERN_INFO "n2_rx_frames=%d\n", stats->n2_rx_frames); + printk (KERN_INFO "tx_timeouts=%d\n", stats->tx_timeouts); + printk (KERN_INFO "rx_timeouts=%d\n", stats->rx_timeouts); + printk (KERN_INFO "n3_tx_packets=%d\n", stats->n3_tx_packets); + printk (KERN_INFO "n3_rx_packets=%d\n", stats->n3_rx_packets); + printk (KERN_INFO "tx_aborts=%d\n", stats->tx_aborts); + printk (KERN_INFO "rx_aborts=%d\n", stats->rx_aborts); +} + +static void x25_dump_devs(wan_device_t *wandev) +{ + struct net_device *dev = wandev->dev; + + printk (KERN_INFO "x25 dev states\n"); + printk (KERN_INFO "name: addr: tbusy:\n"); + printk (KERN_INFO "----------------------------\n"); + + for (; dev; dev = dev->slave) { + x25_channel_t *chan = dev->priv; + + printk (KERN_INFO "%-5.5s %-15.15s %ld\n", + chan->name, chan->addr, dev->tbusy); + } +} + +#endif /* CYCLOMX_X25_DEBUG */ +/* End */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/dlci.c linux/drivers/net/wan/dlci.c --- v2.3.20/linux/drivers/net/wan/dlci.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/dlci.c Mon Oct 11 10:13:25 1999 @@ -0,0 +1,634 @@ +/* + * DLCI Implementation of Frame Relay protocol for Linux, according to + * RFC 1490. This generic device provides en/decapsulation for an + * underlying hardware driver. Routes & IPs are assigned to these + * interfaces. Requires 'dlcicfg' program to create usable + * interfaces, the initial one, 'dlci' is for IOCTL use only. + * + * Version: @(#)dlci.c 0.35 4 Jan 1997 + * + * Author: Mike McLagan + * + * 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 /* for CONFIG_DLCI_COUNT */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +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;ipriv; + + 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;idevname, 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;iname = 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;ipriv); + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "syncppp.h" +#include "z85230.h" + +static int dma; + +struct sv11_device +{ + struct z8530_dev sync; + struct ppp_device netdev; + char name[16]; +}; + +/* + * Network driver support routines + */ + +/* + * Frame receive. Simple for our card as we do sync ppp and there + * is no funny garbage involved + */ + +static void hostess_input(struct z8530_channel *c, struct sk_buff *skb) +{ + /* Drop the CRC - its not a good idea to try and negotiate it ;) */ + skb_trim(skb, skb->len-2); + skb->protocol=htons(ETH_P_WAN_PPP); + skb->mac.raw=skb->data; + skb->dev=c->netdevice; + /* + * Send it to the PPP layer. We dont have time to process + * it right now. + */ + netif_rx(skb); +} + +/* + * We've been placed in the UP state + */ + +static int hostess_open(struct net_device *d) +{ + struct sv11_device *sv11=d->priv; + int err = -1; + + /* + * Link layer up + */ + switch(dma) + { + case 0: + err=z8530_sync_open(d, &sv11->sync.chanA); + break; + case 1: + err=z8530_sync_dma_open(d, &sv11->sync.chanA); + break; + case 2: + err=z8530_sync_txdma_open(d, &sv11->sync.chanA); + break; + } + + if(err) + return err; + /* + * Begin PPP + */ + err=sppp_open(d); + if(err) + { + switch(dma) + { + case 0: + z8530_sync_close(d, &sv11->sync.chanA); + break; + case 1: + z8530_sync_dma_close(d, &sv11->sync.chanA); + break; + case 2: + z8530_sync_txdma_close(d, &sv11->sync.chanA); + break; + } + return err; + } + sv11->sync.chanA.rx_function=hostess_input; + + /* + * Go go go + */ + d->tbusy=0; + MOD_INC_USE_COUNT; + return 0; +} + +static int hostess_close(struct net_device *d) +{ + struct sv11_device *sv11=d->priv; + /* + * Discard new frames + */ + sv11->sync.chanA.rx_function=z8530_null_rx; + /* + * PPP off + */ + sppp_close(d); + /* + * Link layer down + */ + d->tbusy=1; + + switch(dma) + { + case 0: + z8530_sync_close(d, &sv11->sync.chanA); + break; + case 1: + z8530_sync_dma_close(d, &sv11->sync.chanA); + break; + case 2: + z8530_sync_txdma_close(d, &sv11->sync.chanA); + break; + } + MOD_DEC_USE_COUNT; + return 0; +} + +static int hostess_ioctl(struct net_device *d, struct ifreq *ifr, int cmd) +{ + /* struct sv11_device *sv11=d->priv; + z8530_ioctl(d,&sv11->sync.chanA,ifr,cmd) */ + return sppp_do_ioctl(d, ifr,cmd); +} + +static struct enet_statistics *hostess_get_stats(struct net_device *d) +{ + struct sv11_device *sv11=d->priv; + if(sv11) + return z8530_get_stats(&sv11->sync.chanA); + else + return NULL; +} + +/* + * Passed PPP frames, fire them downwind. + */ + +static int hostess_queue_xmit(struct sk_buff *skb, struct net_device *d) +{ + struct sv11_device *sv11=d->priv; + return z8530_queue_xmit(&sv11->sync.chanA, skb); +} + +#ifdef LINUX_21 +static int hostess_neigh_setup(struct neighbour *n) +{ + if (n->nud_state == NUD_NONE) { + n->ops = &arp_broken_ops; + n->output = n->ops->output; + } + return 0; +} + +static int hostess_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) +{ + if (p->tbl->family == AF_INET) { + p->neigh_setup = hostess_neigh_setup; + p->ucast_probes = 0; + p->mcast_probes = 0; + } + return 0; +} + +#else + +static int return_0(struct net_device *d) +{ + return 0; +} + +#endif + +/* + * Description block for a Comtrol Hostess SV11 card + */ + +static struct sv11_device *sv11_init(int iobase, int irq) +{ + struct z8530_dev *dev; + struct sv11_device *sv; + int i; + unsigned long flags; + + /* + * Get the needed I/O space + */ + + if(check_region(iobase, 8)) + { + printk(KERN_WARNING "hostess: I/O 0x%X already in use.\n", iobase); + return NULL; + } + request_region(iobase, 8, "Comtrol SV11"); + + sv=(struct sv11_device *)kmalloc(sizeof(struct sv11_device), GFP_KERNEL); + if(!sv) + goto fail3; + + memset(sv, 0, sizeof(*sv)); + + dev=&sv->sync; + + /* + * Stuff in the I/O addressing + */ + + dev->active = 0; + + dev->chanA.ctrlio=iobase+1; + dev->chanA.dataio=iobase+3; + dev->chanB.ctrlio=-1; + dev->chanB.dataio=-1; + dev->chanA.irqs=&z8530_nop; + dev->chanB.irqs=&z8530_nop; + + outb(0, iobase+4); /* DMA off */ + + /* We want a fast IRQ for this device. Actually we'd like an even faster + IRQ ;) - This is one driver RtLinux is made for */ + + if(request_irq(irq, &z8530_interrupt, SA_INTERRUPT, "Hostess SV/11", dev)<0) + { + printk(KERN_WARNING "hostess: IRQ %d already in use.\n", irq); + goto fail2; + } + + dev->irq=irq; + dev->chanA.private=sv; + dev->chanA.netdevice=&sv->netdev.dev; + dev->chanA.dev=dev; + dev->chanB.dev=dev; + dev->name=sv->name; + + if(dma) + { + /* + * You can have DMA off or 1 and 3 thats the lot + * on the Comtrol. + */ + dev->chanA.txdma=3; + dev->chanA.rxdma=1; + outb(0x03|0x08, iobase+4); /* DMA on */ + if(request_dma(dev->chanA.txdma, "Hostess SV/11 (TX)")!=0) + goto fail; + + if(dma==1) + { + if(request_dma(dev->chanA.rxdma, "Hostess SV/11 (RX)")!=0) + goto dmafail; + } + } + save_flags(flags); + cli(); + + /* + * Begin normal initialise + */ + + if(z8530_init(dev)!=0) + { + printk(KERN_ERR "Z8530 series device not found.\n"); + goto dmafail2; + } + z8530_channel_load(&dev->chanB, z8530_dead_port); + if(dev->type==Z85C30) + z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream); + else + z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream_85230); + + restore_flags(flags); + + + /* + * Now we can take the IRQ + */ + + for(i=0;i<999;i++) + { + sprintf(sv->name,"hdlc%d", i); + if(dev_get(sv->name)==0) + { + struct net_device *d=dev->chanA.netdevice; + + /* + * Initialise the PPP components + */ + sppp_attach(&sv->netdev); + + /* + * Local fields + */ + sprintf(sv->name,"hdlc%d", i); + + d->name = sv->name; + d->base_addr = iobase; + d->irq = irq; + d->priv = sv; + d->init = NULL; + + d->open = hostess_open; + d->stop = hostess_close; + d->hard_start_xmit = hostess_queue_xmit; + d->get_stats = hostess_get_stats; + d->set_multicast_list = NULL; + d->do_ioctl = hostess_ioctl; +#ifdef LINUX_21 + d->neigh_setup = hostess_neigh_setup_dev; + dev_init_buffers(d); +#else + d->init = return_0; +#endif + d->set_mac_address = NULL; + + if(register_netdev(d)==-1) + { + printk(KERN_ERR "%s: unable to register device.\n", + sv->name); + goto fail; + } + + z8530_describe(dev, "I/O", iobase); + dev->active=1; + return sv; + } + } +dmafail2: + if(dma==1) + free_dma(dev->chanA.rxdma); +dmafail: + if(dma) + free_dma(dev->chanA.txdma); +fail: + free_irq(irq, dev); +fail2: + kfree(sv); +fail3: + release_region(iobase,8); + return NULL; +} + +static void sv11_shutdown(struct sv11_device *dev) +{ + sppp_detach(&dev->netdev.dev); + z8530_shutdown(&dev->sync); + unregister_netdev(&dev->netdev.dev); + free_irq(dev->sync.irq, dev); + if(dma) + { + if(dma==1) + free_dma(dev->sync.chanA.rxdma); + free_dma(dev->sync.chanA.txdma); + } + release_region(dev->sync.chanA.ctrlio-1, 8); +} + +#ifdef MODULE + +static int io=0x200; +static int irq=9; + +#ifdef LINUX_21 +MODULE_PARM(io,"i"); +MODULE_PARM_DESC(io, "The I/O base of the Comtrol Hostess SV11 card"); +MODULE_PARM(dma,"i"); +MODULE_PARM_DESC(dma, "Set this to 1 to use DMA1/DMA3 for TX/RX"); +MODULE_PARM(irq,"i"); +MODULE_PARM_DESC(irq, "The interrupt line setting for the Comtrol Hostess SV11 card"); + +MODULE_AUTHOR("Bulding Number Three Ltd"); +MODULE_DESCRIPTION("Modular driver for the Comtrol Hostess SV11"); +#endif + +static struct sv11_device *sv11_unit; + +int init_module(void) +{ + printk(KERN_INFO "SV-11 Z85230 Synchronous Driver v 0.02.\n"); + printk(KERN_INFO "(c) Copyright 1998, Building Number Three Ltd.\n"); + if((sv11_unit=sv11_init(io,irq))==NULL) + return -ENODEV; + return 0; +} + +void cleanup_module(void) +{ + if(sv11_unit) + sv11_shutdown(sv11_unit); +} + +#endif + diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/lapbether.c linux/drivers/net/wan/lapbether.c --- v2.3.20/linux/drivers/net/wan/lapbether.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/lapbether.c Mon Oct 11 10:13:25 1999 @@ -0,0 +1,571 @@ +/* + * "LAPB via ethernet" driver release 001 + * + * This code REQUIRES 2.1.15 or higher/ NET3.038 + * + * This module: + * This module is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * This is a "pseudo" network driver to allow LAPB over Ethernet. + * + * This driver can use any ethernet destination address, and can be + * limited to accept frames from one dedicated ethernet card only. + * + * History + * LAPBETH 001 Jonathan Naylor Cloned from bpqether.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 "); +MODULE_DESCRIPTION("The unofficial LAPB over Ethernet driver"); + +int init_module(void) +{ + return lapbeth_init(); +} + +void cleanup_module(void) +{ + struct lapbethdev *lapbeth; + + dev_remove_pack(&lapbeth_packet_type); + + unregister_netdevice_notifier(&lapbeth_dev_notifier); + + for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth->next) + unregister_netdev(&lapbeth->axdev); +} +#endif diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/sbni.c linux/drivers/net/wan/sbni.c --- v2.3.20/linux/drivers/net/wan/sbni.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/sbni.c Mon Oct 11 10:13:25 1999 @@ -0,0 +1,1533 @@ +/* + * Driver for Granch SBNI-12 leased line network adapters. + * + * Copyright 1997 - 1999, Granch ltd. + * Written 1999 by Yaroslav Polyakov (xenon@granch.ru). + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + * // Whole developers team: + * // Yaroslav Polyakov (xenon@granch.ru) + * // - main developer of this version + * // Alexey Zverev (zverev@granch.ru) + * // - previous SBNI driver for linux + * // Alexey Chirkov (chirkov@granch.ru) + * // - all the hardware work and consulting + * // Max Khon (max@iclub.nsu.ru) + * // - first SBNI driver for linux + * // -------------------------------------------- + * // also I thank: + * // Max Krasnyansky (max@uznet.net) + * // - for bug hunting and many ideas + * // Alan Cox (Alan.Cox@linux.org) + * // - for consulting in some hardcore questions + * // Donald Becker (becker@cesdis.gsfc.nasa.gov) + * // - for pretty nice skeleton + * + * More info and useful utilities to work w/ SBNI you can find at + * http://www.granch.ru. + * + * 3.0.0 = Initial Revision, Yaroslav Polyakov (24 Feb 1999) + * - added pre-calculation for CRC, fixed bug with "len-2" frames, + * - removed outbound fragmentation (MTU=1000), written CRC-calculation + * - on asm, added work with hard_headers and now we have our own cache + * - for them, optionally supported word-interchange on some chipsets, + * - something else I cant remember ;) + * + * 3.0.1 = just fixed some bugs (14 apr 1999). + * - fixed statistical tx bug + * - fixed wrong creation dates (1998 -> 1999) in driver source code ;) + * - fixed source address bug. + * - fixed permanent nirvana bug + * + * 3.1.0 = (Katyusha) (26 apr 1999) + * - Added balancing feature + * + * 3.1.1 = (Medea) (5 aug 1999) + * - Fixed mac.raw bug + * - Thanks to tolix@olviko.ru and + * - to Barnaul Brewery, producers of my favorite beer "Medea". + * + * + */ + + +#undef GOODBUS16 +#define CRCASM +#define KATYUSHA + +#include + +#if LINUX_VERSION_CODE >=0x020200 +#define v22 +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +#include +#include +#include +#include +#include /* for CONFIG_INET. do we need this?*/ + +#include + + + +#ifdef v22 +#include +#include +#endif + +#include "sbni.h" + + +static const char *version = +"sbni.c: ver. 3.1.1 Medea 5 Aug 1999 Yaroslav Polyakov (xenon@granch.ru)\n"; + +int sbni_probe(struct net_device *dev); +static int sbni_probe1(struct net_device *dev, int ioaddr); +static int sbni_open(struct net_device *dev); +static int sbni_start_xmit(struct sk_buff *skb, struct net_device *dev); +static void sbni_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static int sbni_close(struct net_device *dev); +static void sbni_drop_tx_queue(struct net_device *dev); +static struct enet_statistics *sbni_get_stats(struct net_device *dev); +void card_start(struct net_device *dev); +static inline unsigned short sbni_recv(struct net_device *dev); +void change_level(struct net_device *dev); +static inline void sbni_xmit(struct net_device *dev); +static inline void sbni_get_packet(struct net_device* dev); +static void sbni_watchdog(unsigned long arg); +static void set_multicast_list(struct net_device *dev); +static int sbni_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); +static int sbni_set_mac_address(struct net_device *dev, void *addr); +unsigned long calc_crc(char *mem, int len, unsigned initial); +void sbni_nirvana(struct net_device *dev); +static int sbni_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, + void *daddr, void *saddr, unsigned len); + +static int sbni_rebuild_header(struct sk_buff *skb); +static int sbni_header_cache(struct neighbour *neigh, struct hh_cache *hh); + +static inline void sbni_outs(int port, void *data, int len); +static inline void sbni_ins(int port, void *data, int len); + + + +#define SIZE_OF_TIMEOUT_RXL_TAB 4 +static u_char timeout_rxl_tab[] = { + 0x03, 0x05, 0x08, 0x0b +}; + +static u_char rxl_tab[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, + 0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f +}; + +/* A zero-terminated list of I/O addresses to be probed */ +static unsigned int netcard_portlist[] = { + 0x210, 0x2c0, 0x2d0, 0x2f0, 0x220, 0x230, 0x240, 0x250, + 0x260, 0x290, 0x2a0, 0x2b0, 0x224, 0x234, 0x244, 0x254, + 0x264, 0x294, 0x2a4, 0x2b4, 0}; + +static unsigned char magic_reply[] = { + 0x5a,0x06,0x30,0x00,0x00,0x50,0x65,0x44,0x20 +}; + +static int def_baud = DEF_RATE; +static int def_rxl = DEF_RXL_DELTA; +static long def_mac = 0; + + +/* + * CRC-32 stuff + */ + +#define CRC32(c,crc) (crc32tab[((size_t)(crc) ^ (c)) & 0xff] ^ (((crc) >> 8) & 0x00FFFFFF)) +/* CRC generator 0xEDB88320 */ +/* CRC remainder 0x2144DF1C */ +/* CRC initial value 0x00000000 */ +#define CRC32_REMAINDER 0x2144DF1C +#define CRC32_INITIAL 0x00000000 + +static unsigned long crc32tab[] = { + 0xD202EF8D, 0xA505DF1B, 0x3C0C8EA1, 0x4B0BBE37, + 0xD56F2B94, 0xA2681B02, 0x3B614AB8, 0x4C667A2E, + 0xDCD967BF, 0xABDE5729, 0x32D70693, 0x45D03605, + 0xDBB4A3A6, 0xACB39330, 0x35BAC28A, 0x42BDF21C, + 0xCFB5FFE9, 0xB8B2CF7F, 0x21BB9EC5, 0x56BCAE53, + 0xC8D83BF0, 0xBFDF0B66, 0x26D65ADC, 0x51D16A4A, + 0xC16E77DB, 0xB669474D, 0x2F6016F7, 0x58672661, + 0xC603B3C2, 0xB1048354, 0x280DD2EE, 0x5F0AE278, + 0xE96CCF45, 0x9E6BFFD3, 0x0762AE69, 0x70659EFF, + 0xEE010B5C, 0x99063BCA, 0x000F6A70, 0x77085AE6, + 0xE7B74777, 0x90B077E1, 0x09B9265B, 0x7EBE16CD, + 0xE0DA836E, 0x97DDB3F8, 0x0ED4E242, 0x79D3D2D4, + 0xF4DBDF21, 0x83DCEFB7, 0x1AD5BE0D, 0x6DD28E9B, + 0xF3B61B38, 0x84B12BAE, 0x1DB87A14, 0x6ABF4A82, + 0xFA005713, 0x8D076785, 0x140E363F, 0x630906A9, + 0xFD6D930A, 0x8A6AA39C, 0x1363F226, 0x6464C2B0, + 0xA4DEAE1D, 0xD3D99E8B, 0x4AD0CF31, 0x3DD7FFA7, + 0xA3B36A04, 0xD4B45A92, 0x4DBD0B28, 0x3ABA3BBE, + 0xAA05262F, 0xDD0216B9, 0x440B4703, 0x330C7795, + 0xAD68E236, 0xDA6FD2A0, 0x4366831A, 0x3461B38C, + 0xB969BE79, 0xCE6E8EEF, 0x5767DF55, 0x2060EFC3, + 0xBE047A60, 0xC9034AF6, 0x500A1B4C, 0x270D2BDA, + 0xB7B2364B, 0xC0B506DD, 0x59BC5767, 0x2EBB67F1, + 0xB0DFF252, 0xC7D8C2C4, 0x5ED1937E, 0x29D6A3E8, + 0x9FB08ED5, 0xE8B7BE43, 0x71BEEFF9, 0x06B9DF6F, + 0x98DD4ACC, 0xEFDA7A5A, 0x76D32BE0, 0x01D41B76, + 0x916B06E7, 0xE66C3671, 0x7F6567CB, 0x0862575D, + 0x9606C2FE, 0xE101F268, 0x7808A3D2, 0x0F0F9344, + 0x82079EB1, 0xF500AE27, 0x6C09FF9D, 0x1B0ECF0B, + 0x856A5AA8, 0xF26D6A3E, 0x6B643B84, 0x1C630B12, + 0x8CDC1683, 0xFBDB2615, 0x62D277AF, 0x15D54739, + 0x8BB1D29A, 0xFCB6E20C, 0x65BFB3B6, 0x12B88320, + 0x3FBA6CAD, 0x48BD5C3B, 0xD1B40D81, 0xA6B33D17, + 0x38D7A8B4, 0x4FD09822, 0xD6D9C998, 0xA1DEF90E, + 0x3161E49F, 0x4666D409, 0xDF6F85B3, 0xA868B525, + 0x360C2086, 0x410B1010, 0xD80241AA, 0xAF05713C, + 0x220D7CC9, 0x550A4C5F, 0xCC031DE5, 0xBB042D73, + 0x2560B8D0, 0x52678846, 0xCB6ED9FC, 0xBC69E96A, + 0x2CD6F4FB, 0x5BD1C46D, 0xC2D895D7, 0xB5DFA541, + 0x2BBB30E2, 0x5CBC0074, 0xC5B551CE, 0xB2B26158, + 0x04D44C65, 0x73D37CF3, 0xEADA2D49, 0x9DDD1DDF, + 0x03B9887C, 0x74BEB8EA, 0xEDB7E950, 0x9AB0D9C6, + 0x0A0FC457, 0x7D08F4C1, 0xE401A57B, 0x930695ED, + 0x0D62004E, 0x7A6530D8, 0xE36C6162, 0x946B51F4, + 0x19635C01, 0x6E646C97, 0xF76D3D2D, 0x806A0DBB, + 0x1E0E9818, 0x6909A88E, 0xF000F934, 0x8707C9A2, + 0x17B8D433, 0x60BFE4A5, 0xF9B6B51F, 0x8EB18589, + 0x10D5102A, 0x67D220BC, 0xFEDB7106, 0x89DC4190, + 0x49662D3D, 0x3E611DAB, 0xA7684C11, 0xD06F7C87, + 0x4E0BE924, 0x390CD9B2, 0xA0058808, 0xD702B89E, + 0x47BDA50F, 0x30BA9599, 0xA9B3C423, 0xDEB4F4B5, + 0x40D06116, 0x37D75180, 0xAEDE003A, 0xD9D930AC, + 0x54D13D59, 0x23D60DCF, 0xBADF5C75, 0xCDD86CE3, + 0x53BCF940, 0x24BBC9D6, 0xBDB2986C, 0xCAB5A8FA, + 0x5A0AB56B, 0x2D0D85FD, 0xB404D447, 0xC303E4D1, + 0x5D677172, 0x2A6041E4, 0xB369105E, 0xC46E20C8, + 0x72080DF5, 0x050F3D63, 0x9C066CD9, 0xEB015C4F, + 0x7565C9EC, 0x0262F97A, 0x9B6BA8C0, 0xEC6C9856, + 0x7CD385C7, 0x0BD4B551, 0x92DDE4EB, 0xE5DAD47D, + 0x7BBE41DE, 0x0CB97148, 0x95B020F2, 0xE2B71064, + 0x6FBF1D91, 0x18B82D07, 0x81B17CBD, 0xF6B64C2B, + 0x68D2D988, 0x1FD5E91E, 0x86DCB8A4, 0xF1DB8832, + 0x616495A3, 0x1663A535, 0x8F6AF48F, 0xF86DC419, + 0x660951BA, 0x110E612C, 0x88073096, 0xFF000000 +}; + +static inline void sbni_outs(int port, void *data, int len) +{ +#ifdef GOODBUS16 + outsw(port,data,len/2); + if(len & 1) + outb(((char*)data)[len - 1],port); +#else + outsb(port,data,len); +#endif +} + +static inline void sbni_ins(int port, void *data, int len) +{ +#ifdef GOODBUS16 + insw(port,data,len/2); + if(len & 1) + ((char*)data)[len - 1] = inb(port); +#else + insb(port,data,len); +#endif +} + + +static int sbni_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, + void *daddr, void *saddr, unsigned len) +{ + struct sbni_hard_header *hh = (struct sbni_hard_header *) + skb_push(skb, sizeof(struct sbni_hard_header)); + + + if(type!=ETH_P_802_3) + hh->h_proto = htons(type); + else + hh->h_proto = htons(len); + + if(saddr) + memcpy(hh->h_source,saddr,dev->addr_len); + else + memcpy(hh->h_source,dev->dev_addr,dev->addr_len); + + if(daddr) + { + memcpy(hh->h_dest,daddr,dev->addr_len); + return dev->hard_header_len; + } + return -dev->hard_header_len; +} + + +int sbni_header_cache(struct neighbour *neigh, struct hh_cache *hh) +{ + unsigned short type = hh->hh_type; + struct sbni_hard_header *sbni = (struct sbni_hard_header*) + (((u8*)hh->hh_data) - 8); + struct net_device *dev = neigh->dev; + + + if (type == __constant_htons(ETH_P_802_3)) + return -1; + + sbni->h_proto = type; + memcpy(sbni->h_source, dev->dev_addr, dev->addr_len); + memcpy(sbni->h_dest, neigh->ha, dev->addr_len); + return 0; +} + +static int sbni_rebuild_header(struct sk_buff *skb) +{ + struct sbni_hard_header *hh = (struct sbni_hard_header *)skb; + /* + * Only ARP/IP is currently supported + */ + + /* + * Try to get ARP to resolve the header. + */ + +#ifdef CONFIG_INET + return arp_find((unsigned char*)hh->h_dest, skb)? 1 : 0; +#else + return 0; +#endif +} + +static void sbni_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr) +{ + memcpy(((u8*)hh->hh_data) + 2, haddr, dev->addr_len); +} + + + +#ifdef HAVE_DEVLIST +struct netdev_entry sbni_drv = { + "sbni", sbni_probe1, SBNI_IO_EXTENT, netcard_portlist +}; + +#else + +int __init sbni_probe(struct net_device *dev) +{ + int i; + int base_addr = dev ? dev->base_addr : 0; + + DP( printk("%s: sbni_probe\n", dev->name); ) + + if(base_addr > 0x1ff) /* Check a single specified location. */ + return sbni_probe1(dev, base_addr); + else if(base_addr != 0) /* Don't probe at all. */ + return ENXIO; + for(i = 0; (base_addr = netcard_portlist[i]); i++) + { + if(!check_region(base_addr, SBNI_IO_EXTENT) && base_addr != 1) + { + /* Lock this address, or later we'll try it again */ + netcard_portlist[i] = 1; + if(sbni_probe1(dev, base_addr) == 0) + return 0; + } + } + return ENODEV; +} + +#endif /* have devlist*/ + +/* + * The actual probe. + */ + +/* + Valid combinations in CSR0 (for probing): + + VALID_DECODER 0000,0011,1011,1010 + + ; 0 ; - + TR_REQ ; 1 ; + + TR_RDY ; 2 ; - + TR_RDY TR_REQ ; 3 ; + + BU_EMP ; 4 ; + + BU_EMP TR_REQ ; 5 ; + + BU_EMP TR_RDY ; 6 ; - + BU_EMP TR_RDY TR_REQ ; 7 ; + + RC_RDY ; 8 ; + + RC_RDY TR_REQ ; 9 ; + + RC_RDY TR_RDY ; 10 ; - + RC_RDY TR_RDY TR_REQ ; 11 ; - + RC_RDY BU_EMP ; 12 ; - + RC_RDY BU_EMP TR_REQ ; 13 ; - + RC_RDY BU_EMP TR_RDY ; 14 ; - + RC_RDY BU_EMP TR_RDY TR_REQ ; 15 ; - +*/ +#define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200) + +static int __init sbni_probe1(struct net_device *dev, int ioaddr) + +{ + int autoirq = 0; + int bad_card = 0; + unsigned char csr0; + struct net_local* lp; + static int version_printed = 0; + + DP( printk("%s: sbni_probe1 ioaddr=%d\n", dev->name, ioaddr); ) + + if(check_region(ioaddr, SBNI_IO_EXTENT) < 0) + return -ENODEV; + if(version_printed++ == 0) + printk(version); + + /* check for valid combination in CSR0 */ + csr0 = inb(ioaddr + CSR0); + if(csr0 == 0xff || csr0 == 0) + bad_card = 1; + else + { + csr0 &= ~EN_INT; + if(csr0 & BU_EMP) + csr0 |= EN_INT; + if((VALID_DECODER & (1 << (csr0 >> 4))) == 0) + bad_card = 1; + } + + if(bad_card) + return ENODEV; + else + outb(0, ioaddr + CSR0); + if(dev->irq < 2) + { + DP( printk("%s: autoprobing\n", dev->name); ); + autoirq_setup(5); + outb(EN_INT | TR_REQ, ioaddr + CSR0); + outb(PR_RES, ioaddr + CSR1); + autoirq = autoirq_report(5); + + if(autoirq == 0) + { + printk("sbni probe at %#x failed to detect IRQ line\n", ioaddr); + return EAGAIN; + } + } + /* clear FIFO buffer */ + outb(0, ioaddr + CSR0); + + if(autoirq) + dev->irq = autoirq; + + { + int irqval=request_irq(dev->irq, sbni_interrupt, 0, dev->name, dev); + if (irqval) + { + printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval); + return EAGAIN; + } + } + + /* + * Initialize the device structure. + */ + + dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + if(dev->priv == NULL) + { + DP( printk("%s: cannot allocate memory\n", dev->name); ) + return -ENOMEM; + } + + memset(dev->priv, 0, sizeof(struct net_local)); + dev->base_addr = ioaddr; + request_region(ioaddr, SBNI_IO_EXTENT, "sbni"); + + /* + * generate Ethernet address (0x00ff01xxxxxx) + */ + + *(u16*)dev->dev_addr = htons(0x00ff); + *(u32*)(dev->dev_addr+2) = htonl(((def_mac ? def_mac : (u32) dev->priv) & 0x00ffffff) | 0x01000000); + + lp = dev->priv; + if(def_rxl < 0) + { + /* autodetect receive level */ + lp->rxl_curr = 0xf; + lp->rxl_delta = -1; + } else { + /* fixed receive level */ + lp->rxl_curr = def_rxl & 0xf; + lp->rxl_delta = 0; + } + lp->csr1.rxl = rxl_tab[lp->rxl_curr]; + lp->csr1.rate = def_baud & 3; + lp->frame_len = DEF_FRAME_LEN; + printk("%s: sbni adapter at %#lx, using %sIRQ %d, MAC: 00:ff:01:%x:%x:%x\n", + dev->name, dev->base_addr, autoirq ? "auto":"assigned ", dev->irq, + *(unsigned char*)(dev->dev_addr+3), + *(unsigned char*)(dev->dev_addr+4), + *(unsigned char*)(dev->dev_addr+5) + ); + + printk("%s: receive level: ", dev->name); + if(lp->rxl_delta == 0) + printk ("%#1x (fixed)", lp->rxl_curr); + else + printk ("autodetect"); + printk(", baud rate: %u\n", (unsigned)lp->csr1.rate); + + /* + * The SBNI-specific entries in the device structure. + */ + dev->open = &sbni_open; + dev->hard_start_xmit = &sbni_start_xmit; + dev->stop = &sbni_close; + dev->get_stats = &sbni_get_stats; + dev->set_multicast_list = &set_multicast_list; + dev->set_mac_address = &sbni_set_mac_address; + dev->do_ioctl = &sbni_ioctl; + + /* + * Setup the generic properties + */ + + ether_setup(dev); + + dev->hard_header = sbni_header; + dev->hard_header_len = sizeof(struct sbni_hard_header); + dev->rebuild_header=sbni_rebuild_header; + dev->mtu = DEF_FRAME_LEN; + + dev->hard_header_cache = sbni_header_cache; + dev->header_cache_update = sbni_header_cache_update; + + lp->m=dev; + lp->me=dev; + lp->next_lp=NULL; + + return 0; +} + +/* + * Open/initialize the board. + */ + +static int sbni_open(struct net_device *dev) +{ + struct net_local* lp = (struct net_local*)dev->priv; + struct timer_list* watchdog = &lp->watchdog; + + + DP( printk("%s: sbni_open\n", dev->name); ) + + cli(); + lp->currframe = NULL; + + card_start(dev); + dev->start = 1; + /* set timer watchdog */ + init_timer(watchdog); + watchdog->expires = jiffies + SBNI_TIMEOUT; + watchdog->data = (unsigned long)dev; + watchdog->function = sbni_watchdog; + add_timer(watchdog); + DP( printk("%s: sbni timer watchdog initialized\n", dev->name); ); + + sti(); + + MOD_INC_USE_COUNT; + return 0; +} + +static int sbni_close(struct net_device *dev) +{ + int ioaddr = dev->base_addr; + struct net_local* lp = (struct net_local*) dev->priv; + struct timer_list* watchdog = &lp->watchdog; + + + DP( printk("%s: sbni_close\n", dev->name); ) + + cli(); + + sbni_drop_tx_queue(dev); + + dev->tbusy = 1; + dev->start = 0; + + del_timer(watchdog); + + outb(0, ioaddr + CSR0); + sti(); + + MOD_DEC_USE_COUNT; + return 0; +} + +static int sbni_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct net_local *lp = (struct net_local*)dev->priv; + struct sbni_hard_header *hh=(struct sbni_hard_header *)skb->data; + +#ifdef KATYUSHA + struct net_local *nl; + int stop; +#endif + + DP( printk("%s: sbni_start_xmit In \n", dev->name); ); + + + if(lp->me != dev) + panic("sbni: lp->me != dev !!!\nMail to developer (xenon@granch.ru) if you noticed this error\n"); + + if(dev->interrupt) + { + DP( printk("sbni_xmit_start: interrupt\n"); ) + /* May be unloading, don't stamp on */ + return 1; /* the packet buffer this time */ + } + + hh->number = 1; + hh->reserv = 0; + + hh->packetlen = (skb->len - sizeof (unsigned short) - + (sizeof(struct sbni_hard_header) - SBNI_HH_SZ)) + | PACKET_SEND_OK | PACKET_FIRST_FRAME; + + /* we should use hairy method to calculate crc because of extra bytes are + livin between hard header and data*/ + hh->crc = calc_crc((void*)&hh->packetlen, SBNI_HH_SZ - sizeof(unsigned), CRC32_INITIAL); + hh->crc = calc_crc(skb->data + sizeof(struct sbni_hard_header), + skb->len - sizeof(struct sbni_hard_header), + hh->crc); + +#ifdef KATYUSHA + /* looking for first idle device */ + for (stop=0,nl=lp; nl && !stop; nl=nl->next_lp) + { + if((!nl->currframe) && (nl->carrier)) /* if idle */ + { + skb->dev = lp->me; + nl->currframe = skb; + /* set request for transmit */ + outb(inb(nl->me->base_addr + CSR0) | TR_REQ, + nl->me->base_addr + CSR0); + stop=1; + } + } + + if(!stop) /* we havent found any idle.*/ + { + skb_queue_tail(&lp->queue,skb); + outb(inb(dev->base_addr + CSR0) | TR_REQ, dev->base_addr + CSR0); + + } +#else + if (lp->currframe || 1) + { + skb_queue_tail(&lp->queue,skb); + + } + else + { + lp->currframe = skb; + } + /* set request for transmit */ + outb(inb(dev->base_addr + CSR0) | TR_REQ, dev->base_addr + CSR0); +#endif + return 0; +} + +void card_start(struct net_device *dev) +{ + struct net_local *lp = (struct net_local*)dev->priv; + + DP( printk("%s: card_start\n",dev->name); ) + lp->wait_frame_number = 0; + lp->inppos = lp->outpos = 0; + lp->eth_trans_buffer_len = 0; + lp->tr_err = TR_ERROR_COUNT; + lp->last_receive_OK = FALSE; + lp->tr_resend = FALSE; + lp->timer_ticks = CHANGE_LEVEL_START_TICKS; + lp->timeout_rxl = 0; + + lp->waitack=0; + skb_queue_head_init(&lp->queue); + sbni_drop_tx_queue(dev); + dev->tbusy = 0; + + dev->interrupt = 0; + /* Reset the card and set start parameters */ + outb(PR_RES | *(char*)&lp->csr1, dev->base_addr + CSR1); + outb(EN_INT, dev->base_addr + CSR0); +} + +void sbni_nirvana(struct net_device *dev) +{ + sbni_outs(dev->base_addr+DAT,magic_reply,9); +} + +static inline unsigned short sbni_recv(struct net_device *dev) +{ + struct net_local *lp = (struct net_local*)dev->priv; + unsigned long crc; + unsigned short packetlen = 0; + unsigned short packetinf, packetfirst, receiveframeresend; + unsigned char current_frame; + unsigned int i, j; + unsigned char delme,rcv_res=RCV_WR; + + lp->in_stats.all_rx_number++; + + if((delme=inb(dev->base_addr + DAT)) == SBNI_SIG) + { + crc = CRC32_INITIAL; + *(((unsigned char *)&packetlen) + 0) = inb(dev->base_addr + DAT); + crc = CRC32(*(((unsigned char *)&packetlen) + 0), crc); + *(((unsigned char *)&packetlen) + 1) = inb(dev->base_addr + DAT); + crc = CRC32(*(((unsigned char *)&packetlen) + 1), crc); + packetinf = packetlen & PACKET_INF_MASK; + packetfirst = packetlen & PACKET_FIRST_FRAME; + receiveframeresend = packetlen & RECEIVE_FRAME_RESEND; + packetlen = packetlen & PACKET_LEN_MASK; + + + if((packetlen <= SB_MAX_BUFFER_ARRAY - 3) && (packetlen >= 6)) + { + /* read frame number */ + current_frame = inb(dev->base_addr + DAT); + crc = CRC32(current_frame, crc); + /* read HandShake counter */ + lp->HSCounter = inb(dev->base_addr + DAT); + crc = CRC32(lp->HSCounter, crc); + packetlen -= 2; + + sbni_ins(dev->base_addr + DAT, lp->eth_rcv_buffer + lp->inppos, packetlen); + + for(i = lp->inppos; i < (packetlen + lp->inppos); i++) + { + crc = CRC32(lp->eth_rcv_buffer[i], crc); + } + + if(crc == CRC32_REMAINDER) + { + if(packetlen > 4) + rcv_res=RCV_OK; + else if(packetlen == 4) + rcv_res=RCV_NO; + + if(lp->waitack && packetinf == PACKET_RESEND) + lp->in_stats.resend_tx_number++; + + + switch(packetinf) + { + case PACKET_SEND_OK: + { + lp->tr_err = TR_ERROR_COUNT; + lp->tr_resend = FALSE; + /* if(lp->trans_frame_number){ */ + lp->outpos += lp->realframelen; + + /* SendComplete + * not supported + */ + DP( printk("%s: sbni_recv SendComplete\n",dev->name); ); + /* + * We sucessfully sent current packet + */ + + if(lp->waitack) + { + dev_kfree_skb(lp->currframe); + lp->stats.tx_packets++; +#ifdef KATYUSHA + lp->currframe=skb_dequeue(&(((struct net_local*) (lp->m->priv))->queue)); +#else + lp->currframe=skb_dequeue(&lp->queue); +#endif + lp->in_stats.all_tx_number++; + lp->waitack=0; + } + + /* + * reset output active flags + */ + dev->tbusy = 0; + mark_bh(NET_BH); + /*} if */ + } + case PACKET_RESEND: + { + if(lp->tr_err) /**/ + lp->tr_err--; + if(lp->ok_curr < 0xffffffff) + lp->ok_curr++; + if(packetlen > 4 && !(lp->last_receive_OK && receiveframeresend)) + { + if(packetfirst) + { + if(lp->wait_frame_number) + { + for(i = lp->inppos, j = 0; + i < (lp->inppos + packetlen - 4); + i++, j++) + lp->eth_rcv_buffer[j] = lp->eth_rcv_buffer[i]; + } + lp->wait_frame_number = current_frame; + lp->inppos = 0; + } + if(current_frame == lp->wait_frame_number) + { + lp->inppos += (packetlen - 4); + if(lp->wait_frame_number == 1) + { + sbni_get_packet(dev); + lp->inppos = 0; + } + lp->wait_frame_number--; + } + } + lp->last_receive_OK = TRUE; + break; + } + default: + break; + } + } + else + { + DP(printk("%s: bad CRC32\n",dev->name)); + change_level(dev); + } + } + else + { + DP(printk("%s: bad len\n ",dev->name)); + change_level(dev); + lp->stats.rx_over_errors++; + } + } + else + { + DP(printk("%s: bad sig\n",dev->name)); + change_level(dev); + } + outb(inb(dev->base_addr + CSR0) ^ CT_ZER, dev->base_addr + CSR0); + return (rcv_res); +} + +void change_level(struct net_device *dev) +{ + struct net_local *lp = (struct net_local*)dev->priv; + + lp->in_stats.bad_rx_number++; + lp->stats.tx_errors++; + if(lp->rxl_delta == 0) + return; + /* + * set new rxl_delta value + */ + if(lp->rxl_curr == 0) + lp->rxl_delta = 1; + else if(lp->rxl_curr == 0xf) + lp->rxl_delta = -1; + else if(lp->ok_curr < lp->ok_prev) + lp->rxl_delta = -lp->rxl_delta; + /* + * set new rxl_curr value + */ + lp->csr1.rxl = rxl_tab[lp->rxl_curr += lp->rxl_delta]; + outb(*(char*)&lp->csr1, dev->base_addr + CSR1); + + + /* + * update ok_prev/ok_curr counters + */ + lp->ok_prev = lp->ok_curr; + lp->ok_curr = 0; + + DP( printk("%s: receive error, rxl_curr = %d, rxl_delta = %d\n",\ + dev->name,lp->rxl_curr, lp->rxl_delta); ) + +} + +static inline void sbni_xmit(struct net_device *dev) +{ + struct net_local* lp = (struct net_local *)dev->priv; + struct sk_buff *skb; + + skb=lp->currframe; + + DP( printk("%s: sbni_xmit CSR0=%02x\n",dev->name, (unsigned char)inb(dev->base_addr + CSR0)); ); + + /* push signature*/ + outb(SBNI_SIG, dev->base_addr + DAT); + + /* push frame w/o crc [HAiRY]*/ + sbni_outs(dev->base_addr + DAT, + &((struct sbni_hard_header *)(skb->data))->packetlen, + SBNI_HH_SZ - sizeof(unsigned)); + + sbni_outs(dev->base_addr + DAT, + skb->data + sizeof(struct sbni_hard_header), + skb->len - sizeof(struct sbni_hard_header)); /* ÕÓÐÅÅÍ ÅÝÅ */ + + /* push crc */ + sbni_outs(dev->base_addr + DAT, skb->data, sizeof(unsigned)); + + lp->waitack=1; +} + +/* + * The typical workload of the driver: + * Handle the ether interface interrupts. + */ +static void sbni_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct net_local* lp; + u_char csr0; + unsigned short rcv_res = RCV_NO; + + + if(dev == NULL || dev->irq != irq) + { + printk("sbni: irq %d for unknown device\n", irq); + return; + } + + if(dev->interrupt) + { + printk("%s: Reentering the interrupt driver!\n", dev->name); + return; + } + dev->interrupt = 1; + + csr0 = inb(dev->base_addr + CSR0); + DP( printk("%s: entering interrupt handler, CSR0 = %02x\n", dev->name, csr0); ) + + lp=dev->priv; + + if(!lp->carrier) + lp->carrier=1; + + /* + * Disable adapter interrupts + */ + outb((csr0 & ~EN_INT) | TR_REQ, dev->base_addr + CSR0); + lp->timer_ticks = CHANGE_LEVEL_START_TICKS; + csr0 = inb(dev->base_addr + CSR0); + + if(csr0 & (TR_RDY | RC_RDY)) + { + if(csr0 & RC_RDY) + rcv_res = sbni_recv(dev); + + if((lp->currframe) && (rcv_res != RCV_WR)) + sbni_xmit(dev); + else if (rcv_res == RCV_OK) + sbni_nirvana(dev); + + csr0 = inb(dev->base_addr + CSR0); + DP( printk("%s: CSR0 = %02x\n",dev->name, (u_int)csr0); ); + } + + + DP( printk("%s: leaving interrupt handler, CSR0 = %02x\n",dev->name, csr0 | EN_INT); ); + + /* here we should send pong */ + outb(inb(dev->base_addr+CSR0) & ~TR_REQ, dev->base_addr + CSR0); + if(lp->currframe) + outb(inb(dev->base_addr+CSR0) | TR_REQ, dev->base_addr + CSR0); + else + csr0 = inb(dev->base_addr + CSR0); + + /* + * Enable adapter interrupts + */ + + outb(csr0 | EN_INT, dev->base_addr + CSR0); + dev->interrupt = 0; +} + +static struct enet_statistics *sbni_get_stats(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + return &lp->stats; +} + +static inline void sbni_get_packet(struct net_device* dev) +{ + struct net_local* lp = (struct net_local*)dev->priv; + struct sk_buff* skb; + unsigned char *rawp; + + + + skb = dev_alloc_skb(lp->inppos - ETH_HLEN + sizeof(struct sbni_hard_header)); + + if(skb == NULL) + { + DP( printk("%s: Memory squeeze, dropping packet.\n", dev->name); ) + lp->stats.rx_dropped++; + return; + } else { +#ifdef KATYUSHA + skb->dev = lp->m; +#else + skb->dev = dev; +#endif + memcpy((unsigned char*)skb_put(skb, lp->inppos + 8)+8, + lp->eth_rcv_buffer, + lp->inppos); + + + skb->mac.raw = skb->data + 8; + + if((*(char*)lp->eth_rcv_buffer) & 1) + { + if(memcmp(lp->eth_rcv_buffer,dev->broadcast, ETH_ALEN)==0) + skb->pkt_type=PACKET_BROADCAST; + else + skb->pkt_type=PACKET_MULTICAST; + } + else if(dev->flags&(IFF_PROMISC|IFF_ALLMULTI)) + { + if(memcmp(lp->eth_rcv_buffer,dev->dev_addr, ETH_ALEN)) + skb->pkt_type=PACKET_OTHERHOST; + } + + if( htons(*((unsigned short*)(&lp->eth_rcv_buffer[2*ETH_ALEN]))) >= 1536) + skb->protocol = *((unsigned short*)(&lp->eth_rcv_buffer[2*ETH_ALEN])); + else + { + rawp = (unsigned char*)(&lp->eth_rcv_buffer[2*ETH_ALEN]); + if (*(unsigned short *)rawp == 0xFFFF) + skb->protocol=htons(ETH_P_802_3); + else + skb->protocol=htons(ETH_P_802_2); + } + + + skb_pull(skb,SBNI_HH_SZ); + + netif_rx(skb); + lp->stats.rx_packets++; + } + return; +} + +static void sbni_watchdog(unsigned long arg) +{ + struct net_device* dev = (struct net_device*)arg; + struct net_local* lp = (struct net_local *)dev->priv; + u_char csr0; + + + + DP( printk("%s: watchdog start\n",dev->name); ) + /* + * if no pong received and transmission is not in progress + * then assume error + */ + cli(); + csr0 = inb(dev->base_addr + CSR0); + if(csr0 & (RC_CHK | TR_REQ)) + { + if(lp->timer_ticks) + { + if(csr0 & (RC_RDY | BU_EMP)) + { + lp->timer_ticks--; + } + } + else + { + if(lp->rxl_delta) + { + lp->ok_prev = lp->ok_curr; + lp->ok_curr = 0; + lp->rxl_curr = timeout_rxl_tab[lp->timeout_rxl]; + lp->timeout_rxl++; + if(lp->timeout_rxl > SIZE_OF_TIMEOUT_RXL_TAB - 1) + lp->timeout_rxl = 0; + lp->csr1.rxl = rxl_tab[lp->rxl_curr]; + /* + * update ok_prev/ok_curr counters + */ + lp->ok_prev = lp->ok_curr; + lp->ok_curr = 0; + } + if(lp->tr_err) + lp->tr_err--; + else + { + /* Drop the queue of tx packets */ + sbni_drop_tx_queue(dev); + lp->carrier=0; + } + + /* + * send pong + */ + + csr0 = inb(dev->base_addr + CSR0); + outb(csr0 & ~TR_REQ, dev->base_addr + CSR0); + outb(*(char*)(&lp->csr1) | PR_RES, dev->base_addr + CSR1); + lp->in_stats.timeout_number++; + } + } + sti(); + outb(csr0 | RC_CHK, dev->base_addr + CSR0); + if(dev->start) + { + struct timer_list* watchdog = &lp->watchdog; + init_timer(watchdog); + watchdog->expires = jiffies + SBNI_TIMEOUT; + watchdog->data = arg; + watchdog->function = sbni_watchdog; + add_timer(watchdog); + } +} + +static void sbni_drop_tx_queue(struct net_device *dev) +{ + struct net_local* lp = (struct net_local *)dev->priv,*nl; + struct sk_buff *tmp; + + /* first of all, we should try to gift our packets to another interface */ + + nl=(struct net_local *)lp->m->priv; + if(nl==lp) + nl=lp->next_lp; + + if(nl) + { + /* we found device*/ + if(lp->currframe) + { + if(!nl->currframe) + { + nl->currframe=lp->currframe; + } + else + { + skb_queue_head(&((struct net_local*)(lp->m->priv))->queue,lp->currframe); + } + } + lp->currframe=NULL; + + if(!nl->currframe) + nl->currframe=skb_dequeue(&(((struct net_local*)(lp->m->priv))->queue)); + + /* set request for transmit */ + outb(inb(nl->me->base_addr + CSR0) | TR_REQ, nl->me->base_addr + CSR0); + + } + else + { + /* *sigh*, we should forget this packets */ + nl=lp->m->priv; + + while((tmp = skb_dequeue(&nl->queue)) != NULL) + { + dev_kfree_skb(tmp); + lp->stats.tx_packets++; + } + + if (lp->currframe) + { + dev_kfree_skb(lp->currframe); + lp->currframe = NULL; + lp->stats.tx_packets++; + } + } + lp->waitack=0; + dev->tbusy = 0; + + mark_bh(NET_BH); + DP( printk("%s: queue dropping stoped\n",dev->name); ); +} + +/* + * Set or clear the multicast filter for this adaptor. + * num_addrs == -1 Promiscuous mode, receive all packets + * num_addrs == 0 Normal mode, clear multicast list + * num_addrs > 0 Multicast mode, receive normal and MC packets, + * and do best-effort filtering. + */ + +static void set_multicast_list(struct net_device *dev) +{ + /* + * always enabled promiscuous mode. + */ + return; +} + +static int sbni_set_mac_address(struct net_device *dev, void *addr) +{ + /* struct net_local *lp = (struct net_local *)dev->priv; */ + struct sockaddr *saddr = addr; + + if(dev->start) + { + /* Only possible while card isn't started */ + return -EBUSY; + } + memcpy(dev->dev_addr, saddr->sa_data, dev->addr_len); + return (0); +} + +static int sbni_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct net_local* lp = (struct net_local *)dev->priv,*tlp; + struct net_device *slave; + int error = 0; + char tmpstr[6]; + + + switch(cmd) + { + case SIOCDEVGETINSTATS: + { + struct sbni_in_stats *in_stats = (struct sbni_in_stats *)ifr->ifr_data; + DP( printk("%s: SIOCDEVGETINSTATS %08x\n",dev->name,(unsigned)in_stats);) + if(copy_to_user((void *)in_stats, (void *)(&(lp->in_stats)), sizeof(struct sbni_in_stats))) + return -EFAULT; + break; + } + case SIOCDEVRESINSTATS: + { + DP( printk("%s: SIOCDEVRESINSTATS\n",dev->name); ) + lp->in_stats.all_rx_number = 0; + lp->in_stats.bad_rx_number = 0; + lp->in_stats.timeout_number = 0; + lp->in_stats.all_tx_number = 0; + lp->in_stats.resend_tx_number = 0; + break; + } + case SIOCDEVGHWSTATE: + { + struct sbni_flags flags; + flags.rxl = lp->rxl_curr; + flags.rate = lp->csr1.rate; + flags.fixed_rxl = (lp->rxl_delta == 0); + flags.fixed_rate = 1; + ifr->ifr_data = *(caddr_t*)&flags; + DP( printk("%s: get flags (0x%02x)\n",dev->name, (unsigned char)ifr->ifr_data); ) + break; + } + case SIOCDEVSHWSTATE: + { + struct sbni_flags flags; + DP( printk("%s: SIOCDEVSHWSTATE flags=0x%02x\n",dev->name, (unsigned char)ifr->ifr_data); ) + /* root only */ + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + flags = *(struct sbni_flags*)&ifr->ifr_data; + if(flags.fixed_rxl) + { + lp->rxl_delta = 0; + lp->rxl_curr = flags.rxl; + } + else + { + lp->rxl_delta = DEF_RXL_DELTA; + lp->rxl_curr = DEF_RXL; + } + lp->csr1.rxl = rxl_tab[lp->rxl_curr]; + if(flags.fixed_rate) + lp->csr1.rate = flags.rate; + else + lp->csr1.rate = DEF_RATE; + /* + * Don't be afraid... + */ + outb(*(char*)(&lp->csr1) | PR_RES, dev->base_addr + CSR1); + + DP( printk("%s: set flags (0x%02x)\n receive level: %u, baud rate: %u\n",\ + dev->name, (unsigned char)ifr->ifr_data, (unsigned)lp->rxl_curr, (unsigned)lp->csr1.rate); ) + break; + } + + case SIOCDEVENSLAVE: + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if(copy_from_user( tmpstr, ifr->ifr_data, 6)) + return -EFAULT; + slave=dev_get(tmpstr); + if(!(slave && slave->flags & IFF_UP && dev->flags & IFF_UP)) + { + printk("%s: Both devices should be UP to enslave!\n",dev->name); + return -EINVAL; + } + + if(slave) + { + if(!((dev->flags & IFF_SLAVE) || (slave->flags & IFF_SLAVE))) + { + /* drop queue*/ + sbni_drop_tx_queue(slave); + slave->flags |= IFF_SLAVE; + ((struct net_local *)(slave->priv))->m=dev; + while(lp->next_lp) //tail it after last slave + lp=lp->next_lp; + lp->next_lp=slave->priv; + lp=(struct net_local *)dev->priv; + dev->flags |= IFF_MASTER; + } + else + { + printk("%s: one of devices is already slave!\n",dev->name); + return -EBUSY; + } + } + else + { + printk("%s: can't find device %s to enslave\n",dev->name,ifr->ifr_data); + return -ENOENT; + } + break; + + case SIOCDEVEMANSIPATE: + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + + if(dev->flags & IFF_SLAVE) + { + dev->flags &= ~IFF_SLAVE; + /* exclude us from masters slavelist*/ + for(tlp=lp->m->priv;tlp->next_lp!=lp && tlp->next_lp;tlp=tlp->next_lp); + if(tlp->next_lp) + { + tlp->next_lp = lp->next_lp; + if(!((struct net_local *)lp->m->priv)->next_lp) + { + lp->m->flags &= ~IFF_MASTER; + } + lp->next_lp=NULL; + lp->m=dev; + } + else + { + printk("%s: Ooops. drivers structure is mangled!\n",dev->name); + return -EIO; + } + } + else + { + printk("%s: isn't slave device!\n",dev->name); + return -EINVAL; + } + break; + + default: + DP( printk("%s: invalid ioctl: 0x%x\n",dev->name, cmd); ) + error = -EINVAL; + } + return (error); +} + + + +#ifdef CRCASM + +unsigned long calc_crc(char *mem, int len, unsigned initial) +{ + + __asm__ ( + "xorl %%eax,%%eax\n\t" + "1:\n\t" + "lodsb\n\t" + "xorb %%dl,%%al\n\t" + "shrl $8,%%edx\n\t" + "xorl (%%edi,%%eax,4),%%edx\n\t" + "loop 1b\n\t" + "movl %%edx,%%eax" + : + : "S" (mem), "D" (&crc32tab[0]), "c" (len), "d" (initial) + : "eax", "edx", "ecx" + ); + /* return crc; */ +} + +#else + +unsigned long calc_crc(char *mem, int len, unsigned initial) +{ + unsigned crc; + crc = initial; + + for(;len;mem++,len--) + { + crc = CRC32(*mem, crc); + } + return(crc); +} +#endif /* CRCASM */ +#ifdef MODULE + +static int io[SBNI_MAX_NUM_CARDS] = { 0 }; +static int irq[SBNI_MAX_NUM_CARDS] = { 0 }; +static int rxl[SBNI_MAX_NUM_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; +static int baud[SBNI_MAX_NUM_CARDS] = { 0 }; +static long mac[SBNI_MAX_NUM_CARDS] = { 0 }; + +#ifdef v22 +MODULE_PARM(io, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i"); +MODULE_PARM(irq, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i"); +MODULE_PARM(rxl, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i"); +MODULE_PARM(baud, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i"); +MODULE_PARM(mac, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i"); +#endif + + +static int sbniautodetect = -1; + +static struct net_device dev_sbni[SBNI_MAX_NUM_CARDS] = { + { + "sbni0", + 0, 0, 0, 0, /* memory */ + 0, 0, /* base, irq */ + 0, 0, 0, NULL, sbni_probe + }, + { + "sbni1", + 0, 0, 0, 0, /* memory */ + 0, 0, /* base, irq */ + 0, 0, 0, NULL, sbni_probe + }, + { + "sbni2", + 0, 0, 0, 0, /* memory */ + 0, 0, /* base, irq */ + 0, 0, 0, NULL, sbni_probe + }, + { + "sbni3", + 0, 0, 0, 0, /* memory */ + 0, 0, /* base, irq */ + 0, 0, 0, NULL, sbni_probe + }, + { + "sbni4", + 0, 0, 0, 0, /* memory */ + 0, 0, /* base, irq */ + 0, 0, 0, NULL, sbni_probe + }, + { + "sbni5", + 0, 0, 0, 0, /* memory */ + 0, 0, /* base, irq */ + 0, 0, 0, NULL, sbni_probe + }, + { + "sbni6", + 0, 0, 0, 0, /* memory */ + 0, 0, /* base, irq */ + 0, 0, 0, NULL, sbni_probe + }, + { + "sbni7", + 0, 0, 0, 0, /* memory */ + 0, 0, /* base, irq */ + 0, 0, 0, NULL, sbni_probe + } +}; + +int init_module(void) +{ + int devices = 0; + int installed = 0; + int i; + + /* My simple plug for this huge init_module. "XenON */ + + if(sbniautodetect != -1) + { + /* Autodetect mode */ + printk("sbni: Autodetect mode (not recommended!) ...\n"); + if(!sbniautodetect) + sbniautodetect=SBNI_MAX_NUM_CARDS; + printk("Trying to find %d SBNI cards...\n", sbniautodetect); + if(sbniautodetect > SBNI_MAX_NUM_CARDS) + { + sbniautodetect = SBNI_MAX_NUM_CARDS; + printk("sbni: You want to detect too many cards. Truncated to %d\n", SBNI_MAX_NUM_CARDS); + } + for(i = 0; i < sbniautodetect; i++) + { + if(!register_netdev(&dev_sbni[i])) + installed++; + } + if(installed) + return 0; + else + return -EIO; + } + + /* Manual mode */ + for(i = 0; i < SBNI_MAX_NUM_CARDS; i++) + { + if((io[i] != 0) || (irq[i] != 0)) + devices++; + } + for(i = 0; i < devices; i++) + { + dev_sbni[i].irq = irq[i]; + dev_sbni[i].base_addr = io[i]; + def_rxl = rxl[i]; + def_baud = baud[i]; + def_mac = mac[i]; + if(register_netdev(&dev_sbni[i])) + printk("sbni: card not found!\n"); + else + installed++; + } + if(installed) + return 0; + else + return -EIO; +} + +void cleanup_module(void) +{ + int i; + for(i = 0; i < 4; i++) + { + if(dev_sbni[i].priv) + { + free_irq(dev_sbni[i].irq, &dev_sbni[i]); + release_region(dev_sbni[i].base_addr, SBNI_IO_EXTENT); + unregister_netdev(&dev_sbni[i]); + kfree(dev_sbni[i].priv); + dev_sbni[i].priv = NULL; + } + } +} +#endif /* MODULE */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/sbni.h linux/drivers/net/wan/sbni.h --- v2.3.20/linux/drivers/net/wan/sbni.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/sbni.h Mon Oct 11 10:13:25 1999 @@ -0,0 +1,194 @@ +/* + * sbni.h - header file for sbni linux device driver + * + * Copyright (C) 1999 Granch ltd., Yaroslav Polyakov (xenon@granch.ru). + * + */ + +/* + * SBNI12 definitions + * + * Revision 2.0.0 1997/08/27 + * Initial revision + * + * Revision 2.1.0 1999/04/26 + * dev_priv structure changed to support balancing and some other features. + * + */ + +#ifndef __SBNI_H +#define __SBNI_H + +#define SBNI_DEBUG 0 + +#if SBNI_DEBUG +#define DP( A ) A +#else +#define DP( A ) +#endif + +typedef unsigned char BOOLEAN; + +#define TRUE 1 +#define FALSE 0 + +#define SBNI_IO_EXTENT 0x4 +#define SB_MAX_BUFFER_ARRAY 1023 + +#define CSR0 0 +#define CSR1 1 + +#define DAT 2 + +/* CSR0 mapping */ +#define BU_EMP (1 << 1) /* r z */ +#define RC_CHK (1 << 2) /* rw */ +#define CT_ZER (1 << 3) /* w */ +#define TR_REQ (1 << 4) /* rwz* */ + +#define TR_RDY (1 << 5) /* r z */ +#define EN_INT (1 << 6) /* rwz* */ +#define RC_RDY (1 << 7) /* r z */ + +/* CSR1 mapping */ +#define PR_RES (1 << 7) /* w */ + +struct sbni_csr1 { + unsigned rxl:5; + unsigned rate:2; + unsigned:1; +}; + +#define DEF_RXL_DELTA -1 +#define DEF_RXL 0xf +#define DEF_RATE 0 +#define DEF_FRAME_LEN (1023 - 14 - 9) + +#ifdef MODULE + +#define SBNI_MAX_NUM_CARDS 8 +#define SBNI_MAX_SLAVES 8 + + +#endif /* MODULE */ + +#define SBNI_SIG 0x5a + +#define SB_ETHER_MIN_LEN 60 + +#define SB_FILLING_CHAR (unsigned char)0x00 +#define TR_ERROR_COUNT 32 +#define CHANGE_LEVEL_START_TICKS 4 +#define SBNI_INTERNAL_QUEUE_SIZE 10 /* 100 ? */ + +#define PACKET_FIRST_FRAME (unsigned short)0x8000 +#define RECEIVE_FRAME_RESEND (unsigned short)0x0800 +#define PACKET_RESEND 0x4000 +#define PACKET_SEND_OK 0x3000 +#define PACKET_LEN_MASK (unsigned short)0x03ff +#define PACKET_INF_MASK (unsigned short)0x7000 + +#define ETHER_ADDR_LEN 6 + +#define SBNI_TIMEOUT HZ/10 /* ticks to wait for pong or packet */ + /* sbni watchdog called SBNI_HZ times per sec. */ + +struct sbni_in_stats { + unsigned int all_rx_number; + unsigned int bad_rx_number; + unsigned int timeout_number; + unsigned int all_tx_number; + unsigned int resend_tx_number; +}; + + +/* + * Board-specific info in dev->priv. + */ +struct net_local { + struct enet_statistics stats; + + struct timer_list watchdog; + unsigned int realframelen; /* the current size of the SB-frame */ + unsigned int eth_trans_buffer_len; /* tx buffer length */ + unsigned int outpos; + unsigned int inppos; + unsigned int frame_len; /* The set SB-frame size */ + unsigned int tr_err; + unsigned int timer_ticks; + BOOLEAN last_receive_OK; + BOOLEAN tr_resend; + + unsigned char wait_frame_number; + unsigned char eth_trans_buffer[1520]; /* tx buffer */ + unsigned char HSCounter; /* Reserved field */ + unsigned char eth_rcv_buffer[2600]; /* rx buffer */ + struct sbni_csr1 csr1; + /* Internal Statistics */ + struct sbni_in_stats in_stats; + + int rxl_curr; /* current receive level value [0..0xf] */ + int rxl_delta; /* receive level delta (+1, -1) + rxl_delta == 0 - receive level + autodetection + disabled */ + unsigned int ok_curr; /* current ok frames received */ + unsigned int ok_prev; /* previous ok frames received */ + unsigned int timeout_rxl; + + struct sk_buff_head queue; + struct sk_buff *currframe; + BOOLEAN waitack; + + struct net_device *m; /* master */ + struct net_device *me; /* me */ + struct net_local *next_lp; /* next lp */ + + int carrier; + + +}; + + +struct sbni_hard_header { + + /* internal sbni stuff */ + unsigned int crc; /* 4 */ + unsigned short packetlen; /* 2 */ + unsigned char number; /* 1 */ + unsigned char reserv; /* 1 */ + + /* 8 */ + + /* ethernet stuff */ + unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ + unsigned char h_source[ETH_ALEN]; /* source ether addr */ + unsigned short h_proto; /* packet type ID field */ + /* +14 */ + /* 22 */ + +}; + +#define SBNI_HH_SZ 22 + +struct sbni_flags { + unsigned rxl:4; + unsigned rate:2; + unsigned fixed_rxl:1; + unsigned fixed_rate:1; +}; + +#define RCV_NO 0 +#define RCV_OK 1 +#define RCV_WR 2 + + +#define SIOCDEVGETINSTATS SIOCDEVPRIVATE +#define SIOCDEVRESINSTATS SIOCDEVPRIVATE+1 +#define SIOCDEVGHWSTATE SIOCDEVPRIVATE+2 +#define SIOCDEVSHWSTATE SIOCDEVPRIVATE+3 +#define SIOCDEVENSLAVE SIOCDEVPRIVATE+4 +#define SIOCDEVEMANSIPATE SIOCDEVPRIVATE+5 + + +#endif /* __SBNI_H */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/sdla.c linux/drivers/net/wan/sdla.c --- v2.3.20/linux/drivers/net/wan/sdla.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/sdla.c Mon Oct 11 10:13:25 1999 @@ -0,0 +1,1696 @@ +/* + * SDLA An implementation of a driver for the Sangoma S502/S508 series + * multi-protocol PC interface card. Initial offering is with + * the DLCI driver, providing Frame Relay support for linux. + * + * Global definitions for the Frame relay interface. + * + * Version: @(#)sdla.c 0.30 12 Sep 1996 + * + * Credits: Sangoma Technologies, for the use of 2 cards for an extended + * period of time. + * David Mandelstam 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 + * + * 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 /* for CONFIG_DLCI_MAX */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +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;imaster[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;imaster[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;imaster[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;imaster[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;imaster[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;idlci[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;idlci[i]) + dlcis[len++] = abs(flp->dlci[i]); + len *= 2; + + if (flp->config.station == FRAD_STATION_NODE) + { + for(i=0;idlci[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;idlci[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;idlci[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;idlci[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;imaster[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;idlci[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;ibase_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;ibase_addr + i) != byte) + break; + + if (i == SDLA_IO_EXTENTS) + { + outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL); + if ((inb(dev->base_addr + SDLA_S502_STS) & 0x7E) == 0x30) + { + outb(SDLA_S507_ENABLE, dev->base_addr + SDLA_REG_CONTROL); + if ((inb(dev->base_addr + SDLA_S502_STS) & 0x7E) == 0x32) + { + outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL); + flp->type = SDLA_S507; + } + } + } + } + + if (flp->type == SDLA_UNKNOWN) + { + outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL); + if ((inb(dev->base_addr + SDLA_S508_STS) & 0x3F) == 0x00) + { + outb(SDLA_S508_INTEN, dev->base_addr + SDLA_REG_CONTROL); + if ((inb(dev->base_addr + SDLA_S508_STS) & 0x3F) == 0x10) + { + outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL); + flp->type = SDLA_S508; + } + } + } + + if (flp->type == SDLA_UNKNOWN) + { + outb(SDLA_S502A_HALT, dev->base_addr + SDLA_REG_CONTROL); + if (inb(dev->base_addr + SDLA_S502_STS) == 0x40) + { + outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL); + if (inb(dev->base_addr + SDLA_S502_STS) == 0x40) + { + outb(SDLA_S502A_INTEN, dev->base_addr + SDLA_REG_CONTROL); + if (inb(dev->base_addr + SDLA_S502_STS) == 0x44) + { + outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL); + flp->type = SDLA_S502A; + } + } + } + } + + if (flp->type == SDLA_UNKNOWN) + { + printk(KERN_NOTICE "%s: Unknown card type\n", dev->name); + return(-ENODEV); + } + + switch(dev->base_addr) + { + case 0x270: + case 0x280: + case 0x380: + case 0x390: + if ((flp->type != SDLA_S508) && (flp->type != SDLA_S507)) + return(-EINVAL); + } + + switch (map->irq) + { + case 2: + if (flp->type != SDLA_S502E) + return(-EINVAL); + break; + + case 10: + case 11: + case 12: + case 15: + case 4: + if ((flp->type != SDLA_S508) && (flp->type != SDLA_S507)) + return(-EINVAL); + + case 3: + case 5: + case 7: + if (flp->type == SDLA_S502A) + return(-EINVAL); + break; + + default: + return(-EINVAL); + } + dev->irq = map->irq; + + if (request_irq(dev->irq, &sdla_isr, 0, dev->name, dev)) + return(-EAGAIN); + + if (flp->type == SDLA_S507) + { + switch(dev->irq) + { + case 3: + flp->state = SDLA_S507_IRQ3; + break; + case 4: + flp->state = SDLA_S507_IRQ4; + break; + case 5: + flp->state = SDLA_S507_IRQ5; + break; + case 7: + flp->state = SDLA_S507_IRQ7; + break; + case 10: + flp->state = SDLA_S507_IRQ10; + break; + case 11: + flp->state = SDLA_S507_IRQ11; + break; + case 12: + flp->state = SDLA_S507_IRQ12; + break; + case 15: + flp->state = SDLA_S507_IRQ15; + break; + } + } + + for(i=0;i < sizeof(valid_mem) / sizeof (int) ; i++) + if (valid_mem[i] == map->mem_start) + break; + + if (i == sizeof(valid_mem) / sizeof(int)) + /* + * FIXME: + * BUG BUG BUG: MUST RELEASE THE IRQ WE ALLOCATED IN + * ALL THESE CASES + * + */ + return(-EINVAL); + + if ((flp->type == SDLA_S502A) && (((map->mem_start & 0xF000) >> 12) == 0x0E)) + return(-EINVAL); + + if ((flp->type != SDLA_S507) && ((map->mem_start >> 16) == 0x0B)) + return(-EINVAL); + + if ((flp->type == SDLA_S507) && ((map->mem_start >> 16) == 0x0D)) + return(-EINVAL); + + dev->mem_start = map->mem_start; + dev->mem_end = dev->mem_start + 0x2000; + + byte = flp->type != SDLA_S508 ? SDLA_8K_WINDOW : 0; + byte |= (map->mem_start & 0xF000) >> (12 + (flp->type == SDLA_S508 ? 1 : 0)); + switch(flp->type) + { + case SDLA_S502A: + case SDLA_S502E: + switch (map->mem_start >> 16) + { + case 0x0A: + byte |= SDLA_S502_SEG_A; + break; + case 0x0C: + byte |= SDLA_S502_SEG_C; + break; + case 0x0D: + byte |= SDLA_S502_SEG_D; + break; + case 0x0E: + byte |= SDLA_S502_SEG_E; + break; + } + break; + case SDLA_S507: + switch (map->mem_start >> 16) + { + case 0x0A: + byte |= SDLA_S507_SEG_A; + break; + case 0x0B: + byte |= SDLA_S507_SEG_B; + break; + case 0x0C: + byte |= SDLA_S507_SEG_C; + break; + case 0x0E: + byte |= SDLA_S507_SEG_E; + break; + } + break; + case SDLA_S508: + switch (map->mem_start >> 16) + { + case 0x0A: + byte |= SDLA_S508_SEG_A; + break; + case 0x0C: + byte |= SDLA_S508_SEG_C; + break; + case 0x0D: + byte |= SDLA_S508_SEG_D; + break; + case 0x0E: + byte |= SDLA_S508_SEG_E; + break; + } + break; + } + + /* set the memory bits, and enable access */ + outb(byte, dev->base_addr + SDLA_REG_PC_WINDOW); + + switch(flp->type) + { + case SDLA_S502E: + flp->state = SDLA_S502E_ENABLE; + break; + case SDLA_S507: + flp->state |= SDLA_MEMEN; + break; + case SDLA_S508: + flp->state = SDLA_MEMEN; + break; + } + outb(flp->state, dev->base_addr + SDLA_REG_CONTROL); + + flp->initialized = 1; + return(0); +} + +static struct net_device_stats *sdla_stats(struct net_device *dev) +{ + struct frad_local *flp; + flp = dev->priv; + + return(&flp->stats); +} + +int __init sdla_init(struct net_device *dev) +{ + struct frad_local *flp; + + /* allocate the private data structure */ + flp = kmalloc(sizeof(struct frad_local), GFP_KERNEL); + if (!flp) + return(-ENOMEM); + + memset(flp, 0, sizeof(struct frad_local)); + dev->priv = flp; + + dev->flags = 0; + dev->open = sdla_open; + dev->stop = sdla_close; + dev->do_ioctl = sdla_ioctl; + dev->set_config = sdla_set_config; + dev->get_stats = sdla_stats; + dev->hard_start_xmit = sdla_transmit; + dev->change_mtu = sdla_change_mtu; + + dev->type = 0xFFFF; + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->mtu = SDLA_MAX_MTU; + + dev_init_buffers(dev); + + flp->activate = sdla_activate; + flp->deactivate = sdla_deactivate; + flp->assoc = sdla_assoc; + flp->deassoc = sdla_deassoc; + flp->dlci_conf = sdla_dlci_conf; + + init_timer(&flp->timer); + flp->timer.expires = 1; + flp->timer.data = (unsigned long) dev; + flp->timer.function = sdla_poll; + + return(0); +} + +void __init sdla_setup(void) +{ + printk("%s.\n", version); + register_frad(devname); +} + +#ifdef MODULE +static struct net_device sdla0 = {"sdla0", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, sdla_init}; + +int init_module(void) +{ + int result; + + sdla_setup(); + if ((result = register_netdev(&sdla0)) != 0) + return result; + return 0; +} + +void cleanup_module(void) +{ + unregister_netdev(&sdla0); + if (sdla0.priv) + kfree(sdla0.priv); + if (sdla0.irq) + free_irq(sdla0.irq, &sdla0); +} +#endif /* MODULE */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/sdla_fr.c linux/drivers/net/wan/sdla_fr.c --- v2.3.20/linux/drivers/net/wan/sdla_fr.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/sdla_fr.c Mon Oct 11 10:13:25 1999 @@ -0,0 +1,3127 @@ +/***************************************************************************** +* sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module. +* +* Author(s): Gene Kozin +* Jaspreet Singh +* +* 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 /* printk(), and other useful stuff */ +#include /* offsetof(), etc. */ +#include /* return codes */ +#include /* inline memset(), etc. */ +#include /* kmalloc(), kfree() */ +#include /* WAN router definitions */ +#include /* WANPIPE common user API definitions */ +#include /* ARPHRD_* defines */ +#include /* htons(), etc. */ +#include /* for inb(), outb(), etc. */ +#include /* for do_gettimeofday */ +#define _GNUC_ +#include /* frame relay firmware API definitions */ +#include + +/****** Defines & Macros ****************************************************/ + +#define MAX_CMD_RETRY 10 /* max number of firmware retries */ +#define FR_HEADER_LEN 8 /* max encapsulation header size */ +#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ + +/* Q.922 frame types */ + +#define Q922_UI 0x03 /* Unnumbered Info frame */ +#define Q922_XID 0xAF /* ??? */ + +/* DLCI configured or not */ + +#define DLCI_NOT_CONFIGURED 0x00 +#define DLCI_CONFIG_PENDING 0x01 +#define DLCI_CONFIGURED 0x02 + +/* CIR enabled or not */ + +#define CIR_ENABLED 0x00 +#define CIR_DISABLED 0x01 + +/* Interrupt mode for DLCI = 0 */ + +#define BUFFER_INTR_MODE 0x00 +#define DLCI_LIST_INTR_MODE 0x01 + +/* Transmit Interrupt Status */ + +#define DISABLED 0x00 +#define WAITING_TO_BE_ENABLED 0x01 + +/* For handle_IPXWAN() */ + +#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) + +/****** Data Structures *****************************************************/ + +/* This is an extention of the 'struct net_device' we create for each network + * interface to keep the rest of channel-specific data. + */ +typedef struct fr_channel { + char name[WAN_IFNAME_SZ + 1]; /* interface name, ASCIIZ */ + unsigned dlci_configured; /* check whether configured or not */ + unsigned cir_status; /* check whether CIR enabled or not */ + unsigned dlci; /* logical channel number */ + unsigned cir; /* committed information rate */ + unsigned bc; /* committed burst size */ + unsigned be; /* excess burst size */ + unsigned mc; /* multicast support on or off */ + unsigned tx_int_status; /* Transmit Interrupt Status */ + unsigned short pkt_length; /* Packet Length */ + unsigned long router_start_time; /* Router start time in seconds */ + unsigned long tick_counter; /* counter for transmit time out */ + char dev_pending_devtint; /* interface pending dev_tint() */ + char state; /* channel state */ + void *dlci_int_interface; /* pointer to the DLCI Interface */ + unsigned long IB_addr; /* physical address of Interface Byte */ + unsigned long state_tick; /* time of the last state change */ + sdla_t *card; /* -> owner */ + struct net_device_stats ifstats; /* interface statistics */ + unsigned long if_send_entry; + unsigned long if_send_skb_null; + unsigned long if_send_broadcast; + unsigned long if_send_multicast; + unsigned long if_send_critical_ISR; + unsigned long if_send_critical_non_ISR; + unsigned long if_send_busy; + unsigned long if_send_busy_timeout; + unsigned long if_send_FPIPE_request; + unsigned long if_send_DRVSTATS_request; + unsigned long if_send_wan_disconnected; + unsigned long if_send_dlci_disconnected; + unsigned long if_send_no_bfrs; + unsigned long if_send_adptr_bfrs_full; + unsigned long if_send_bfrs_passed_to_adptr; + unsigned long rx_intr_no_socket; + unsigned long rx_intr_dev_not_started; + unsigned long rx_intr_FPIPE_request; + unsigned long rx_intr_DRVSTATS_request; + unsigned long rx_intr_bfr_not_passed_to_stack; + unsigned long rx_intr_bfr_passed_to_stack; + unsigned long UDP_FPIPE_mgmt_kmalloc_err; + unsigned long UDP_FPIPE_mgmt_direction_err; + unsigned long UDP_FPIPE_mgmt_adptr_type_err; + unsigned long UDP_FPIPE_mgmt_adptr_cmnd_OK; + unsigned long UDP_FPIPE_mgmt_adptr_cmnd_timeout; + unsigned long UDP_FPIPE_mgmt_adptr_send_passed; + unsigned long UDP_FPIPE_mgmt_adptr_send_failed; + unsigned long UDP_FPIPE_mgmt_not_passed_to_stack; + unsigned long UDP_FPIPE_mgmt_passed_to_stack; + unsigned long UDP_FPIPE_mgmt_no_socket; + unsigned long UDP_DRVSTATS_mgmt_kmalloc_err; + unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK; + unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; + unsigned long UDP_DRVSTATS_mgmt_adptr_send_passed; + unsigned long UDP_DRVSTATS_mgmt_adptr_send_failed; + unsigned long UDP_DRVSTATS_mgmt_not_passed_to_stack; + unsigned long UDP_DRVSTATS_mgmt_passed_to_stack; + unsigned long UDP_DRVSTATS_mgmt_no_socket; + unsigned long router_up_time; +} fr_channel_t; + +typedef struct dlci_status { + unsigned short dlci PACKED; + unsigned char state PACKED; +} dlci_status_t; + +typedef struct dlci_IB_mapping { + unsigned short dlci PACKED; + unsigned long addr_value PACKED; +} dlci_IB_mapping_t; + +/* This structure is used for DLCI list Tx interrupt mode. It is used to + enable interrupt bit and set the packet length for transmission + */ + +typedef struct fr_dlci_interface { + unsigned char gen_interrupt PACKED; + unsigned short packet_length PACKED; + unsigned char reserved PACKED; +} fr_dlci_interface_t; + +static unsigned short num_frames; +static unsigned long curr_trace_addr; +static unsigned long start_trace_addr; +static unsigned short available_buffer_space; +static char TracingEnabled; /* variable for keeping track of enabling/disabling FT1 monitor status */ +static int rCount = 0; +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/* variable for keeping track of number of interrupts generated during + * interrupt test routine + */ +static int Intr_test_counter; + +/****** Function Prototypes *************************************************/ + +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update(wan_device_t * wandev); +static int new_if(wan_device_t * wandev, struct net_device *dev, + wanif_conf_t * conf); +static int del_if(wan_device_t * wandev, struct net_device *dev); +/* WANPIPE-specific entry points */ +static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data); +/* Network device interface */ +static int if_init(struct net_device *dev); +static int if_open(struct net_device *dev); +static int if_close(struct net_device *dev); +static int if_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, unsigned len); +static int if_rebuild_hdr(struct sk_buff *skb); +static int if_send(struct sk_buff *skb, struct net_device *dev); +static struct net_device_stats *if_stats(struct net_device *dev); +/* Interrupt handlers */ +static void fr502_isr(sdla_t * card); +static void fr508_isr(sdla_t * card); +static void fr502_rx_intr(sdla_t * card); +static void fr508_rx_intr(sdla_t * card); +static void tx_intr(sdla_t * card); +static void spur_intr(sdla_t * card); +/* Background polling routines */ +static void wpf_poll(sdla_t * card); +/* Frame relay firmware interface functions */ +static int fr_read_version(sdla_t * card, char *str); +static int fr_configure(sdla_t * card, fr_conf_t * conf); +static int fr_dlci_configure(sdla_t * card, fr_dlc_conf_t * conf, unsigned dlci); +static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu); +static int fr_comm_enable(sdla_t * card); +static int fr_comm_disable(sdla_t * card); +static int fr_get_err_stats(sdla_t * card); +static int fr_get_stats(sdla_t * card); +static int fr_add_dlci(sdla_t * card, int dlci, int num); +static int fr_activate_dlci(sdla_t * card, int dlci, int num); +static int fr_issue_isf(sdla_t * card, int isf); +static int fr502_send(sdla_t * card, int dlci, int attr, int len, void *buf); +static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf); +/* Firmware asynchronous event handlers */ +static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox); +static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox); +static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox); +/* Miscellaneous functions */ +static int update_chan_state(struct net_device *dev); +static void set_chan_state(struct net_device *dev, int state); +static struct net_device *find_channel(sdla_t * card, unsigned dlci); +static int is_tx_ready(sdla_t * card, fr_channel_t * chan); +static unsigned int dec_to_uint(unsigned char *str, int len); +static int reply_udp(unsigned char *data, unsigned int mbox_len); +static int intr_test(sdla_t * card); +static void init_chan_statistics(fr_channel_t * chan); +static void init_global_statistics(sdla_t * card); +static void read_DLCI_IB_mapping(sdla_t * card, fr_channel_t * chan); +/* Udp management functions */ +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, int dlci, fr_channel_t * chan); +static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, int dlci, fr_channel_t * chan); +static int udp_pkt_type(struct sk_buff *skb, sdla_t * card); +/* IPX functions */ +static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number); + +/****** Public Functions ****************************************************/ + +/*============================================================================ + * Frame relay protocol initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wpf_init(sdla_t * card, wandev_conf_t * conf) +{ + union { + char str[80]; + fr_conf_t cfg; + } u; + int i; + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_FR) + { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + /* Initialize protocol-specific fields of adapter data space */ + switch (card->hw.fwid) + { + case SFID_FR502: + card->mbox = (void *) (card->hw.dpmbase + FR502_MBOX_OFFS); + card->rxmb = (void *) (card->hw.dpmbase + FR502_RXMB_OFFS); + card->flags = (void *) (card->hw.dpmbase + FR502_FLAG_OFFS); + card->isr = &fr502_isr; + break; + case SFID_FR508: + card->mbox = (void *) (card->hw.dpmbase + FR508_MBOX_OFFS); + card->flags = (void *) (card->hw.dpmbase + FR508_FLAG_OFFS); + card->isr = &fr508_isr; + break; + default: + return -EINVAL; + } + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + if (fr_read_version(card, NULL) || fr_read_version(card, u.str)) + return -EIO; + printk(KERN_INFO "%s: running frame relay firmware v%s\n", + card->devname, u.str); + /* Adjust configuration */ + conf->mtu = max(min(conf->mtu, 4080), FR_CHANNEL_MTU + FR_HEADER_LEN); + conf->bps = min(conf->bps, 2048000); + /* Configure adapter firmware */ + memset(&u.cfg, 0, sizeof(u.cfg)); + u.cfg.mtu = conf->mtu; + u.cfg.kbps = conf->bps / 1000; + u.cfg.cir_fwd = u.cfg.cir_bwd = 16; + u.cfg.bc_fwd = u.cfg.bc_bwd = 16; + if (conf->station == WANOPT_CPE) + { + u.cfg.options = 0x0080; + printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname); + } + else + { + u.cfg.options = 0x0081; + } + switch (conf->u.fr.signalling) + { + case WANOPT_FR_Q933: + u.cfg.options |= 0x0200; + break; + case WANOPT_FR_LMI: + u.cfg.options |= 0x0400; + break; + } + if (conf->station == WANOPT_CPE) + { + u.cfg.options |= 0x8000; /* auto config DLCI */ + card->u.f.dlci_num = 0; + } + else + { + u.cfg.station = 1; /* switch emulation mode */ + /* For switch emulation we have to create a list of dlci(s) + * that will be sent to be global SET_DLCI_CONFIGURATION + * command in fr_configure() routine. + */ + card->u.f.dlci_num = min(max(conf->u.fr.dlci_num, 1), 100); + for (i = 0; i < card->u.f.dlci_num; i++) + { + card->u.f.node_dlci[i] = (unsigned short) + conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16; + } + } + if (conf->clocking == WANOPT_INTERNAL) + u.cfg.port |= 0x0001; + if (conf->interface == WANOPT_RS232) + u.cfg.port |= 0x0002; + if (conf->u.fr.t391) + u.cfg.t391 = min(conf->u.fr.t391, 30); + else + u.cfg.t391 = 5; + if (conf->u.fr.t392) + u.cfg.t392 = min(conf->u.fr.t392, 30); + else + u.cfg.t392 = 15; + if (conf->u.fr.n391) + u.cfg.n391 = min(conf->u.fr.n391, 255); + else + u.cfg.n391 = 2; + if (conf->u.fr.n392) + u.cfg.n392 = min(conf->u.fr.n392, 10); + else + u.cfg.n392 = 3; + if (conf->u.fr.n393) + u.cfg.n393 = min(conf->u.fr.n393, 10); + else + u.cfg.n393 = 4; + if (fr_configure(card, &u.cfg)) + return -EIO; + if (card->hw.fwid == SFID_FR508) + { + fr_buf_info_t *buf_info = + (void *) (card->hw.dpmbase + FR508_RXBC_OFFS); + card->rxmb = (void *) (buf_info->rse_next - FR_MB_VECTOR + card->hw.dpmbase); + card->u.f.rxmb_base = (void *) (buf_info->rse_base - FR_MB_VECTOR + card->hw.dpmbase); + card->u.f.rxmb_last = (void *) (buf_info->rse_base + (buf_info->rse_num - 1) * + sizeof(fr_buf_ctl_t) - FR_MB_VECTOR + card->hw.dpmbase); + card->u.f.rx_base = buf_info->buf_base; + card->u.f.rx_top = buf_info->buf_top; + } + card->wandev.mtu = conf->mtu; + card->wandev.bps = conf->bps; + card->wandev.interface = conf->interface; + card->wandev.clocking = conf->clocking; + card->wandev.station = conf->station; + card->poll = &wpf_poll; + card->exec = &wpf_exec; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.state = WAN_DISCONNECTED; + card->wandev.ttl = conf->ttl; + card->wandev.udp_port = conf->udp_port; + card->wandev.enable_tx_int = 0; + card->irq_dis_if_send_count = 0; + card->irq_dis_poll_count = 0; + card->wandev.enable_IPX = conf->enable_IPX; + if (conf->network_number) + card->wandev.network_number = conf->network_number; + else + card->wandev.network_number = 0xDEADBEEF; + /* Intialize global statistics for a card */ + init_global_statistics(card); + TracingEnabled = 0; + return 0; +} + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * Update device status & statistics. + */ + +static int update(wan_device_t * wandev) +{ + sdla_t *card; + /* sanity checks */ + if ((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + if (wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + if (test_and_set_bit(0, (void *) &wandev->critical)) + return -EAGAIN; + card = wandev->private; + fr_get_err_stats(card); + fr_get_stats(card); + wandev->critical = 0; + return 0; +} + +/*============================================================================ + * Create new logical channel. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ + +static int new_if(wan_device_t * wandev, struct net_device *dev, wanif_conf_t * conf) +{ + sdla_t *card = wandev->private; + fr_channel_t *chan; + int err = 0; + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) + { + printk(KERN_INFO "%s: invalid interface name!\n", + card->devname); + return -EINVAL; + } + /* allocate and initialize private data */ + chan = kmalloc(sizeof(fr_channel_t), GFP_KERNEL); + if (chan == NULL) + return -ENOMEM; + memset(chan, 0, sizeof(fr_channel_t)); + strcpy(chan->name, conf->name); + chan->card = card; + /* verify media address */ + if (is_digit(conf->addr[0])) + { + int dlci = dec_to_uint(conf->addr, 0); + if (dlci && (dlci <= 4095)) + { + chan->dlci = dlci; + } + else + { + printk(KERN_ERR "%s: invalid DLCI %u on interface %s!\n", + wandev->name, dlci, chan->name); + err = -EINVAL; + } + } + else + { + printk(KERN_ERR "%s: invalid media address on interface %s!\n", + wandev->name, chan->name); + err = -EINVAL; + } + if (err) + { + kfree(chan); + return err; + } + /* place cir,be,bc and other channel specific information into the + * chan structure + */ + if (conf->cir) + { + chan->cir = max(1, min(conf->cir, 512)); + chan->cir_status = CIR_ENABLED; + if (conf->bc) + chan->bc = max(1, min(conf->bc, 512)); + if (conf->be) + chan->be = max(0, min(conf->be, 511)); + } + else + chan->cir_status = CIR_DISABLED; + chan->mc = conf->mc; + chan->dlci_configured = DLCI_NOT_CONFIGURED; + chan->tx_int_status = DISABLED; + init_chan_statistics(chan); + /* prepare network device data space for registration */ + dev->name = chan->name; + dev->init = &if_init; + dev->priv = chan; + return 0; +} +/*============================================================================ + * Delete logical channel. + */ +static int del_if(wan_device_t * wandev, struct net_device *dev) +{ + if (dev->priv) + { + kfree(dev->priv); + dev->priv = NULL; + } + return 0; +} + +/****** WANPIPE-specific entry points ***************************************/ + +/*============================================================================ + * Execute adapter interface command. + */ +static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data) +{ + fr_mbox_t *mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err, len; + fr_cmd_t cmd; + if(copy_from_user((void *) &cmd, u_cmd, sizeof(cmd))) + return -EFAULT; + /* execute command */ + do + { + memcpy(&mbox->cmd, &cmd, sizeof(cmd)); + if (cmd.length) + { + if(copy_from_user((void *) &mbox->data, u_data, cmd.length)) + return -EFAULT; + } + if (sdla_exec(mbox)) + err = mbox->cmd.result; + else + return -EIO; + } + while (err && retry-- && fr_event(card, err, mbox)); + + /* return result */ + + if(copy_to_user(u_cmd, (void *) &mbox->cmd, sizeof(fr_cmd_t))) + return -EFAULT; + len = mbox->cmd.length; + if (len && u_data && copy_to_user(u_data, (void *) &mbox->data, len)) + return -EFAULT; + return 0; +} + +/****** Network Device Interface ********************************************/ +/*============================================================================ + * Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. + */ +static int if_init(struct net_device *dev) +{ + fr_channel_t *chan = dev->priv; + sdla_t *card = chan->card; + wan_device_t *wandev = &card->wandev; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = &if_header; + dev->rebuild_header = &if_rebuild_hdr; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + /* Initialize media-specific parameters */ + dev->type = ARPHRD_DLCI; /* ARP h/w type */ + dev->mtu = FR_CHANNEL_MTU; + dev->hard_header_len = FR_HEADER_LEN; /* media header length */ + dev->addr_len = 2; /* hardware address length */ + *(unsigned short *) dev->dev_addr = htons(chan->dlci); + /* Initialize hardware parameters (just for reference) */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = (unsigned long)wandev->maddr; + dev->mem_end = dev->mem_start + wandev->msize - 1; + /* Set transmit buffer queue length */ + dev->tx_queue_len = 10; + /* Initialize socket buffers */ + dev_init_buffers(dev); + set_chan_state(dev, WAN_DISCONNECTED); + return 0; +} + +/*============================================================================ + * Open network interface. + * o if this is the first open, then enable communications and interrupts. + * o prevent module from unloading by incrementing use count + * + * Return 0 if O.k. or errno. + */ + +static int if_open(struct net_device *dev) +{ + fr_channel_t *chan = dev->priv; + sdla_t *card = chan->card; + struct net_device *dev2; + int err = 0; + fr508_flags_t *flags = card->flags; + struct timeval tv; + if (dev->start) + return -EBUSY; /* only one open is allowed */ + if (test_and_set_bit(0, (void *) &card->wandev.critical)) + return -EAGAIN; + if (!card->open_cnt) + { + Intr_test_counter = 0; + card->intr_mode = INTR_TEST_MODE; + err = intr_test(card); + if ((err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) { + printk(KERN_INFO + "%s: Interrupt Test Failed, Counter: %i\n", + card->devname, Intr_test_counter); + err = -EIO; + card->wandev.critical = 0; + return err; + } + printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n" + ,card->devname, Intr_test_counter); + /* The following allocates and intializes a circular + * link list of interfaces per card. + */ + card->devs_struct = kmalloc(sizeof(load_sharing_t), GFP_KERNEL); + if (card->devs_struct == NULL) + return -ENOMEM; + card->dev_to_devtint_next = card->devs_struct; + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { + (card->devs_struct)->dev_ptr = dev2; + if (dev2->slave == NULL) + (card->devs_struct)->next = card->dev_to_devtint_next; + else { + (card->devs_struct)->next = kmalloc( + sizeof(load_sharing_t), GFP_KERNEL); + if ((card->devs_struct)->next == NULL) + return -ENOMEM; + card->devs_struct = (card->devs_struct)->next; + } + } + card->devs_struct = card->dev_to_devtint_next; + card->intr_mode = BUFFER_INTR_MODE; + /* + check all the interfaces for the device to see if CIR has + been enabled for any DLCI(s). If so then use the DLCI list + Interrupt mode for fr_set_intr_mode(), otherwise use the default global interrupt mode + */ + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { + if (((fr_channel_t *) dev2->priv)->cir_status + == CIR_ENABLED) { + card->intr_mode = DLCI_LIST_INTR_MODE; + break; + } + } + /* + If you enable comms and then set ints, you get a Tx int as you + perform the SET_INT_TRIGGERS command. So, we only set int + triggers and then adjust the interrupt mask (to disable Tx ints) before enabling comms. + */ + if (card->intr_mode == BUFFER_INTR_MODE) { + if (fr_set_intr_mode(card, 0x03, card->wandev.mtu)) { + err = -EIO; + card->wandev.critical = 0; + return err; + } + printk(KERN_INFO + "%s: Global Buffering Tx Interrupt Mode\n" + ,card->devname); + } else if (card->intr_mode == DLCI_LIST_INTR_MODE) { + if (fr_set_intr_mode(card, 0x83, card->wandev.mtu)) { + err = -EIO; + card->wandev.critical = 0; + return err; + } + printk(KERN_INFO + "%s: DLCI list Tx Interrupt Mode\n", + card->devname); + } + flags->imask &= ~0x02; + if (fr_comm_enable(card)) { + err = -EIO; + card->wandev.critical = 0; + return err; + } + wanpipe_set_state(card, WAN_CONNECTED); + if (card->wandev.station == WANOPT_CPE) { + /* CPE: issue full status enquiry */ + fr_issue_isf(card, FR_ISF_FSE); + } else { /* FR switch: activate DLCI(s) */ + /* For Switch emulation we have to ADD and ACTIVATE + * the DLCI(s) that were configured with the SET_DLCI_ + * CONFIGURATION command. Add and Activate will fail if + * DLCI specified is not included in the list. + * + * Also If_open is called once for each interface. But + * it does not get in here for all the interface. So + * we have to pass the entire list of DLCI(s) to add + * activate routines. + */ + fr_add_dlci(card, + card->u.f.node_dlci[0], card->u.f.dlci_num); + fr_activate_dlci(card, + card->u.f.node_dlci[0], card->u.f.dlci_num); + } + } + dev->mtu = min(dev->mtu, card->wandev.mtu - FR_HEADER_LEN); + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + wanpipe_open(card); + update_chan_state(dev); + do_gettimeofday(&tv); + chan->router_start_time = tv.tv_sec; + card->wandev.critical = 0; + return err; +} + +/*============================================================================ + * Close network interface. + * o if this is the last open, then disable communications and interrupts. + * o reset flags. + */ + +static int if_close(struct net_device *dev) +{ + fr_channel_t *chan = dev->priv; + sdla_t *card = chan->card; + if (test_and_set_bit(0, (void *) &card->wandev.critical)) + return -EAGAIN; + dev->start = 0; + wanpipe_close(card); + if (!card->open_cnt) + { + wanpipe_set_state(card, WAN_DISCONNECTED); + fr_set_intr_mode(card, 0, 0); + fr_comm_disable(card); + } + card->wandev.critical = 0; + return 0; +} + +/*============================================================================ + * Build media header. + * o encapsulate packet according to encapsulation type. + * + * The trick here is to put packet type (Ethertype) into 'protocol' field of + * the socket buffer, so that we don't forget it. If encapsulation fails, + * set skb->protocol to 0 and discard packet later. + * + * Return: media header length. + */ + +static int if_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, unsigned len) +{ + int hdr_len = 0; + skb->protocol = type; + hdr_len = wanrouter_encapsulate(skb, dev); + if (hdr_len < 0) + { + hdr_len = 0; + skb->protocol = 0; + } + skb_push(skb, 1); + skb->data[0] = Q922_UI; + ++hdr_len; + return hdr_len; +} + +/*============================================================================ + * Re-build media header. + * + * Return: 1 physical address resolved. + * 0 physical address not resolved + */ + +static int if_rebuild_hdr(struct sk_buff *skb) +{ + struct net_device *dev=skb->dev; + fr_channel_t *chan = dev->priv; + sdla_t *card = chan->card; + printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", + card->devname, dev->name); + return 1; +} + +/*============================================================================ + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission) to block a timer-based + * transmit from overlapping. + * o check link state. If link is not up, then drop the packet. + * o check channel status. If it's down then initiate a call. + * o pass a packet to corresponding WAN device. + * o free socket buffer + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + */ + +static int if_send(struct sk_buff *skb, struct net_device *dev) +{ + fr_channel_t *chan = dev->priv; + sdla_t *card = chan->card; + int retry = 0, err; + unsigned char *sendpacket; + struct net_device *dev2; + unsigned long check_braddr, check_mcaddr; + fr508_flags_t *adptr_flags = card->flags; + int udp_type, send_data; + fr_dlci_interface_t *dlci_interface = chan->dlci_int_interface; + unsigned long host_cpu_flags; + ++chan->if_send_entry; + + if (dev->tbusy) + { + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this * is only used as a last resort. + */ + ++chan->if_send_busy; + ++chan->ifstats.collisions; + if ((jiffies - chan->tick_counter) < (5 * HZ)) + return 1; + + printk(KERN_INFO "%s: Transmit timed out\n", chan->name); + ++chan->if_send_busy_timeout; + /* unbusy all the interfaces on the card */ + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) + dev2->tbusy = 0; + } + sendpacket = skb->data; + udp_type = udp_pkt_type(skb, card); + if (udp_type == UDP_DRVSTATS_TYPE) + { + ++chan->if_send_DRVSTATS_request; + process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev, 0, + chan); + dev_kfree_skb(skb); + return 0; + } + else if (udp_type == UDP_FPIPE_TYPE) + ++chan->if_send_FPIPE_request; + /* retreive source address in two forms: broadcast & multicast */ + check_braddr = sendpacket[17]; + check_mcaddr = sendpacket[14]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[16]; + check_mcaddr |= sendpacket[15]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[15]; + check_mcaddr |= sendpacket[16]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[14]; + check_mcaddr |= sendpacket[17]; + /* if the Source Address is a Multicast address */ + if ((chan->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001) && + (check_mcaddr <= 0xFFFFFFFE)) + { + printk(KERN_INFO "%s: Multicast Src. Addr. silently discarded\n" + ,card->devname); + dev_kfree_skb(skb); + ++chan->ifstats.tx_dropped; + ++chan->if_send_multicast; + return 0; + } + disable_irq(card->hw.irq); + ++card->irq_dis_if_send_count; + if (test_and_set_bit(0, (void *) &card->wandev.critical)) + { + if (card->wandev.critical == CRITICAL_IN_ISR) + { + ++chan->if_send_critical_ISR; + if (card->intr_mode == DLCI_LIST_INTR_MODE) + { + /* The enable_tx_int flag is set here so that if + * the critical flag is set due to an interrupt + * then we want to enable transmit interrupts + * again. + */ + card->wandev.enable_tx_int = 1; + /* Setting this flag to WAITING_TO_BE_ENABLED + * specifies that interrupt bit has to be + * enabled for that particular interface. + * (delayed interrupt) + */ + chan->tx_int_status = WAITING_TO_BE_ENABLED; + /* This is used for enabling dynamic calculation + * of CIRs relative to the packet length. + */ + chan->pkt_length = skb->len; + dev->tbusy = 1; + chan->tick_counter = jiffies; + } + else + { + card->wandev.enable_tx_int = 1; + dev->tbusy = 1; + chan->tick_counter = jiffies; + } + save_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && + (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return 1; + } + ++chan->if_send_critical_non_ISR; + ++chan->ifstats.tx_dropped; + dev_kfree_skb(skb); + save_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && + (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return 0; + } + card->wandev.critical = 0x21; + if (udp_type == UDP_FPIPE_TYPE) + { + err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, + dev, 0, chan); + } + else if (card->wandev.state != WAN_CONNECTED) + { + ++chan->if_send_wan_disconnected; + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + } + else if (chan->state != WAN_CONNECTED) + { + ++chan->if_send_dlci_disconnected; + update_chan_state(dev); + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + } + else if (!is_tx_ready(card, chan)) + { + if (card->intr_mode == DLCI_LIST_INTR_MODE) + { + dlci_interface->gen_interrupt |= 0x40; + dlci_interface->packet_length = skb->len; + } + dev->tbusy = 1; + chan->tick_counter = jiffies; + adptr_flags->imask |= 0x02; + ++chan->if_send_no_bfrs; + retry = 1; + } + else + { + send_data = 1; + /* If it's an IPX packet */ + if (sendpacket[1] == 0x00 && + sendpacket[2] == 0x80 && + sendpacket[6] == 0x81 && + sendpacket[7] == 0x37) + { + if (card->wandev.enable_IPX) + { + switch_net_numbers(sendpacket, + card->wandev.network_number, 0); + } + else + { + /* increment some statistic here! */ + send_data = 0; + } + } + if (send_data) + { + err = (card->hw.fwid == SFID_FR508) ? + fr508_send(card, chan->dlci, 0, skb->len, skb->data) : + fr502_send(card, chan->dlci, 0, skb->len, skb->data); + if (err) + { + if (card->intr_mode == DLCI_LIST_INTR_MODE) + { + dlci_interface->gen_interrupt |= 0x40; + dlci_interface->packet_length = skb->len; + } + dev->tbusy = 1; + chan->tick_counter = jiffies; + adptr_flags->imask |= 0x02; + retry = 1; + ++chan->if_send_adptr_bfrs_full; + ++chan->ifstats.tx_errors; + ++card->wandev.stats.tx_errors; + } + else + { + ++chan->if_send_bfrs_passed_to_adptr; + ++chan->ifstats.tx_packets; + ++card->wandev.stats.tx_packets; + chan->ifstats.tx_bytes += skb->len; + card->wandev.stats.tx_bytes += skb->len; + } + } + } + if (!retry) + dev_kfree_skb(skb); + + card->wandev.critical = 0; + save_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return retry; +} + +/*============================================================================ + * Reply to UDP Management system. + * Return nothing. + */ + +static int reply_udp(unsigned char *data, unsigned int mbox_len) +{ + unsigned short len, udp_length, temp, i, ip_length; + unsigned long sum; + /* Set length of packet */ + len = mbox_len + 62; + /* fill in UDP reply */ + data[38] = 0x02; + /* fill in UDP length */ + udp_length = mbox_len + 40; + /* put it on an even boundary */ + if (udp_length & 0x0001) + { + udp_length += 1; + len += 1; + } + temp = (udp_length << 8) | (udp_length >> 8); + memcpy(&data[26], &temp, 2); + /* swap UDP ports */ + memcpy(&temp, &data[22], 2); + memcpy(&data[22], &data[24], 2); + memcpy(&data[24], &temp, 2); + /* add UDP pseudo header */ + temp = 0x1100; + memcpy(&data[udp_length + 22], &temp, 2); + temp = (udp_length << 8) | (udp_length >> 8); + memcpy(&data[udp_length + 24], &temp, 2); + /* calculate UDP checksum */ + data[28] = data[29] = 0; + sum = 0; + for (i = 0; i < udp_length + 12; i += 2) + { + memcpy(&temp, &data[14 + i], 2); + sum += (unsigned long) temp; + } + while (sum >> 16) + sum = (sum & 0xffffUL) + (sum >> 16); + + temp = (unsigned short) sum; + temp = ~temp; + if (temp == 0) + temp = 0xffff; + memcpy(&data[28], &temp, 2); + /* fill in IP length */ + ip_length = udp_length + 20; + temp = (ip_length << 8) | (ip_length >> 8); + memcpy(&data[4], &temp, 2); + /* swap IP addresses */ + memcpy(&temp, &data[14], 2); + memcpy(&data[14], &data[18], 2); + memcpy(&data[18], &temp, 2); + memcpy(&temp, &data[16], 2); + memcpy(&data[16], &data[20], 2); + memcpy(&data[20], &temp, 2); + /* fill in IP checksum */ + data[12] = data[13] = 0; + sum = 0; + for (i = 0; i < 20; i += 2) + { + memcpy(&temp, &data[2 + i], 2); + sum += (unsigned long) temp; + } + while (sum >> 16) + sum = (sum & 0xffffUL) + (sum >> 16); + temp = (unsigned short) sum; + temp = ~temp; + if (temp == 0) + temp = 0xffff; + memcpy(&data[12], &temp, 2); + return len; +} /* reply_udp */ +/* + If incoming is 0 (outgoing)- if the net numbers is ours make it 0 + if incoming is 1 - if the net number is 0 make it ours + */ + +static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) +{ + unsigned long pnetwork_number; + pnetwork_number = (unsigned long) ((sendpacket[14] << 24) + + (sendpacket[15] << 16) + (sendpacket[16] << 8) + + sendpacket[17]); + if (!incoming) { + /* If the destination network number is ours, make it 0 */ + if (pnetwork_number == network_number) { + sendpacket[14] = sendpacket[15] = sendpacket[16] = + sendpacket[17] = 0x00; + } + } else { + /* If the incoming network is 0, make it ours */ + if (pnetwork_number == 0) + { + sendpacket[14] = (unsigned char) (network_number >> 24); + sendpacket[15] = (unsigned char) ((network_number & + 0x00FF0000) >> 16); + sendpacket[16] = (unsigned char) ((network_number & + 0x0000FF00) >> 8); + sendpacket[17] = (unsigned char) (network_number & + 0x000000FF); + } + } + pnetwork_number = (unsigned long) ((sendpacket[26] << 24) + + (sendpacket[27] << 16) + (sendpacket[28] << 8) + + sendpacket[29]); + if (!incoming) { + /* If the source network is ours, make it 0 */ + if (pnetwork_number == network_number) + { + sendpacket[26] = sendpacket[27] = sendpacket[28] = + sendpacket[29] = 0x00; + } + } else { + /* If the source network is 0, make it ours */ + if (pnetwork_number == 0) { + sendpacket[26] = (unsigned char) (network_number >> 24); + sendpacket[27] = (unsigned char) ((network_number & + 0x00FF0000) >> 16); + sendpacket[28] = (unsigned char) ((network_number & + 0x0000FF00) >> 8); + sendpacket[29] = (unsigned char) (network_number & + 0x000000FF); + } + } +} /* switch_net_numbers */ + +/*============================================================================ + * Get Ethernet-style interface statistics. + * Return a pointer to struct net_device_stats. + */ + +static struct net_device_stats *if_stats(struct net_device *dev) +{ + fr_channel_t *chan = dev->priv; + if(chan==NULL) + return NULL; + + return &chan->ifstats; +} + +/****** Interrupt Handlers **************************************************/ +/*============================================================================ + * S502 frame relay interrupt service routine. + */ + +static void fr502_isr(sdla_t * card) +{ + fr502_flags_t *flags = card->flags; + switch (flags->iflag) + { + case 0x01: /* receive interrupt */ + fr502_rx_intr(card); + break; + case 0x02: /* transmit interrupt */ + flags->imask &= ~0x02; + tx_intr(card); + break; + default: + spur_intr(card); + } + flags->iflag = 0; +} +/*============================================================================ + * S508 frame relay interrupt service routine. + */ + +static void fr508_isr(sdla_t * card) +{ + fr508_flags_t *flags = card->flags; + fr_buf_ctl_t *bctl; + char *ptr = &flags->iflag; + struct net_device *dev = card->wandev.dev; + struct net_device *dev2; + int i; + unsigned long host_cpu_flags; + unsigned disable_tx_intr = 1; + fr_channel_t *chan; + fr_dlci_interface_t *dlci_interface; + /* This flag prevents nesting of interrupts. See sdla_isr() routine + * in sdlamain.c. + */ + card->in_isr = 1; + ++card->statistics.isr_entry; + if (test_and_set_bit(0, (void *) &card->wandev.critical)) + { + printk(KERN_INFO "fr508_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, flags->iflag); + ++card->statistics.isr_already_critical; + card->in_isr = 0; + return; + } + /* For all interrupts set the critical flag to CRITICAL_RX_INTR. + * If the if_send routine is called with this flag set it will set + * the enable transmit flag to 1. (for a delayed interrupt) + */ + card->wandev.critical = CRITICAL_IN_ISR; + card->dlci_int_mode_unbusy = 0; + card->buff_int_mode_unbusy = 0; + switch (flags->iflag) + { + case 0x01: /* receive interrupt */ + ++card->statistics.isr_rx; + fr508_rx_intr(card); + break; + case 0x02: /* transmit interrupt */ + ++card->statistics.isr_tx; + bctl = (void *) (flags->tse_offs - FR_MB_VECTOR + + card->hw.dpmbase); + bctl->flag = 0xA0; + if (card->intr_mode == DLCI_LIST_INTR_MODE) + { + /* Find the structure and make it unbusy */ + dev = find_channel(card, flags->dlci); + dev->tbusy = 0; + /* This is used to perform devtint at the + * end of the isr + */ + card->dlci_int_mode_unbusy = 1; + /* check to see if any other interfaces are + * busy. If so then do not disable the tx + * interrupts + */ + for (dev2 = card->wandev.dev; dev2; + dev2 = dev2->slave) + { + if (dev2->tbusy == 1) + { + disable_tx_intr = 0; + break; + } + } + if (disable_tx_intr) + flags->imask &= ~0x02; + } + else if (card->intr_mode == BUFFER_INTR_MODE) + { + for (dev2 = card->wandev.dev; dev2; + dev2 = dev2->slave) + { + if (!dev2 || !dev2->start) + { + ++card->statistics.tx_intr_dev_not_started; + continue; + } + if (dev2->tbusy) + { + card->buff_int_mode_unbusy = 1; + ((fr_channel_t *) dev2->priv)->dev_pending_devtint = 1; + dev2->tbusy = 0; + } + else + ((fr_channel_t *) dev2->priv)->dev_pending_devtint = 0; + } + flags->imask &= ~0x02; + } + break; + case 0x08: + Intr_test_counter++; + ++card->statistics.isr_intr_test; + break; + default: + ++card->statistics.isr_spurious; + spur_intr(card); + printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n", + card->devname, flags->iflag); + printk(KERN_INFO "%s: ID Bytes = ", card->devname); + for (i = 0; i < 8; i++) + printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); + printk(KERN_INFO "\n"); + break; + } + card->wandev.critical = CRITICAL_INTR_HANDLED; + if (card->wandev.enable_tx_int) + { + if (card->intr_mode == DLCI_LIST_INTR_MODE) + { + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) + { + chan = dev2->priv; + if (chan->tx_int_status == WAITING_TO_BE_ENABLED) + { + dlci_interface = chan->dlci_int_interface; + dlci_interface->gen_interrupt |= 0x40; + dlci_interface->packet_length = chan->pkt_length; + chan->tx_int_status = DISABLED; + } + } + } + card->wandev.enable_tx_int = 0; + flags->imask |= 0x02; + ++card->statistics.isr_enable_tx_int; + } + save_flags(host_cpu_flags); + cli(); + card->in_isr = 0; + card->wandev.critical = 0xD1; + flags->iflag = 0; + card->wandev.critical = 0; + restore_flags(host_cpu_flags); + /* Device is now ready to send. The instant this is executed the If_Send + routine is called. That is why this is put at the bottom of the ISR + to prevent a endless loop condition caused by repeated Interrupts and + enable_tx_int flag. + */ + if (card->dlci_int_mode_unbusy) + mark_bh(NET_BH); + if (card->buff_int_mode_unbusy) + { + for (;;) + { + if (((fr_channel_t *) ((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint == 1) + { + ((fr_channel_t *) ((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint = 0; + mark_bh(NET_BH); + } + if ((card->devs_struct)->next == card->dev_to_devtint_next) + break; + card->devs_struct = (card->devs_struct)->next; + } + card->devs_struct = (card->dev_to_devtint_next)->next; + card->dev_to_devtint_next = card->devs_struct; + } +} +/*============================================================================ + * Receive interrupt handler. + */ + +static void fr502_rx_intr(sdla_t * card) +{ + fr_mbox_t *mbox = card->rxmb; + struct sk_buff *skb; + struct net_device *dev; + fr_channel_t *chan; + unsigned dlci, len; + void *buf; + unsigned char *sendpacket; + unsigned char buf2[3]; + int udp_type; + sdla_mapmem(&card->hw, FR502_RX_VECTOR); + dlci = mbox->cmd.dlci; + len = mbox->cmd.length; + /* Find network interface for this packet */ + dev = find_channel(card, dlci); + if (dev == NULL) + { + /* Invalid channel, discard packet */ + printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n", + card->devname, dlci); + sdla_mapmem(&card->hw, FR_MB_VECTOR); + } + chan = dev->priv; + if (!dev->start) + { + ++chan->ifstats.rx_dropped; + sdla_mapmem(&card->hw, FR_MB_VECTOR); + } + /* Allocate socket buffer */ + skb = dev_alloc_skb(len); + if (skb == NULL) + { + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + ++chan->ifstats.rx_dropped; + sdla_mapmem(&card->hw, FR_MB_VECTOR); + } + /* Copy data to the socket buffer */ + buf = skb_put(skb, len); + memcpy(buf, mbox->data, len); + sdla_mapmem(&card->hw, FR_MB_VECTOR); + /* Check if it's a UDP management packet */ + sendpacket = skb->data; + memcpy(&buf2, &card->wandev.udp_port, 2); + udp_type = udp_pkt_type(skb, card); + if ((udp_type == UDP_FPIPE_TYPE) || (udp_type == UDP_DRVSTATS_TYPE)) + { + if (udp_type == UDP_DRVSTATS_TYPE) + { + ++chan->rx_intr_DRVSTATS_request; + process_udp_driver_call(UDP_PKT_FRM_NETWORK, card, skb, + dev, dlci, chan); + } + else + { + ++chan->rx_intr_FPIPE_request; + process_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, card, skb, + dev, dlci, chan); + } + } + else + { + /* Decapsulate packet and pass it up the protocol stack */ + skb->dev = dev; + buf = skb_pull(skb, 1); /* remove hardware header */ + if (!wanrouter_type_trans(skb, dev)) + { + /* can't decapsulate packet */ + dev_kfree_skb(skb); + ++chan->ifstats.rx_errors; + ++card->wandev.stats.rx_errors; + } + else + { + netif_rx(skb); + ++chan->ifstats.rx_packets; + ++card->wandev.stats.rx_packets; + chan->ifstats.rx_bytes += skb->len; + card->wandev.stats.rx_bytes += skb->len; + } + } + sdla_mapmem(&card->hw, FR_MB_VECTOR); +} +/*============================================================================ + * Receive interrupt handler. + */ + +static void fr508_rx_intr(sdla_t * card) +{ + fr_buf_ctl_t *frbuf = card->rxmb; + struct sk_buff *skb; + struct net_device *dev; + fr_channel_t *chan; + unsigned dlci, len, offs; + void *buf; + unsigned rx_count = 0; + fr508_flags_t *flags = card->flags; + char *ptr = &flags->iflag; + int i, err, udp_type; + if (frbuf->flag != 0x01) + { + printk(KERN_INFO + "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", + card->devname, (unsigned) frbuf, frbuf->flag); + printk(KERN_INFO "%s: ID Bytes = ", card->devname); + for (i = 0; i < 8; i++) + printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); + printk(KERN_INFO "\n"); + ++card->statistics.rx_intr_corrupt_rx_bfr; + return; + } + + do + { + len = frbuf->length; + dlci = frbuf->dlci; + offs = frbuf->offset; + /* Find network interface for this packet */ + dev = find_channel(card, dlci); + chan = dev->priv; + if (dev == NULL) + { + /* Invalid channel, discard packet */ + printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n" + ,card->devname, dlci); + ++card->statistics.rx_intr_on_orphaned_DLCI; + } + else + { + skb = dev_alloc_skb(len); + if (!dev->start || (skb == NULL)) + { + ++chan->ifstats.rx_dropped; + if (dev->start) + { + printk(KERN_INFO + "%s: no socket buffers available!\n", + card->devname); + ++chan->rx_intr_no_socket; + } else + ++chan->rx_intr_dev_not_started; + } + else + { + /* Copy data to the socket buffer */ + if ((offs + len) > card->u.f.rx_top + 1) + { + unsigned tmp = card->u.f.rx_top - offs + 1; + buf = skb_put(skb, tmp); + sdla_peek(&card->hw, offs, buf, tmp); + offs = card->u.f.rx_base; + len -= tmp; + } + buf = skb_put(skb, len); + sdla_peek(&card->hw, offs, buf, len); + udp_type = udp_pkt_type(skb, card); + if (udp_type == UDP_DRVSTATS_TYPE) + { + ++chan->rx_intr_DRVSTATS_request; + process_udp_driver_call( + UDP_PKT_FRM_NETWORK, card, skb, + dev, dlci, chan); + } + else if (udp_type == UDP_FPIPE_TYPE) + { + ++chan->rx_intr_FPIPE_request; + err = process_udp_mgmt_pkt( + UDP_PKT_FRM_NETWORK, card, + skb, dev, dlci, chan); + } + else if (handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number)) + { + if (card->wandev.enable_IPX) + fr508_send(card, dlci, 0, skb->len, skb->data); + } + else + { + /* Decapsulate packet and pass it up the + protocol stack */ + skb->dev = dev; + /* remove hardware header */ + buf = skb_pull(skb, 1); + if (!wanrouter_type_trans(skb, dev)) + { + /* can't decapsulate packet */ + dev_kfree_skb(skb); + ++chan-> + rx_intr_bfr_not_passed_to_stack; + ++chan-> + ifstats.rx_errors; + ++card-> + wandev.stats.rx_errors; + } + else + { + netif_rx(skb); + ++chan->rx_intr_bfr_passed_to_stack; + ++chan->ifstats.rx_packets; + ++card->wandev.stats.rx_packets; + chan->ifstats.rx_bytes += skb->len; + card->wandev.stats.rx_bytes += skb->len; + } + } + } + } + /* Release buffer element and calculate a pointer to the next + one */ + frbuf->flag = 0; + card->rxmb = ++frbuf; + if ((void *) frbuf > card->u.f.rxmb_last) + card->rxmb = card->u.f.rxmb_base; + /* The loop put in is temporary, that is why the break is + * placed here. (?????) + */ + break; + frbuf = card->rxmb; + } + while (frbuf->flag && ((++rx_count) < 4)); +} +/*============================================================================ + * Transmit interrupt handler. + * o print a warning + * o + * If number of spurious interrupts exceeded some limit, then ??? + */ +static void tx_intr(sdla_t * card) +{ + struct net_device *dev = card->wandev.dev; + if (card->intr_mode == BUFFER_INTR_MODE) + { + for (; dev; dev = dev->slave) + { + if (!dev || !dev->start) + { + ++card->statistics.tx_intr_dev_not_started; + continue; + } + dev->tbusy = 0; + mark_bh(NET_BH); + } + } + else + { + dev->tbusy = 0; + mark_bh(NET_BH); + } +} + +/*============================================================================ + * Spurious interrupt handler. + * o print a warning + * o + * If number of spurious interrupts exceeded some limit, then ??? + */ + +static void spur_intr(sdla_t * card) +{ + printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); +} + +/* + Return 0 for non-IPXWAN packet + 1 for IPXWAN packet or IPX is not enabled! + */ + +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number) +{ + int i; + if (sendpacket[1] == 0x00 && + sendpacket[2] == 0x80 && + sendpacket[6] == 0x81 && + sendpacket[7] == 0x37) + { + /* It's an IPX packet */ + if (!enable_IPX) { + /* Return 1 so we don't pass it up the stack. */ + return 1; + } + } + else + { + /* It's not IPX so return and pass it up the stack. */ + return 0; + } + if (sendpacket[24] == 0x90 && + sendpacket[25] == 0x04) + { + /* It's IPXWAN */ + if (sendpacket[10] == 0x02 && + sendpacket[42] == 0x00) + { + /* It's a timer request packet */ + printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", devname); + /* Go through the routing options and answer no to every */ + /* option except Unnumbered RIP/SAP */ + for (i = 49; sendpacket[i] == 0x00; i += 5) + { + /* 0x02 is the option for Unnumbered RIP/SAP */ + if (sendpacket[i + 4] != 0x02) + { + sendpacket[i + 1] = 0; + } + } + /* Skip over the extended Node ID option */ + if (sendpacket[i] == 0x04) + i += 8; + /* We also want to turn off all header compression opt. */ + for (; sendpacket[i] == 0x80;) + { + sendpacket[i + 1] = 0; + i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; + } + /* Set the packet type to timer response */ + sendpacket[42] = 0x01; + printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", devname); + } + else if (sendpacket[42] == 0x02) + { + /* This is an information request packet */ + printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n", devname); + /* Set the packet type to information response */ + sendpacket[42] = 0x03; + /* Set the router name */ + sendpacket[59] = 'F'; + sendpacket[60] = 'P'; + sendpacket[61] = 'I'; + sendpacket[62] = 'P'; + sendpacket[63] = 'E'; + sendpacket[64] = '-'; + sendpacket[65] = CVHexToAscii(network_number >> 28); + sendpacket[66] = CVHexToAscii((network_number & 0x0F000000) >> 24); + sendpacket[67] = CVHexToAscii((network_number & 0x00F00000) >> 20); + sendpacket[68] = CVHexToAscii((network_number & 0x000F0000) >> 16); + sendpacket[69] = CVHexToAscii((network_number & 0x0000F000) >> 12); + sendpacket[70] = CVHexToAscii((network_number & 0x00000F00) >> 8); + sendpacket[71] = CVHexToAscii((network_number & 0x000000F0) >> 4); + sendpacket[72] = CVHexToAscii(network_number & 0x0000000F); + for (i = 73; i < 107; i += 1) + sendpacket[i] = 0; + printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", devname); + } + else + { + printk(KERN_INFO "%s: Unknown IPXWAN packet!\n", devname); + return 0; + } + /* Set the WNodeID to our network address */ + sendpacket[43] = (unsigned char) (network_number >> 24); + sendpacket[44] = (unsigned char) ((network_number & 0x00FF0000) >> 16); + sendpacket[45] = (unsigned char) ((network_number & 0x0000FF00) >> 8); + sendpacket[46] = (unsigned char) (network_number & 0x000000FF); + return 1; + } + /* If we get here, its an IPX-data packet so it'll get passed up the stack. */ + /* switch the network numbers */ + switch_net_numbers(sendpacket, network_number, 1); + return 0; +} + +/****** Background Polling Routines ****************************************/ + +/*============================================================================ + * Main polling routine. + * This routine is repeatedly called by the WANPIPE 'thead' to allow for + * time-dependent housekeeping work. + * + * o fetch asynchronous network events. + * + * Notes: + * 1. This routine may be called on interrupt context with all interrupts + * enabled. Beware! + */ + +static void wpf_poll(sdla_t * card) +{ +/* struct net_device* dev = card->wandev.dev; */ + fr508_flags_t *flags = card->flags; + unsigned long host_cpu_flags; + ++card->statistics.poll_entry; + if (((jiffies - card->state_tick) < HZ) || + (card->intr_mode == INTR_TEST_MODE)) + return; + disable_irq(card->hw.irq); + ++card->irq_dis_poll_count; + if (test_and_set_bit(0, (void *) &card->wandev.critical)) + { + ++card->statistics.poll_already_critical; + save_flags(host_cpu_flags); + cli(); + if ((!card->irq_dis_if_send_count) && + (!(--card->irq_dis_poll_count))) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return; + } + card->wandev.critical = 0x11; + ++card->statistics.poll_processed; + /* This is to be changed later ??? */ + /* + if( dev && dev->tbusy && !(flags->imask & 0x02) ) { + printk(KERN_INFO "%s: Wpf_Poll: tbusy = 0x01, imask = 0x%02X\n", card->devname, flags->imask); + } + */ + if (flags->event) + { + fr_mbox_t *mbox = card->mbox; + int err; + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.command = FR_READ_STATUS; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err) + fr_event(card, err, mbox); + } + card->wandev.critical = 0; + save_flags(host_cpu_flags); + cli(); + if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + card->state_tick = jiffies; +} + +/****** Frame Relay Firmware-Specific Functions *****************************/ + +/*============================================================================ + * Read firmware code version. + * o fill string str with firmware version info. + */ + +static int fr_read_version(sdla_t * card, char *str) +{ + fr_mbox_t *mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.command = FR_READ_CODE_VERSION; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && fr_event(card, err, mbox)); + + if (!err && str) + { + int len = mbox->cmd.length; + memcpy(str, mbox->data, len); + str[len] = '\0'; + } + return err; +} +/*============================================================================ + * Set global configuration. + */ + +static int fr_configure(sdla_t * card, fr_conf_t * conf) +{ + fr_mbox_t *mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int dlci_num = card->u.f.dlci_num; + int err, i; + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + memcpy(mbox->data, conf, sizeof(fr_conf_t)); + if (dlci_num) + for (i = 0; i < dlci_num; ++i) + ((fr_conf_t *) mbox->data)->dlci[i] = + card->u.f.node_dlci[i]; + mbox->cmd.command = FR_SET_CONFIG; + mbox->cmd.length = + sizeof(fr_conf_t) + dlci_num * sizeof(short); + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + + return err; +} +/*============================================================================ + * Set DLCI configuration. + */ +static int fr_dlci_configure(sdla_t * card, fr_dlc_conf_t * conf, unsigned dlci) +{ + fr_mbox_t *mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + memcpy(mbox->data, conf, sizeof(fr_dlc_conf_t)); + mbox->cmd.dlci = (unsigned short) dlci; + mbox->cmd.command = FR_SET_CONFIG; + mbox->cmd.length = 0x0E; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry--); + return err; +} +/*============================================================================ + * Set interrupt mode. + */ +static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu) +{ + fr_mbox_t *mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + if (card->hw.fwid == SFID_FR502) + { + fr502_intr_ctl_t *ictl = (void *) mbox->data; + memset(ictl, 0, sizeof(fr502_intr_ctl_t)); + ictl->mode = mode; + ictl->tx_len = mtu; + mbox->cmd.length = sizeof(fr502_intr_ctl_t); + } + else + { + fr508_intr_ctl_t *ictl = (void *) mbox->data; + memset(ictl, 0, sizeof(fr508_intr_ctl_t)); + ictl->mode = mode; + ictl->tx_len = mtu; + ictl->irq = card->hw.irq; + mbox->cmd.length = sizeof(fr508_intr_ctl_t); + } + mbox->cmd.command = FR_SET_INTR_MODE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + + return err; +} +/*============================================================================ + * Enable communications. + */ +static int fr_comm_enable(sdla_t * card) +{ + fr_mbox_t *mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.command = FR_COMM_ENABLE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + + return err; +} +/*============================================================================ + * Disable communications. + */ +static int fr_comm_disable(sdla_t * card) +{ + fr_mbox_t *mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.command = FR_COMM_DISABLE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + + return err; +} +/*============================================================================ + * Get communications error statistics. + */ +static int fr_get_err_stats(sdla_t * card) +{ + fr_mbox_t *mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.command = FR_READ_ERROR_STATS; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + + if (!err) + { + fr_comm_stat_t *stats = (void *) mbox->data; + card->wandev.stats.rx_over_errors = stats->rx_overruns; + card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; + card->wandev.stats.rx_missed_errors = stats->rx_aborts; + card->wandev.stats.rx_length_errors = stats->rx_too_long; + card->wandev.stats.tx_aborted_errors = stats->tx_aborts; + } + return err; +} +/*============================================================================ + * Get statistics. + */ +static int fr_get_stats(sdla_t * card) +{ + fr_mbox_t *mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.command = FR_READ_STATISTICS; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + + if (!err) + { + fr_link_stat_t *stats = (void *) mbox->data; + card->wandev.stats.rx_frame_errors = stats->rx_bad_format; + card->wandev.stats.rx_dropped = stats->rx_dropped + stats->rx_dropped2; + } + return err; +} +/*============================================================================ + * Add DLCI(s) (Access Node only!). + * This routine will perform the ADD_DLCIs command for the specified DLCI. + */ +static int fr_add_dlci(sdla_t * card, int dlci, int num) +{ + fr_mbox_t *mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err, i; + do + { + unsigned short *dlci_list = (void *) mbox->data; + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + for (i = 0; i < num; ++i) + dlci_list[i] = card->u.f.node_dlci[i]; + mbox->cmd.length = num * sizeof(short); + mbox->cmd.command = FR_ADD_DLCI; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + + return err; +} +/*============================================================================ + * Activate DLCI(s) (Access Node only!). + * This routine will perform the ACTIVATE_DLCIs command with a list of DLCIs. + */ +static int fr_activate_dlci(sdla_t * card, int dlci, int num) +{ + fr_mbox_t *mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err, i; + do + { + unsigned short *dlci_list = (void *) mbox->data; + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + for (i = 0; i < num; ++i) + dlci_list[i] = card->u.f.node_dlci[i]; + mbox->cmd.length = num * sizeof(short); + mbox->cmd.command = FR_ACTIVATE_DLCI; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + + return err; +} +/*============================================================================ + * Issue in-channel signalling frame. + */ +static int fr_issue_isf(sdla_t * card, int isf) +{ + fr_mbox_t *mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->data[0] = isf; + mbox->cmd.length = 1; + mbox->cmd.command = FR_ISSUE_IS_FRAME; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + + return err; +} +/*============================================================================ + * Send a frame (S502 version). + */ +static int fr502_send(sdla_t * card, int dlci, int attr, int len, void *buf) +{ + fr_mbox_t *mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + memcpy(mbox->data, buf, len); + mbox->cmd.dlci = dlci; + mbox->cmd.attr = attr; + mbox->cmd.length = len; + mbox->cmd.command = FR_WRITE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + + return err; +} +/*============================================================================ + * Send a frame (S508 version). + */ +static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf) +{ + fr_mbox_t *mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.dlci = dlci; + mbox->cmd.attr = attr; + mbox->cmd.length = len; + mbox->cmd.command = FR_WRITE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + + if (!err) + { + fr_buf_ctl_t *frbuf = (void *) (*(unsigned long *) mbox->data - + FR_MB_VECTOR + card->hw.dpmbase); + sdla_poke(&card->hw, frbuf->offset, buf, len); + frbuf->flag = 0x01; + } + return err; +} + +/****** Firmware Asynchronous Event Handlers ********************************/ + +/*============================================================================ + * Main asynchronous event/error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ + +static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox) +{ + fr508_flags_t *flags = card->flags; + char *ptr = &flags->iflag; + int i; + switch (event) + { + case FRRES_MODEM_FAILURE: + return fr_modem_failure(card, mbox); + case FRRES_CHANNEL_DOWN: + wanpipe_set_state(card, WAN_DISCONNECTED); + return 1; + case FRRES_CHANNEL_UP: + wanpipe_set_state(card, WAN_CONNECTED); + return 1; + case FRRES_DLCI_CHANGE: + return fr_dlci_change(card, mbox); + case FRRES_DLCI_MISMATCH: + printk(KERN_INFO "%s: DLCI list mismatch!\n", + card->devname); + return 1; + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, mbox->cmd.command); + printk(KERN_INFO "%s: ID Bytes = ", card->devname); + for (i = 0; i < 8; i++) + printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); + printk(KERN_INFO "\n"); + break; + case FRRES_DLCI_INACTIVE: + printk(KERN_ERR "%s: DLCI %u is inactive!\n", + card->devname, mbox->cmd.dlci); + break; + case FRRES_CIR_OVERFLOW: + break; + case FRRES_BUFFER_OVERFLOW: + break; + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" + ,card->devname, mbox->cmd.command, event); + } + return 0; +} + +/*============================================================================ + * Handle modem error. + * + * Return zero if previous command has to be cancelled. + */ +static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox) +{ + printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)\n", + card->devname, mbox->data[0]); + switch (mbox->cmd.command) + { + case FR_WRITE: + case FR_READ: + return 0; + } + return 1; +} +/*============================================================================ + * Handle DLCI status change. + * + * Return zero if previous command has to be cancelled. + */ +static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox) +{ + dlci_status_t *status = (void *) mbox->data; + int cnt = mbox->cmd.length / sizeof(dlci_status_t); + fr_dlc_conf_t cfg; + fr_channel_t *chan; + struct net_device *dev2; + for (; cnt; --cnt, ++status) + { + unsigned short dlci = status->dlci; + struct net_device *dev = find_channel(card, dlci); + if (dev == NULL) + { + printk(KERN_INFO + "%s: CPE contains unconfigured DLCI= %d\n", + card->devname, dlci); + } + else + { + if (status->state & 0x01) + { + printk(KERN_INFO + "%s: DLCI %u has been deleted!\n", + card->devname, dlci); + if (dev && dev->start) + set_chan_state(dev, WAN_DISCONNECTED); + } + else if (status->state & 0x02) + { + printk(KERN_INFO + "%s: DLCI %u becomes active!\n", + card->devname, dlci); + chan = dev->priv; + /* This flag is used for configuring specific + DLCI(s) when they become active. + */ + chan->dlci_configured = DLCI_CONFIG_PENDING; + if (dev && dev->start) + set_chan_state(dev, WAN_CONNECTED); + } + } + } + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) + { + chan = dev2->priv; + if (chan->dlci_configured == DLCI_CONFIG_PENDING) + { + memset(&cfg, 0, sizeof(cfg)); + if (chan->cir_status == CIR_DISABLED) + { + cfg.cir_fwd = cfg.cir_bwd = 16; + cfg.bc_fwd = cfg.bc_bwd = 16; + cfg.conf_flags = 0x0001; + printk(KERN_INFO "%s: CIR Disabled for %s\n", + card->devname, chan->name); + } else if (chan->cir_status == CIR_ENABLED) { + cfg.cir_fwd = cfg.cir_bwd = chan->cir; + cfg.bc_fwd = cfg.bc_bwd = chan->bc; + cfg.be_fwd = cfg.be_bwd = chan->be; + cfg.conf_flags = 0x0000; + printk(KERN_INFO "%s: CIR Enabled for %s\n", + card->devname, chan->name); + } + if (fr_dlci_configure(card, &cfg, chan->dlci)) + { + printk(KERN_INFO + "%s: DLCI Configure failed for %d\n", + card->devname, chan->dlci); + return 1; + } + chan->dlci_configured = DLCI_CONFIGURED; + /* Read the interface byte mapping into the channel + structure. + */ + if (card->intr_mode == DLCI_LIST_INTR_MODE) + read_DLCI_IB_mapping(card, chan); + } + } + return 1; +} +/******* Miscellaneous ******************************************************/ + +/*============================================================================ + * Update channel state. + */ +static int update_chan_state(struct net_device *dev) +{ + fr_channel_t *chan = dev->priv; + sdla_t *card = chan->card; + fr_mbox_t *mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + int dlci_found = 0; + + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.command = FR_LIST_ACTIVE_DLCI; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + + if (!err) + { + unsigned short *list = (void *) mbox->data; + int cnt = mbox->cmd.length / sizeof(short); + for (; cnt; --cnt, ++list) + { + if (*list == chan->dlci) + { + dlci_found = 1; + set_chan_state(dev, WAN_CONNECTED); + break; + } + } + if (!dlci_found) + printk(KERN_INFO "%s: DLCI %u is inactive\n", + card->devname, chan->dlci); + } + + return err; +} +/*============================================================================ + * Set channel state. + */ +static void set_chan_state(struct net_device *dev, int state) +{ + fr_channel_t *chan = dev->priv; + sdla_t *card = chan->card; + unsigned long flags; + + save_flags(flags); + cli(); + + if (chan->state != state) + { + switch (state) + { + case WAN_CONNECTED: + printk(KERN_INFO "%s: interface %s connected!\n" + ,card->devname, dev->name); + break; + case WAN_CONNECTING: + printk(KERN_INFO + "%s: interface %s connecting...\n", + card->devname, dev->name); + break; + case WAN_DISCONNECTED: + printk(KERN_INFO + "%s: interface %s disconnected!\n", + card->devname, dev->name); + break; + } + chan->state = state; + } + chan->state_tick = jiffies; + restore_flags(flags); +} + +/*============================================================================ + * Find network device by its channel number. + */ +static struct net_device *find_channel(sdla_t * card, unsigned dlci) +{ + struct net_device *dev; + for (dev = card->wandev.dev; dev; dev = dev->slave) + if (((fr_channel_t *) dev->priv)->dlci == dlci) + break; + return dev; +} +/*============================================================================ + * Check to see if a frame can be sent. If no transmit buffers available, + * enable transmit interrupts. + * + * Return: 1 - Tx buffer(s) available + * 0 - no buffers available + */ + +static int is_tx_ready(sdla_t * card, fr_channel_t * chan) +{ + if (card->hw.fwid == SFID_FR508) + { + unsigned char sb = inb(card->hw.port); + if (sb & 0x02) + return 1; + } + else + { + fr502_flags_t *flags = card->flags; + if (flags->tx_ready) + return 1; + flags->imask |= 0x02; + } + return 0; +} + +/*============================================================================ + * Convert decimal string to unsigned integer. + * If len != 0 then only 'len' characters of the string are converted. + */ +static unsigned int dec_to_uint(unsigned char *str, int len) +{ + unsigned val; + if (!len) + len = strlen(str); + for (val = 0; len && is_digit(*str); ++str, --len) + val = (val * 10) + (*str - (unsigned) '0'); + return val; +} + +/*============================================================================== + * Process UDP call of type FPIPE8ND + */ + +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, int dlci, fr_channel_t * chan) +{ + int c_retry = MAX_CMD_RETRY; + unsigned char *data; + unsigned char *buf; + unsigned char buf2[5]; + unsigned int loops, frames, len; + unsigned long data_ptr; + unsigned short real_len, buffer_length; + struct sk_buff *new_skb; + unsigned char *sendpacket; + fr_mbox_t *mbox = card->mbox; + int err; + struct timeval tv; + int udp_mgmt_req_valid = 1; + sendpacket = skb->data; + memcpy(&buf2, &card->wandev.udp_port, 2); + if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) + { + printk(KERN_INFO + "%s: Error allocating memory for UDP management cmnd 0x%02X", + card->devname, data[47]); + ++chan->UDP_FPIPE_mgmt_kmalloc_err; + return 1; + } + memcpy(data, sendpacket, skb->len); + switch (data[47]) + { + /* FPIPE_ENABLE_TRACE */ + case 0x41: + /* FPIPE_DISABLE_TRACE */ + case 0x42: + /* FPIPE_GET_TRACE_INFO */ + case 0x43: + /* SET FT1 MODE */ + case 0x81: + if (udp_pkt_src == UDP_PKT_FRM_NETWORK) + { + ++chan->UDP_FPIPE_mgmt_direction_err; + udp_mgmt_req_valid = 0; + break; + } + /* FPIPE_FT1_READ_STATUS */ + case 0x44: + /* FT1 MONITOR STATUS */ + case 0x80: + if (card->hw.fwid != SFID_FR508) + { + ++chan->UDP_FPIPE_mgmt_adptr_type_err; + udp_mgmt_req_valid = 0; + } + break; + default: + break; + } + if (!udp_mgmt_req_valid) + { + /* set length to 0 */ + data[48] = data[49] = 0; + /* set return code */ + data[50] = (card->hw.fwid != SFID_FR508) ? 0x1F : 0xCD; + } + else + { + switch (data[47]) + { + /* FPIPE_ENABLE_TRACE */ + case 0x41: + if (!TracingEnabled) + { + do + { + /* SET_TRACE_CONFIGURATION */ + mbox->cmd.command = 0x60; + mbox->cmd.length = 1; + mbox->cmd.dlci = 0x00; + mbox->data[0] = 0x37; + err = sdla_exec(mbox) ? + mbox->cmd.result : CMD_TIMEOUT; + } + while (err && c_retry-- && fr_event(card, err, mbox)); + + if (err) + { + TracingEnabled = 0; + /* set the return code */ + data[50] = mbox->cmd.result; + mbox->cmd.length = 0; + break; + } + /* get num_frames */ + sdla_peek(&card->hw, 0x9000, &num_frames, 2); + sdla_peek(&card->hw, 0x9002, &curr_trace_addr,4); + start_trace_addr = curr_trace_addr; + /* MAX_SEND_BUFFER_SIZE - + * sizeof(UDP_MGMT_PACKET) - 41 */ + available_buffer_space = 1926; + /* set return code */ + data[50] = 0; + } + else + { + /* set return code to line trace already + enabled */ + data[50] = 1; + } + mbox->cmd.length = 0; + TracingEnabled = 1; + break; + /* FPIPE_DISABLE_TRACE */ + case 0x42: + if (TracingEnabled) + { + do + { + /* SET_TRACE_CONFIGURATION */ + mbox->cmd.command = 0x60; + mbox->cmd.length = 1; + mbox->cmd.dlci = 0x00; + mbox->data[0] = 0x36; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && c_retry-- && fr_event(card, err, mbox)); + } + /* set return code */ + data[50] = 0; + mbox->cmd.length = 0; + TracingEnabled = 0; + break; + /* FPIPE_GET_TRACE_INFO */ + case 0x43: + /* Line trace cannot be performed on the 502 */ + if (!TracingEnabled) + { + /* set return code */ + data[50] = 1; + mbox->cmd.length = 0; + break; + } + buffer_length = 0; + loops = (num_frames < 20) ? num_frames : 20; + for (frames = 0; frames < loops; frames += 1) + { + sdla_peek(&card->hw, curr_trace_addr, &buf2, 1); + /* no data on board so exit */ + if (buf2[0] == 0x00) + break; + /* 1+sizeof(FRAME_DATA) = 9 */ + if ((available_buffer_space - buffer_length) < 9) + { + /* indicate we have more frames on board + and exit */ + data[62] |= 0x02; + break; + } + /* get frame status */ + sdla_peek(&card->hw, curr_trace_addr + 0x05, &data[62 + buffer_length], 1); + /* get time stamp */ + sdla_peek(&card->hw, curr_trace_addr + 0x06, &data[66 + buffer_length], 2); + /* get frame length */ + sdla_peek(&card->hw, curr_trace_addr + 0x01, &data[64 + buffer_length], 2); + /* get pointer to real data */ + sdla_peek(&card->hw, curr_trace_addr + 0x0C,&data_ptr, 4); + /* see if we can fit the frame into the user buffer */ + memcpy(&real_len, &data[64 + buffer_length], 2); + if (data_ptr == 0 || real_len + 8 > available_buffer_space) + { + data[63 + buffer_length] = 0x00; + } + else + { + /* we can take it next time */ + if (available_buffer_space - buffer_length < real_len + 8) + { + data[62] |= 0x02; + break; + } + /* ok, get the frame */ + data[63 + buffer_length] = 0x01; + /* get the data */ + sdla_peek(&card->hw, data_ptr, &data[68 + buffer_length], real_len); + /* zero the opp flag to show we got the frame */ + buf2[0] = 0x00; + sdla_poke(&card->hw, curr_trace_addr, &buf2, 1); + /* now move onto the next frame */ + curr_trace_addr += 16; + /* check if we passed the last address */ + if (curr_trace_addr >= (start_trace_addr + num_frames * 16)) + curr_trace_addr = start_trace_addr; + /* update buffer length and make sure + its even */ + if (data[63 + buffer_length] == 0x01) + buffer_length += real_len - 1; + /* for the header */ + buffer_length += 8; + if (buffer_length & 0x0001) + buffer_length += 1; + } + } + /* ok now set the total number of frames passed in the + high 5 bits */ + data[62] = (frames << 3) | data[62]; + /* set the data length */ + mbox->cmd.length = buffer_length; + memcpy(&data[48], &buffer_length, 2); + data[50] = 0; + break; + /* FPIPE_FT1_READ_STATUS */ + case 0x44: + sdla_peek(&card->hw, 0xF020, &data[62], 2); + data[48] = 2; + data[49] = 0; + data[50] = 0; + mbox->cmd.length = 2; + break; + /* FPIPE_FLUSH_DRIVER_STATS */ + case 0x48: + init_chan_statistics(chan); + init_global_statistics(card); + mbox->cmd.length = 0; + break; + case 0x49: + do_gettimeofday(&tv); + chan->router_up_time = tv.tv_sec - chan->router_start_time; + *(unsigned long *) &data[62] = chan->router_up_time; + mbox->cmd.length = 4; + break; + /* FPIPE_KILL_BOARD */ + case 0x50: + break; + /* FT1 MONITOR STATUS */ + case 0x80: + if (data[62] == 1) + { + if (rCount++ != 0) + { + data[50] = 0; + mbox->cmd.length = 1; + break; + } + } + /* Disable FT1 MONITOR STATUS */ + if (data[62] == 0) + { + if (--rCount != 0) + { + data[50] = 0; + mbox->cmd.length = 1; + break; + } + } + default: + do + { + memcpy(&mbox->cmd, &sendpacket[47], sizeof(fr_cmd_t)); + if (mbox->cmd.length) + memcpy(&mbox->data, &sendpacket[62],mbox->cmd.length); + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && c_retry-- && fr_event(card, err, mbox)); + + if (!err) + { + ++chan->UDP_FPIPE_mgmt_adptr_cmnd_OK; + memcpy(data, sendpacket, skb->len); + memcpy(&data[47], &mbox->cmd, sizeof(fr_cmd_t)); + if (mbox->cmd.length) + { + memcpy(&data[62], &mbox->data,mbox->cmd.length); + } + } + else + { + ++chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout; + } + } + } + /* Fill UDP TTL */ + data[10] = card->wandev.ttl; + len = reply_udp(data, mbox->cmd.length); + if (udp_pkt_src == UDP_PKT_FRM_NETWORK) + { + err = fr508_send(card, dlci, 0, len, data); + if (err) + ++chan->UDP_FPIPE_mgmt_adptr_send_passed; + else + ++chan->UDP_FPIPE_mgmt_adptr_send_failed; + dev_kfree_skb(skb); + } + else + { + /* Allocate socket buffer */ + if ((new_skb = dev_alloc_skb(len)) != NULL) + { + /* copy data into new_skb */ + buf = skb_put(new_skb, len); + memcpy(buf, data, len); + /* Decapsulate packet and pass it up the protocol + stack */ + new_skb->dev = dev; + buf = skb_pull(new_skb, 1); /* remove hardware header */ + if (!wanrouter_type_trans(new_skb, dev)) + { + ++chan->UDP_FPIPE_mgmt_not_passed_to_stack; + /* can't decapsulate packet */ + dev_kfree_skb(new_skb); + } + else + { + ++chan->UDP_FPIPE_mgmt_passed_to_stack; + netif_rx(new_skb); + } + } + else + { + ++chan->UDP_FPIPE_mgmt_no_socket; + printk(KERN_INFO + "%s: UDP mgmt cmnd, no socket buffers available!\n", + card->devname); + } + } + kfree(data); + return 0; +} +/*============================================================================== + * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_ + * TEST_COUNTER times. + */ + +static int intr_test(sdla_t * card) +{ + fr_mbox_t *mb = card->mbox; + int err, i; + /* The critical flag is unset here because we want to get into the + ISR without the flag already set. The If_open sets the flag. + */ + card->wandev.critical = 0; + err = fr_set_intr_mode(card, 0x08, card->wandev.mtu); + if (err == CMD_OK) + { + for (i = 0; i < MAX_INTR_TEST_COUNTER; i++) + { + /* Run command READ_CODE_VERSION */ + memset(&mb->cmd, 0, sizeof(fr_cmd_t)); + mb->cmd.length = 0; + mb->cmd.command = 0x40; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) + fr_event(card, err, mb); + } + } + else + { + return err; + } + err = fr_set_intr_mode(card, 0, card->wandev.mtu); + if (err != CMD_OK) + return err; + card->wandev.critical = 1; + return 0; +} +/*============================================================================ + * Process UDP call of type DRVSTATS. + */ +static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, int dlci, fr_channel_t * chan) +{ + int c_retry = MAX_CMD_RETRY; + unsigned char *sendpacket; + unsigned char buf2[5]; + unsigned char *data; + unsigned char *buf; + unsigned int len; + fr_mbox_t *mbox = card->mbox; + struct sk_buff *new_skb; + int err; + sendpacket = skb->data; + memcpy(&buf2, &card->wandev.udp_port, 2); + if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) + { + printk(KERN_INFO + "%s: Error allocating memory for UDP DRIVER STATS cmnd0x%02X" + ,card->devname, data[45]); + ++chan->UDP_DRVSTATS_mgmt_kmalloc_err; + return 1; + } + memcpy(data, sendpacket, skb->len); + switch (data[47]) + { + case 0x45: + *(unsigned long *) &data[62] = chan->if_send_entry; + *(unsigned long *) &data[66] = chan->if_send_skb_null; + *(unsigned long *) &data[70] = chan->if_send_broadcast; + *(unsigned long *) &data[74] = chan->if_send_multicast; + *(unsigned long *) &data[78] = chan->if_send_critical_ISR; + *(unsigned long *) &data[82] = chan->if_send_critical_non_ISR; + *(unsigned long *) &data[86] = chan->if_send_busy; + *(unsigned long *) &data[90] = chan->if_send_busy_timeout; + *(unsigned long *) &data[94] = chan->if_send_DRVSTATS_request; + *(unsigned long *) &data[98] = chan->if_send_FPIPE_request; + *(unsigned long *) &data[102] = chan->if_send_wan_disconnected; + *(unsigned long *) &data[106] = chan->if_send_dlci_disconnected; + *(unsigned long *) &data[110] = chan->if_send_no_bfrs; + *(unsigned long *) &data[114] = chan->if_send_adptr_bfrs_full; + *(unsigned long *) &data[118] = chan->if_send_bfrs_passed_to_adptr; + *(unsigned long *) &data[120] = card->irq_dis_if_send_count; + mbox->cmd.length = 62; + break; + case 0x46: + *(unsigned long *) &data[62] = card->statistics.isr_entry; + *(unsigned long *) &data[66] = card->statistics.isr_already_critical; + *(unsigned long *) &data[70] = card->statistics.isr_rx; + *(unsigned long *) &data[74] = card->statistics.isr_tx; + *(unsigned long *) &data[78] = card->statistics.isr_intr_test; + *(unsigned long *) &data[82] = card->statistics.isr_spurious; + *(unsigned long *) &data[86] = card->statistics.isr_enable_tx_int; + *(unsigned long *) &data[90] = card->statistics.tx_intr_dev_not_started; + *(unsigned long *) &data[94] = card->statistics.rx_intr_corrupt_rx_bfr; + *(unsigned long *) &data[98] = card->statistics.rx_intr_on_orphaned_DLCI; + *(unsigned long *) &data[102] = chan->rx_intr_no_socket; + *(unsigned long *) &data[106] = chan->rx_intr_dev_not_started; + *(unsigned long *) &data[110] = chan->rx_intr_DRVSTATS_request; + *(unsigned long *) &data[114] = chan->rx_intr_FPIPE_request; + *(unsigned long *) &data[118] = chan->rx_intr_bfr_not_passed_to_stack; + *(unsigned long *) &data[122] = chan->rx_intr_bfr_passed_to_stack; + mbox->cmd.length = 64; + break; + case 0x47: + *(unsigned long *) &data[62] = chan->UDP_FPIPE_mgmt_kmalloc_err; + *(unsigned long *) &data[66] = chan->UDP_FPIPE_mgmt_adptr_type_err; + *(unsigned long *) &data[70] = chan->UDP_FPIPE_mgmt_direction_err; + *(unsigned long *) &data[74] = chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout; + *(unsigned long *) &data[78] = chan->UDP_FPIPE_mgmt_adptr_cmnd_OK; + *(unsigned long *) &data[82] = chan->UDP_FPIPE_mgmt_adptr_send_passed; + *(unsigned long *) &data[86] = chan->UDP_FPIPE_mgmt_adptr_send_failed; + *(unsigned long *) &data[90] = chan->UDP_FPIPE_mgmt_no_socket; + *(unsigned long *) &data[94] = chan->UDP_FPIPE_mgmt_not_passed_to_stack; + *(unsigned long *) &data[98] = chan->UDP_FPIPE_mgmt_passed_to_stack; + *(unsigned long *) &data[102] = chan->UDP_DRVSTATS_mgmt_kmalloc_err; + *(unsigned long *) &data[106] = chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; + *(unsigned long *) &data[110] = chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; + *(unsigned long *) &data[114] = chan->UDP_DRVSTATS_mgmt_adptr_send_passed; + *(unsigned long *) &data[118] = chan->UDP_DRVSTATS_mgmt_adptr_send_failed; + *(unsigned long *) &data[122] = chan->UDP_DRVSTATS_mgmt_no_socket; + *(unsigned long *) &data[126] = chan->UDP_DRVSTATS_mgmt_not_passed_to_stack; + *(unsigned long *) &data[130] = chan->UDP_DRVSTATS_mgmt_passed_to_stack; + *(unsigned long *) &data[134] = card->statistics.poll_entry; + *(unsigned long *) &data[138] = card->statistics.poll_already_critical; + *(unsigned long *) &data[142] = card->statistics.poll_processed; + *(unsigned long *) &data[144] = card->irq_dis_poll_count; + mbox->cmd.length = 86; + break; + default: + do + { + memcpy(&mbox->cmd, &sendpacket[47], sizeof(fr_cmd_t)); + if (mbox->cmd.length) + memcpy(&mbox->data, &sendpacket[62], mbox->cmd.length); + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && c_retry-- && fr_event(card, err, mbox)); + + if (!err) + { + ++chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; + memcpy(data, sendpacket, skb->len); + memcpy(&data[47], &mbox->cmd, sizeof(fr_cmd_t)); + if (mbox->cmd.length) + memcpy(&data[62], &mbox->data, mbox->cmd.length); + } + else + { + ++chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; + } + } + /* Fill UDP TTL */ + data[10] = card->wandev.ttl; + len = reply_udp(data, mbox->cmd.length); + if (udp_pkt_src == UDP_PKT_FRM_NETWORK) + { + err = fr508_send(card, dlci, 0, len, data); + if (err) + ++chan->UDP_DRVSTATS_mgmt_adptr_send_failed; + else + ++chan->UDP_DRVSTATS_mgmt_adptr_send_passed; + dev_kfree_skb(skb); + } + else + { + /* Allocate socket buffer */ + if ((new_skb = dev_alloc_skb(len)) != NULL) + { + /* copy data into new_skb */ + buf = skb_put(new_skb, len); + memcpy(buf, data, len); + /* Decapsulate packet and pass it up the + protocol stack */ + new_skb->dev = dev; + /* remove hardware header */ + buf = skb_pull(new_skb, 1); + if (!wanrouter_type_trans(new_skb, dev)) + { + /* can't decapsulate packet */ + ++chan->UDP_DRVSTATS_mgmt_not_passed_to_stack; + dev_kfree_skb(new_skb); + } + else + { + ++chan->UDP_DRVSTATS_mgmt_passed_to_stack; + netif_rx(new_skb); + } + } + else + { + ++chan->UDP_DRVSTATS_mgmt_no_socket; + printk(KERN_INFO "%s: UDP mgmt cmnd, no socket buffers available!\n", card->devname); + } + } + kfree(data); + return 0; +} + +/*============================================================================== + * Determine what type of UDP call it is. DRVSTATS or FPIPE8ND ? + */ + +static int udp_pkt_type(struct sk_buff *skb, sdla_t * card) +{ + unsigned char *sendpacket; + unsigned char buf2[5]; + sendpacket = skb->data; + memcpy(&buf2, &card->wandev.udp_port, 2); + if (sendpacket[2] == 0x45 && /* IP packet */ + sendpacket[11] == 0x11 && /* UDP packet */ + sendpacket[24] == buf2[1] && /* UDP Port */ + sendpacket[25] == buf2[0] && + sendpacket[38] == 0x01) + { + if (sendpacket[30] == 0x46 && /* FPIPE8ND: Signature */ + sendpacket[31] == 0x50 && + sendpacket[32] == 0x49 && + sendpacket[33] == 0x50 && + sendpacket[34] == 0x45 && + sendpacket[35] == 0x38 && + sendpacket[36] == 0x4E && + sendpacket[37] == 0x44) + { + return UDP_FPIPE_TYPE; + } else if (sendpacket[30] == 0x44 && /* DRVSTATS: Signature */ + sendpacket[31] == 0x52 && + sendpacket[32] == 0x56 && + sendpacket[33] == 0x53 && + sendpacket[34] == 0x54 && + sendpacket[35] == 0x41 && + sendpacket[36] == 0x54 && + sendpacket[37] == 0x53) + { + return UDP_DRVSTATS_TYPE; + } + else + return UDP_INVALID_TYPE; + } + else + return UDP_INVALID_TYPE; +} +/*============================================================================== + * Initializes the Statistics values in the fr_channel structure. + */ + +void init_chan_statistics(fr_channel_t * chan) +{ + chan->if_send_entry = 0; + chan->if_send_skb_null = 0; + chan->if_send_broadcast = 0; + chan->if_send_multicast = 0; + chan->if_send_critical_ISR = 0; + chan->if_send_critical_non_ISR = 0; + chan->if_send_busy = 0; + chan->if_send_busy_timeout = 0; + chan->if_send_FPIPE_request = 0; + chan->if_send_DRVSTATS_request = 0; + chan->if_send_wan_disconnected = 0; + chan->if_send_dlci_disconnected = 0; + chan->if_send_no_bfrs = 0; + chan->if_send_adptr_bfrs_full = 0; + chan->if_send_bfrs_passed_to_adptr = 0; + chan->rx_intr_no_socket = 0; + chan->rx_intr_dev_not_started = 0; + chan->rx_intr_FPIPE_request = 0; + chan->rx_intr_DRVSTATS_request = 0; + chan->rx_intr_bfr_not_passed_to_stack = 0; + chan->rx_intr_bfr_passed_to_stack = 0; + chan->UDP_FPIPE_mgmt_kmalloc_err = 0; + chan->UDP_FPIPE_mgmt_direction_err = 0; + chan->UDP_FPIPE_mgmt_adptr_type_err = 0; + chan->UDP_FPIPE_mgmt_adptr_cmnd_OK = 0; + chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout = 0; + chan->UDP_FPIPE_mgmt_adptr_send_passed = 0; + chan->UDP_FPIPE_mgmt_adptr_send_failed = 0; + chan->UDP_FPIPE_mgmt_not_passed_to_stack = 0; + chan->UDP_FPIPE_mgmt_passed_to_stack = 0; + chan->UDP_FPIPE_mgmt_no_socket = 0; + chan->UDP_DRVSTATS_mgmt_kmalloc_err = 0; + chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK = 0; + chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout = 0; + chan->UDP_DRVSTATS_mgmt_adptr_send_passed = 0; + chan->UDP_DRVSTATS_mgmt_adptr_send_failed = 0; + chan->UDP_DRVSTATS_mgmt_not_passed_to_stack = 0; + chan->UDP_DRVSTATS_mgmt_passed_to_stack = 0; + chan->UDP_DRVSTATS_mgmt_no_socket = 0; +} +/*============================================================================== + * Initializes the Statistics values in the Sdla_t structure. + */ + +void init_global_statistics(sdla_t * card) +{ + /* Intialize global statistics for a card */ + card->statistics.isr_entry = 0; + card->statistics.isr_already_critical = 0; + card->statistics.isr_rx = 0; + card->statistics.isr_tx = 0; + card->statistics.isr_intr_test = 0; + card->statistics.isr_spurious = 0; + card->statistics.isr_enable_tx_int = 0; + card->statistics.rx_intr_corrupt_rx_bfr = 0; + card->statistics.rx_intr_on_orphaned_DLCI = 0; + card->statistics.tx_intr_dev_not_started = 0; + card->statistics.poll_entry = 0; + card->statistics.poll_already_critical = 0; + card->statistics.poll_processed = 0; +} + +static void read_DLCI_IB_mapping(sdla_t * card, fr_channel_t * chan) +{ + fr_mbox_t *mbox = card->mbox; + int retry = MAX_CMD_RETRY; + dlci_IB_mapping_t *result; + int err, counter, found; + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.command = FR_READ_DLCI_IB_MAPPING; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + + if (mbox->cmd.result != 0) + printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", chan->name); + + counter = mbox->cmd.length / sizeof(dlci_IB_mapping_t); + result = (void *) mbox->data; + found = 0; + for (; counter; --counter, ++result) + { + if (result->dlci == chan->dlci) + { + printk(KERN_INFO "%s: DLCI= %d, IB addr = %lx for %s\n" + ,card->devname, result->dlci, result->addr_value ,chan->name); + chan->IB_addr = result->addr_value; + chan->dlci_int_interface = (void *) (card->hw.dpmbase + + (chan->IB_addr & 0x00001FFF)); + found = 1; + break; + } + } + if (!found) + printk(KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n", + card->devname, chan->dlci); +} + +/****** End *****************************************************************/ diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/sdla_ppp.c linux/drivers/net/wan/sdla_ppp.c --- v2.3.20/linux/drivers/net/wan/sdla_ppp.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/sdla_ppp.c Mon Oct 11 10:13:25 1999 @@ -0,0 +1,2261 @@ +/***************************************************************************** +* sdla_ppp.c WANPIPE(tm) Multiprotocol WAN Link Driver. PPP module. +* +* Author: Jaspreet Singh +* +* 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 /* printk(), and other useful stuff */ +#include /* offsetof(), etc. */ +#include /* return codes */ +#include /* inline memset(), etc. */ +#include /* kmalloc(), kfree() */ +#include /* WAN router definitions */ +#include /* WANPIPE common user API definitions */ +#include /* ARPHRD_* defines */ +#include /* htons(), etc. */ +#include /* copyto/from user */ +#define _GNUC_ +#include /* PPP firmware API definitions */ + +/****** Defines & Macros ****************************************************/ + +#ifdef _DEBUG_ +#define STATIC +#else +#define STATIC static +#endif +#define PPP_DFLT_MTU 1500 /* default MTU */ +#define PPP_MAX_MTU 4000 /* maximum MTU */ +#define PPP_HDR_LEN 1 +#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ +#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ + +/* For handle_IPXWAN() */ +#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) + +/******Data Structures*****************************************************/ +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with PPP specific data + */ + +typedef struct ppp_private_area +{ + sdla_t *card; + unsigned long router_start_time; /*router start time in sec */ + unsigned long tick_counter; /*used for 5 second counter */ + unsigned mc; /*multicast support on or off */ + /* PPP specific statistics */ + unsigned long if_send_entry; + unsigned long if_send_skb_null; + unsigned long if_send_broadcast; + unsigned long if_send_multicast; + unsigned long if_send_critical_ISR; + unsigned long if_send_critical_non_ISR; + unsigned long if_send_busy; + unsigned long if_send_busy_timeout; + unsigned long if_send_DRVSTATS_request; + unsigned long if_send_PTPIPE_request; + unsigned long if_send_wan_disconnected; + unsigned long if_send_adptr_bfrs_full; + unsigned long if_send_protocol_error; + unsigned long if_send_tx_int_enabled; + unsigned long if_send_bfr_passed_to_adptr; + unsigned long rx_intr_no_socket; + unsigned long rx_intr_DRVSTATS_request; + unsigned long rx_intr_PTPIPE_request; + unsigned long rx_intr_bfr_not_passed_to_stack; + unsigned long rx_intr_bfr_passed_to_stack; + unsigned long UDP_PTPIPE_mgmt_kmalloc_err; + unsigned long UDP_PTPIPE_mgmt_adptr_type_err; + unsigned long UDP_PTPIPE_mgmt_direction_err; + unsigned long UDP_PTPIPE_mgmt_adptr_cmnd_timeout; + unsigned long UDP_PTPIPE_mgmt_adptr_cmnd_OK; + unsigned long UDP_PTPIPE_mgmt_passed_to_adptr; + unsigned long UDP_PTPIPE_mgmt_passed_to_stack; + unsigned long UDP_PTPIPE_mgmt_no_socket; + unsigned long UDP_DRVSTATS_mgmt_kmalloc_err; + unsigned long UDP_DRVSTATS_mgmt_adptr_type_err; + unsigned long UDP_DRVSTATS_mgmt_direction_err; + unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; + unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK; + unsigned long UDP_DRVSTATS_mgmt_passed_to_adptr; + unsigned long UDP_DRVSTATS_mgmt_passed_to_stack; + unsigned long UDP_DRVSTATS_mgmt_no_socket; + unsigned long router_up_time; +} ppp_private_area_t; + +/* variable for keeping track of enabling/disabling FT1 monitor status */ + +static int rCount = 0; +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/****** Function Prototypes *************************************************/ + +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update(wan_device_t * wandev); +static int new_if(wan_device_t * wandev, struct net_device *dev, + wanif_conf_t * conf); +static int del_if(wan_device_t * wandev, struct net_device *dev); +/* WANPIPE-specific entry points */ +static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data); +/* Network device interface */ +static int if_init(struct net_device *dev); +static int if_open(struct net_device *dev); +static int if_close(struct net_device *dev); +static int if_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, unsigned len); +static int if_rebuild_hdr(struct sk_buff *skb); +static int if_send(struct sk_buff *skb, struct net_device *dev); +static struct enet_statistics *if_stats(struct net_device *dev); +/* PPP firmware interface functions */ +static int ppp_read_version(sdla_t * card, char *str); +static int ppp_configure(sdla_t * card, void *data); +static int ppp_set_intr_mode(sdla_t * card, unsigned mode); +static int ppp_comm_enable(sdla_t * card); +static int ppp_comm_disable(sdla_t * card); +static int ppp_get_err_stats(sdla_t * card); +static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto); +static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb); +/* Interrupt handlers */ +STATIC void wpp_isr(sdla_t * card); +static void rx_intr(sdla_t * card); +static void tx_intr(sdla_t * card); +/* Background polling routines */ +static void wpp_poll(sdla_t * card); +static void poll_active(sdla_t * card); +static void poll_connecting(sdla_t * card); +static void poll_disconnected(sdla_t * card); +/* Miscellaneous functions */ +static int config502(sdla_t * card); +static int config508(sdla_t * card); +static void show_disc_cause(sdla_t * card, unsigned cause); +static unsigned char bps_to_speed_code(unsigned long bps); +static int reply_udp(unsigned char *data, unsigned int mbox_len); +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, ppp_private_area_t * ppp_priv_area); +static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, ppp_private_area_t * ppp_priv_area); +static void init_ppp_tx_rx_buff(sdla_t * card); +static int intr_test(sdla_t * card); +static int udp_pkt_type(struct sk_buff *skb, sdla_t * card); +static void init_ppp_priv_struct(ppp_private_area_t * ppp_priv_area); +static void init_global_statistics(sdla_t * card); +static int Intr_test_counter; +static char TracingEnabled; +static unsigned long curr_trace_addr; +static unsigned long start_trace_addr; +static unsigned short available_buffer_space; +/* IPX functions */ +static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto); + +/****** Public Functions ****************************************************/ + +/*============================================================================ + * PPP protocol initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wpp_init(sdla_t * card, wandev_conf_t * conf) +{ + union { + char str[80]; + } u; + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_PPP) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + /* Initialize protocol-specific fields */ + switch (card->hw.fwid) { + case SFID_PPP502: + card->mbox = (void *) (card->hw.dpmbase + PPP502_MB_OFFS); + card->flags = (void *) (card->hw.dpmbase + PPP502_FLG_OFFS); + break; + case SFID_PPP508: + card->mbox = (void *) (card->hw.dpmbase + PPP508_MB_OFFS); + card->flags = (void *) (card->hw.dpmbase + PPP508_FLG_OFFS); + break; + default: + return -EINVAL; + } + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + if (ppp_read_version(card, NULL) || ppp_read_version(card, u.str)) + return -EIO; + printk(KERN_INFO "%s: running PPP firmware v%s\n", card->devname, u.str); + /* Adjust configuration and set defaults */ + card->wandev.mtu = (conf->mtu) ? + min(conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU; + card->wandev.bps = conf->bps; + card->wandev.interface = conf->interface; + card->wandev.clocking = conf->clocking; + card->wandev.station = conf->station; + card->isr = &wpp_isr; + card->poll = &wpp_poll; + card->exec = &wpp_exec; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.state = WAN_DISCONNECTED; + card->wandev.udp_port = conf->udp_port; + card->wandev.ttl = conf->ttl; + card->irq_dis_if_send_count = 0; + card->irq_dis_poll_count = 0; + TracingEnabled = 0; + card->wandev.enable_IPX = conf->enable_IPX; + if (conf->network_number) + card->wandev.network_number = conf->network_number; + else + card->wandev.network_number = 0xDEADBEEF; + /* initialize global statistics */ + init_global_statistics(card); + return 0; +} + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * Update device status & statistics. + */ +static int update(wan_device_t * wandev) +{ + sdla_t *card; + /* sanity checks */ + if ((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + if (wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + if (test_and_set_bit(0, (void *) &wandev->critical)) + return -EAGAIN; + card = wandev->private; + ppp_get_err_stats(card); + wandev->critical = 0; + return 0; +} + +/*============================================================================ + * Create new logical channel. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ + +static int new_if(wan_device_t * wandev, struct net_device *dev, wanif_conf_t * conf) +{ + sdla_t *card = wandev->private; + ppp_private_area_t *ppp_priv_area; + if (wandev->ndev) + return -EEXIST; + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + printk(KERN_INFO "%s: invalid interface name!\n", + card->devname); + return -EINVAL; + } + /* allocate and initialize private data */ + ppp_priv_area = kmalloc(sizeof(ppp_private_area_t), GFP_KERNEL); + if (ppp_priv_area == NULL) + return -ENOMEM; + memset(ppp_priv_area, 0, sizeof(ppp_private_area_t)); + ppp_priv_area->card = card; + /* initialize data */ + strcpy(card->u.p.if_name, conf->name); + /* initialize data in ppp_private_area structure */ + init_ppp_priv_struct(ppp_priv_area); + ppp_priv_area->mc = conf->mc; + /* prepare network device data space for registration */ + dev->name = card->u.p.if_name; + dev->init = &if_init; + dev->priv = ppp_priv_area; + return 0; +} + +/*============================================================================ + * Delete logical channel. + */ + +static int del_if(wan_device_t * wandev, struct net_device *dev) +{ + if (dev->priv) { + kfree(dev->priv); + dev->priv = NULL; + } + return 0; +} + +/****** WANPIPE-specific entry points ***************************************/ + +/*============================================================================ + * Execute adapter interface command. + */ + +static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data) +{ + ppp_mbox_t *mbox = card->mbox; + int len; + if(copy_from_user((void *) &mbox->cmd, u_cmd, sizeof(ppp_cmd_t))) + return -EFAULT; + len = mbox->cmd.length; + if (len) { + if(copy_from_user((void *) &mbox->data, u_data, len)) + return -EFAULT; + } + /* execute command */ + if (!sdla_exec(mbox)) + return -EIO; + /* return result */ + if(copy_to_user(u_cmd, (void *) &mbox->cmd, sizeof(ppp_cmd_t))) + return -EFAULT; + len = mbox->cmd.length; + if (len && u_data && copy_to_user(u_data, (void *) &mbox->data, len)) + return -EFAULT; + return 0; +} + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. + */ + +static int if_init(struct net_device *dev) +{ + ppp_private_area_t *ppp_priv_area = dev->priv; + sdla_t *card = ppp_priv_area->card; + wan_device_t *wandev = &card->wandev; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = &if_header; + dev->rebuild_header = &if_rebuild_hdr; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + /* Initialize media-specific parameters */ + dev->type = ARPHRD_PPP; /* ARP h/w type */ + dev->mtu = wandev->mtu; + dev->hard_header_len = PPP_HDR_LEN; /* media header length */ + /* Initialize hardware parameters (just for reference) */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = (unsigned long)wandev->maddr; + dev->mem_end = dev->mem_start + wandev->msize - 1; + /* Set transmit buffer queue length */ + dev->tx_queue_len = 100; + /* Initialize socket buffers */ + dev_init_buffers(dev); + return 0; +} + +/*============================================================================ + * Open network interface. + * o enable communications and interrupts. + * o prevent module from unloading by incrementing use count + * + * Return 0 if O.k. or errno. + */ + +static int if_open(struct net_device *dev) +{ + ppp_private_area_t *ppp_priv_area = dev->priv; + sdla_t *card = ppp_priv_area->card; + ppp_flags_t *flags = card->flags; + struct timeval tv; + int err = 0; + if (dev->start) + return -EBUSY; /* only one open is allowed */ + if (test_and_set_bit(0, (void *) &card->wandev.critical)) + return -EAGAIN; + if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card)) { + err = -EIO; + card->wandev.critical = 0; + return err; + } + Intr_test_counter = 0; + err = intr_test(card); + if ((err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) { + printk(KERN_INFO "%s: Interrupt Test Failed, Counter: %i\n", + card->devname, Intr_test_counter); + err = -EIO; + card->wandev.critical = 0; + return err; + } + printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", + card->devname, Intr_test_counter); + /* Initialize Rx/Tx buffer control fields */ + init_ppp_tx_rx_buff(card); + if (ppp_set_intr_mode(card, 0x03)) { + err = -EIO; + card->wandev.critical = 0; + return err; + } + flags->imask &= ~0x02; + if (ppp_comm_enable(card)) { + err = -EIO; + card->wandev.critical = 0; + return err; + } + wanpipe_set_state(card, WAN_CONNECTING); + wanpipe_open(card); + dev->mtu = min(dev->mtu, card->wandev.mtu); + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + do_gettimeofday(&tv); + ppp_priv_area->router_start_time = tv.tv_sec; + card->wandev.critical = 0; + return err; +} + +/*============================================================================ + * Close network interface. + * o if this is the last open, then disable communications and interrupts. + * o reset flags. + */ + +static int if_close(struct net_device *dev) +{ + ppp_private_area_t *ppp_priv_area = dev->priv; + sdla_t *card = ppp_priv_area->card; + if (test_and_set_bit(0, (void *) &card->wandev.critical)) + return -EAGAIN; + dev->start = 0; + wanpipe_close(card); + wanpipe_set_state(card, WAN_DISCONNECTED); + ppp_set_intr_mode(card, 0); + ppp_comm_disable(card); + card->wandev.critical = 0; + return 0; +} + +/*============================================================================ + * Build media header. + * + * The trick here is to put packet type (Ethertype) into 'protocol' field of + * the socket buffer, so that we don't forget it. If packet type is not + * supported, set skb->protocol to 0 and discard packet later. + * + * Return: media header length. + */ + +static int if_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, unsigned len) +{ + switch (type) + { + case ETH_P_IP: + case ETH_P_IPX: + skb->protocol = type; + break; + default: + skb->protocol = 0; + } + return PPP_HDR_LEN; +} + +/*============================================================================ + * Re-build media header. + * + * Return: 1 physical address resolved. + * 0 physical address not resolved + */ + +static int if_rebuild_hdr(struct sk_buff *skb) +{ + struct net_device *dev=skb->dev; + ppp_private_area_t *ppp_priv_area = dev->priv; + sdla_t *card = ppp_priv_area->card; + printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", + card->devname, dev->name); + return 1; +} + +/*============================================================================ + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission) to block a timer-based + * transmit from overlapping. + * o check link state. If link is not up, then drop the packet. + * o execute adapter send command. + * o free socket buffer + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + */ + +static int if_send(struct sk_buff *skb, struct net_device *dev) +{ + ppp_private_area_t *ppp_priv_area = dev->priv; + sdla_t *card = ppp_priv_area->card; + unsigned char *sendpacket; + unsigned long check_braddr, check_mcaddr; + unsigned long host_cpu_flags; + ppp_flags_t *flags = card->flags; + int retry = 0; + int err, udp_type; + ++ppp_priv_area->if_send_entry; + if (skb == NULL) { + /* If we get here, some higher layer thinks we've missed an + * tx-done interrupt. + */ + printk(KERN_INFO "%s: interface %s got kicked!\n", + card->devname, dev->name); + ++ppp_priv_area->if_send_skb_null; + mark_bh(NET_BH); + return 0; + } + if (dev->tbusy) { + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + ++ppp_priv_area->if_send_busy; + ++card->wandev.stats.collisions; + if ((jiffies - ppp_priv_area->tick_counter) < (5 * HZ)) { + return 1; + } + printk(KERN_INFO "%s: Transmit times out\n", card->devname); + ++ppp_priv_area->if_send_busy_timeout; + /* unbusy the card (because only one interface per card) */ + dev->tbusy = 0; + } + sendpacket = skb->data; + udp_type = udp_pkt_type(skb, card); + if (udp_type == UDP_DRVSTATS_TYPE) { + ++ppp_priv_area->if_send_DRVSTATS_request; + process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev, + ppp_priv_area); + dev_kfree_skb(skb); + return 0; + } else if (udp_type == UDP_PTPIPE_TYPE) + ++ppp_priv_area->if_send_PTPIPE_request; + /* retreive source address in two forms: broadcast & multicast */ + check_braddr = sendpacket[15]; + check_mcaddr = sendpacket[12]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[14]; + check_mcaddr |= sendpacket[13]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[13]; + check_mcaddr |= sendpacket[14]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[12]; + check_mcaddr |= sendpacket[15]; + /* if the Source Address is a Multicast address */ + if ((ppp_priv_area->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001) + && (check_mcaddr <= 0xFFFFFFFE)) { + printk(KERN_INFO "%s: Mutlicast Src. Addr. silently discarded\n" + ,card->devname); + dev_kfree_skb(skb); + ++ppp_priv_area->if_send_multicast; + ++card->wandev.stats.tx_dropped; + return 0; + } + disable_irq(card->hw.irq); + ++card->irq_dis_if_send_count; + if (test_and_set_bit(0, (void *) &card->wandev.critical)) { + if (card->wandev.critical == CRITICAL_IN_ISR) { + /* If the critical flag is set due to an Interrupt + * then set enable transmit interrupt flag to enable + * transmit interrupt. (delay interrupt) + */ + card->wandev.enable_tx_int = 1; + dev->tbusy = 1; + /* set the counter to see if we get the interrupt in + * 5 seconds. + */ + ppp_priv_area->tick_counter = jiffies; + ++ppp_priv_area->if_send_critical_ISR; + save_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && + (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return 1; + } + dev_kfree_skb(skb); + ++ppp_priv_area->if_send_critical_non_ISR; + save_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && + (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return 0; + } + if (udp_type == UDP_PTPIPE_TYPE) { + err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, + dev, ppp_priv_area); + } else if (card->wandev.state != WAN_CONNECTED) { + ++ppp_priv_area->if_send_wan_disconnected; + ++card->wandev.stats.tx_dropped; + } else if (!skb->protocol) { + ++ppp_priv_area->if_send_protocol_error; + ++card->wandev.stats.tx_errors; + } else { + /*If it's IPX change the network numbers to 0 if they're ours. */ + if (skb->protocol == ETH_P_IPX) { + if (card->wandev.enable_IPX) { + switch_net_numbers(skb->data, + card->wandev.network_number, 0); + } else { + ++card->wandev.stats.tx_dropped; + goto tx_done; + } + } + if (ppp_send(card, skb->data, skb->len, skb->protocol)) { + retry = 1; + dev->tbusy = 1; + ++ppp_priv_area->if_send_adptr_bfrs_full; + ++ppp_priv_area->if_send_tx_int_enabled; + ppp_priv_area->tick_counter = jiffies; + ++card->wandev.stats.tx_errors; + flags->imask |= 0x02; /* unmask Tx interrupts */ + } else { + ++ppp_priv_area->if_send_bfr_passed_to_adptr; + ++card->wandev.stats.tx_packets; + card->wandev.stats.tx_bytes += skb->len; + } + } +tx_done: + if (!retry) { + dev_kfree_skb(skb); + } + card->wandev.critical = 0; + save_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return retry; +} + +/*============================================================================ + * Reply to UDP Management system. + * Return length of reply. + */ + +static int reply_udp(unsigned char *data, unsigned int mbox_len) +{ + unsigned short len, udp_length, temp, i, ip_length; + unsigned long sum; + /* Set length of packet */ + len = mbox_len + 60; + /* fill in UDP reply */ + data[36] = 0x02; + /* fill in UDP length */ + udp_length = mbox_len + 40; + /* put it on an even boundary */ + if (udp_length & 0x0001) { + udp_length += 1; + len += 1; + } + temp = (udp_length << 8) | (udp_length >> 8); + memcpy(&data[24], &temp, 2); + /* swap UDP ports */ + memcpy(&temp, &data[20], 2); + memcpy(&data[20], &data[22], 2); + memcpy(&data[22], &temp, 2); + /* add UDP pseudo header */ + temp = 0x1100; + memcpy(&data[udp_length + 20], &temp, 2); + temp = (udp_length << 8) | (udp_length >> 8); + memcpy(&data[udp_length + 22], &temp, 2); + /* calculate UDP checksum */ + data[26] = data[27] = 0; + sum = 0; + for (i = 0; i < udp_length + 12; i += 2) { + memcpy(&temp, &data[12 + i], 2); + sum += (unsigned long) temp; + } + while (sum >> 16) { + sum = (sum & 0xffffUL) + (sum >> 16); + } + temp = (unsigned short) sum; + temp = ~temp; + if (temp == 0) + temp = 0xffff; + memcpy(&data[26], &temp, 2); + /* fill in IP length */ + ip_length = udp_length + 20; + temp = (ip_length << 8) | (ip_length >> 8); + memcpy(&data[2], &temp, 2); + /* swap IP addresses */ + memcpy(&temp, &data[12], 2); + memcpy(&data[12], &data[16], 2); + memcpy(&data[16], &temp, 2); + memcpy(&temp, &data[14], 2); + memcpy(&data[14], &data[18], 2); + memcpy(&data[18], &temp, 2); + /* fill in IP checksum */ + data[10] = data[11] = 0; + sum = 0; + for (i = 0; i < 20; i += 2) { + memcpy(&temp, &data[i], 2); + sum += (unsigned long) temp; + } + while (sum >> 16) { + sum = (sum & 0xffffUL) + (sum >> 16); + } + temp = (unsigned short) sum; + temp = ~temp; + if (temp == 0) + temp = 0xffff; + memcpy(&data[10], &temp, 2); + return len; +} /* reply_udp */ + +/* + If incoming is 0 (outgoing)- if the net numbers is ours make it 0 + if incoming is 1 - if the net number is 0 make it ours + */ + +static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) +{ + unsigned long pnetwork_number; + pnetwork_number = (unsigned long) ((sendpacket[6] << 24) + + (sendpacket[7] << 16) + (sendpacket[8] << 8) + + sendpacket[9]); + if (!incoming) { + /* If the destination network number is ours, make it 0 */ + if (pnetwork_number == network_number) { + sendpacket[6] = sendpacket[7] = sendpacket[8] = + sendpacket[9] = 0x00; + } + } else { + /* If the incoming network is 0, make it ours */ + if (pnetwork_number == 0) { + sendpacket[6] = (unsigned char) (network_number >> 24); + sendpacket[7] = (unsigned char) ((network_number & + 0x00FF0000) >> 16); + sendpacket[8] = (unsigned char) ((network_number & + 0x0000FF00) >> 8); + sendpacket[9] = (unsigned char) (network_number & + 0x000000FF); + } + } + pnetwork_number = (unsigned long) ((sendpacket[18] << 24) + + (sendpacket[19] << 16) + (sendpacket[20] << 8) + + sendpacket[21]); + if (!incoming) { + /* If the source network is ours, make it 0 */ + if (pnetwork_number == network_number) { + sendpacket[18] = sendpacket[19] = sendpacket[20] = + sendpacket[21] = 0x00; + } + } else { + /* If the source network is 0, make it ours */ + if (pnetwork_number == 0) { + sendpacket[18] = (unsigned char) (network_number >> 24); + sendpacket[19] = (unsigned char) ((network_number & + 0x00FF0000) >> 16); + sendpacket[20] = (unsigned char) ((network_number & + 0x0000FF00) >> 8); + sendpacket[21] = (unsigned char) (network_number & + 0x000000FF); + } + } +} /* switch_net_numbers */ + +/*============================================================================ + * Get Ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ + +static struct enet_statistics *if_stats(struct net_device *dev) +{ + ppp_private_area_t *ppp_priv_area = dev->priv; + sdla_t *card; + + /* + * Device is down:No statistics + */ + + if(ppp_priv_area==NULL) + return NULL; + + card = ppp_priv_area->card; + return &card->wandev.stats; +} + +/****** PPP Firmware Interface Functions ************************************/ + +/*============================================================================ + * Read firmware code version. + * Put code version as ASCII string in str. + */ + +static int ppp_read_version(sdla_t * card, char *str) +{ + ppp_mbox_t *mb = card->mbox; + int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + mb->cmd.command = PPP_READ_CODE_VERSION; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) + ppp_error(card, err, mb); + else if (str) { + int len = mb->cmd.length; + memcpy(str, mb->data, len); + str[len] = '\0'; + } + return err; +} + +/*============================================================================ + * Configure PPP firmware. + */ + +static int ppp_configure(sdla_t * card, void *data) +{ + ppp_mbox_t *mb = card->mbox; + int data_len = (card->hw.fwid == SFID_PPP502) ? + sizeof(ppp502_conf_t) : sizeof(ppp508_conf_t); + int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + memcpy(mb->data, data, data_len); + mb->cmd.length = data_len; + mb->cmd.command = PPP_SET_CONFIG; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) + ppp_error(card, err, mb); + return err; +} + +/*============================================================================ + * Set interrupt mode. + */ + +static int ppp_set_intr_mode(sdla_t * card, unsigned mode) +{ + ppp_mbox_t *mb = card->mbox; + int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + mb->data[0] = mode; + switch (card->hw.fwid) { + case SFID_PPP502: + mb->cmd.length = 1; + break; + case SFID_PPP508: + default: + mb->data[1] = card->hw.irq; + mb->cmd.length = 2; + } + mb->cmd.command = PPP_SET_INTR_FLAGS; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) + ppp_error(card, err, mb); + return err; +} + +/*============================================================================ + * Enable communications. + */ + +static int ppp_comm_enable(sdla_t * card) +{ + ppp_mbox_t *mb = card->mbox; + int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + mb->cmd.command = PPP_COMM_ENABLE; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) + ppp_error(card, err, mb); + return err; +} + +/*============================================================================ + * Disable communications. + */ + +static int ppp_comm_disable(sdla_t * card) +{ + ppp_mbox_t *mb = card->mbox; + int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + mb->cmd.command = PPP_COMM_DISABLE; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) + ppp_error(card, err, mb); + return err; +} + +/*============================================================================ + * Get communications error statistics. + */ + +static int ppp_get_err_stats(sdla_t * card) +{ + ppp_mbox_t *mb = card->mbox; + int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + mb->cmd.command = PPP_READ_ERROR_STATS; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err == CMD_OK) { + ppp_err_stats_t *stats = (void *) mb->data; + card->wandev.stats.rx_over_errors = stats->rx_overrun; + card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; + card->wandev.stats.rx_missed_errors = stats->rx_abort; + card->wandev.stats.rx_length_errors = stats->rx_lost; + card->wandev.stats.tx_aborted_errors = stats->tx_abort; + } else + ppp_error(card, err, mb); + return err; +} + +/*============================================================================ + * Send packet. + * Return: 0 - o.k. + * 1 - no transmit buffers available + */ + +static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto) +{ + ppp_buf_ctl_t *txbuf = card->u.p.txbuf; + unsigned long addr; + if (txbuf->flag) + return 1 + ; + if (card->hw.fwid == SFID_PPP502) + addr = (txbuf->buf.o_p[1] << 8) + txbuf->buf.o_p[0]; + else + addr = txbuf->buf.ptr; + sdla_poke(&card->hw, addr, data, len); + txbuf->length = len; /* frame length */ + if (proto == ETH_P_IPX) + txbuf->proto = 0x01; /* protocol ID */ + txbuf->flag = 1; /* start transmission */ + /* Update transmit buffer control fields */ + card->u.p.txbuf = ++txbuf; + if ((void *) txbuf > card->u.p.txbuf_last) + card->u.p.txbuf = card->u.p.txbuf_base; + return 0; +} + +/****** Firmware Error Handler **********************************************/ + +/*============================================================================ + * Firmware error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ + +static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb) +{ + unsigned cmd = mb->cmd.command; + switch (err) { + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" + ,card->devname, cmd, err); + } + return 0; +} + +/****** Interrupt Handlers **************************************************/ + +/*============================================================================ + * PPP interrupt service routine. + */ + +STATIC void wpp_isr(sdla_t * card) +{ + ppp_flags_t *flags = card->flags; + char *ptr = &flags->iflag; + unsigned long host_cpu_flags; + struct net_device *dev = card->wandev.dev; + int i; + card->in_isr = 1; + ++card->statistics.isr_entry; + if (test_and_set_bit(0, (void *) &card->wandev.critical)) { + ++card->statistics.isr_already_critical; + printk(KERN_INFO "%s: Critical while in ISR!\n", card->devname); + card->in_isr = 0; + return; + } + /* For all interrupts set the critical flag to CRITICAL_IN_ISR. + * If the if_send routine is called with this flag set it will set + * the enable transmit flag to 1. (for a delayed interrupt) + */ + card->wandev.critical = CRITICAL_IN_ISR; + card->buff_int_mode_unbusy = 0; + switch (flags->iflag) { + case 0x01: /* receive interrupt */ + ++card->statistics.isr_rx; + rx_intr(card); + break; + case 0x02: /* transmit interrupt */ + ++card->statistics.isr_tx; + flags->imask &= ~0x02; + dev->tbusy = 0; + card->buff_int_mode_unbusy = 1; + break; + case 0x08: + ++Intr_test_counter; + ++card->statistics.isr_intr_test; + break; + default: /* unexpected interrupt */ + ++card->statistics.isr_spurious; + printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", + card->devname, flags->iflag); + printk(KERN_INFO "%s: ID Bytes = ", card->devname); + for (i = 0; i < 8; i++) + printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); + printk(KERN_INFO "\n"); + } + /* The critical flag is set to CRITICAL_INTR_HANDLED to let the + * if_send call know that the interrupt is handled so that + * transmit interrupts are not enabled again. + */ + card->wandev.critical = CRITICAL_INTR_HANDLED; + /* If the enable transmit interrupt flag is set then enable transmit + * interrupt on the board. This only goes through if if_send is called + * and the critical flag is set due to an Interrupt. + */ + if (card->wandev.enable_tx_int) { + flags->imask |= 0x02; + card->wandev.enable_tx_int = 0; + ++card->statistics.isr_enable_tx_int; + } + save_flags(host_cpu_flags); + cli(); + card->in_isr = 0; + flags->iflag = 0; + card->wandev.critical = 0; + restore_flags(host_cpu_flags); + if (card->buff_int_mode_unbusy) + mark_bh(NET_BH); +} + +/*============================================================================ + * Receive interrupt handler. + */ + +static void rx_intr(sdla_t * card) +{ + ppp_buf_ctl_t *rxbuf = card->rxmb; + struct net_device *dev = card->wandev.dev; + ppp_private_area_t *ppp_priv_area; + struct sk_buff *skb; + unsigned len; + void *buf; + int i, err; + ppp_flags_t *flags = card->flags; + char *ptr = &flags->iflag; + int udp_type; + if (rxbuf->flag != 0x01) { + printk(KERN_INFO + "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", + card->devname, (unsigned) rxbuf, rxbuf->flag); + printk(KERN_INFO "%s: ID Bytes = ", card->devname); + for (i = 0; i < 8; i++) + printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); + printk(KERN_INFO "\n"); + ++card->statistics.rx_intr_corrupt_rx_bfr; + return; + } + if (dev && dev->start) { + len = rxbuf->length; + ppp_priv_area = dev->priv; + /* Allocate socket buffer */ + skb = dev_alloc_skb(len); + if (skb != NULL) { + /* Copy data to the socket buffer */ + if (card->hw.fwid == SFID_PPP502) { + unsigned addr = (rxbuf->buf.o_p[1] << 8) + + rxbuf->buf.o_p[0]; + buf = skb_put(skb, len); + sdla_peek(&card->hw, addr, buf, len); + } else { + unsigned addr = rxbuf->buf.ptr; + if ((addr + len) > card->u.p.rx_top + 1) { + unsigned tmp = card->u.p.rx_top - addr + + 1; + buf = skb_put(skb, tmp); + sdla_peek(&card->hw, addr, buf, tmp); + addr = card->u.p.rx_base; + len -= tmp; + } + buf = skb_put(skb, len); + sdla_peek(&card->hw, addr, buf, len); + } + /* Decapsulate packet */ + switch (rxbuf->proto) { + case 0x00: + skb->protocol = htons(ETH_P_IP); + break; + case 0x01: + skb->protocol = htons(ETH_P_IPX); + break; + } + udp_type = udp_pkt_type(skb, card); + if (udp_type == UDP_DRVSTATS_TYPE) { + ++ppp_priv_area->rx_intr_DRVSTATS_request; + process_udp_driver_call( + UDP_PKT_FRM_NETWORK, card, skb, + dev, ppp_priv_area); + dev_kfree_skb(skb); + } else if (udp_type == UDP_PTPIPE_TYPE) { + ++ppp_priv_area->rx_intr_PTPIPE_request; + err = process_udp_mgmt_pkt( + UDP_PKT_FRM_NETWORK, card, + skb, dev, ppp_priv_area); + dev_kfree_skb(skb); + } else if (handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) { + if (card->wandev.enable_IPX) { + ppp_send(card, skb->data, skb->len, ETH_P_IPX); + dev_kfree_skb(skb); + } else { + ++card->wandev.stats.rx_dropped; + } + } else { + /* Pass it up the protocol stack */ + skb->dev = dev; + skb->mac.raw = skb->data; + netif_rx(skb); + ++card->wandev.stats.rx_packets; + card->wandev.stats.rx_bytes += skb->len; + ++ppp_priv_area->rx_intr_bfr_passed_to_stack; + } + } else { + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + ++card->wandev.stats.rx_dropped; + ++ppp_priv_area->rx_intr_no_socket; + } + } else + ++card->statistics.rx_intr_dev_not_started; + /* Release buffer element and calculate a pointer to the next one */ + rxbuf->flag = (card->hw.fwid == SFID_PPP502) ? 0xFF : 0x00; + card->rxmb = ++rxbuf; + if ((void *) rxbuf > card->u.p.rxbuf_last) + card->rxmb = card->u.p.rxbuf_base; +} + +/*============================================================================ + * Transmit interrupt handler. + */ + +static void tx_intr(sdla_t * card) +{ + struct net_device *dev = card->wandev.dev; + if (!dev || !dev->start) { + ++card->statistics.tx_intr_dev_not_started; + return; + } + dev->tbusy = 0; + mark_bh(NET_BH); +} + +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) +{ + int i; + if (proto == htons(ETH_P_IPX)) { + /* It's an IPX packet */ + if (!enable_IPX) { + /* Return 1 so we don't pass it up the stack. */ + return 1; + } + } else { + /* It's not IPX so pass it up the stack. */ + return 0; + } + if (sendpacket[16] == 0x90 && + sendpacket[17] == 0x04) { + /* It's IPXWAN */ + if (sendpacket[2] == 0x02 && + sendpacket[34] == 0x00) { + /* It's a timer request packet */ + printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", devname); + /* Go through the routing options and answer no to every */ + /* option except Unnumbered RIP/SAP */ + for (i = 41; sendpacket[i] == 0x00; i += 5) { + /* 0x02 is the option for Unnumbered RIP/SAP */ + if (sendpacket[i + 4] != 0x02) { + sendpacket[i + 1] = 0; + } + } + /* Skip over the extended Node ID option */ + if (sendpacket[i] == 0x04) { + i += 8; + } + /* We also want to turn off all header compression opt. */ + for (; sendpacket[i] == 0x80;) { + sendpacket[i + 1] = 0; + i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; + } + /* Set the packet type to timer response */ + sendpacket[34] = 0x01; + printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", devname); + } else if (sendpacket[34] == 0x02) { + /* This is an information request packet */ + printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n", devname); + /* Set the packet type to information response */ + sendpacket[34] = 0x03; + /* Set the router name */ + sendpacket[51] = 'P'; + sendpacket[52] = 'T'; + sendpacket[53] = 'P'; + sendpacket[54] = 'I'; + sendpacket[55] = 'P'; + sendpacket[56] = 'E'; + sendpacket[57] = '-'; + sendpacket[58] = CVHexToAscii(network_number >> 28); + sendpacket[59] = CVHexToAscii((network_number & 0x0F000000) >> 24); + sendpacket[60] = CVHexToAscii((network_number & 0x00F00000) >> 20); + sendpacket[61] = CVHexToAscii((network_number & 0x000F0000) >> 16); + sendpacket[62] = CVHexToAscii((network_number & 0x0000F000) >> 12); + sendpacket[63] = CVHexToAscii((network_number & 0x00000F00) >> 8); + sendpacket[64] = CVHexToAscii((network_number & 0x000000F0) >> 4); + sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); + for (i = 66; i < 99; i += 1) + sendpacket[i] = 0; + printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", devname); + } else { + printk(KERN_INFO "%s: Unknown IPXWAN packet!\n", devname); + return 0; + } + /* Set the WNodeID to our network address */ + sendpacket[35] = (unsigned char) (network_number >> 24); + sendpacket[36] = (unsigned char) ((network_number & 0x00FF0000) >> 16); + sendpacket[37] = (unsigned char) ((network_number & 0x0000FF00) >> 8); + sendpacket[38] = (unsigned char) (network_number & 0x000000FF); + return 1; + } else { + /* If we get here's its an IPX-data packet, so it'll get passed up the stack. */ + /* switch the network numbers */ + switch_net_numbers(sendpacket, network_number, 1); + return 0; + } +} + +/****** Background Polling Routines ****************************************/ + +/*============================================================================ + * Main polling routine. + * This routine is repeatedly called by the WANPIPE 'thread' to allow for + * time-dependent housekeeping work. + * + * Notes: + * 1. This routine may be called on interrupt context with all interrupts + * enabled. Beware! + */ + +static void wpp_poll(sdla_t * card) +{ + struct net_device *dev = card->wandev.dev; + ppp_flags_t *adptr_flags = card->flags; + unsigned long host_cpu_flags; + ++card->statistics.poll_entry; + /* The wpp_poll is called continously by the WANPIPE thread to allow + * for line state housekeeping. However if we are in a connected state + * then we do not need to go through all the checks everytime. When in + * connected state execute wpp_poll once every second. + */ + if (card->wandev.state == WAN_CONNECTED) { + if ((jiffies - card->state_tick) < HZ) + return; + } + disable_irq(card->hw.irq); + ++card->irq_dis_poll_count; + if (test_and_set_bit(0, (void *) &card->wandev.critical)) { + ++card->statistics.poll_already_critical; + printk(KERN_INFO "%s: critical inside wpp_poll\n", + card->devname); + save_flags(host_cpu_flags); + cli(); + if ((!card->irq_dis_if_send_count) && + (!(--card->irq_dis_poll_count))) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return; + } + ++card->statistics.poll_processed; + if (dev && dev->tbusy && !(adptr_flags->imask & 0x02)) { + ++card->statistics.poll_tbusy_bad_status; + printk(KERN_INFO "%s: Wpp_Poll: tbusy = 0x01, imask = 0x%02X\n" + ,card->devname, adptr_flags->imask); + } + switch (card->wandev.state) { + case WAN_CONNECTED: + card->state_tick = jiffies; + poll_active(card); + break; + case WAN_CONNECTING: + poll_connecting(card); + break; + case WAN_DISCONNECTED: + poll_disconnected(card); + break; + default: + printk(KERN_INFO "%s: Unknown Poll State 0x%02X\n", + card->devname, card->wandev.state); + break; + } + card->wandev.critical = 0; + save_flags(host_cpu_flags); + cli(); + if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); +} + +/*============================================================================ + * Monitor active link phase. + */ + +static void poll_active(sdla_t * card) +{ + ppp_flags_t *flags = card->flags; + /* We check the lcp_state to see if we are in DISCONNECTED state. + * We are considered to be connected for lcp states 0x06, 0x07, 0x08 + * and 0x09. + */ + if ((flags->lcp_state <= 0x05) || (flags->disc_cause & 0x03)) { + wanpipe_set_state(card, WAN_DISCONNECTED); + show_disc_cause(card, flags->disc_cause); + } +} + +/*============================================================================ + * Monitor link establishment phase. + * o if connection timed out, disconnect the link. + */ + +static void poll_connecting(sdla_t * card) +{ + ppp_flags_t *flags = card->flags; + if (flags->lcp_state == 0x09) { + wanpipe_set_state(card, WAN_CONNECTED); + } else if (flags->disc_cause & 0x03) { + wanpipe_set_state(card, WAN_DISCONNECTED); + show_disc_cause(card, flags->disc_cause); + } +} + +/*============================================================================ + * Monitor physical link disconnected phase. + * o if interface is up and the hold-down timeout has expired, then retry + * connection. + */ + +static void poll_disconnected(sdla_t * card) +{ + struct net_device *dev = card->wandev.dev; + if (dev && dev->start && + ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) { + wanpipe_set_state(card, WAN_CONNECTING); + if (ppp_comm_enable(card) == CMD_OK) + init_ppp_tx_rx_buff(card); + } +} + +/****** Miscellaneous Functions *********************************************/ + +/*============================================================================ + * Configure S502 adapter. + */ + +static int config502(sdla_t * card) +{ + ppp502_conf_t cfg; + /* Prepare PPP configuration structure */ + memset(&cfg, 0, sizeof(ppp502_conf_t)); + if (card->wandev.clocking) + cfg.line_speed = bps_to_speed_code(card->wandev.bps); + cfg.txbuf_num = 4; + cfg.mtu_local = card->wandev.mtu; + cfg.mtu_remote = card->wandev.mtu; + cfg.restart_tmr = 30; + cfg.auth_rsrt_tmr = 30; + cfg.auth_wait_tmr = 300; + cfg.mdm_fail_tmr = 5; + cfg.dtr_drop_tmr = 1; + cfg.connect_tmout = 0; /* changed it from 900 */ + cfg.conf_retry = 10; + cfg.term_retry = 2; + cfg.fail_retry = 5; + cfg.auth_retry = 10; + cfg.ip_options = 0x80; + cfg.ipx_options = 0xA0; + cfg.conf_flags |= 0x0E; +/* + cfg.ip_local = dev->pa_addr; + cfg.ip_remote = dev->pa_dstaddr; + */ + return ppp_configure(card, &cfg); +} + +/*============================================================================ + * Configure S508 adapter. + */ + +static int config508(sdla_t * card) +{ + ppp508_conf_t cfg; + /* Prepare PPP configuration structure */ + memset(&cfg, 0, sizeof(ppp508_conf_t)); + if (card->wandev.clocking) + cfg.line_speed = card->wandev.bps; + if (card->wandev.interface == WANOPT_RS232) + cfg.conf_flags |= 0x0020; + cfg.conf_flags |= 0x300; /*send Configure-Request packets forever */ + cfg.txbuf_percent = 60; /* % of Tx bufs */ + cfg.mtu_local = card->wandev.mtu; + cfg.mtu_remote = card->wandev.mtu; + cfg.restart_tmr = 30; + cfg.auth_rsrt_tmr = 30; + cfg.auth_wait_tmr = 300; + cfg.mdm_fail_tmr = 100; + cfg.dtr_drop_tmr = 1; + cfg.connect_tmout = 0; /* changed it from 900 */ + cfg.conf_retry = 10; + cfg.term_retry = 2; + cfg.fail_retry = 5; + cfg.auth_retry = 10; + cfg.ip_options = 0x80; + cfg.ipx_options = 0xA0; +/* + cfg.ip_local = dev->pa_addr; + cfg.ip_remote = dev->pa_dstaddr; + */ + return ppp_configure(card, &cfg); +} + +/*============================================================================ + * Show disconnection cause. + */ + +static void show_disc_cause(sdla_t * card, unsigned cause) +{ + if (cause & 0x0002) + printk(KERN_INFO "%s: link terminated by peer\n", + card->devname); + else if (cause & 0x0004) + printk(KERN_INFO "%s: link terminated by user\n", + card->devname); + else if (cause & 0x0008) + printk(KERN_INFO "%s: authentication failed\n", card->devname); + else if (cause & 0x0010) + printk(KERN_INFO + "%s: authentication protocol negotiation failed\n", + card->devname); + else if (cause & 0x0020) + printk(KERN_INFO + "%s: peer's request for authentication rejected\n", + card->devname); + else if (cause & 0x0040) + printk(KERN_INFO "%s: MRU option rejected by peer\n", + card->devname); + else if (cause & 0x0080) + printk(KERN_INFO "%s: peer's MRU was too small\n", + card->devname); + else if (cause & 0x0100) + printk(KERN_INFO "%s: failed to negotiate peer's LCP options\n", + card->devname); + else if (cause & 0x0200) + printk(KERN_INFO "%s: failed to negotiate peer's IPCP options\n" + ,card->devname); + else if (cause & 0x0400) + printk(KERN_INFO + "%s: failed to negotiate peer's IPXCP options\n", + card->devname); +} + +/*============================================================================ + * Convert line speed in bps to a number used by S502 code. + */ + +static unsigned char bps_to_speed_code(unsigned long bps) +{ + unsigned char number; + if (bps <= 1200) + number = 0x01; + else if (bps <= 2400) + number = 0x02; + else if (bps <= 4800) + number = 0x03; + else if (bps <= 9600) + number = 0x04; + else if (bps <= 19200) + number = 0x05; + else if (bps <= 38400) + number = 0x06; + else if (bps <= 45000) + number = 0x07; + else if (bps <= 56000) + number = 0x08; + else if (bps <= 64000) + number = 0x09; + else if (bps <= 74000) + number = 0x0A; + else if (bps <= 112000) + number = 0x0B; + else if (bps <= 128000) + number = 0x0C; + else + number = 0x0D; + return number; +} + +/*============================================================================ + * Process UDP call of type DRVSTATS. + */ + +static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, ppp_private_area_t * ppp_priv_area) +{ + unsigned char *sendpacket; + unsigned char buf2[5]; + unsigned char *data; + unsigned char *buf; + unsigned int len; + ppp_mbox_t *mbox = card->mbox; + struct sk_buff *new_skb; + int err; + sendpacket = skb->data; + memcpy(&buf2, &card->wandev.udp_port, 2); + if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) { + printk(KERN_INFO + "%s: Error allocating memory for UDP DRIVER STATS cmnd0x%02X" + ,card->devname, data[45]); + ++ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err; + return 1; + } + memcpy(data, sendpacket, skb->len); + switch (data[45]) { + /* PPIPE_DRIVER_STATISTICS */ + case 0x26: + *(unsigned long *) &data[60] = + ppp_priv_area->if_send_entry; + *(unsigned long *) &data[64] = + ppp_priv_area->if_send_skb_null; + *(unsigned long *) &data[68] = + ppp_priv_area->if_send_broadcast; + *(unsigned long *) &data[72] = + ppp_priv_area->if_send_multicast; + *(unsigned long *) &data[76] = + ppp_priv_area->if_send_critical_ISR; + *(unsigned long *) &data[80] = + ppp_priv_area->if_send_critical_non_ISR; + *(unsigned long *) &data[84] = + ppp_priv_area->if_send_busy; + *(unsigned long *) &data[88] = + ppp_priv_area->if_send_busy_timeout; + *(unsigned long *) &data[92] = + ppp_priv_area->if_send_DRVSTATS_request; + *(unsigned long *) &data[96] = + ppp_priv_area->if_send_PTPIPE_request; + *(unsigned long *) &data[100] = + ppp_priv_area->if_send_wan_disconnected; + *(unsigned long *) &data[104] = + ppp_priv_area->if_send_adptr_bfrs_full; + *(unsigned long *) &data[108] = + ppp_priv_area->if_send_protocol_error; + *(unsigned long *) &data[112] = + ppp_priv_area->if_send_tx_int_enabled; + *(unsigned long *) &data[116] = + ppp_priv_area->if_send_bfr_passed_to_adptr; + *(unsigned long *) &data[118] = + card->irq_dis_if_send_count; + mbox->cmd.length = 62; + break; + case 0x27: + *(unsigned long *) &data[60] = card->statistics.isr_entry; + *(unsigned long *) &data[64] = + card->statistics.isr_already_critical; + *(unsigned long *) &data[68] = card->statistics.isr_rx; + *(unsigned long *) &data[72] = card->statistics.isr_tx; + *(unsigned long *) &data[76] = + card->statistics.isr_intr_test; + *(unsigned long *) &data[80] = + card->statistics.isr_spurious; + *(unsigned long *) &data[84] = + card->statistics.isr_enable_tx_int; + *(unsigned long *) &data[88] = + card->statistics.rx_intr_corrupt_rx_bfr; + *(unsigned long *) &data[92] = + ppp_priv_area->rx_intr_no_socket; + *(unsigned long *) &data[96] = + ppp_priv_area->rx_intr_DRVSTATS_request; + *(unsigned long *) &data[100] = + ppp_priv_area->rx_intr_PTPIPE_request; + *(unsigned long *) &data[104] = + ppp_priv_area->rx_intr_bfr_passed_to_stack; + *(unsigned long *) &data[108] = + card->statistics.rx_intr_dev_not_started; + *(unsigned long *) &data[112] = + card->statistics.tx_intr_dev_not_started; + mbox->cmd.length = 56; + break; + case 0x28: + *(unsigned long *) &data[60] = + ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err; + *(unsigned long *) &data[64] = + ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err; + *(unsigned long *) &data[68] = + ppp_priv_area->UDP_PTPIPE_mgmt_direction_err; + *(unsigned long *) &data[72] = + ppp_priv_area-> + UDP_PTPIPE_mgmt_adptr_cmnd_timeout; + *(unsigned long *) &data[76] = + ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK; + *(unsigned long *) &data[80] = + ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr; + *(unsigned long *) &data[84] = + ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack; + *(unsigned long *) &data[88] = + ppp_priv_area->UDP_PTPIPE_mgmt_no_socket; + *(unsigned long *) &data[92] = + ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err; + *(unsigned long *) &data[96] = + ppp_priv_area-> + UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; + *(unsigned long *) &data[100] = + ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; + *(unsigned long *) &data[104] = + ppp_priv_area-> + UDP_DRVSTATS_mgmt_passed_to_adptr; + *(unsigned long *) &data[108] = + ppp_priv_area-> + UDP_DRVSTATS_mgmt_passed_to_stack; + *(unsigned long *) &data[112] = + ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket; + *(unsigned long *) &data[116] = + card->statistics.poll_entry; + *(unsigned long *) &data[120] = + card->statistics.poll_already_critical; + *(unsigned long *) &data[124] = + card->statistics.poll_processed; + *(unsigned long *) &data[126] = + card->irq_dis_poll_count; + mbox->cmd.length = 70; + break; + default: + /* it's a board command */ + memcpy(&mbox->cmd, &sendpacket[45], sizeof(ppp_cmd_t)); + if (mbox->cmd.length) { + memcpy(&mbox->data, &sendpacket[60], + mbox->cmd.length); + } + /* run the command on the board */ + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) { + ppp_error(card, err, mbox); + ++ppp_priv_area-> + UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; + break; + } + ++ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; + /* copy the result back to our buffer */ + memcpy(data, sendpacket, skb->len); + memcpy(&data[45], &mbox->cmd, sizeof(ppp_cmd_t)); + if (mbox->cmd.length) { + memcpy(&data[60], &mbox->data, mbox->cmd.length); + } + } + /* Fill UDP TTL */ + data[8] = card->wandev.ttl; + len = reply_udp(data, mbox->cmd.length); + if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { + ++ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_adptr; + ppp_send(card, data, len, skb->protocol); + } else { + /* Pass it up the stack + Allocate socket buffer */ + if ((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ + buf = skb_put(new_skb, len); + memcpy(buf, data, len); + ++ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack; + /* Decapsulate packet and pass it up the protocol + stack */ + new_skb->protocol = htons(ETH_P_IP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; + netif_rx(new_skb); + } else { + ++ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket; + printk(KERN_INFO "no socket buffers available!\n"); + } + } + kfree(data); + return 0; +} + +/*============================================================================= + * Process UDP call of type PTPIPEAB. + */ + +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, + struct sk_buff *skb, struct net_device *dev, + ppp_private_area_t * ppp_priv_area) +{ + unsigned char *sendpacket; + unsigned char buf2[5]; + unsigned char *data; + unsigned char *buf; + unsigned int frames, len; + struct sk_buff *new_skb; + unsigned short buffer_length, real_len; + unsigned long data_ptr; + int udp_mgmt_req_valid = 1; + ppp_mbox_t *mbox = card->mbox; + struct timeval tv; + int err; + sendpacket = skb->data; + memcpy(&buf2, &card->wandev.udp_port, 2); + if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) { + printk(KERN_INFO + "%s: Error allocating memory for UDP management cmnd0x%02X" + ,card->devname, data[45]); + ++ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err; + return 1; + } + memcpy(data, sendpacket, skb->len); + switch (data[45]) { + /* FT1 MONITOR STATUS */ + case 0x80: + if (card->hw.fwid != SFID_PPP508) { + ++ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err; + udp_mgmt_req_valid = 0; + break; + } + /* PPIPE_ENABLE_TRACING */ + case 0x20: + /* PPIPE_DISABLE_TRACING */ + case 0x21: + /* PPIPE_GET_TRACE_INFO */ + case 0x22: + /* SET FT1 MODE */ + case 0x81: + if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { + ++ppp_priv_area->UDP_PTPIPE_mgmt_direction_err; + udp_mgmt_req_valid = 0; + } + break; + default: + break; + } + if (!udp_mgmt_req_valid) { + /* set length to 0 */ + data[46] = data[47] = 0; + /* set return code */ + data[48] = 0xCD; + } else { + switch (data[45]) { + /* PPIPE_ENABLE_TRACING */ + case 0x20: + if (!TracingEnabled) { + /* OPERATE_DATALINE_MONITOR */ + mbox->cmd.command = 0x33; + mbox->cmd.length = 1; + mbox->data[0] = 0x03; + err = sdla_exec(mbox) ? + mbox->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) { + ppp_error(card, err, mbox); + TracingEnabled = 0; + /* set the return code */ + data[48] = mbox->cmd.result; + mbox->cmd.length = 0; + break; + } + if (card->hw.fwid == SFID_PPP502) { + sdla_peek(&card->hw, 0x9000, &buf2, 2); + } else { + sdla_peek(&card->hw, 0xC000, &buf2, 2); + } + curr_trace_addr = 0; + memcpy(&curr_trace_addr, &buf2, 2); + start_trace_addr = curr_trace_addr; + /* MAX_SEND_BUFFER_SIZE -sizeof(UDP_MGMT_PACKET) + - 41 */ + available_buffer_space = 1926; + } + data[48] = 0; + mbox->cmd.length = 0; + TracingEnabled = 1; + break; + /* PPIPE_DISABLE_TRACING */ + case 0x21: + if (TracingEnabled) { + /* OPERATE_DATALINE_MONITOR */ + mbox->cmd.command = 0x3; + mbox->cmd.length = 1; + mbox->data[0] = 0x00; + err = sdla_exec(mbox) ? + mbox->cmd.result : CMD_TIMEOUT; + } + /*set return code */ + data[48] = 0; + mbox->cmd.length = 0; + TracingEnabled = 0; + break; + /* PPIPE_GET_TRACE_INFO */ + case 0x22: + if (TracingEnabled) { + buffer_length = 0; + /* frames < NUM_TRACE_FRAMES */ + for (frames = 0; frames < 62; frames += 1) { + sdla_peek(&card->hw, curr_trace_addr, + &buf2, 1); + /* no data on board so exit */ + if (buf2[0] == 0x00) + break; + /*1+sizeof(FRAME_DATA) = 9 */ + if ((available_buffer_space - + buffer_length) < 9) { + /*indicate we have more frames + on board and exit */ + data[60] |= 0x02; + break; + } + /* get frame status */ + sdla_peek(&card->hw, curr_trace_addr + + 0x01, &data[60 + buffer_length], 1); + /* get time stamp */ + sdla_peek(&card->hw, curr_trace_addr + + 0x06, &data[64 + buffer_length], 2); + /* get frame length */ + sdla_peek(&card->hw, curr_trace_addr + + 0x02, &data[62 + buffer_length], 2); + /* get pointer to real data */ + sdla_peek(&card->hw, curr_trace_addr + + 0x04, &buf2, 2); + data_ptr = 0; + memcpy(&data_ptr, &buf2, 2); + /* see if we can fit the frame into the + user buffer */ + memcpy(&real_len, + &data[62 + buffer_length], 2); + if ((data_ptr == 0) || + ((real_len + 8) > + available_buffer_space)) { + data[61 + buffer_length] = 0x00; + } else { + /* we can take it next time */ + if ((available_buffer_space - + buffer_length) < + (real_len + 8)) { + data[60] |= 0x02; + break; + } + /* ok, get the frame */ + data[61 + buffer_length] = 0x01; + /* get the data */ + sdla_peek(&card->hw, data_ptr, + &data[66 + buffer_length], + real_len); + /* zero the opp flag to + show we got the frame */ + buf2[0] = 0x00; + sdla_poke(&card->hw, + curr_trace_addr, &buf2, 1); + /* now move onto the next + frame */ + curr_trace_addr += 8; + /* check if we passed the last + address */ + if (curr_trace_addr >= + start_trace_addr + 0x1F0) { + curr_trace_addr = + start_trace_addr; + } + /* update buffer length and make sure its even */ + if (data[61 + buffer_length] + == 0x01) { + buffer_length += + real_len - 1; + } + /* for the header */ + buffer_length += 8; + if (buffer_length & 0x0001) + buffer_length += 1; + } + } + /* ok now set the total number of frames passed + in the high 5 bits */ + data[60] = (frames << 2) | data[60]; + /* set the data length */ + mbox->cmd.length = buffer_length; + memcpy(&data[46], &buffer_length, 2); + /* set return code */ + data[48] = 0; + } else { + /* set return code */ + data[48] = 1; + mbox->cmd.length = 0; + } + break; + /* PPIPE_GET_IBA_DATA */ + case 0x23: + mbox->cmd.length = 0x09; + if (card->hw.fwid == SFID_PPP502) { + sdla_peek(&card->hw, 0xA003, &data[60], + mbox->cmd.length); + } else { + sdla_peek(&card->hw, 0xF003, &data[60], + mbox->cmd.length); + } + /* set the length of the data */ + data[46] = 0x09; + /* set return code */ + data[48] = 0x00; + break; + /* PPIPE_KILL_BOARD */ + case 0x24: + break; + /* PPIPE_FT1_READ_STATUS */ + case 0x25: + sdla_peek(&card->hw, 0xF020, &data[60], 2); + data[46] = 2; + data[47] = 0; + data[48] = 0; + mbox->cmd.length = 2; + break; + case 0x29: + init_ppp_priv_struct(ppp_priv_area); + init_global_statistics(card); + mbox->cmd.length = 0; + break; + case 0x30: + do_gettimeofday(&tv); + ppp_priv_area->router_up_time = tv.tv_sec - + ppp_priv_area->router_start_time; + *(unsigned long *) &data[60] = + ppp_priv_area->router_up_time; + mbox->cmd.length = 4; + break; + /* FT1 MONITOR STATUS */ + case 0x80: + /* Enable FT1 MONITOR STATUS */ + if (data[60] == 1) { + if (rCount++ != 0) { + data[48] = 0; + mbox->cmd.length = 1; + break; + } + } + /* Disable FT1 MONITOR STATUS */ + if (data[60] == 0) { + if (--rCount != 0) { + data[48] = 0; + mbox->cmd.length = 1; + break; + } + } + default: + /* it's a board command */ + memcpy(&mbox->cmd, &sendpacket[45], sizeof(ppp_cmd_t)); + if (mbox->cmd.length) { + memcpy(&mbox->data, &sendpacket[60], + mbox->cmd.length); + } + /* run the command on the board */ + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) { + ppp_error(card, err, mbox); + ++ppp_priv_area-> + UDP_PTPIPE_mgmt_adptr_cmnd_timeout; + break; + } + ++ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK; + /* copy the result back to our buffer */ + memcpy(data, sendpacket, skb->len); + memcpy(&data[45], &mbox->cmd, sizeof(ppp_cmd_t)); + if (mbox->cmd.length) { + memcpy(&data[60], &mbox->data, mbox->cmd.length); + } + } /* end of switch */ + } /* end of else */ + /* Fill UDP TTL */ + data[8] = card->wandev.ttl; + len = reply_udp(data, mbox->cmd.length); + if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { + ++ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr; + ppp_send(card, data, len, skb->protocol); + } else { + /* Pass it up the stack + Allocate socket buffer */ + if ((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ + buf = skb_put(new_skb, len); + memcpy(buf, data, len); + ++ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack; + /* Decapsulate packet and pass it up the protocol + stack */ + new_skb->protocol = htons(ETH_P_IP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; + netif_rx(new_skb); + } else { + ++ppp_priv_area->UDP_PTPIPE_mgmt_no_socket; + printk(KERN_INFO "no socket buffers available!\n"); + } + } + kfree(data); + return 0; +} + +/*============================================================================= + * Initial the ppp_private_area structure. + */ + +static void init_ppp_priv_struct(ppp_private_area_t * ppp_priv_area) +{ + ppp_priv_area->if_send_entry = 0; + ppp_priv_area->if_send_skb_null = 0; + ppp_priv_area->if_send_broadcast = 0; + ppp_priv_area->if_send_multicast = 0; + ppp_priv_area->if_send_critical_ISR = 0; + ppp_priv_area->if_send_critical_non_ISR = 0; + ppp_priv_area->if_send_busy = 0; + ppp_priv_area->if_send_busy_timeout = 0; + ppp_priv_area->if_send_DRVSTATS_request = 0; + ppp_priv_area->if_send_PTPIPE_request = 0; + ppp_priv_area->if_send_wan_disconnected = 0; + ppp_priv_area->if_send_adptr_bfrs_full = 0; + ppp_priv_area->if_send_bfr_passed_to_adptr = 0; + ppp_priv_area->rx_intr_no_socket = 0; + ppp_priv_area->rx_intr_DRVSTATS_request = 0; + ppp_priv_area->rx_intr_PTPIPE_request = 0; + ppp_priv_area->rx_intr_bfr_not_passed_to_stack = 0; + ppp_priv_area->rx_intr_bfr_passed_to_stack = 0; + ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err = 0; + ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err = 0; + ppp_priv_area->UDP_PTPIPE_mgmt_direction_err = 0; + ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_timeout = 0; + ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK = 0; + ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr = 0; + ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack = 0; + ppp_priv_area->UDP_PTPIPE_mgmt_no_socket = 0; + ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err = 0; + ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_type_err = 0; + ppp_priv_area->UDP_DRVSTATS_mgmt_direction_err = 0; + ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout = 0; + ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK = 0; + ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_adptr = 0; + ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack = 0; + ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket = 0; +} + +/*============================================================================ + * Initialize Global Statistics + */ + +static void init_global_statistics(sdla_t * card) +{ + card->statistics.isr_entry = 0; + card->statistics.isr_already_critical = 0; + card->statistics.isr_tx = 0; + card->statistics.isr_rx = 0; + card->statistics.isr_intr_test = 0; + card->statistics.isr_spurious = 0; + card->statistics.isr_enable_tx_int = 0; + card->statistics.rx_intr_corrupt_rx_bfr = 0; + card->statistics.rx_intr_dev_not_started = 0; + card->statistics.tx_intr_dev_not_started = 0; + card->statistics.poll_entry = 0; + card->statistics.poll_already_critical = 0; + card->statistics.poll_processed = 0; + card->statistics.poll_tbusy_bad_status = 0; +} + +/*============================================================================ + * Initialize Receive and Transmit Buffers. + */ + +static void init_ppp_tx_rx_buff(sdla_t * card) +{ + if (card->hw.fwid == SFID_PPP502) { + ppp502_buf_info_t *info = + (void *) (card->hw.dpmbase + PPP502_BUF_OFFS); + card->u.p.txbuf_base = + (void *) (card->hw.dpmbase + info->txb_offs); + card->u.p.txbuf_last = (ppp_buf_ctl_t *) card->u.p.txbuf_base + + (info->txb_num - 1); + card->u.p.rxbuf_base = + (void *) (card->hw.dpmbase + info->rxb_offs); + card->u.p.rxbuf_last = (ppp_buf_ctl_t *) card->u.p.rxbuf_base + + (info->rxb_num - 1); + } else { + ppp508_buf_info_t *info = + (void *) (card->hw.dpmbase + PPP508_BUF_OFFS); + card->u.p.txbuf_base = (void *) (card->hw.dpmbase + + (info->txb_ptr - PPP508_MB_VECT)); + card->u.p.txbuf_last = (ppp_buf_ctl_t *) card->u.p.txbuf_base + + (info->txb_num - 1); + card->u.p.rxbuf_base = (void *) (card->hw.dpmbase + + (info->rxb_ptr - PPP508_MB_VECT)); + card->u.p.rxbuf_last = (ppp_buf_ctl_t *) card->u.p.rxbuf_base + + (info->rxb_num - 1); + card->u.p.rx_base = info->rxb_base; + card->u.p.rx_top = info->rxb_end; + } + card->u.p.txbuf = card->u.p.txbuf_base; + card->rxmb = card->u.p.rxbuf_base; +} + +/*============================================================================= + * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR + * _TEST_COUNTER times. + */ + +static int intr_test(sdla_t * card) +{ + ppp_mbox_t *mb = card->mbox; + int err, i; + /* The critical flag is unset because during initialization (if_open) + * we want the interrupts to be enabled so that when the wpp_isr is + * called it does not exit due to critical flag set. + */ + card->wandev.critical = 0; + err = ppp_set_intr_mode(card, 0x08); + if (err == CMD_OK) { + for (i = 0; i < MAX_INTR_TEST_COUNTER; i++) { + /* Run command READ_CODE_VERSION */ + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + mb->cmd.length = 0; + mb->cmd.command = 0x10; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) + ppp_error(card, err, mb); + } + } else + return err; + err = ppp_set_intr_mode(card, 0); + if (err != CMD_OK) + return err; + card->wandev.critical = 1; + return 0; +} + +/*============================================================================== + * Determine what type of UDP call it is. DRVSTATS or PTPIPEAB ? + */ + +static int udp_pkt_type(struct sk_buff *skb, sdla_t * card) +{ + unsigned char *sendpacket; + unsigned char buf2[5]; + sendpacket = skb->data; + memcpy(&buf2, &card->wandev.udp_port, 2); + if (sendpacket[0] == 0x45 && /* IP packet */ + sendpacket[9] == 0x11 && /* UDP packet */ + sendpacket[22] == buf2[1] && /* UDP Port */ + sendpacket[23] == buf2[0] && + sendpacket[36] == 0x01) { + if (sendpacket[28] == 0x50 && /* PTPIPEAB: Signature */ + sendpacket[29] == 0x54 && + sendpacket[30] == 0x50 && + sendpacket[31] == 0x49 && + sendpacket[32] == 0x50 && + sendpacket[33] == 0x45 && + sendpacket[34] == 0x41 && + sendpacket[35] == 0x42) { + return UDP_PTPIPE_TYPE; + } else if (sendpacket[28] == 0x44 && /* DRVSTATS: Signature */ + sendpacket[29] == 0x52 && + sendpacket[30] == 0x56 && + sendpacket[31] == 0x53 && + sendpacket[32] == 0x54 && + sendpacket[33] == 0x41 && + sendpacket[34] == 0x54 && + sendpacket[35] == 0x53) { + return UDP_DRVSTATS_TYPE; + } else + return UDP_INVALID_TYPE; + } else + return UDP_INVALID_TYPE; +} + +/****** End *****************************************************************/ diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/sdla_x25.c linux/drivers/net/wan/sdla_x25.c --- v2.3.20/linux/drivers/net/wan/sdla_x25.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/sdla_x25.c Mon Oct 11 10:13:25 1999 @@ -0,0 +1,2435 @@ +/***************************************************************************** +* sdla_x25.c WANPIPE(tm) Multiprotocol WAN Link Driver. X.25 module. +* +* Author: Gene Kozin +* +* 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 /* printk(), and other useful stuff */ +#include /* offsetof(), etc. */ +#include /* return codes */ +#include /* inline memset(), etc. */ +#include /* kmalloc(), kfree() */ +#include /* WAN router definitions */ +#include /* WANPIPE common user API definitions */ +#include /* htons(), etc. */ +#include + +#define _GNUC_ +#include /* X.25 firmware API definitions */ + +/****** Defines & Macros ****************************************************/ + +#define CMD_OK 0 /* normal firmware return code */ +#define CMD_TIMEOUT 0xFF /* firmware command timed out */ +#define MAX_CMD_RETRY 10 /* max number of firmware retries */ + +#define X25_CHAN_MTU 4096 /* unfragmented logical channel MTU */ +#define X25_HRDHDR_SZ 7 /* max encapsulation header size */ +#define X25_CONCT_TMOUT (90*HZ) /* link connection timeout */ +#define X25_RECON_TMOUT (10*HZ) /* link connection timeout */ +#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ +#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ + +/* For IPXWAN */ +#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) + +/****** Data Structures *****************************************************/ + +/* This is an extention of the 'struct net_device' we create for each network + * interface to keep the rest of X.25 channel-specific data. + */ +typedef struct x25_channel +{ + char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ + char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ + unsigned lcn; /* logical channel number */ + unsigned tx_pkt_size; + unsigned short protocol; /* ethertype, 0 - multiplexed */ + char svc; /* 0 - permanent, 1 - switched */ + char state; /* channel state */ + char drop_sequence; /* mark sequence for dropping */ + unsigned long state_tick; /* time of the last state change */ + unsigned idle_timeout; /* sec, before disconnecting */ + unsigned long i_timeout_sofar; /* # of sec's we've been idle */ + unsigned hold_timeout; /* sec, before re-connecting */ + unsigned long tick_counter; /* counter for transmit time out */ + char devtint; /* Weather we should dev_tint() */ + struct sk_buff* rx_skb; /* receive socket buffer */ + struct sk_buff* tx_skb; /* transmit socket buffer */ + sdla_t* card; /* -> owner */ + int ch_idx; + struct net_device_stats ifstats; /* interface statistics */ +} x25_channel_t; + +typedef struct x25_call_info +{ + char dest[17]; /* ASCIIZ destination address */ + char src[17]; /* ASCIIZ source address */ + char nuser; /* number of user data bytes */ + unsigned char user[127]; /* user data */ + char nfacil; /* number of facilities */ + struct + { + unsigned char code; + unsigned char parm; + } facil[64]; /* facilities */ +} x25_call_info_t; + +/****** Function Prototypes *************************************************/ + +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, struct net_device* dev, + wanif_conf_t* conf); +static int del_if (wan_device_t* wandev, struct net_device* dev); + +/* WANPIPE-specific entry points */ +static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data); + +/* Network device interface */ +static int if_init (struct net_device* dev); +static int if_open (struct net_device* dev); +static int if_close (struct net_device* dev); +static int if_header (struct sk_buff* skb, struct net_device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len); +static int if_rebuild_hdr (struct sk_buff* skb); +static int if_send (struct sk_buff* skb, struct net_device* dev); +static struct net_device_stats * if_stats (struct net_device* dev); + +/* Interrupt handlers */ +static void wpx_isr (sdla_t* card); +static void rx_intr (sdla_t* card); +static void tx_intr (sdla_t* card); +static void status_intr (sdla_t* card); +static void event_intr (sdla_t* card); +static void spur_intr (sdla_t* card); + +/* Background polling routines */ +static void wpx_poll (sdla_t* card); +static void poll_disconnected (sdla_t* card); +static void poll_connecting (sdla_t* card); +static void poll_active (sdla_t* card); + +/* X.25 firmware interface functions */ +static int x25_get_version (sdla_t* card, char* str); +static int x25_configure (sdla_t* card, TX25Config* conf); +static int x25_get_err_stats (sdla_t* card); +static int x25_get_stats (sdla_t* card); +static int x25_set_intr_mode (sdla_t* card, int mode); +static int x25_close_hdlc (sdla_t* card); +static int x25_open_hdlc (sdla_t* card); +static int x25_setup_hdlc (sdla_t* card); +static int x25_set_dtr (sdla_t* card, int dtr); +static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan); +static int x25_place_call (sdla_t* card, x25_channel_t* chan); +static int x25_accept_call (sdla_t* card, int lcn, int qdm); +static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn); +static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf); +static int x25_fetch_events (sdla_t* card); +static int x25_error (sdla_t* card, int err, int cmd, int lcn); + +/* X.25 asynchronous event handlers */ +static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); +static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); +static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); +static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); +static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); + +/* Miscellaneous functions */ +static int connect (sdla_t* card); +static int disconnect (sdla_t* card); +static struct net_device* get_dev_by_lcn(wan_device_t* wandev, unsigned lcn); +static int chan_connect (struct net_device* dev); +static int chan_disc (struct net_device* dev); +static void set_chan_state (struct net_device* dev, int state); +static int chan_send (struct net_device* dev, struct sk_buff* skb); +static unsigned char bps_to_speed_code (unsigned long bps); +static unsigned int dec_to_uint (unsigned char* str, int len); +static unsigned int hex_to_uint (unsigned char* str, int len); +static void parse_call_info (unsigned char* str, x25_call_info_t* info); + +/* IPX functions */ +static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto); + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/****** Global Data ********************************************************** + * Note: All data must be explicitly initialized!!! + */ + +/****** Public Functions ****************************************************/ + +/*============================================================================ + * X.25 Protocol Initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and X.25 firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wpx_init (sdla_t* card, wandev_conf_t* conf) +{ + union + { + char str[80]; + TX25Config cfg; + } u; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_X25) + { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id) + ; + return -EINVAL; + } + + /* Initialize protocol-specific fields */ + card->mbox = (void*)(card->hw.dpmbase + X25_MBOX_OFFS); + card->rxmb = (void*)(card->hw.dpmbase + X25_RXMBOX_OFFS); + card->flags = (void*)(card->hw.dpmbase + X25_STATUS_OFFS); + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + if (x25_get_version(card, NULL) || x25_get_version(card, u.str)) + return -EIO + ; + printk(KERN_INFO "%s: running X.25 firmware v%s\n", + card->devname, u.str) + ; + + /* Configure adapter. Here we set resonable defaults, then parse + * device configuration structure and set configuration options. + * Most configuration options are verified and corrected (if + * necessary) since we can't rely on the adapter to do so and don't + * want it to fail either. + */ + memset(&u.cfg, 0, sizeof(u.cfg)); + u.cfg.t1 = 3; + u.cfg.n2 = 10; + u.cfg.autoHdlc = 1; /* automatic HDLC connection */ + u.cfg.hdlcWindow = 7; + u.cfg.pktWindow = 2; + u.cfg.station = 1; /* DTE */ + u.cfg.options = 0x00B0; /* disable D-bit pragmatics */ + u.cfg.ccittCompat = 1988; + u.cfg.t10t20 = 30; + u.cfg.t11t21 = 30; + u.cfg.t12t22 = 30; + u.cfg.t13t23 = 30; + u.cfg.t16t26 = 30; + u.cfg.t28 = 30; + u.cfg.r10r20 = 5; + u.cfg.r12r22 = 5; + u.cfg.r13r23 = 5; + u.cfg.responseOpt = 1; /* RR's after every packet */ + + if (conf->clocking != WANOPT_EXTERNAL) + u.cfg.baudRate = bps_to_speed_code(conf->bps) + ; + if (conf->station != WANOPT_DTE) + { + u.cfg.station = 0; /* DCE mode */ + } + if (conf->interface != WANOPT_RS232 ) { + u.cfg.hdlcOptions |= 0x80; /* V35 mode */ + } + /* adjust MTU */ + if (!conf->mtu || (conf->mtu >= 1024)) + card->wandev.mtu = 1024 + ; + else if (conf->mtu >= 512) + card->wandev.mtu = 512 + ; + else if (conf->mtu >= 256) + card->wandev.mtu = 256 + ; + else if (conf->mtu >= 128) + card->wandev.mtu = 128 + ; + else card->wandev.mtu = 64; + u.cfg.defPktSize = u.cfg.pktMTU = card->wandev.mtu; + + if (conf->u.x25.hi_pvc) + { + card->u.x.hi_pvc = min(conf->u.x25.hi_pvc, 4095); + card->u.x.lo_pvc = min(conf->u.x25.lo_pvc, card->u.x.hi_pvc); + } + if (conf->u.x25.hi_svc) + { + card->u.x.hi_svc = min(conf->u.x25.hi_svc, 4095); + card->u.x.lo_svc = min(conf->u.x25.lo_svc, card->u.x.hi_svc); + } + u.cfg.loPVC = card->u.x.lo_pvc; + u.cfg.hiPVC = card->u.x.hi_pvc; + u.cfg.loTwoWaySVC = card->u.x.lo_svc; + u.cfg.hiTwoWaySVC = card->u.x.hi_svc; + + if (conf->u.x25.hdlc_window) + u.cfg.hdlcWindow = min(conf->u.x25.hdlc_window, 7) + ; + if (conf->u.x25.pkt_window) + u.cfg.pktWindow = min(conf->u.x25.pkt_window, 7) + ; + if (conf->u.x25.t1) + u.cfg.t1 = min(conf->u.x25.t1, 30) + ; + u.cfg.t2 = min(conf->u.x25.t2, 29); + u.cfg.t4 = min(conf->u.x25.t4, 240); + if (conf->u.x25.n2) + u.cfg.n2 = min(conf->u.x25.n2, 30) + ; + if (conf->u.x25.ccitt_compat) + u.cfg.ccittCompat = conf->u.x25.ccitt_compat + ; + + /* initialize adapter */ + if ((x25_configure(card, &u.cfg) != CMD_OK) || + (x25_close_hdlc(card) != CMD_OK) || /* close HDLC link */ + (x25_set_dtr(card, 0) != CMD_OK)) /* drop DTR */ + return -EIO + ; + + /* Initialize protocol-specific fields of adapter data space */ + card->wandev.bps = conf->bps; + card->wandev.interface = conf->interface; + card->wandev.clocking = conf->clocking; + card->wandev.station = conf->station; + card->isr = &wpx_isr; + card->poll = &wpx_poll; + card->exec = &wpx_exec; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.state = WAN_DISCONNECTED; + card->wandev.enable_tx_int = 0; + card->irq_dis_if_send_count = 0; + card->irq_dis_poll_count = 0; + card->wandev.enable_IPX = conf->enable_IPX; + + if (conf->network_number) + card->wandev.network_number = conf->network_number; + else + card->wandev.network_number = 0xDEADBEEF; + return 0; +} + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * Update device status & statistics. + */ +static int update (wan_device_t* wandev) +{ + sdla_t* card; + + /* sanity checks */ + if ((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + if (wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + if (test_and_set_bit(0, (void*)&wandev->critical)) + return -EAGAIN; + card = wandev->private; + + x25_get_err_stats(card); + x25_get_stats(card); + wandev->critical = 0; + return 0; +} + +/*============================================================================ + * Create new logical channel. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + x25_channel_t* chan; + int err = 0; + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) + { + printk(KERN_INFO "%s: invalid interface name!\n", + card->devname) + ; + return -EINVAL; + } + + /* allocate and initialize private data */ + chan = kmalloc(sizeof(x25_channel_t), GFP_KERNEL); + if (chan == NULL) + return -ENOMEM + ; + memset(chan, 0, sizeof(x25_channel_t)); + strcpy(chan->name, conf->name); + chan->card = card; + chan->protocol = ETH_P_IP; + chan->tx_skb = chan->rx_skb = NULL; + + /* verify media address */ + if (conf->addr[0] == '@') /* SVC */ + { + chan->svc = 1; + strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ); + + /* Set channel timeouts (default if not specified) */ + chan->idle_timeout = (conf->idle_timeout) ? conf->idle_timeout : 90; + chan->hold_timeout = (conf->hold_timeout) ? conf->hold_timeout : 10; + } + else if (is_digit(conf->addr[0])) /* PVC */ + { + int lcn = dec_to_uint(conf->addr, 0); + + if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc)) + { + chan->lcn = lcn; + } + else + { + printk(KERN_ERR + "%s: PVC %u is out of range on interface %s!\n", + wandev->name, lcn, chan->name) + ; + err = -EINVAL; + } + } + else + { + printk(KERN_ERR + "%s: invalid media address on interface %s!\n", + wandev->name, chan->name) + ; + err = -EINVAL; + } + if (err) + { + kfree(chan); + return err; + } + + /* prepare network device data space for registration */ + dev->name = chan->name; + dev->init = &if_init; + dev->priv = chan; + return 0; +} + +/*============================================================================ + * Delete logical channel. + */ +static int del_if (wan_device_t* wandev, struct net_device* dev) +{ + if (dev->priv) + { + kfree(dev->priv); + dev->priv = NULL; + } + return 0; +} + +/****** WANPIPE-specific entry points ***************************************/ + +/*============================================================================ + * Execute adapter interface command. + */ + +static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err, len; + TX25Cmd cmd; + + if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) + return -EFAULT; + + /* execute command */ + + do + { + memcpy(&mbox->cmd, &cmd, sizeof(cmd)); + if (cmd.length) + { + if(copy_from_user((void*)&mbox->data, u_data, cmd.length)) + return-EFAULT; + } + if (sdla_exec(mbox)) + err = mbox->cmd.result + ; + else return -EIO; + } + while (err && retry-- && x25_error(card, err, cmd.command, cmd.lcn)); + + /* return result */ + if(copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(TX25Cmd))) + return -EFAULT; + len = mbox->cmd.length; + if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)) + return -EFAULT; + return 0; +} + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. + */ +static int if_init (struct net_device* dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + wan_device_t* wandev = &card->wandev; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = &if_header; + dev->rebuild_header = &if_rebuild_hdr; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + + /* Initialize media-specific parameters */ + dev->type = 30; /* ARP h/w type */ + dev->mtu = X25_CHAN_MTU; + dev->hard_header_len = X25_HRDHDR_SZ; /* media header length */ + dev->addr_len = 2; /* hardware address length */ + if (!chan->svc) + *(unsigned short*)dev->dev_addr = htons(chan->lcn); + + /* Initialize hardware parameters (just for reference) */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = (unsigned long)wandev->maddr; + dev->mem_end = dev->mem_end + wandev->msize - 1; + + /* Set transmit buffer queue length */ + dev->tx_queue_len = 10; + + /* Initialize socket buffers */ + + dev_init_buffers(dev); + set_chan_state(dev, WAN_DISCONNECTED); + return 0; +} + +/*============================================================================ + * Open network interface. + * o prevent module from unloading by incrementing use count + * o if link is disconnected then initiate connection + * + * Return 0 if O.k. or errno. + */ +static int if_open (struct net_device* dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + + if (dev->start) + return -EBUSY; /* only one open is allowed */ + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + wanpipe_open(card); + + /* If this is the first open, initiate physical connection */ + if (card->open_cnt == 1) + connect(card); + card->wandev.critical = 0; + return 0; +} + +/*============================================================================ + * Close network interface. + * o reset flags. + * o if there's no more open channels then disconnect physical link. + */ +static int if_close (struct net_device* dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev->start = 0; + if ((chan->state == WAN_CONNECTED) || (chan->state == WAN_CONNECTING)) + chan_disc(dev); + + wanpipe_close(card); + + /* If this is the last close, disconnect physical link */ + if (!card->open_cnt) + disconnect(card); + + card->wandev.critical = 0; + return 0; +} + +/*============================================================================ + * Build media header. + * o encapsulate packet according to encapsulation type. + * + * The trick here is to put packet type (Ethertype) into 'protocol' field of + * the socket buffer, so that we don't forget it. If encapsulation fails, + * set skb->protocol to 0 and discard packet later. + * + * Return: media header length. + */ +static int if_header (struct sk_buff* skb, struct net_device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len) +{ + x25_channel_t* chan = dev->priv; + int hdr_len = dev->hard_header_len; + + skb->protocol = type; + if (!chan->protocol) + { + hdr_len = wanrouter_encapsulate(skb, dev); + if (hdr_len < 0) + { + hdr_len = 0; + skb->protocol = 0; + } + } + return hdr_len; +} + +/*============================================================================ + * Re-build media header. + * + * Return: 1 physical address resolved. + * 0 physical address not resolved + */ + +static int if_rebuild_hdr (struct sk_buff* skb) +{ + struct net_device *dev=skb->dev; + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + + printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", + card->devname, dev->name); + return 1; +} + +/*============================================================================ + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission). + * o check link state. If link is not up, then drop the packet. + * o check channel status. If it's down then initiate a call. + * o pass a packet to corresponding WAN device. + * o free socket buffer + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + */ + +static int if_send (struct sk_buff* skb, struct net_device* dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + struct net_device *dev2; + TX25Status* status = card->flags; + unsigned long host_cpu_flags; + + if (dev->tbusy) + { + ++chan->ifstats.rx_dropped; + if ((jiffies - chan->tick_counter) < (5*HZ)) + { + return dev->tbusy; + } + printk(KERN_INFO "%s: Transmit time out %s!\n", + card->devname, dev->name) + ; + for( dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) + { + dev2->tbusy = 0; + } + } + chan->tick_counter = jiffies; + + disable_irq(card->hw.irq); + ++card->irq_dis_if_send_count; + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + { + printk(KERN_INFO "Hit critical in if_send()!\n"); + if (card->wandev.critical == CRITICAL_IN_ISR) + { + card->wandev.enable_tx_int = 1; + dev->tbusy = 1; + + save_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && + (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + + return dev->tbusy; + } + dev_kfree_skb(skb); + + save_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && + (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + + return dev->tbusy; + } + + /* Below is only until we have per-channel IPX going.... */ + if(!(chan->svc)) + chan->protocol = skb->protocol; + + if (card->wandev.state != WAN_CONNECTED) + ++chan->ifstats.tx_dropped; + + /* Below is only until we have per-channel IPX going.... */ + else if ( (chan->svc) && (chan->protocol && (chan->protocol != skb->protocol))) + { + printk(KERN_INFO + "%s: unsupported Ethertype 0x%04X on interface %s!\n", + card->devname, skb->protocol, dev->name); + ++chan->ifstats.tx_errors; + } + else switch (chan->state) + { + case WAN_DISCONNECTED: + /* Try to establish connection. If succeded, then start + * transmission, else drop a packet. + */ + if (chan_connect(dev) != 0) + { + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + break; + } + /* fall through */ + + case WAN_CONNECTED: + if( skb->protocol == ETH_P_IPX ) + { + if(card->wandev.enable_IPX) + { + switch_net_numbers( skb->data, + card->wandev.network_number, 0); + } + else + { + ++card->wandev.stats.tx_dropped; + ++chan->ifstats.tx_dropped; + goto tx_done; + } + } + dev->trans_start = jiffies; + if(chan_send(dev, skb)) + { + dev->tbusy = 1; + status->imask |= 0x2; + } + break; + + default: + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + } +tx_done: + if (!dev->tbusy) + dev_kfree_skb(skb); + + card->wandev.critical = 0; + save_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return dev->tbusy; +} + +/*============================================================================ + * Get Ethernet-style interface statistics. + * Return a pointer to struct net_device_stats + */ + +static struct net_device_stats* if_stats (struct net_device* dev) +{ + x25_channel_t* chan = dev->priv; + if(chan==NULL) + return NULL; + return &chan->ifstats; +} + +/****** Interrupt Handlers **************************************************/ + +/*============================================================================ + * X.25 Interrupt Service Routine. + */ + +static void wpx_isr (sdla_t* card) +{ + TX25Status* status = card->flags; + struct net_device *dev; + unsigned long host_cpu_flags; + + card->in_isr = 1; + card->buff_int_mode_unbusy = 0; + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + { + + printk(KERN_INFO "wpx_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, status->iflags); + card->in_isr = 0; + return; + } + + /* For all interrupts set the critical flag to CRITICAL_RX_INTR. + * If the if_send routine is called with this flag set it will set + * the enable transmit flag to 1. (for a delayed interrupt) + */ + card->wandev.critical = CRITICAL_IN_ISR; + + switch (status->iflags) + { + case 0x01: /* receive interrupt */ + rx_intr(card); + break; + + case 0x02: /* transmit interrupt */ + tx_intr(card); + card->buff_int_mode_unbusy = 1; + status->imask &= ~0x2; + break; + + case 0x04: /* modem status interrupt */ + status_intr(card); + break; + + case 0x10: /* network event interrupt */ + event_intr(card); + break; + + default: /* unwanted interrupt */ + spur_intr(card); + } + card->wandev.critical = CRITICAL_INTR_HANDLED; + if( card->wandev.enable_tx_int) + { + card->wandev.enable_tx_int = 0; + status->imask |= 0x2; + } + save_flags(host_cpu_flags); + cli(); + card->in_isr = 0; + status->iflags = 0; /* clear interrupt condition */ + card->wandev.critical = 0; + restore_flags(host_cpu_flags); + + if(card->buff_int_mode_unbusy) + { + for(dev = card->wandev.dev; dev; dev = dev->slave) + { + if(((x25_channel_t*)dev->priv)->devtint) + { + mark_bh(NET_BH); + return; + } + } + } +} + +/*============================================================================ + * Receive interrupt handler. + * This routine handles fragmented IP packets using M-bit according to the + * RFC1356. + * o map ligical channel number to network interface. + * o allocate socket buffer or append received packet to the existing one. + * o if M-bit is reset (i.e. it's the last packet in a sequence) then + * decapsulate packet and pass socket buffer to the protocol stack. + * + * Notes: + * 1. When allocating a socket buffer, if M-bit is set then more data is + * comming and we have to allocate buffer for the maximum IP packet size + * expected on this channel. + * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no + * socket buffers available) the whole packet sequence must be discarded. + */ + +static void rx_intr (sdla_t* card) +{ + TX25Mbox* rxmb = card->rxmb; + unsigned lcn = rxmb->cmd.lcn; /* logical channel number */ + unsigned len = rxmb->cmd.length; /* packet length */ + unsigned qdm = rxmb->cmd.qdm; /* Q,D and M bits */ + wan_device_t* wandev = &card->wandev; + struct net_device* dev = get_dev_by_lcn(wandev, lcn); + x25_channel_t* chan; + struct sk_buff* skb; + void* bufptr; + + if (dev == NULL) + { + /* Invalid channel, discard packet */ + printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n", + card->devname, lcn); + return; + } + + chan = dev->priv; + chan->i_timeout_sofar = jiffies; + if (chan->drop_sequence) + { + if (!(qdm & 0x01)) chan->drop_sequence = 0; + return; + } + + skb = chan->rx_skb; + if (skb == NULL) + { + /* Allocate new socket buffer */ + int bufsize = (qdm & 0x01) ? dev->mtu : len; + + skb = dev_alloc_skb(bufsize + dev->hard_header_len); + if (skb == NULL) + { + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + chan->drop_sequence = 1; /* set flag */ + ++chan->ifstats.rx_dropped; + return; + } + skb->dev = dev; + skb->protocol = htons(chan->protocol); + chan->rx_skb = skb; + } + + if (skb_tailroom(skb) < len) + { + /* No room for the packet. Call off the whole thing! */ + dev_kfree_skb(skb); + chan->rx_skb = NULL; + if (qdm & 0x01) chan->drop_sequence = 1; + + printk(KERN_INFO "%s: unexpectedly long packet sequence " + "on interface %s!\n", card->devname, dev->name); + ++chan->ifstats.rx_length_errors; + return; + } + + /* Append packet to the socket buffer */ + bufptr = skb_put(skb, len); + memcpy(bufptr, rxmb->data, len); + + if (qdm & 0x01) + return; /* more data is comming */ + + dev->last_rx = jiffies; /* timestamp */ + chan->rx_skb = NULL; /* dequeue packet */ + + /* Decapsulate packet, if necessary */ + if (!skb->protocol && !wanrouter_type_trans(skb, dev)) + { + /* can't decapsulate packet */ + dev_kfree_skb(skb); + ++chan->ifstats.rx_errors; + } + else + { + if( handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) + { + if( card->wandev.enable_IPX ) + { + if(chan_send(dev, skb)) + { + chan->tx_skb = skb; + } + else + { + dev_kfree_skb(skb); + } + } + else + { + /* FIXME: increment IPX packet dropped statistic */ + } + } + else + { + netif_rx(skb); + ++chan->ifstats.rx_packets; + chan->ifstats.rx_bytes += skb->len; + } + } +} + +/*============================================================================ + * Transmit interrupt handler. + * o Release socket buffer + * o Clear 'tbusy' flag + */ + +static void tx_intr (sdla_t* card) +{ + struct net_device *dev; + + /* unbusy all devices and then dev_tint(); */ + for(dev = card->wandev.dev; dev; dev = dev->slave) + { + ((x25_channel_t*)dev->priv)->devtint = dev->tbusy; + dev->tbusy = 0; + } + +} + +/*============================================================================ + * Modem status interrupt handler. + */ +static void status_intr (sdla_t* card) +{ +} + +/*============================================================================ + * Network event interrupt handler. + */ +static void event_intr (sdla_t* card) +{ +} + +/*============================================================================ + * Spurious interrupt handler. + * o print a warning + * o + * If number of spurious interrupts exceeded some limit, then ??? + */ +static void spur_intr (sdla_t* card) +{ + printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); +} + +/****** Background Polling Routines ****************************************/ + +/*============================================================================ + * Main polling routine. + * This routine is repeatedly called by the WANPIPE 'thread' to allow for + * time-dependent housekeeping work. + * + * Notes: + * 1. This routine may be called on interrupt context with all interrupts + * enabled. Beware! + */ + +static void wpx_poll (sdla_t* card) +{ + unsigned long host_cpu_flags; + + disable_irq(card->hw.irq); + ++card->irq_dis_poll_count; + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + { + printk(KERN_INFO "%s: critical in polling!\n",card->devname); + save_flags(host_cpu_flags); + cli(); + if ((!card->irq_dis_if_send_count) && + (!(--card->irq_dis_poll_count))) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return; + } + + switch(card->wandev.state) + { + case WAN_CONNECTED: + poll_active(card); + break; + + case WAN_CONNECTING: + poll_connecting(card); + break; + + case WAN_DISCONNECTED: + poll_disconnected(card); + } + card->wandev.critical = 0; + save_flags(host_cpu_flags); + cli(); + if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); +} + +/*============================================================================ + * Handle physical link establishment phase. + * o if connection timed out, disconnect the link. + */ +static void poll_connecting (sdla_t* card) +{ + TX25Status* status = card->flags; + + if (status->gflags & X25_HDLC_ABM) + { + wanpipe_set_state(card, WAN_CONNECTED); + x25_set_intr_mode(card, 0x83); /* enable Rx interrupts */ + status->imask &= ~0x2; /* mask Tx interupts */ + } + else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT) + disconnect(card); +} + +/*============================================================================ + * Handle physical link disconnected phase. + * o if hold-down timeout has expired and there are open interfaces, connect + * link. + */ +static void poll_disconnected (sdla_t* card) +{ + if (card->open_cnt && ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) + connect(card); +} + +/*============================================================================ + * Handle active link phase. + * o fetch X.25 asynchronous events. + * o kick off transmission on all interfaces. + */ +static void poll_active (sdla_t* card) +{ + struct net_device* dev; + + /* Fetch X.25 asynchronous events */ + x25_fetch_events(card); + + for (dev = card->wandev.dev; dev; dev = dev->slave) + { + x25_channel_t* chan = dev->priv; + struct sk_buff* skb = chan->tx_skb; + + /* If there is a packet queued for transmission then kick + * the channel's send routine. When transmission is complete + * or if error has occurred, release socket buffer and reset + * 'tbusy' flag. + */ + if (skb && (chan_send(dev, skb) == 0)) + { + chan->tx_skb = NULL; + dev->tbusy = 0; + dev_kfree_skb(skb); + } + + /* If SVC has been idle long enough, close virtual circuit */ + + if(( chan->svc )&&( chan->state == WAN_CONNECTED )) + { + if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout ) + { + /* Close svc */ + printk(KERN_INFO "%s: Closing down Idle link %s on LCN %d\n",card->devname,chan->name,chan->lcn); + chan->i_timeout_sofar = jiffies; + chan_disc(dev); + } + } + } +} + +/****** SDLA Firmware-Specific Functions ************************************* + * Almost all X.25 commands can unexpetedly fail due to so called 'X.25 + * asynchronous events' such as restart, interrupt, incoming call request, + * call clear request, etc. They can't be ignored and have to be dealt with + * immediately. To tackle with this problem we execute each interface command + * in a loop until good return code is received or maximum number of retries + * is reached. Each interface command returns non-zero return code, an + * asynchronous event/error handler x25_error() is called. + */ + +/*============================================================================ + * Read X.25 firmware version. + * Put code version as ASCII string in str. + */ +static int x25_get_version (sdla_t* card, char* str) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.command = X25_READ_CODE_VERSION; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && + x25_error(card, err, X25_READ_CODE_VERSION, 0)); + + if (!err && str) + { + int len = mbox->cmd.length; + memcpy(str, mbox->data, len); + str[len] = '\0'; + } + return err; +} + +/*============================================================================ + * Configure adapter. + */ + +static int x25_configure (sdla_t* card, TX25Config* conf) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + memcpy(mbox->data, (void*)conf, sizeof(TX25Config)); + mbox->cmd.length = sizeof(TX25Config); + mbox->cmd.command = X25_SET_CONFIGURATION; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0)); + return err; +} + +/*============================================================================ + * Get communications error statistics. + */ +static int x25_get_err_stats (sdla_t* card) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.command = X25_HDLC_READ_COMM_ERR; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0)); + + if (!err) + { + THdlcCommErr* stats = (void*)mbox->data; + + card->wandev.stats.rx_over_errors = stats->rxOverrun; + card->wandev.stats.rx_crc_errors = stats->rxBadCrc; + card->wandev.stats.rx_missed_errors = stats->rxAborted; + card->wandev.stats.tx_aborted_errors = stats->txAborted; + } + return err; +} + +/*============================================================================ + * Get protocol statistics. + */ +static int x25_get_stats (sdla_t* card) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.command = X25_READ_STATISTICS; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0)); + + if (!err) + { + TX25Stats* stats = (void*)mbox->data; + + card->wandev.stats.rx_packets = stats->rxData; + card->wandev.stats.tx_packets = stats->rxData; + } + return err; +} + +/*============================================================================ + * Close HDLC link. + */ +static int x25_close_hdlc (sdla_t* card) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.command = X25_HDLC_LINK_CLOSE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_CLOSE, 0)); + + return err; +} + +/*============================================================================ + * Open HDLC link. + */ +static int x25_open_hdlc (sdla_t* card) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.command = X25_HDLC_LINK_OPEN; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_OPEN, 0)); + + return err; +} + +/*============================================================================ + * Setup HDLC link. + */ +static int x25_setup_hdlc (sdla_t* card) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.command = X25_HDLC_LINK_SETUP; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_SETUP, 0)); + + return err; +} + +/*============================================================================ + * Set (raise/drop) DTR. + */ +static int x25_set_dtr (sdla_t* card, int dtr) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->data[0] = 0; + mbox->data[2] = 0; + mbox->data[1] = dtr ? 0x02 : 0x01; + mbox->cmd.length = 3; + mbox->cmd.command = X25_SET_GLOBAL_VARS; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && x25_error(card, err, X25_SET_GLOBAL_VARS, 0)); + + return err; +} + +/*============================================================================ + * Set interrupt mode. + */ +static int x25_set_intr_mode (sdla_t* card, int mode) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->data[0] = mode; + if (card->hw.fwid == SFID_X25_508) + { + mbox->data[1] = card->hw.irq; + mbox->cmd.length = 2; + } + else mbox->cmd.length = 1; + mbox->cmd.command = X25_SET_INTERRUPT_MODE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)) ; + return err; +} + +/*============================================================================ + * Read X.25 channel configuration. + */ +static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int lcn = chan->lcn; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.lcn = lcn; + mbox->cmd.command = X25_READ_CHANNEL_CONFIG; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && x25_error(card, err, X25_READ_CHANNEL_CONFIG, lcn)); + + if (!err) + { + TX25Status* status = card->flags; + + /* calculate an offset into the array of status bytes */ + if (card->u.x.hi_svc <= 255) + chan->ch_idx = lcn - 1; + else + { + int offset; + + switch (mbox->data[0] && 0x1F) + { + case 0x01: + offset = status->pvc_map; break; + case 0x03: + offset = status->icc_map; break; + case 0x07: + offset = status->twc_map; break; + case 0x0B: + offset = status->ogc_map; break; + default: + offset = 0; + } + chan->ch_idx = lcn - 1 - offset; + } + + /* get actual transmit packet size on this channel */ + switch(mbox->data[1] & 0x38) + { + case 0x00: + chan->tx_pkt_size = 16; + break; + case 0x08: + chan->tx_pkt_size = 32; + break; + case 0x10: + chan->tx_pkt_size = 64; + break; + case 0x18: + chan->tx_pkt_size = 128; + break; + case 0x20: + chan->tx_pkt_size = 256; + break; + case 0x28: + chan->tx_pkt_size = 512; + break; + case 0x30: + chan->tx_pkt_size = 1024; + break; + } + printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n", + card->devname, lcn, chan->tx_pkt_size); + } + return err; +} + +/*============================================================================ + * Place X.25 call. + */ + +static int x25_place_call (sdla_t* card, x25_channel_t* chan) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + char str[64]; + + sprintf(str, "-d%s -uCC", chan->addr); + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + strcpy(mbox->data, str); + mbox->cmd.length = strlen(str); + mbox->cmd.command = X25_PLACE_CALL; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && x25_error(card, err, X25_PLACE_CALL, 0)); + + if (!err) + { + chan->lcn = mbox->cmd.lcn; + chan->protocol = ETH_P_IP; + } + return err; +} + +/*============================================================================ + * Accept X.25 call. + */ + +static int x25_accept_call (sdla_t* card, int lcn, int qdm) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.lcn = lcn; + mbox->cmd.qdm = qdm; + mbox->cmd.command = X25_ACCEPT_CALL; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && x25_error(card, err, X25_ACCEPT_CALL, lcn)); + + return err; +} + +/*============================================================================ + * Clear X.25 call. + */ +static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.lcn = lcn; + mbox->cmd.cause = cause; + mbox->cmd.diagn = diagn; + mbox->cmd.command = X25_CLEAR_CALL; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && x25_error(card, err, X25_CLEAR_CALL, lcn)); + + return err; +} + +/*============================================================================ + * Send X.25 data packet. + */ +static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + memcpy(mbox->data, buf, len); + mbox->cmd.length = len; + mbox->cmd.lcn = lcn; + mbox->cmd.qdm = qdm; + mbox->cmd.command = X25_WRITE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && x25_error(card, err, X25_WRITE, lcn)); + return err; +} + +/*============================================================================ + * Fetch X.25 asynchronous events. + */ +static int x25_fetch_events (sdla_t* card) +{ + TX25Status* status = card->flags; + TX25Mbox* mbox = card->mbox; + int err = 0; + + if (status->gflags & 0x20) + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.command = X25_IS_DATA_AVAILABLE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err) + x25_error(card, err, X25_IS_DATA_AVAILABLE, 0); + } + return err; +} + +/*============================================================================ + * X.25 asynchronous event/error handler. + * This routine is called each time interface command returns non-zero + * return code to handle X.25 asynchronous events and common errors. + * Return non-zero to repeat command or zero to cancel it. + * + * Notes: + * 1. This function may be called recursively, as handling some of the + * asynchronous events (e.g. call request) requires execution of the + * interface command(s) that, in turn, may also return asynchronous + * events. To avoid re-entrancy problems we copy mailbox to dynamically + * allocated memory before processing events. + */ +static int x25_error (sdla_t* card, int err, int cmd, int lcn) +{ + int retry = 1; + unsigned dlen = ((TX25Mbox*)card->mbox)->cmd.length; + TX25Mbox* mb; + + mb = kmalloc(sizeof(TX25Mbox) + dlen, GFP_ATOMIC); + if (mb == NULL) + { + printk(KERN_ERR "%s: x25_error() out of memory!\n", + card->devname); + return 0; + } + memcpy(mb, card->mbox, sizeof(TX25Mbox) + dlen); + switch (err) + { + case 0x40: /* X.25 asynchronous packet was received */ + mb->data[dlen] = '\0'; + switch (mb->cmd.pktType & 0x7F) + { + case 0x30: /* incoming call */ + retry = incoming_call(card, cmd, lcn, mb); + break; + + case 0x31: /* connected */ + retry = call_accepted(card, cmd, lcn, mb); + break; + + case 0x02: /* call clear request */ + retry = call_cleared(card, cmd, lcn, mb); + break; + + case 0x04: /* reset request */ + printk(KERN_INFO "%s: X.25 reset request on LCN %d! " + "Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.lcn, mb->cmd.cause, + mb->cmd.diagn); + break; + + case 0x08: /* restart request */ + retry = restart_event(card, cmd, lcn, mb); + break; + + default: + printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! " + "Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.pktType, + mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn); + } + break; + + case 0x41: /* X.25 protocol violation indication */ + printk(KERN_INFO + "%s: X.25 protocol violation on LCN %d! " + "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.lcn, + mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn); + break; + + case 0x42: /* X.25 timeout */ + retry = timeout_event(card, cmd, lcn, mb); + break; + + case 0x43: /* X.25 retry limit exceeded */ + printk(KERN_INFO + "%s: exceeded X.25 retry limit on LCN %d! " + "Packet:0x%02X Diagn:0x%02X\n", card->devname, + mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn); + break; + + case 0x08: /* modem failure */ + printk(KERN_INFO "%s: modem failure!\n", card->devname); + break; + + case 0x09: /* N2 retry limit */ + printk(KERN_INFO "%s: exceeded HDLC retry limit!\n", + card->devname); + break; + + case 0x06: /* unnumbered frame was received while in ABM */ + printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n", + card->devname, mb->data[0]); + break; + + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, cmd); + retry = 0; /* abort command */ + break; + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", + card->devname, cmd, err); + retry = 0; /* abort command */ + } + kfree(mb); + return retry; +} + +/****** X.25 Asynchronous Event Handlers ************************************* + * These functions are called by the x25_error() and should return 0, if + * the command resulting in the asynchronous event must be aborted. + */ + +/*============================================================================ + * Handle X.25 incoming call request. + * RFC 1356 establishes the following rules: + * 1. The first octet in the Call User Data (CUD) field of the call + * request packet contains NLPID identifying protocol encapsulation. + * 2. Calls MUST NOT be accepted unless router supports requested + * protocol encapsulation. + * 3. A diagnostic code 249 defined by ISO/IEC 8208 may be used when + * clearing a call because protocol encapsulation is not supported. + * 4. If an incoming call is received while a call request is pending + * (i.e. call collision has occurred), the incoming call shall be + * rejected and call request shall be retried. + */ + +static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) +{ + wan_device_t* wandev = &card->wandev; + int new_lcn = mb->cmd.lcn; + struct net_device* dev = get_dev_by_lcn(wandev, new_lcn); + x25_channel_t* chan = NULL; + int accept = 0; /* set to '1' if o.k. to accept call */ + x25_call_info_t* info; + + /* Make sure there is no call collision */ + if (dev != NULL) + { + printk(KERN_INFO + "%s: X.25 incoming call collision on LCN %d!\n", + card->devname, new_lcn); + x25_clear_call(card, new_lcn, 0, 0); + return 1; + } + + /* Make sure D bit is not set in call request */ + if (mb->cmd.qdm & 0x02) + { + printk(KERN_INFO + "%s: X.25 incoming call on LCN %d with D-bit set!\n", + card->devname, new_lcn); + x25_clear_call(card, new_lcn, 0, 0); + return 1; + } + + /* Parse call request data */ + info = kmalloc(sizeof(x25_call_info_t), GFP_ATOMIC); + if (info == NULL) + { + printk(KERN_ERR + "%s: not enough memory to parse X.25 incoming call " + "on LCN %d!\n", card->devname, new_lcn); + x25_clear_call(card, new_lcn, 0, 0); + return 1; + } + parse_call_info(mb->data, info); + printk(KERN_INFO "%s: X.25 incoming call on LCN %d! Call data: %s\n", + card->devname, new_lcn, mb->data); + + /* Find available channel */ + for (dev = wandev->dev; dev; dev = dev->slave) + { + chan = dev->priv; + + if (!chan->svc || (chan->state != WAN_DISCONNECTED)) + continue; + if (strcmp(info->src, chan->addr) == 0) + break; + /* If just an '@' is specified, accept all incoming calls */ + if (strcmp(chan->addr, "") == 0) + break; + } + + if (dev == NULL) + { + printk(KERN_INFO "%s: no channels available!\n", + card->devname); + x25_clear_call(card, new_lcn, 0, 0); + } + + /* Check requested protocol encapsulation */ + else if (info->nuser == 0) + { + printk(KERN_INFO + "%s: no user data in incoming call on LCN %d!\n", + card->devname, new_lcn); + x25_clear_call(card, new_lcn, 0, 0); + } + else switch (info->user[0]) + { + case 0: /* multiplexed */ + chan->protocol = 0; + accept = 1; + break; + + case NLPID_IP: /* IP datagrams */ + chan->protocol = ETH_P_IP; + accept = 1; + break; + + case NLPID_SNAP: /* IPX datagrams */ + chan->protocol = ETH_P_IPX; + accept = 1; + break; + default: + printk(KERN_INFO + "%s: unsupported NLPID 0x%02X in incoming call " + "on LCN %d!\n", card->devname, info->user[0], new_lcn); + x25_clear_call(card, new_lcn, 0, 249); + } + + if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK)) + { + chan->lcn = new_lcn; + if (x25_get_chan_conf(card, chan) == CMD_OK) + set_chan_state(dev, WAN_CONNECTED); + else + x25_clear_call(card, new_lcn, 0, 0); + } + kfree(info); + return 1; +} + +/*============================================================================ + * Handle accepted call. + */ + +static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) +{ + unsigned new_lcn = mb->cmd.lcn; + struct net_device* dev = get_dev_by_lcn(&card->wandev, new_lcn); + x25_channel_t* chan; + + printk(KERN_INFO "%s: X.25 call accepted on LCN %d!\n", + card->devname, new_lcn); + if (dev == NULL) + { + printk(KERN_INFO + "%s: clearing orphaned connection on LCN %d!\n", + card->devname, new_lcn); + x25_clear_call(card, new_lcn, 0, 0); + return 1; + } + + /* Get channel configuration and notify router */ + chan = dev->priv; + if (x25_get_chan_conf(card, chan) != CMD_OK) + { + x25_clear_call(card, new_lcn, 0, 0); + return 1; + } + set_chan_state(dev, WAN_CONNECTED); + return 1; +} + +/*============================================================================ + * Handle cleared call. + */ + +static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) +{ + unsigned new_lcn = mb->cmd.lcn; + struct net_device* dev = get_dev_by_lcn(&card->wandev, new_lcn); + + printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X " + "Diagn:0x%02X\n", + card->devname, new_lcn, mb->cmd.cause, mb->cmd.diagn); + if (dev == NULL) + return 1; + set_chan_state(dev, WAN_DISCONNECTED); + return ((cmd == X25_WRITE) && (lcn == new_lcn)) ? 0 : 1; +} + +/*============================================================================ + * Handle X.25 restart event. + */ + +static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) +{ + wan_device_t* wandev = &card->wandev; + struct net_device* dev; + + printk(KERN_INFO + "%s: X.25 restart request! Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.cause, mb->cmd.diagn); + + /* down all logical channels */ + for (dev = wandev->dev; dev; dev = dev->slave) + set_chan_state(dev, WAN_DISCONNECTED); + return (cmd == X25_WRITE) ? 0 : 1; +} + +/*============================================================================ + * Handle timeout event. + */ +static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) +{ + unsigned new_lcn = mb->cmd.lcn; + + if (mb->cmd.pktType == 0x05) /* call request time out */ + { + struct net_device* dev = get_dev_by_lcn(&card->wandev, new_lcn); + + printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n", + card->devname, new_lcn); + if (dev) + set_chan_state(dev, WAN_DISCONNECTED); + } + else printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n", + card->devname, mb->cmd.pktType, new_lcn); + return 1; +} + +/******* Miscellaneous ******************************************************/ + +/*============================================================================ + * Establish physical connection. + * o open HDLC and raise DTR + * + * Return: 0 connection established + * 1 connection is in progress + * <0 error + */ +static int connect (sdla_t* card) +{ + if (x25_open_hdlc(card) || x25_setup_hdlc(card)) + return -EIO; + wanpipe_set_state(card, WAN_CONNECTING); + return 1; +} + +/*============================================================================ + * Tear down physical connection. + * o close HDLC link + * o drop DTR + * + * Return: 0 + * <0 error + */ +static int disconnect (sdla_t* card) +{ + wanpipe_set_state(card, WAN_DISCONNECTED); + x25_set_intr_mode(card, 0); /* disable interrupt generation */ + x25_close_hdlc(card); /* close HDLC link */ + x25_set_dtr(card, 0); /* drop DTR */ + return 0; +} + +/*============================================================================ + * Find network device by its channel number. + */ +static struct net_device* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn) +{ + struct net_device* dev; + + for (dev = wandev->dev; dev; dev = dev->slave) + if (((x25_channel_t*)dev->priv)->lcn == lcn) + break; + return dev; +} + +/*============================================================================ + * Initiate connection on the logical channel. + * o for PVC we just get channel configuration + * o for SVCs place an X.25 call + * + * Return: 0 connected + * >0 connection in progress + * <0 failure + */ +static int chan_connect (struct net_device* dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + + if (chan->svc) + { + if (!chan->addr[0]) + return -EINVAL; /* no destination address */ + printk(KERN_INFO "%s: placing X.25 call to %s ...\n", + card->devname, chan->addr); + if (x25_place_call(card, chan) != CMD_OK) + return -EIO; + set_chan_state(dev, WAN_CONNECTING); + return 1; + } + else + { + if (x25_get_chan_conf(card, chan) != CMD_OK) + return -EIO; + set_chan_state(dev, WAN_CONNECTED); + } + return 0; +} + +/*============================================================================ + * Disconnect logical channel. + * o if SVC then clear X.25 call + */ +static int chan_disc (struct net_device* dev) +{ + x25_channel_t* chan = dev->priv; + + if (chan->svc) + x25_clear_call(chan->card, chan->lcn, 0, 0); + set_chan_state(dev, WAN_DISCONNECTED); + return 0; +} + +/*============================================================================ + * Set logical channel state. + */ +static void set_chan_state (struct net_device* dev, int state) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + unsigned long flags; + + save_flags(flags); + cli(); + if (chan->state != state) + { + switch (state) + { + case WAN_CONNECTED: + printk (KERN_INFO "%s: interface %s connected!\n", + card->devname, dev->name); + *(unsigned short*)dev->dev_addr = htons(chan->lcn); + chan->i_timeout_sofar = jiffies; + break; + + case WAN_CONNECTING: + printk (KERN_INFO "%s: interface %s connecting...\n", + card->devname, dev->name); + break; + + case WAN_DISCONNECTED: + printk (KERN_INFO "%s: interface %s disconnected!\n", + card->devname, dev->name); + if (chan->svc) + { + *(unsigned short*)dev->dev_addr = 0; + chan->lcn = 0; + } + break; + } + chan->state = state; + } + chan->state_tick = jiffies; + restore_flags(flags); +} + +/*============================================================================ + * Send packet on a logical channel. + * When this function is called, tx_skb field of the channel data space + * points to the transmit socket buffer. When transmission is complete, + * release socket buffer and reset 'tbusy' flag. + * + * Return: 0 - transmission complete + * 1 - busy + * + * Notes: + * 1. If packet length is greater than MTU for this channel, we'll fragment + * the packet into 'complete sequence' using M-bit. + * 2. When transmission is complete, an event notification should be issued + * to the router. + */ +static int chan_send (struct net_device* dev, struct sk_buff* skb) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + TX25Status* status = card->flags; + unsigned len, qdm; + + /* Check to see if channel is ready */ + if (!(status->cflags[chan->ch_idx] & 0x40)) + return 1; + + if (skb->len > chan->tx_pkt_size) + { + len = chan->tx_pkt_size; + qdm = 0x01; /* set M-bit (more data) */ + } + else /* final packet */ + { + len = skb->len; + qdm = 0; + } + switch(x25_send(card, chan->lcn, qdm, len, skb->data)) + { + case 0x00: /* success */ + chan->i_timeout_sofar = jiffies; + if (qdm) + { + skb_pull(skb, len); + return 1; + } + ++chan->ifstats.tx_packets; + chan->ifstats.tx_bytes += skb->len; + break; + + case 0x33: /* Tx busy */ + return 1; + + default: /* failure */ + ++chan->ifstats.tx_errors; +/* return 1; */ + } + return 0; +} + +/*============================================================================ + * Parse X.25 call request data and fill x25_call_info_t structure. + */ + +static void parse_call_info (unsigned char* str, x25_call_info_t* info) +{ + memset(info, 0, sizeof(x25_call_info_t)); + for (; *str; ++str) + { + int i; + unsigned ch; + + if (*str == '-') switch (str[1]) + { + case 'd': /* destination address */ + for (i = 0; i < 16; ++i) + { + ch = str[2+i]; + if (!is_digit(ch)) + break; + info->dest[i] = ch; + } + break; + + case 's': /* source address */ + for (i = 0; i < 16; ++i) + { + ch = str[2+i]; + if (!is_digit(ch)) + break; + info->src[i] = ch; + } + break; + + case 'u': /* user data */ + for (i = 0; i < 127; ++i) + { + ch = str[2+2*i]; + if (!is_hex_digit(ch)) + break; + info->user[i] = hex_to_uint(&str[2+2*i], 2); + } + info->nuser = i; + break; + + case 'f': /* facilities */ + for (i = 0; i < 64; ++i) + { + ch = str[2+4*i]; + if (!is_hex_digit(ch)) + break; + info->facil[i].code = + hex_to_uint(&str[2+4*i], 2); + ch = str[4+4*i]; + if (!is_hex_digit(ch)) + break; + info->facil[i].parm = + hex_to_uint(&str[4+4*i], 2); + } + info->nfacil = i; + break; + } + } +} + +/*============================================================================ + * Convert line speed in bps to a number used by S502 code. + */ +static unsigned char bps_to_speed_code (unsigned long bps) +{ + unsigned char number; + + if (bps <= 1200) number = 0x01 ; + else if (bps <= 2400) number = 0x02; + else if (bps <= 4800) number = 0x03; + else if (bps <= 9600) number = 0x04; + else if (bps <= 19200) number = 0x05; + else if (bps <= 38400) number = 0x06; + else if (bps <= 45000) number = 0x07; + else if (bps <= 56000) number = 0x08; + else if (bps <= 64000) number = 0x09; + else if (bps <= 74000) number = 0x0A; + else if (bps <= 112000) number = 0x0B; + else if (bps <= 128000) number = 0x0C; + else number = 0x0D; + + return number; +} + +/*============================================================================ + * Convert decimal string to unsigned integer. + * If len != 0 then only 'len' characters of the string are converted. + */ +static unsigned int dec_to_uint (unsigned char* str, int len) +{ + unsigned val; + + if (!len) len = strlen(str); + for (val = 0; len && is_digit(*str); ++str, --len) + val = (val * 10) + (*str - (unsigned)'0'); + return val; +} + +/*============================================================================ + * Convert hex string to unsigned integer. + * If len != 0 then only 'len' characters of the string are conferted. + */ +static unsigned int hex_to_uint (unsigned char* str, int len) +{ + unsigned val, ch; + + if (!len) len = strlen(str); + for (val = 0; len; ++str, --len) + { + ch = *str; + if (is_digit(ch)) + val = (val << 4) + (ch - (unsigned)'0'); + else if (is_hex_digit(ch)) + val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10); + else + break; + } + return val; +} + + +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) +{ + int i; + + if( proto == htons(ETH_P_IPX) ) { + /* It's an IPX packet */ + if(!enable_IPX) { + /* Return 1 so we don't pass it up the stack. */ + return 1; + } + } else { + /* It's not IPX so pass it up the stack. */ + return 0; + } + + if( sendpacket[16] == 0x90 && + sendpacket[17] == 0x04) + { + /* It's IPXWAN */ + + if( sendpacket[2] == 0x02 && + sendpacket[34] == 0x00) + { + /* It's a timer request packet */ + printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); + + /* Go through the routing options and answer no to every + * option except Unnumbered RIP/SAP */ + for(i = 41; sendpacket[i] == 0x00; i += 5) + { + /* 0x02 is the option for Unnumbered RIP/SAP */ + if( sendpacket[i + 4] != 0x02) + sendpacket[i + 1] = 0; + } + + /* Skip over the extended Node ID option */ + if( sendpacket[i] == 0x04 ) + i += 8; + + /* We also want to turn off all header compression opt. */ + for(; sendpacket[i] == 0x80 ;) + { + sendpacket[i + 1] = 0; + i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; + } + + /* Set the packet type to timer response */ + sendpacket[34] = 0x01; + + printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); + } + else if( sendpacket[34] == 0x02 ) + { + /* This is an information request packet */ + printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); + + /* Set the packet type to information response */ + sendpacket[34] = 0x03; + + /* Set the router name */ + sendpacket[51] = 'X'; + sendpacket[52] = 'T'; + sendpacket[53] = 'P'; + sendpacket[54] = 'I'; + sendpacket[55] = 'P'; + sendpacket[56] = 'E'; + sendpacket[57] = '-'; + sendpacket[58] = CVHexToAscii(network_number >> 28); + sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24); + sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20); + sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16); + sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12); + sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8); + sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); + sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); + for(i = 66; i < 99; i+= 1) + sendpacket[i] = 0; + + printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); + } + else + { + printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); + return 0; + } + + /* Set the WNodeID to our network address */ + sendpacket[35] = (unsigned char)(network_number >> 24); + sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16); + sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8); + sendpacket[38] = (unsigned char)(network_number & 0x000000FF); + + return 1; + } else { + /* If we get here its an IPX-data packet, so it'll get passed up the stack. + switch the network numbers */ + switch_net_numbers(sendpacket, network_number, 1); + return 0; + } +} + +/* + If incoming is 0 (outgoing)- if the net numbers is ours make it 0 + if incoming is 1 - if the net number is 0 make it ours + +*/ + +static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) +{ + unsigned long pnetwork_number; + + pnetwork_number = (unsigned long)((sendpacket[6] << 24) + + (sendpacket[7] << 16) + (sendpacket[8] << 8) + + sendpacket[9]); + + if (!incoming) + { + /* If the destination network number is ours, make it 0 */ + if( pnetwork_number == network_number) + { + sendpacket[6] = sendpacket[7] = sendpacket[8] = + sendpacket[9] = 0x00; + } + } + else + { + /* If the incoming network is 0, make it ours */ + if( pnetwork_number == 0) + { + sendpacket[6] = (unsigned char)(network_number >> 24); + sendpacket[7] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[8] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[9] = (unsigned char)(network_number & + 0x000000FF); + } + } + + + pnetwork_number = (unsigned long)((sendpacket[18] << 24) + + (sendpacket[19] << 16) + (sendpacket[20] << 8) + + sendpacket[21]); + + if( !incoming ) + { + /* If the source network is ours, make it 0 */ + if( pnetwork_number == network_number) + { + sendpacket[18] = sendpacket[19] = sendpacket[20] = + sendpacket[21] = 0x00; + } + } + else + { + /* If the source network is 0, make it ours */ + if( pnetwork_number == 0 ) + { + sendpacket[18] = (unsigned char)(network_number >> 24); + sendpacket[19] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[20] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[21] = (unsigned char)(network_number & + 0x000000FF); + } + } +} /* switch_net_numbers */ + + +/****** End *****************************************************************/ diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/sdladrv.c linux/drivers/net/wan/sdladrv.c --- v2.3.20/linux/drivers/net/wan/sdladrv.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/sdladrv.c Mon Oct 11 10:13:25 1999 @@ -0,0 +1,1857 @@ +/***************************************************************************** +* sdladrv.c SDLA Support Module. Main module. +* +* This module is a library of common hardware-specific functions +* used by all Sangoma drivers. +* +* Author: Gene Kozin +* Fixes: Arnaldo Carvalho de Melo +* +* 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 /* printk(), and other useful stuff */ +#include /* offsetof(), etc. */ +#include /* return codes */ +#include /* inline memset(), etc. */ +#include /* support for loadable modules */ +#include /* for jiffies, HZ, etc. */ +#include /* API definitions */ +#include /* SDLA firmware module definitions */ +#include /* 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 /* API definitions */ +#include /* SDLA firmware module definitions */ +#include /* for inb(), outb(), etc. */ +#define _INB(port) (inb(port)) +#define _OUTB(port, byte) (outb((port),(byte))) +#define SYSTEM_TICK lbolt + +#else +#error Unknown system type! +#endif + +#define MOD_VERSION 3 +#define MOD_RELEASE 0 + +#define SDLA_IODELAY 100 /* I/O Rd/Wr delay, 10 works for 486DX2-66 */ +#define EXEC_DELAY 20 /* shared memory access delay, mks */ +#define EXEC_TIMEOUT (HZ*2) /* command timeout, in ticks */ + +/* I/O port address range */ +#define S502A_IORANGE 3 +#define S502E_IORANGE 4 +#define S503_IORANGE 3 +#define S507_IORANGE 4 +#define S508_IORANGE 4 + +/* Maximum amount of memory */ +#define S502_MAXMEM 0x10000L +#define S503_MAXMEM 0x10000L +#define S507_MAXMEM 0x40000L +#define S508_MAXMEM 0x40000L + +/* Minimum amount of memory */ +#define S502_MINMEM 0x8000L +#define S503_MINMEM 0x8000L +#define S507_MINMEM 0x20000L +#define S508_MINMEM 0x20000L + +/****** Function Prototypes *************************************************/ + +/* Module entry points. These are called by the OS and must be public. */ +int init_module (void); +void cleanup_module (void); + +/* Hardware-specific functions */ +static int sdla_detect (sdlahw_t* hw); +static int sdla_autodpm (sdlahw_t* hw); +static int sdla_setdpm (sdlahw_t* hw); +static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len); +static int sdla_init (sdlahw_t* hw); +static unsigned long sdla_memtest (sdlahw_t* hw); +static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo); +static unsigned char make_config_byte (sdlahw_t* hw); +static int sdla_start (sdlahw_t* hw, unsigned addr); + +static int init_s502a (sdlahw_t* hw); +static int init_s502e (sdlahw_t* hw); +static int init_s503 (sdlahw_t* hw); +static int init_s507 (sdlahw_t* hw); +static int init_s508 (sdlahw_t* hw); + +static int detect_s502a (int port); +static int detect_s502e (int port); +static int detect_s503 (int port); +static int detect_s507 (int port); +static int detect_s508 (int port); + +/* Miscellaneous functions */ +static int calibrate_delay (int mks); +static int get_option_index (unsigned* optlist, unsigned optval); +static unsigned check_memregion (void* ptr, unsigned len); +static unsigned test_memregion (void* ptr, unsigned len); +static unsigned short checksum (unsigned char* buf, unsigned len); + +/****** Global Data ********************************************************** + * Note: All data must be explicitly initialized!!! + */ + +/* private data */ +static char modname[] = "sdladrv"; +static char fullname[] = "SDLA Support Module"; +static char copyright[] = "(c) 1995-1996 Sangoma Technologies Inc."; +static unsigned exec_idle; + +/* Hardware configuration options. + * These are arrays of configuration options used by verification routines. + * The first element of each array is its size (i.e. number of options). + */ +static unsigned s502_port_options[] = + { 4, 0x250, 0x300, 0x350, 0x360 } +; +static unsigned s503_port_options[] = + { 8, 0x250, 0x254, 0x300, 0x304, 0x350, 0x354, 0x360, 0x364 } +; +static unsigned s508_port_options[] = + { 8, 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390 } +; + +static unsigned s502a_irq_options[] = { 0 }; +static unsigned s502e_irq_options[] = { 4, 2, 3, 5, 7 }; +static unsigned s503_irq_options[] = { 5, 2, 3, 4, 5, 7 }; +static unsigned s508_irq_options[] = { 8, 3, 4, 5, 7, 10, 11, 12, 15 }; + +static unsigned s502a_dpmbase_options[] = +{ + 28, + 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, + 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, + 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, + 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, +}; +static unsigned s507_dpmbase_options[] = +{ + 32, + 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, + 0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000, + 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000, + 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000, +}; +static unsigned s508_dpmbase_options[] = /* incl. S502E and S503 */ +{ + 32, + 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, + 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000, + 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, 0xDE000, + 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000, +}; + +/* +static unsigned s502_dpmsize_options[] = { 2, 0x2000, 0x10000 }; +static unsigned s507_dpmsize_options[] = { 2, 0x2000, 0x4000 }; +static unsigned s508_dpmsize_options[] = { 1, 0x2000 }; +*/ + +static unsigned s502a_pclk_options[] = { 2, 3600, 7200 }; +static unsigned s502e_pclk_options[] = { 5, 3600, 5000, 7200, 8000, 10000 }; +static unsigned s503_pclk_options[] = { 3, 7200, 8000, 10000 }; +static unsigned s507_pclk_options[] = { 1, 12288 }; +static unsigned s508_pclk_options[] = { 1, 16000 }; + +/* Host memory control register masks */ +static unsigned char s502a_hmcr[] = +{ + 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, /* A0000 - AC000 */ + 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, /* C0000 - CC000 */ + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, /* D0000 - DC000 */ + 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, /* E0000 - EC000 */ +}; +static unsigned char s502e_hmcr[] = +{ + 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, /* A0000 - AE000 */ + 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E, /* C0000 - CE000 */ + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* D0000 - DE000 */ + 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E, /* E0000 - EE000 */ +}; +static unsigned char s507_hmcr[] = +{ + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* A0000 - AE000 */ + 0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, /* B0000 - BE000 */ + 0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E, /* C0000 - CE000 */ + 0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, /* E0000 - EE000 */ +}; +static unsigned char s508_hmcr[] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* A0000 - AE000 */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* C0000 - CE000 */ + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* D0000 - DE000 */ + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* E0000 - EE000 */ +}; + +static unsigned char s507_irqmask[] = +{ + 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0 +}; + +/******* Kernel Loadable Module Entry Points ********************************/ + +/*============================================================================ + * Module 'insert' entry point. + * o print announcement + * o initialize static data + * o calibrate SDLA shared memory access delay. + * + * Return: 0 Ok + * < 0 error. + * Context: process + */ + +#ifdef MODULE +int init_module (void) +{ + printk(KERN_INFO "%s v%u.%u %s\n", + fullname, MOD_VERSION, MOD_RELEASE, copyright); + exec_idle = calibrate_delay(EXEC_DELAY); +#ifdef WANDEBUG + printk(KERN_DEBUG "%s: exec_idle = %d\n", modname, exec_idle); +#endif + return 0; +} + +/*============================================================================ + * Module 'remove' entry point. + * o release all remaining system resources + */ +void cleanup_module (void) +{ +} +#endif + +/******* Kernel APIs ********************************************************/ + +/*============================================================================ + * Set up adapter. + * o detect adapter type + * o verify hardware configuration options + * o check for hardware conflicts + * o set up adapter shared memory + * o test adapter memory + * o load firmware + * Return: 0 ok. + * < 0 error + */ + +EXPORT_SYMBOL(sdla_setup); + +int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len) +{ + unsigned* irq_opt = NULL; /* IRQ options */ + unsigned* dpmbase_opt = NULL; /* DPM window base options */ + unsigned* pclk_opt = NULL; /* CPU clock rate options */ + int err; + + if (sdla_detect(hw)) + { + printk(KERN_ERR "%s: adapter S%04u not found at port 0x%X!\n", + modname, hw->type, hw->port) + ; + return -EINVAL; + } + printk(KERN_INFO "%s: found S%04u card at port 0x%X.\n", + modname, hw->type, hw->port) + ; + + hw->dpmsize = SDLA_WINDOWSIZE; + switch (hw->type) + { + case SDLA_S502A: + hw->io_range = S502A_IORANGE; + irq_opt = s502a_irq_options; + dpmbase_opt = s502a_dpmbase_options; + pclk_opt = s502a_pclk_options; + break; + + case SDLA_S502E: + hw->io_range = S502E_IORANGE; + irq_opt = s502e_irq_options; + dpmbase_opt = s508_dpmbase_options; + pclk_opt = s502e_pclk_options; + break; + + case SDLA_S503: + hw->io_range = S503_IORANGE; + irq_opt = s503_irq_options; + dpmbase_opt = s508_dpmbase_options; + pclk_opt = s503_pclk_options; + break; + + case SDLA_S507: + hw->io_range = S507_IORANGE; + irq_opt = s508_irq_options; + dpmbase_opt = s507_dpmbase_options; + pclk_opt = s507_pclk_options; + break; + + case SDLA_S508: + hw->io_range = S508_IORANGE; + irq_opt = s508_irq_options; + dpmbase_opt = s508_dpmbase_options; + pclk_opt = s508_pclk_options; + break; + } + + /* Verify IRQ configuration options */ + if (!get_option_index(irq_opt, hw->irq)) + { + printk(KERN_ERR "%s: IRQ %d is illegal!\n", + modname, hw->irq) + ; + return -EINVAL; + } + + /* Verify CPU clock rate configuration options */ + if (hw->pclk == 0) + hw->pclk = pclk_opt[1] /* use default */ + ; + else if (!get_option_index(pclk_opt, hw->pclk)) + { + printk(KERN_ERR "%s: CPU clock %u is illegal!\n", + modname, hw->pclk) + ; + return -EINVAL; + } + printk(KERN_INFO "%s: assuming CPU clock rate of %u kHz.\n", + modname, hw->pclk) + ; + + /* Setup adapter dual-port memory window and test memory */ + if (hw->dpmbase == 0) + { + err = sdla_autodpm(hw); + if (err) + { + printk(KERN_ERR + "%s: can't find available memory region!\n", + modname) + ; + return err; + } + } + else if (!get_option_index(dpmbase_opt, virt_to_phys(hw->dpmbase))) + { + printk(KERN_ERR "%s: memory address 0x%lX is illegal!\n", + modname, virt_to_phys(hw->dpmbase)) + ; + return -EINVAL; + } + else if (sdla_setdpm(hw)) + { + printk(KERN_ERR + "%s: 8K memory region at 0x%lX is not available!\n", + modname, virt_to_phys(hw->dpmbase)); + return -EINVAL; + } + printk(KERN_INFO "%s: dual-port memory window is set at 0x%lX.\n", + modname, virt_to_phys(hw->dpmbase)); + + printk(KERN_INFO "%s: found %luK bytes of on-board memory.\n", + modname, hw->memory / 1024); + + /* Load firmware. If loader fails then shut down adapter */ + err = sdla_load(hw, sfm, len); + if (err) sdla_down(hw); /* shutdown adapter */ + return err; +} + +/*============================================================================ + * Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc. + */ + +EXPORT_SYMBOL(sdla_down); + +int sdla_down (sdlahw_t* hw) +{ + unsigned port = hw->port; + int i; + + if (!port) return -EFAULT; + + switch (hw->type) + { + case SDLA_S502A: + _OUTB(port, 0x08); /* halt CPU */ + _OUTB(port, 0x08); + _OUTB(port, 0x08); + hw->regs[0] = 0x08; + _OUTB(port + 1, 0xFF); /* close memory window */ + hw->regs[1] = 0xFF; + break; + + case SDLA_S502E: + _OUTB(port + 3, 0); /* stop CPU */ + _OUTB(port, 0); /* reset board */ + for (i = 0; i < S502E_IORANGE; ++i) + hw->regs[i] = 0 + ; + break; + + case SDLA_S503: + case SDLA_S507: + case SDLA_S508: + _OUTB(port, 0); /* reset board logic */ + hw->regs[0] = 0; + break; + + default: + return -EINVAL; + } + return 0; +} + +/*============================================================================ + * Map shared memory window into SDLA address space. + */ + +EXPORT_SYMBOL(sdla_mapmem); + +int sdla_mapmem (sdlahw_t* hw, unsigned long addr) +{ + unsigned port = hw->port; + register int tmp; + + switch (hw->type) + { + case SDLA_S502A: + case SDLA_S502E: + if (addr < S502_MAXMEM) /* verify parameter */ + { + tmp = addr >> 13; /* convert to register mask */ + _OUTB(port + 2, tmp); + hw->regs[2] = tmp; + } + else return -EINVAL; + break; + + case SDLA_S503: + if (addr < S503_MAXMEM) /* verify parameter */ + { + tmp = (hw->regs[0] & 0x8F) | ((addr >> 9) & 0x70); + _OUTB(port, tmp); + hw->regs[0] = tmp; + } + else return -EINVAL; + break; + + case SDLA_S507: + if (addr < S507_MAXMEM) + { + if (!(_INB(port) & 0x02)) + return -EIO + ; + tmp = addr >> 13; /* convert to register mask */ + _OUTB(port + 2, tmp); + hw->regs[2] = tmp; + } + else return -EINVAL; + break; + + case SDLA_S508: + if (addr < S508_MAXMEM) + { + tmp = addr >> 13; /* convert to register mask */ + _OUTB(port + 2, tmp); + hw->regs[2] = tmp; + } + else return -EINVAL; + break; + + default: + return -EINVAL; + } + hw->vector = addr & 0xFFFFE000L; + return 0; +} + +/*============================================================================ + * Enable interrupt generation. + */ + +EXPORT_SYMBOL(sdla_inten); + +int sdla_inten (sdlahw_t* hw) +{ + unsigned port = hw->port; + int tmp, i; + + switch (hw->type) + { + case SDLA_S502E: + /* Note thar interrupt control operations on S502E are allowed + * only if CPU is enabled (bit 0 of status register is set). + */ + if (_INB(port) & 0x01) + { + _OUTB(port, 0x02); /* bit1 = 1, bit2 = 0 */ + _OUTB(port, 0x06); /* bit1 = 1, bit2 = 1 */ + hw->regs[0] = 0x06; + } + else return -EIO; + break; + + case SDLA_S503: + tmp = hw->regs[0] | 0x04; + _OUTB(port, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (!(_INB(port) & 0x02)) /* verify */ + return -EIO + ; + break; + + case SDLA_S508: + tmp = hw->regs[0] | 0x10; + _OUTB(port, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (!(_INB(port + 1) & 0x10)) /* verify */ + return -EIO + ; + break; + + case SDLA_S502A: + case SDLA_S507: + break; + + default: + return -EINVAL; + + } + return 0; +} + +/*============================================================================ + * Disable interrupt generation. + */ + +EXPORT_SYMBOL(sdla_intde); + +int sdla_intde (sdlahw_t* hw) +{ + unsigned port = hw->port; + int tmp, i; + + switch (hw->type) + { + case SDLA_S502E: + /* Notes: + * 1) interrupt control operations are allowed only if CPU is + * enabled (bit 0 of status register is set). + * 2) disabling interrupts using bit 1 of control register + * causes IRQ line go high, therefore we are going to use + * 0x04 instead: lower it to inhibit interrupts to PC. + */ + if (_INB(port) & 0x01) + { + _OUTB(port, hw->regs[0] & ~0x04); + hw->regs[0] &= ~0x04; + } + else return -EIO; + break; + + case SDLA_S503: + tmp = hw->regs[0] & ~0x04; + _OUTB(port, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (_INB(port) & 0x02) /* verify */ + return -EIO + ; + break; + + case SDLA_S508: + tmp = hw->regs[0] & ~0x10; + _OUTB(port, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (_INB(port) & 0x10) /* verify */ + return -EIO + ; + break; + + case SDLA_S502A: + case SDLA_S507: + break; + + default: + return -EINVAL; + } + return 0; +} + +/*============================================================================ + * Acknowledge SDLA hardware interrupt. + */ + +EXPORT_SYMBOL(sdla_intack); + +int sdla_intack (sdlahw_t* hw) +{ + unsigned port = hw->port; + int tmp; + + switch (hw->type) + { + case SDLA_S502E: + /* To acknoledge hardware interrupt we have to toggle bit 3 of + * control register: \_/ + * Note that interrupt control operations on S502E are allowed + * only if CPU is enabled (bit 1 of status register is set). + */ + if (_INB(port) & 0x01) + { + tmp = hw->regs[0] & ~0x04; + _OUTB(port, tmp); + tmp |= 0x04; + _OUTB(port, tmp); + hw->regs[0] = tmp; + } + else return -EIO; + break; + + case SDLA_S503: + if (_INB(port) & 0x04) + { + tmp = hw->regs[0] & ~0x08; + _OUTB(port, tmp); + tmp |= 0x08; + _OUTB(port, tmp); + hw->regs[0] = tmp; + } + break; + + case SDLA_S502A: + case SDLA_S507: + case SDLA_S508: + break; + + default: + return -EINVAL; + } + return 0; +} + +/*============================================================================ + * Generate an interrupt to adapter's CPU. + */ + +EXPORT_SYMBOL(sdla_intr); + +int sdla_intr (sdlahw_t* hw) +{ + unsigned port = hw->port; + + switch (hw->type) + { + case SDLA_S502A: + if (!(_INB(port) & 0x40)) + { + _OUTB(port, 0x10); /* issue NMI to CPU */ + hw->regs[0] = 0x10; + } + else return -EIO; + break; + + case SDLA_S507: + if ((_INB(port) & 0x06) == 0x06) + { + _OUTB(port + 3, 0); + } + else return -EIO; + break; + + case SDLA_S508: + if (_INB(port + 1) & 0x02) + { + _OUTB(port, 0x08); + } + else return -EIO; + break; + + case SDLA_S502E: + case SDLA_S503: + default: + return -EINVAL; + } + return 0; +} + +/*============================================================================ + * Execute Adapter Command. + * o Set exec flag. + * o Busy-wait until flag is reset. + * o Return number of loops made, or 0 if command timed out. + */ + +EXPORT_SYMBOL(sdla_exec); + +int sdla_exec (void* opflag) +{ + volatile unsigned char* flag = opflag; + unsigned long tstop; + int nloops; + + if (*flag) return 0; /* ???? */ + + *flag = 1; + tstop = SYSTEM_TICK + EXEC_TIMEOUT; + for (nloops = 1; *flag; ++nloops) + { + unsigned delay = exec_idle; + while (--delay); /* delay */ + if (SYSTEM_TICK > tstop) return 0; /* time is up! */ + } + return nloops; +} + +/*============================================================================ + * Read absolute adapter memory. + * Transfer data from adapter's memory to data buffer. + * + * Note: + * Care should be taken when crossing dual-port memory window boundary. + * This function is not atomic, so caller must disable interrupt if + * interrupt routines are accessing adapter shared memory. + */ + +EXPORT_SYMBOL(sdla_peek); + +int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) +{ + unsigned long oldvec = hw->vector; + unsigned winsize = hw->dpmsize; + unsigned curpos, curlen; /* current offset and block size */ + unsigned long curvec; /* current DPM window vector */ + int err = 0; + + if (addr + len > hw->memory) /* verify arguments */ + return -EINVAL + ; + while (len && !err) + { + curpos = addr % winsize; /* current window offset */ + curvec = addr - curpos; /* current window vector */ + curlen = (len > (winsize - curpos)) ? (winsize - curpos) : len; + + /* Relocate window and copy block of data */ + err = sdla_mapmem(hw, curvec); + memcpy(buf, (void *)((u8 *)hw->dpmbase + curpos), curlen); + addr += curlen; + (char*)buf += curlen; + len -= curlen; + } + + /* Restore DPM window position */ + sdla_mapmem(hw, oldvec); + return err; +} + +/*============================================================================ + * Write Absolute Adapter Memory. + * Transfer data from data buffer to adapter's memory. + * + * Note: + * Care should be taken when crossing dual-port memory window boundary. + * This function is not atomic, so caller must disable interrupt if + * interrupt routines are accessing adapter shared memory. + */ + +EXPORT_SYMBOL(sdla_poke); + +int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) +{ + unsigned long oldvec = hw->vector; + unsigned winsize = hw->dpmsize; + unsigned curpos, curlen; /* current offset and block size */ + unsigned long curvec; /* current DPM window vector */ + int err = 0; + + if (addr + len > hw->memory) /* verify arguments */ + return -EINVAL + ; + while (len && !err) + { + curpos = addr % winsize; /* current window offset */ + curvec = addr - curpos; /* current window vector */ + curlen = (len > (winsize - curpos)) ? (winsize - curpos) : len; + + /* Relocate window and copy block of data */ + sdla_mapmem(hw, curvec); + memcpy((void*)((u8 *)hw->dpmbase + curpos), buf, curlen); + addr += curlen; + (char*)buf += curlen; + len -= curlen; + } + + /* Restore DPM window position */ + sdla_mapmem(hw, oldvec); + return err; +} + +#ifdef DONT_COMPIPLE_THIS +#endif /* DONT_COMPIPLE_THIS */ + +/****** Hardware-Specific Functions *****************************************/ + +/*============================================================================ + * Detect adapter type. + * o if adapter type is specified then call detection routine for that adapter + * type. Otherwise call detection routines for every adapter types until + * adapter is detected. + * + * Notes: + * 1) Detection tests are destructive! Adapter will be left in shutdown state + * after the test. + */ +static int sdla_detect (sdlahw_t* hw) +{ + unsigned port = hw->port; + int err = 0; + + if (!port) + return -EFAULT + ; + switch (hw->type) + { + case SDLA_S502A: + if (!detect_s502a(port)) err = -ENODEV; + break; + + case SDLA_S502E: + if (!detect_s502e(port)) err = -ENODEV; + break; + + case SDLA_S503: + if (!detect_s503(port)) err = -ENODEV; + break; + + case SDLA_S507: + if (!detect_s507(port)) err = -ENODEV; + break; + + case SDLA_S508: + if (!detect_s508(port)) err = -ENODEV; + break; + + default: + if (detect_s502a(port)) + hw->type = SDLA_S502A + ; + else if (detect_s502e(port)) + hw->type = SDLA_S502E + ; + else if (detect_s503(port)) + hw->type = SDLA_S503 + ; + else if (detect_s507(port)) + hw->type = SDLA_S507 + ; + else if (detect_s508(port)) + hw->type = SDLA_S508 + ; + else err = -ENODEV; + } + return err; +} + +/*============================================================================ + * Autoselect memory region. + * o try all available DMP address options from the top down until success. + */ +static int sdla_autodpm (sdlahw_t* hw) +{ + int i, err = -EINVAL; + unsigned* opt; + + switch (hw->type) + { + case SDLA_S502A: + opt = s502a_dpmbase_options; + break; + + case SDLA_S502E: + case SDLA_S503: + case SDLA_S508: + opt = s508_dpmbase_options; + break; + + case SDLA_S507: + opt = s507_dpmbase_options; + break; + + default: + return -EINVAL; + } + + for (i = opt[0]; i && err; --i) + { + hw->dpmbase = phys_to_virt(opt[i]); + err = sdla_setdpm(hw); + } + return err; +} + +/*============================================================================ + * Set up adapter dual-port memory window. + * o shut down adapter + * o make sure that no physical memory exists in this region, i.e entire + * region reads 0xFF and is not writable when adapter is shut down. + * o initialize adapter hardware + * o make sure that region is usable with SDLA card, i.e. we can write to it + * when adapter is configured. + */ +static int sdla_setdpm (sdlahw_t* hw) +{ + int err; + + /* Shut down card and verify memory region */ + sdla_down(hw); + if (check_memregion(hw->dpmbase, hw->dpmsize)) + return -EINVAL + ; + + /* Initialize adapter and test on-board memory segment by segment. + * If memory size appears to be less than shared memory window size, + * assume that memory region is unusable. + */ + err = sdla_init(hw); + if (err) return err; + + if (sdla_memtest(hw) < hw->dpmsize) /* less than window size */ + { + sdla_down(hw); + return -EIO; + } + sdla_mapmem(hw, 0L); /* set window vector at bottom */ + return 0; +} + +/*============================================================================ + * Load adapter from the memory image of the SDLA firmware module. + * o verify firmware integrity and compatibility + * o start adapter up + */ +static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len) +{ + int i; + + /* Verify firmware signature */ + if (strcmp(sfm->signature, SFM_SIGNATURE)) + { + printk(KERN_ERR "%s: not SDLA firmware!\n", + modname) + ; + return -EINVAL; + } + + /* Verify firmware module format version */ + if (sfm->version != SFM_VERSION) + { + printk(KERN_ERR + "%s: firmware format %u rejected! Expecting %u.\n", + modname, sfm->version, SFM_VERSION) + ; + return -EINVAL; + } + + /* Verify firmware module length and checksum */ + if ((len - offsetof(sfm_t, image) != sfm->info.codesize) || + (checksum((void*)&sfm->info, + sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum)) + { + printk(KERN_ERR "%s: firmware corrupted!\n", modname); + return -EINVAL; + } + + /* Announce */ + printk(KERN_INFO "%s: loading %s (ID=%u)...\n", modname, + (sfm->descr[0] != '\0') ? sfm->descr : "unknown firmware", + sfm->info.codeid) + ; + + /* Scan through the list of compatible adapters and make sure our + * adapter type is listed. + */ + for (i = 0; + (i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hw->type); + ++i) + ; + if (i == SFM_MAX_SDLA) + { + printk(KERN_ERR "%s: firmware is not compatible with S%u!\n", + modname, hw->type) + ; + return -EINVAL; + } + + /* Make sure there is enough on-board memory */ + if (hw->memory < sfm->info.memsize) + { + printk(KERN_ERR + "%s: firmware needs %lu bytes of on-board memory!\n", + modname, sfm->info.memsize) + ; + return -EINVAL; + } + + /* Move code onto adapter */ + if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize)) + { + printk(KERN_ERR "%s: failed to load code segment!\n", + modname) + ; + return -EIO; + } + + /* Prepare boot-time configuration data and kick-off CPU */ + sdla_bootcfg(hw, &sfm->info); + if (sdla_start(hw, sfm->info.startoffs)) + { + printk(KERN_ERR "%s: Damn... Adapter won't start!\n", + modname) + ; + return -EIO; + } + + /* position DPM window over the mailbox and enable interrupts */ + if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw)) + { + printk(KERN_ERR "%s: adapter hardware failure!\n", + modname) + ; + return -EIO; + } + hw->fwid = sfm->info.codeid; /* set firmware ID */ + return 0; +} + +/*============================================================================ + * Initialize SDLA hardware: setup memory window, IRQ, etc. + */ +static int sdla_init (sdlahw_t* hw) +{ + int i; + + for (i = 0; i < SDLA_MAXIORANGE; ++i) + hw->regs[i] = 0 + ; + switch (hw->type) + { + case SDLA_S502A: return init_s502a(hw); + case SDLA_S502E: return init_s502e(hw); + case SDLA_S503: return init_s503(hw); + case SDLA_S507: return init_s507(hw); + case SDLA_S508: return init_s508(hw); + } + return -EINVAL; +} + +/*============================================================================ + * Test adapter on-board memory. + * o slide DPM window from the bottom up and test adapter memory segment by + * segment. + * Return adapter memory size. + */ +static unsigned long sdla_memtest (sdlahw_t* hw) +{ + unsigned long memsize; + unsigned winsize; + + for (memsize = 0, winsize = hw->dpmsize; + !sdla_mapmem(hw, memsize) && + (test_memregion(hw->dpmbase, winsize) == winsize) + ; + memsize += winsize) + ; + hw->memory = memsize; + return memsize; +} + +/*============================================================================ + * Prepare boot-time firmware configuration data. + * o position DPM window + * o initialize configuration data area + */ +static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo) +{ + unsigned char* data; + + if (!sfminfo->datasize) return 0; /* nothing to do */ + + if (sdla_mapmem(hw, sfminfo->dataoffs) != 0) + return -EIO + ; + data = (void*)((u8 *)hw->dpmbase + (sfminfo->dataoffs - hw->vector)); + memset(data, 0, sfminfo->datasize); + + data[0x00] = make_config_byte(hw); + switch (sfminfo->codeid) + { + case SFID_X25_502: + case SFID_X25_508: + data[0x01] = 3; /* T1 timer */ + data[0x03] = 10; /* N2 */ + data[0x06] = 7; /* HDLC window size */ + data[0x0B] = 1; /* DTE */ + data[0x0C] = 2; /* X.25 packet window size */ + *(short*)&data[0x0D] = 128; /* default X.25 data size */ + *(short*)&data[0x0F] = 128; /* maximum X.25 data size */ + break; + } + return 0; +} + +/*============================================================================ + * Prepare configuration byte identifying adapter type and CPU clock rate. + */ +static unsigned char make_config_byte (sdlahw_t* hw) +{ + unsigned char byte = 0; + + switch (hw->pclk) + { + case 5000: byte = 0x01; break; + case 7200: byte = 0x02; break; + case 8000: byte = 0x03; break; + case 10000: byte = 0x04; break; + case 16000: byte = 0x05; break; + } + switch (hw->type) + { + case SDLA_S502E: byte |= 0x80; break; + case SDLA_S503: byte |= 0x40; break; + } + return byte; +} + +/*============================================================================ + * Start adapter's CPU. + * o calculate a pointer to adapter's cold boot entry point + * o position DPM window + * o place boot instruction (jp addr) at cold boot entry point + * o start CPU + */ +static int sdla_start (sdlahw_t* hw, unsigned addr) +{ + unsigned port = hw->port; + unsigned char *bootp; + int err, tmp, i; + + if (!port) return -EFAULT; + + switch (hw->type) + { + case SDLA_S502A: + bootp = hw->dpmbase; + bootp += 0x66; + break; + + case SDLA_S502E: + case SDLA_S503: + case SDLA_S507: + case SDLA_S508: + bootp = hw->dpmbase; + break; + + default: + return -EINVAL; + } + + err = sdla_mapmem(hw, 0); + if (err) return err; + + *bootp = 0xC3; /* Z80: 'jp' opcode */ + bootp++; + *((unsigned short*)(bootp)) = addr; + + switch (hw->type) + { + case SDLA_S502A: + _OUTB(port, 0x10); /* issue NMI to CPU */ + hw->regs[0] = 0x10; + break; + + case SDLA_S502E: + _OUTB(port + 3, 0x01); /* start CPU */ + hw->regs[3] = 0x01; + for (i = 0; i < SDLA_IODELAY; ++i); + if (_INB(port) & 0x01) /* verify */ + { + /* + * Enabling CPU changes functionality of the + * control register, so we have to reset its + * mirror. + */ + _OUTB(port, 0); /* disable interrupts */ + hw->regs[0] = 0; + } + else return -EIO; + break; + + case SDLA_S503: + tmp = hw->regs[0] | 0x09; /* set bits 0 and 3 */ + _OUTB(port, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); + if (!(_INB(port) & 0x01)) /* verify */ + return -EIO + ; + break; + + case SDLA_S507: + tmp = hw->regs[0] | 0x02; + _OUTB(port, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); + if (!(_INB(port) & 0x04)) /* verify */ + return -EIO + ; + break; + + case SDLA_S508: + tmp = hw->regs[0] | 0x02; + _OUTB(port, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); + if (!(_INB(port + 1) & 0x02)) /* verify */ + return -EIO + ; + break; + + default: + return -EINVAL; + } + return 0; +} + +/*============================================================================ + * Initialize S502A adapter. + */ +static int init_s502a (sdlahw_t* hw) +{ + unsigned port = hw->port; + int tmp, i; + + if (!detect_s502a(port)) + return -ENODEV + ; + hw->regs[0] = 0x08; + hw->regs[1] = 0xFF; + + /* Verify configuration options */ + i = get_option_index(s502a_dpmbase_options, virt_to_phys(hw->dpmbase)); + if (i == 0) + return -EINVAL + ; + + tmp = s502a_hmcr[i - 1]; + switch (hw->dpmsize) + { + case 0x2000: + tmp |= 0x01; + break; + + case 0x10000L: + break; + + default: + return -EINVAL; + } + + /* Setup dual-port memory window (this also enables memory access) */ + _OUTB(port + 1, tmp); + hw->regs[1] = tmp; + hw->regs[0] = 0x08; + return 0; +} + +/*============================================================================ + * Initialize S502E adapter. + */ +static int init_s502e (sdlahw_t* hw) +{ + unsigned port = hw->port; + int tmp, i; + + if (!detect_s502e(port)) + return -ENODEV + ; + + /* Verify configuration options */ + i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); + if (i == 0) + return -EINVAL + ; + + tmp = s502e_hmcr[i - 1]; + switch (hw->dpmsize) + { + case 0x2000: + tmp |= 0x01; + break; + + case 0x10000L: + break; + + default: + return -EINVAL; + } + + /* Setup dual-port memory window */ + _OUTB(port + 1, tmp); + hw->regs[1] = tmp; + + /* Enable memory access */ + _OUTB(port, 0x02); + hw->regs[0] = 0x02; + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + return (_INB(port) & 0x02) ? 0 : -EIO; +} + +/*============================================================================ + * Initialize S503 adapter. + * --------------------------------------------------------------------------- + */ +static int init_s503 (sdlahw_t* hw) +{ + unsigned port = hw->port; + int tmp, i; + + if (!detect_s503(port)) + return -ENODEV + ; + + /* Verify configuration options */ + i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); + if (i == 0) + return -EINVAL + ; + + tmp = s502e_hmcr[i - 1]; + switch (hw->dpmsize) + { + case 0x2000: + tmp |= 0x01; + break; + + case 0x10000L: + break; + + default: + return -EINVAL; + } + + /* Setup dual-port memory window */ + _OUTB(port + 1, tmp); + hw->regs[1] = tmp; + + /* Enable memory access */ + _OUTB(port, 0x02); + hw->regs[0] = 0x02; /* update mirror */ + return 0; +} + +/*============================================================================ + * Initialize S507 adapter. + */ +static int init_s507 (sdlahw_t* hw) +{ + unsigned port = hw->port; + int tmp, i; + + if (!detect_s507(port)) + return -ENODEV + ; + + /* Verify configuration options */ + i = get_option_index(s507_dpmbase_options, virt_to_phys(hw->dpmbase)); + if (i == 0) + return -EINVAL + ; + + tmp = s507_hmcr[i - 1]; + switch (hw->dpmsize) + { + case 0x2000: + tmp |= 0x01; + break; + + case 0x10000L: + break; + + default: + return -EINVAL; + } + + /* Enable adapter's logic */ + _OUTB(port, 0x01); + hw->regs[0] = 0x01; + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (!(_INB(port) & 0x20)) + return -EIO + ; + + /* Setup dual-port memory window */ + _OUTB(port + 1, tmp); + hw->regs[1] = tmp; + + /* Enable memory access */ + tmp = hw->regs[0] | 0x04; + if (hw->irq) + { + i = get_option_index(s508_irq_options, hw->irq); + if (i) tmp |= s507_irqmask[i - 1]; + } + _OUTB(port, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + return (_INB(port) & 0x08) ? 0 : -EIO; +} + +/*============================================================================ + * Initialize S508 adapter. + */ +static int init_s508 (sdlahw_t* hw) +{ + unsigned port = hw->port; + int tmp, i; + + if (!detect_s508(port)) + return -ENODEV + ; + + /* Verify configuration options */ + i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); + if (i == 0) + return -EINVAL + ; + + /* Setup memory configuration */ + tmp = s508_hmcr[i - 1]; + _OUTB(port + 1, tmp); + hw->regs[1] = tmp; + + /* Enable memory access */ + _OUTB(port, 0x04); + hw->regs[0] = 0x04; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + return (_INB(port + 1) & 0x04) ? 0 : -EIO; +} + +/*============================================================================ + * Detect S502A adapter. + * Following tests are used to detect S502A adapter: + * 1. All registers other than status (BASE) should read 0xFF + * 2. After writing 00001000b to control register, status register should + * read 01000000b. + * 3. After writing 0 to control register, status register should still + * read 01000000b. + * 4. After writing 00000100b to control register, status register should + * read 01000100b. + * Return 1 if detected o.k. or 0 if failed. + * Note: This test is destructive! Adapter will be left in shutdown + * state after the test. + */ +static int detect_s502a (int port) +{ + int i, j; + + if (!get_option_index(s502_port_options, port)) + return 0 + ; + for (j = 1; j < SDLA_MAXIORANGE; ++j) + { + if (_INB(port + j) != 0xFF) + return 0 + ; + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + } + + _OUTB(port, 0x08); /* halt CPU */ + _OUTB(port, 0x08); + _OUTB(port, 0x08); + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (_INB(port) != 0x40) + return 0 + ; + _OUTB(port, 0x00); + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (_INB(port) != 0x40) + return 0 + ; + _OUTB(port, 0x04); + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (_INB(port) != 0x44) + return 0 + ; + + /* Reset adapter */ + _OUTB(port, 0x08); + _OUTB(port, 0x08); + _OUTB(port, 0x08); + _OUTB(port + 1, 0xFF); + return 1; +} + +/*============================================================================ + * Detect S502E adapter. + * Following tests are used to verify adapter presence: + * 1. All registers other than status (BASE) should read 0xFF. + * 2. After writing 0 to CPU control register (BASE+3), status register + * (BASE) should read 11111000b. + * 3. After writing 00000100b to port BASE (set bit 2), status register + * (BASE) should read 11111100b. + * Return 1 if detected o.k. or 0 if failed. + * Note: This test is destructive! Adapter will be left in shutdown + * state after the test. + */ +static int detect_s502e (int port) +{ + int i, j; + + if (!get_option_index(s502_port_options, port)) + return 0 + ; + for (j = 1; j < SDLA_MAXIORANGE; ++j) + { + if (_INB(port + j) != 0xFF) + return 0 + ; + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + } + + _OUTB(port + 3, 0); /* CPU control reg. */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (_INB(port) != 0xF8) /* read status */ + return 0 + ; + _OUTB(port, 0x04); /* set bit 2 */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (_INB(port) != 0xFC) /* verify */ + return 0 + ; + + /* Reset adapter */ + _OUTB(port, 0); + return 1; +} + +/*============================================================================ + * Detect s503 adapter. + * Following tests are used to verify adapter presence: + * 1. All registers other than status (BASE) should read 0xFF. + * 2. After writing 0 to control register (BASE), status register (BASE) + * should read 11110000b. + * 3. After writing 00000100b (set bit 2) to control register (BASE), + * status register should read 11110010b. + * Return 1 if detected o.k. or 0 if failed. + * Note: This test is destructive! Adapter will be left in shutdown + * state after the test. + */ +static int detect_s503 (int port) +{ + int i, j; + + if (!get_option_index(s503_port_options, port)) + return 0 + ; + for (j = 1; j < SDLA_MAXIORANGE; ++j) + { + if (_INB(port + j) != 0xFF) + return 0 + ; + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + } + + _OUTB(port, 0); /* reset control reg.*/ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (_INB(port) != 0xF0) /* read status */ + return 0 + ; + _OUTB(port, 0x04); /* set bit 2 */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if (_INB(port) != 0xF2) /* verify */ + return 0 + ; + + /* Reset adapter */ + _OUTB(port, 0); + return 1; +} + +/*============================================================================ + * Detect s507 adapter. + * Following tests are used to detect s507 adapter: + * 1. All ports should read the same value. + * 2. After writing 0x00 to control register, status register should read + * ?011000?b. + * 3. After writing 0x01 to control register, status register should read + * ?011001?b. + * Return 1 if detected o.k. or 0 if failed. + * Note: This test is destructive! Adapter will be left in shutdown + * state after the test. + */ +static int detect_s507 (int port) +{ + int tmp, i, j; + + if (!get_option_index(s508_port_options, port)) + return 0 + ; + tmp = _INB(port); + for (j = 1; j < S507_IORANGE; ++j) + { + if (_INB(port + j) != tmp) + return 0 + ; + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + } + + _OUTB(port, 0x00); + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if ((_INB(port) & 0x7E) != 0x30) + return 0 + ; + _OUTB(port, 0x01); + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if ((_INB(port) & 0x7E) != 0x32) + return 0 + ; + + /* Reset adapter */ + _OUTB(port, 0x00); + return 1; +} + +/*============================================================================ + * Detect s508 adapter. + * Following tests are used to detect s508 adapter: + * 1. After writing 0x00 to control register, status register should read + * ??000000b. + * 2. After writing 0x10 to control register, status register should read + * ??010000b + * Return 1 if detected o.k. or 0 if failed. + * Note: This test is destructive! Adapter will be left in shutdown + * state after the test. + */ +static int detect_s508 (int port) +{ + int i; + + if (!get_option_index(s508_port_options, port)) + return 0 + ; + _OUTB(port, 0x00); + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if ((_INB(port + 1) & 0x3F) != 0x00) + return 0 + ; + _OUTB(port, 0x10); + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + if ((_INB(port + 1) & 0x3F) != 0x10) + return 0 + ; + + /* Reset adapter */ + _OUTB(port, 0x00); + return 1; +} + +/******* Miscellaneous ******************************************************/ + +/*============================================================================ + * Calibrate SDLA memory access delay. + * Count number of idle loops made within 1 second and then calculate the + * number of loops that should be made to achive desired delay. + */ +static int calibrate_delay (int mks) +{ + unsigned int delay; + unsigned long stop; + + for (delay = 0, stop = SYSTEM_TICK + HZ; SYSTEM_TICK < stop; ++delay); + return (delay/(1000000L/mks) + 1); +} + +/*============================================================================ + * Get option's index into the options list. + * Return option's index (1 .. N) or zero if option is invalid. + */ +static int get_option_index (unsigned* optlist, unsigned optval) +{ + int i; + + for (i = 1; i <= optlist[0]; ++i) + if ( optlist[i] == optval) return i + ; + return 0; +} + +/*============================================================================ + * Check memory region to see if it's available. + * Return: 0 ok. + */ +static unsigned check_memregion (void* ptr, unsigned len) +{ + volatile unsigned char* p = ptr; + + for (; len && (*p == 0xFF); --len, ++p) + { + *p = 0; /* attempt to write 0 */ + if (*p != 0xFF) /* still has to read 0xFF */ + { + *p = 0xFF; /* restore original value */ + break; /* not good */ + } + } + return len; +} + +/*============================================================================ + * Test memory region. + * Return: size of the region that passed the test. + * Note: Region size must be multiple of 2 ! + */ +static unsigned test_memregion (void* ptr, unsigned len) +{ + volatile unsigned short* w_ptr; + unsigned len_w = len >> 1; /* region len in words */ + unsigned i; + + for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) + *w_ptr = 0xAA55 + ; + for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) + if (*w_ptr != 0xAA55) + { + len_w = i; + break; + } + ; + for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) + *w_ptr = 0x55AA + ; + for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) + if (*w_ptr != 0x55AA) + { + len_w = i; + break; + } + ; + for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) *w_ptr = 0; + return len_w << 1; +} + +/*============================================================================ + * Calculate 16-bit CRC using CCITT polynomial. + */ +static unsigned short checksum (unsigned char* buf, unsigned len) +{ + unsigned short crc = 0; + unsigned mask, flag; + + for (; len; --len, ++buf) + { + for (mask = 0x80; mask; mask >>= 1) + { + flag = (crc & 0x8000); + crc <<= 1; + crc |= ((*buf & mask) ? 1 : 0); + if (flag) crc ^= 0x1021; + } + } + return crc; +} + + +/****** End *****************************************************************/ diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/sdlamain.c linux/drivers/net/wan/sdlamain.c --- v2.3.20/linux/drivers/net/wan/sdlamain.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/sdlamain.c Mon Oct 11 10:13:25 1999 @@ -0,0 +1,628 @@ +/***************************************************************************** +* sdlamain.c WANPIPE(tm) Multiprotocol WAN Link Driver. Main module. +* +* Author: Gene Kozin +* Jaspreet Singh +* Fixes: Arnaldo Carvalho de Melo +* +* 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 /* OS configuration options */ +#include /* offsetof(), etc. */ +#include /* return codes */ +#include /* inline memset(), etc. */ +#include /* kmalloc(), kfree() */ +#include /* printk(), and other useful stuff */ +#include /* support for loadable modules */ +#include /* request_region(), release_region() */ +#include /* for kernel task queues */ +#include /* WAN router definitions */ +#include /* WANPIPE common user API definitions */ +#include /* kernel <-> user copy */ +#include /* phys_to_virt() */ +#include /* __init (when not using as a module) */ + + +/****** Defines & Macros ****************************************************/ + +#ifdef _DEBUG_ +#define STATIC +#else +#define STATIC static +#endif + +#define DRV_VERSION 4 /* version number */ +#define DRV_RELEASE 1 /* release (minor version) number */ +#define MAX_CARDS 8 /* max number of adapters */ + +#ifndef CONFIG_WANPIPE_CARDS /* configurable option */ +#define CONFIG_WANPIPE_CARDS 1 +#endif + +#define CMD_OK 0 /* normal firmware return code */ +#define CMD_TIMEOUT 0xFF /* firmware command timed out */ +#define MAX_CMD_RETRY 10 /* max number of firmware retries */ + +/****** Function Prototypes *************************************************/ + +/* Module entry points */ +int init_module (void); +void cleanup_module (void); + +/* WAN link driver entry points */ +static int setup (wan_device_t* wandev, wandev_conf_t* conf); +static int shutdown (wan_device_t* wandev); +static int ioctl (wan_device_t* wandev, unsigned cmd, unsigned long arg); + +/* IOCTL hanlers */ +static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump); +static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec); + +/* Miscellaneous functions */ +STATIC void sdla_isr (int irq, void* dev_id, struct pt_regs *regs); +STATIC void sdla_poll (void* data); + +/****** Global Data ********************************************************** + * Note: All data must be explicitly initialized!!! + */ + +/* private data */ +static char drvname[] = "wanpipe"; +static char fullname[] = "WANPIPE(tm) Multiprotocol Driver"; +static char copyright[] = "(c) 1995-1996 Sangoma Technologies Inc."; +static int ncards = CONFIG_WANPIPE_CARDS; +static int active = 0; /* number of active cards */ +static sdla_t* card_array = NULL; /* adapter data space */ + +/* Task queue element for creating a 'thread' */ +static struct tq_struct sdla_tq = +{ + NULL, /* .next */ + 0, /* .sync */ + &sdla_poll, /* .routine */ + NULL /* .data */ +}; + +/******* Kernel Loadable Module Entry Points ********************************/ + +/*============================================================================ + * Module 'insert' entry point. + * o print announcement + * o allocate adapter data space + * o initialize static data + * o register all cards with WAN router + * o calibrate SDLA shared memory access delay. + * + * Return: 0 Ok + * < 0 error. + * Context: process + */ + +#ifdef MODULE +int init_module (void) +#else +int __init wanpipe_init(void) +#endif +{ + int cnt, err = 0; + + printk(KERN_INFO "%s v%u.%u %s\n", + fullname, DRV_VERSION, DRV_RELEASE, copyright) + ; + + /* Verify number of cards and allocate adapter data space */ + ncards = min(ncards, MAX_CARDS); + ncards = max(ncards, 1); + card_array = kmalloc(sizeof(sdla_t) * ncards, GFP_KERNEL); + if (card_array == NULL) + return -ENOMEM + ; + memset(card_array, 0, sizeof(sdla_t) * ncards); + + /* Register adapters with WAN router */ + for (cnt = 0; cnt < ncards; ++cnt) + { + sdla_t* card = &card_array[cnt]; + wan_device_t* wandev = &card->wandev; + + sprintf(card->devname, "%s%d", drvname, cnt + 1); + wandev->magic = ROUTER_MAGIC; + wandev->name = card->devname; + wandev->private = card; + wandev->enable_tx_int = 0; + wandev->setup = &setup; + wandev->shutdown = &shutdown; + wandev->ioctl = &ioctl; + err = register_wan_device(wandev); + if (err) + { + printk(KERN_ERR + "%s: %s registration failed with error %d!\n", + drvname, card->devname, err) + ; + break; + } + } + if (cnt) + ncards = cnt; /* adjust actual number of cards */ + else + { + kfree(card_array); + err = -ENODEV; + } + return err; +} + +#ifdef MODULE +/*============================================================================ + * Module 'remove' entry point. + * o unregister all adapters from the WAN router + * o release all remaining system resources + */ +void cleanup_module (void) +{ + int i; + + for (i = 0; i < ncards; ++i) + { + sdla_t* card = &card_array[i]; + unregister_wan_device(card->devname); + } + kfree(card_array); +} + +#endif + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * Setup/confugure WAN link driver. + * o check adapter state + * o make sure firmware is present in configuration + * o make sure I/O port and IRQ are specified + * o make sure I/O region is available + * o allocate interrupt vector + * o setup SDLA hardware + * o call appropriate routine to perform protocol-specific initialization + * o mark I/O region as used + * o if this is the first active card, then schedule background task + * + * This function is called when router handles ROUTER_SETUP IOCTL. The + * configuration structure is in kernel memory (including extended data, if + * any). + */ + +static int setup (wan_device_t* wandev, wandev_conf_t* conf) +{ + sdla_t* card; + int err = 0; + int irq; + + /* Sanity checks */ + if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL)) + return -EFAULT; + + card = wandev->private; + if (wandev->state != WAN_UNCONFIGURED) + return -EBUSY; /* already configured */ + + if (!conf->data_size || (conf->data == NULL)) + { + printk(KERN_ERR + "%s: firmware not found in configuration data!\n", + wandev->name); + return -EINVAL; + } + if (conf->ioport <= 0) + { + printk(KERN_ERR + "%s: can't configure without I/O port address!\n", + wandev->name); + return -EINVAL; + } + + if (conf->irq <= 0) + { + printk(KERN_ERR "%s: can't configure without IRQ!\n", + wandev->name); + return -EINVAL; + } + + /* Make sure I/O port region is available */ + if (check_region(conf->ioport, SDLA_MAXIORANGE)) + { + printk(KERN_ERR "%s: I/O region 0x%X - 0x%X is in use!\n", + wandev->name, conf->ioport, + conf->ioport + SDLA_MAXIORANGE); + return -EINVAL; + } + + /* Allocate IRQ */ + irq = (conf->irq == 2) ? 9 : conf->irq; /* IRQ2 -> IRQ9 */ + if (request_irq(irq, sdla_isr, 0, wandev->name, card)) + { + printk(KERN_ERR "%s: can't reserve IRQ %d!\n", + wandev->name, irq); + return -EINVAL; + } + + /* Configure hardware, load firmware, etc. */ + memset(&card->hw, 0, sizeof(sdlahw_t)); + card->hw.port = conf->ioport; + card->hw.irq = (conf->irq == 9) ? 2 : conf->irq; + /* Compute the virtual address of the card in kernel space */ + if(conf->maddr) + card->hw.dpmbase = phys_to_virt(conf->maddr); + else /* But 0 means NULL */ + card->hw.dpmbase = (void *)conf->maddr; + + card->hw.dpmsize = SDLA_WINDOWSIZE; + card->hw.type = conf->hw_opt[0]; + card->hw.pclk = conf->hw_opt[1]; + err = sdla_setup(&card->hw, conf->data, conf->data_size); + if (err) + { + free_irq(irq, card); + return err; + } + + /* Intialize WAN device data space */ + wandev->irq = irq; + wandev->dma = 0; + wandev->ioport = card->hw.port; + wandev->maddr = card->hw.dpmbase; + wandev->msize = card->hw.dpmsize; + wandev->hw_opt[0] = card->hw.type; + wandev->hw_opt[1] = card->hw.pclk; + wandev->hw_opt[2] = card->hw.memory; + wandev->hw_opt[3] = card->hw.fwid; + + /* Protocol-specific initialization */ + switch (card->hw.fwid) + { +#ifdef CONFIG_WANPIPE_X25 + case SFID_X25_502: + case SFID_X25_508: + err = wpx_init(card, conf); + break; +#endif + +#ifdef CONFIG_WANPIPE_FR + case SFID_FR502: + case SFID_FR508: + err = wpf_init(card, conf); + break; +#endif + +#ifdef CONFIG_WANPIPE_PPP + case SFID_PPP502: + case SFID_PPP508: + err = wpp_init(card, conf); + break; +#endif + + default: + printk(KERN_ERR "%s: this firmware is not supported!\n", + wandev->name) + ; + err = -EINVAL; + } + if (err) + { + sdla_down(&card->hw); + free_irq(irq, card); + return err; + } + /* Reserve I/O region and schedule background task */ +/* printk(KERN_INFO "about to request\n");*/ + request_region(card->hw.port, card->hw.io_range, wandev->name); +/* printk(KERN_INFO "request done\n");*/ + if (++active == 1) + queue_task(&sdla_tq, &tq_scheduler); + + wandev->critical = 0; + return 0; +} + +/*============================================================================ + * Shut down WAN link driver. + * o shut down adapter hardware + * o release system resources. + * + * This function is called by the router when device is being unregistered or + * when it handles ROUTER_DOWN IOCTL. + */ +static int shutdown (wan_device_t* wandev) +{ + sdla_t* card; + + /* sanity checks */ + if ((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if (wandev->state == WAN_UNCONFIGURED) + return 0; + + /* If wee are in a critical section we lose */ + if (test_and_set_bit(0, (void*)&wandev->critical)) + return -EAGAIN; + + card = wandev->private; + wandev->state = WAN_UNCONFIGURED; + + if (--active == 0) + schedule(); /* stop background thread */ + +/* printk(KERN_INFO "active now %d\n", active); + + printk(KERN_INFO "About to call sdla_down\n");*/ + sdla_down(&card->hw); +/* printk(KERN_INFO "sdla_down done\n"); + printk(KERN_INFO "About to call free_irq\n");*/ + free_irq(wandev->irq, card); +/* printk(KERN_INFO "free_irq done\n"); + printk(KERN_INFO "About to call release_region\n");*/ + release_region(card->hw.port, card->hw.io_range); +/* printk(KERN_INFO "release_region done\n");*/ + wandev->critical = 0; + return 0; +} + +/*============================================================================ + * Driver I/O control. + * o verify arguments + * o perform requested action + * + * This function is called when router handles one of the reserved user + * IOCTLs. Note that 'arg' stil points to user address space. + */ +static int ioctl (wan_device_t* wandev, unsigned cmd, unsigned long arg) +{ + int err; + + /* sanity checks */ + if ((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT + ; + if (wandev->state == WAN_UNCONFIGURED) + return -ENODEV + ; + if (test_and_set_bit(0, (void*)&wandev->critical)) + return -EAGAIN + ; + switch (cmd) + { + case WANPIPE_DUMP: + err = ioctl_dump(wandev->private, (void*)arg); + break; + + case WANPIPE_EXEC: + err = ioctl_exec(wandev->private, (void*)arg); + break; + + default: + err = -EINVAL; + } + wandev->critical = 0; + return err; +} + +/****** Driver IOCTL Hanlers ************************************************/ + +/*============================================================================ + * Dump adapter memory to user buffer. + * o verify request structure + * o copy request structure to kernel data space + * o verify length/offset + * o verify user buffer + * o copy adapter memory image to user buffer + * + * Note: when dumping memory, this routine switches curent dual-port memory + * vector, so care must be taken to avoid racing conditions. + */ +static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump) +{ + sdla_dump_t dump; + unsigned winsize; + unsigned long oldvec; /* DPM window vector */ + unsigned long flags; + int err = 0; + + if(copy_from_user((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t))) + return -EFAULT; + + if ((dump.magic != WANPIPE_MAGIC) || + (dump.offset + dump.length > card->hw.memory)) + return -EINVAL; + + winsize = card->hw.dpmsize; + save_flags(flags); + cli(); /* >>> critical section start <<< */ + oldvec = card->hw.vector; + while (dump.length) + { + unsigned pos = dump.offset % winsize; /* current offset */ + unsigned long vec = dump.offset - pos; /* current vector */ + unsigned len = (dump.length > (winsize - pos)) ? + (winsize - pos) : dump.length + ; + if (sdla_mapmem(&card->hw, vec) != 0) /* relocate window */ + { + err = -EIO; + break; + } + /* FIXME::: COPY TO KERNEL BUFFER FIRST ?? */ + sti(); /* Not ideal but tough we have to do this */ + if(copy_to_user((void *)dump.ptr, + (u8 *)card->hw.dpmbase + pos, len)) + return -EFAULT; + cli(); + dump.length -= len; + dump.offset += len; + (char*)dump.ptr += len; + } + sdla_mapmem(&card->hw, oldvec); /* restore DPM window position */ + restore_flags(flags); /* >>> critical section end <<< */ + return err; +} + +/*============================================================================ + * Execute adapter firmware command. + * o verify request structure + * o copy request structure to kernel data space + * o call protocol-specific 'exec' function + */ +static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec) +{ + sdla_exec_t exec; + + if (card->exec == NULL) + return -ENODEV; + + if(copy_from_user((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t))) + return -EFAULT; + if ((exec.magic != WANPIPE_MAGIC) || (exec.cmd == NULL)) + return -EINVAL; + return card->exec(card, exec.cmd, exec.data); +} + +/******* Miscellaneous ******************************************************/ + +/*============================================================================ + * SDLA Interrupt Service Routine. + * o acknowledge SDLA hardware interrupt. + * o call protocol-specific interrupt service routine, if any. + */ +STATIC void sdla_isr (int irq, void* dev_id, struct pt_regs *regs) +{ +#define card ((sdla_t*)dev_id) + + if (!card || (card->wandev.state == WAN_UNCONFIGURED)) + return + ; + if (card->in_isr) + { + printk(KERN_WARNING "%s: interrupt re-entrancy on IRQ %d!\n", + card->devname, card->wandev.irq) + ; + return; + } + + sdla_intack(&card->hw); + if (card->isr) + card->isr(card); + +#undef card +} + +/*============================================================================ + * SDLA polling routine. + * This routine simulates kernel thread to perform various housekeeping job. + * + * o for each configured device call its poll() routine + * o if there is at least one active card, then reschedule itself once again + */ +STATIC void sdla_poll (void* data) +{ + int i; + + for (i = 0; i < ncards; ++i) + { + sdla_t* card = &card_array[i]; + + if ((card->wandev.state != WAN_UNCONFIGURED) && card->poll && + !card->wandev.critical) + { + card->poll(card); + } + } + if (active) + queue_task(&sdla_tq, &tq_scheduler); +} + +/*============================================================================ + * This routine is called by the protocol-specific modules when network + * interface is being open. The only reason we need this, is because we + * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's + * defined more than once into the same kernel module. + */ +void wanpipe_open (sdla_t* card) +{ + ++card->open_cnt; + MOD_INC_USE_COUNT; +} + +/*============================================================================ + * This routine is called by the protocol-specific modules when network + * interface is being closed. The only reason we need this, is because we + * have to call MOD_DEC_USE_COUNT, but cannot include 'module.h' where it's + * defined more than once into the same kernel module. + */ +void wanpipe_close (sdla_t* card) +{ + --card->open_cnt; + MOD_DEC_USE_COUNT; +} + +/*============================================================================ + * Set WAN device state. + */ +void wanpipe_set_state (sdla_t* card, int state) +{ + unsigned long flags; + + save_flags(flags); + cli(); + if (card->wandev.state != state) + { + switch (state) + { + case WAN_CONNECTED: + printk (KERN_INFO "%s: link connected!\n", + card->devname) + ; + break; + + case WAN_CONNECTING: + printk (KERN_INFO "%s: link connecting...\n", + card->devname) + ; + break; + + case WAN_DISCONNECTED: + printk (KERN_INFO "%s: link disconnected!\n", + card->devname) + ; + break; + } + card->wandev.state = state; + } + card->state_tick = jiffies; + restore_flags(flags); +} + +/****** End *****************************************************************/ diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/sealevel.c linux/drivers/net/wan/sealevel.c --- v2.3.20/linux/drivers/net/wan/sealevel.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/sealevel.c Mon Oct 11 10:13:25 1999 @@ -0,0 +1,471 @@ +#define LINUX_21 + +/* + * Sealevel Systems 4021 driver. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * (c) Copyright 1999 Building Number Three Ltd + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "syncppp.h" +#include "z85230.h" + + +struct slvl_device +{ + struct z8530_channel *chan; + struct ppp_device netdev; + char name[16]; + int channel; +}; + + +struct slvl_board +{ + struct slvl_device dev[2]; + struct z8530_dev board; + int iobase; +}; + +/* + * Network driver support routines + */ + +/* + * Frame receive. Simple for our card as we do sync ppp and there + * is no funny garbage involved + */ + +static void sealevel_input(struct z8530_channel *c, struct sk_buff *skb) +{ + /* Drop the CRC - its not a good idea to try and negotiate it ;) */ + skb_trim(skb, skb->len-2); + skb->protocol=htons(ETH_P_WAN_PPP); + skb->mac.raw=skb->data; + skb->dev=c->netdevice; + /* + * Send it to the PPP layer. We dont have time to process + * it right now. + */ + netif_rx(skb); +} + +/* + * We've been placed in the UP state + */ + +static int sealevel_open(struct net_device *d) +{ + struct slvl_device *slvl=d->priv; + int err = -1; + int unit = slvl->channel; + + /* + * Link layer up. + */ + + switch(unit) + { + case 0: + err=z8530_sync_dma_open(d, slvl->chan); + break; + case 1: + err=z8530_sync_open(d, slvl->chan); + break; + } + + if(err) + return err; + /* + * Begin PPP + */ + err=sppp_open(d); + if(err) + { + switch(unit) + { + case 0: + z8530_sync_dma_close(d, slvl->chan); + break; + case 1: + z8530_sync_close(d, slvl->chan); + break; + } + return err; + } + + slvl->chan->rx_function=sealevel_input; + + /* + * Go go go + */ + d->tbusy=0; + MOD_INC_USE_COUNT; + return 0; +} + +static int sealevel_close(struct net_device *d) +{ + struct slvl_device *slvl=d->priv; + int unit = slvl->channel; + + /* + * Discard new frames + */ + + slvl->chan->rx_function=z8530_null_rx; + + /* + * PPP off + */ + sppp_close(d); + /* + * Link layer down + */ + d->tbusy=1; + + switch(unit) + { + case 0: + z8530_sync_dma_close(d, slvl->chan); + break; + case 1: + z8530_sync_close(d, slvl->chan); + break; + } + MOD_DEC_USE_COUNT; + return 0; +} + +static int sealevel_ioctl(struct net_device *d, struct ifreq *ifr, int cmd) +{ + /* struct slvl_device *slvl=d->priv; + z8530_ioctl(d,&slvl->sync.chanA,ifr,cmd) */ + return sppp_do_ioctl(d, ifr,cmd); +} + +static struct enet_statistics *sealevel_get_stats(struct net_device *d) +{ + struct slvl_device *slvl=d->priv; + if(slvl) + return z8530_get_stats(slvl->chan); + else + return NULL; +} + +/* + * Passed PPP frames, fire them downwind. + */ + +static int sealevel_queue_xmit(struct sk_buff *skb, struct net_device *d) +{ + struct slvl_device *slvl=d->priv; + return z8530_queue_xmit(slvl->chan, skb); +} + +#ifdef LINUX_21 +static int sealevel_neigh_setup(struct neighbour *n) +{ + if (n->nud_state == NUD_NONE) { + n->ops = &arp_broken_ops; + n->output = n->ops->output; + } + return 0; +} + +static int sealevel_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) +{ + if (p->tbl->family == AF_INET) { + p->neigh_setup = sealevel_neigh_setup; + p->ucast_probes = 0; + p->mcast_probes = 0; + } + return 0; +} + +#else + +static int return_0(struct net_device *d) +{ + return 0; +} + +#endif + +/* + * Description block for a Comtrol Hostess SV11 card + */ + +static struct slvl_board *slvl_init(int iobase, int irq, int txdma, int rxdma, int slow) +{ + struct z8530_dev *dev; + struct slvl_device *sv; + struct slvl_board *b; + + int i; + unsigned long flags; + int u; + + /* + * Get the needed I/O space + */ + + if(check_region(iobase, 8)) + { + printk(KERN_WARNING "sealevel: I/O 0x%X already in use.\n", iobase); + return NULL; + } + request_region(iobase, 8, "Sealevel 4021"); + + b=(struct slvl_board *)kmalloc(sizeof(struct slvl_board), GFP_KERNEL); + if(!b) + goto fail3; + + memset(b, 0, sizeof(*sv)); + + b->dev[0].chan = &b->board.chanA; + b->dev[1].chan = &b->board.chanB; + + dev=&b->board; + + /* + * Stuff in the I/O addressing + */ + + dev->active = 0; + + b->iobase = iobase; + + /* + * Select 8530 delays for the old board + */ + + if(slow) + iobase |= Z8530_PORT_SLEEP; + + dev->chanA.ctrlio=iobase+1; + dev->chanA.dataio=iobase; + dev->chanB.ctrlio=iobase+3; + dev->chanB.dataio=iobase+2; + + dev->chanA.irqs=&z8530_nop; + dev->chanB.irqs=&z8530_nop; + + /* + * Assert DTR enable DMA + */ + + outb(3|(1<<7), b->iobase+4); + + + /* We want a fast IRQ for this device. Actually we'd like an even faster + IRQ ;) - This is one driver RtLinux is made for */ + + if(request_irq(irq, &z8530_interrupt, SA_INTERRUPT, "SeaLevel", dev)<0) + { + printk(KERN_WARNING "sealevel: IRQ %d already in use.\n", irq); + goto fail2; + } + + dev->irq=irq; + dev->chanA.private=&b->dev[0]; + dev->chanB.private=&b->dev[1]; + dev->chanA.netdevice=&b->dev[0].netdev.dev; + dev->chanB.netdevice=&b->dev[1].netdev.dev; + dev->chanA.dev=dev; + dev->chanB.dev=dev; + dev->name=b->dev[0].name; + + dev->chanA.txdma=3; + dev->chanA.rxdma=1; + if(request_dma(dev->chanA.txdma, "SeaLevel (TX)")!=0) + goto fail; + + if(request_dma(dev->chanA.rxdma, "SeaLevel (RX)")!=0) + goto dmafail; + + save_flags(flags); + cli(); + + /* + * Begin normal initialise + */ + + if(z8530_init(dev)!=0) + { + printk(KERN_ERR "Z8530 series device not found.\n"); + goto dmafail2; + } + if(dev->type==Z85C30) + { + z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream); + z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream); + } + else + { + z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream_85230); + z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream_85230); + } + + /* + * Now we can take the IRQ + */ + + restore_flags(flags); + + for(u=0; u<2; u++) + { + sv=&b->dev[u]; + sv->channel = u; + + for(i=0;i<999;i++) + { + sprintf(sv->name,"hdlc%d", i); + if(dev_get(sv->name)==0) + { + struct net_device *d=sv->chan->netdevice; + + /* + * Initialise the PPP components + */ + sppp_attach(&sv->netdev); + + /* + * Local fields + */ + sprintf(sv->name,"hdlc%d", i); + + d->name = sv->name; + d->base_addr = iobase; + d->irq = irq; + d->priv = sv; + d->init = NULL; + + d->open = sealevel_open; + d->stop = sealevel_close; + d->hard_start_xmit = sealevel_queue_xmit; + d->get_stats = sealevel_get_stats; + d->set_multicast_list = NULL; + d->do_ioctl = sealevel_ioctl; +#ifdef LINUX_21 + d->neigh_setup = sealevel_neigh_setup_dev; + dev_init_buffers(d); +#else + d->init = return_0; +#endif + d->set_mac_address = NULL; + + if(register_netdev(d)==-1) + { + printk(KERN_ERR "%s: unable to register device.\n", + sv->name); + goto fail_unit; + } + + break; + } + } + } + z8530_describe(dev, "I/O", iobase); + dev->active=1; + return b; + +fail_unit: + if(u==1) + unregister_netdev(b->dev[0].chan->netdevice); + +dmafail2: + free_dma(dev->chanA.rxdma); +dmafail: + free_dma(dev->chanA.txdma); +fail: + free_irq(irq, dev); +fail2: + kfree(b); +fail3: + release_region(iobase,8); + return NULL; +} + +static void slvl_shutdown(struct slvl_board *b) +{ + int u; + + z8530_shutdown(&b->board); + + for(u=0; u<2; u++) + { + sppp_detach(&b->dev[u].netdev.dev); + unregister_netdev(&b->dev[u].netdev.dev); + } + + free_irq(b->board.irq, &b->board); + free_dma(b->board.chanA.rxdma); + free_dma(b->board.chanA.txdma); + /* DMA off on the card, drop DTR */ + outb(0, b->iobase); + release_region(b->iobase, 8); +} + +#ifdef MODULE + +static int io=0x238; +static int txdma=1; +static int rxdma=3; +static int irq=5; +static int slow=0; + +#ifdef LINUX_21 +MODULE_PARM(io,"i"); +MODULE_PARM_DESC(io, "The I/O base of the Sealevel card"); +MODULE_PARM(txdma,"i"); +MODULE_PARM_DESC(txdma, "Transmit DMA channel"); +MODULE_PARM(rxdma,"i"); +MODULE_PARM_DESC(rxdma, "Receive DMA channel"); +MODULE_PARM(irq,"i"); +MODULE_PARM_DESC(irq, "The interrupt line setting for the SeaLevel card"); +MODULE_PARM(slow,"i"); +MODULE_PARM_DESC(slow, "Set this for an older Sealevel card such as the 4012"); + +MODULE_AUTHOR("Bulding Number Three Ltd"); +MODULE_DESCRIPTION("Modular driver for the SeaLevel 4021"); +#endif + +static struct slvl_board *slvl_unit; + +int init_module(void) +{ + printk(KERN_INFO "SeaLevel Z85230 Synchronous Driver v 0.01.\n"); + printk(KERN_INFO "(c) Copyright 1998, Building Number Three Ltd.\n"); + if((slvl_unit=slvl_init(io,irq, txdma, rxdma, slow))==NULL) + return -ENODEV; + return 0; +} + +void cleanup_module(void) +{ + if(slvl_unit) + slvl_shutdown(slvl_unit); +} + +#endif + diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/syncppp.c linux/drivers/net/wan/syncppp.c --- v2.3.20/linux/drivers/net/wan/syncppp.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/syncppp.c Mon Oct 11 10:13:25 1999 @@ -0,0 +1,1315 @@ +/* + * NET3: A (fairly minimal) implementation of synchronous PPP for Linux + * as well as a CISCO HDLC implementation. See the copyright + * message below for the original source. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the license, or (at your option) any later version. + * + * Note however. This code is also used in a different form by FreeBSD. + * Therefore when making any non OS specific change please consider + * contributing it back to the original author under the terms + * below in addition. + * -- Alan + * + * Port for Linux-2.1 by Jan "Yenya" Kasprzak + */ + +/* + * Synchronous PPP/Cisco link level subroutines. + * Keepalive protocol implemented in both Cisco and PPP modes. + * + * Copyright (C) 1994 Cronyx Ltd. + * Author: Serge Vakulenko, + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "syncppp.h" + +#define MAXALIVECNT 6 /* max. alive packets */ + +#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ +#define PPP_UI 0x03 /* Unnumbered Information */ +#define PPP_IP 0x0021 /* Internet Protocol */ +#define PPP_ISO 0x0023 /* ISO OSI Protocol */ +#define PPP_XNS 0x0025 /* Xerox NS Protocol */ +#define PPP_IPX 0x002b /* Novell IPX Protocol */ +#define PPP_LCP 0xc021 /* Link Control Protocol */ +#define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */ + +#define LCP_CONF_REQ 1 /* PPP LCP configure request */ +#define LCP_CONF_ACK 2 /* PPP LCP configure acknowledge */ +#define LCP_CONF_NAK 3 /* PPP LCP configure negative ack */ +#define LCP_CONF_REJ 4 /* PPP LCP configure reject */ +#define LCP_TERM_REQ 5 /* PPP LCP terminate request */ +#define LCP_TERM_ACK 6 /* PPP LCP terminate acknowledge */ +#define LCP_CODE_REJ 7 /* PPP LCP code reject */ +#define LCP_PROTO_REJ 8 /* PPP LCP protocol reject */ +#define LCP_ECHO_REQ 9 /* PPP LCP echo request */ +#define LCP_ECHO_REPLY 10 /* PPP LCP echo reply */ +#define LCP_DISC_REQ 11 /* PPP LCP discard request */ + +#define LCP_OPT_MRU 1 /* maximum receive unit */ +#define LCP_OPT_ASYNC_MAP 2 /* async control character map */ +#define LCP_OPT_AUTH_PROTO 3 /* authentication protocol */ +#define LCP_OPT_QUAL_PROTO 4 /* quality protocol */ +#define LCP_OPT_MAGIC 5 /* magic number */ +#define LCP_OPT_RESERVED 6 /* reserved */ +#define LCP_OPT_PROTO_COMP 7 /* protocol field compression */ +#define LCP_OPT_ADDR_COMP 8 /* address/control field compression */ + +#define IPCP_CONF_REQ LCP_CONF_REQ /* PPP IPCP configure request */ +#define IPCP_CONF_ACK LCP_CONF_ACK /* PPP IPCP configure acknowledge */ +#define IPCP_CONF_NAK LCP_CONF_NAK /* PPP IPCP configure negative ack */ +#define IPCP_CONF_REJ LCP_CONF_REJ /* PPP IPCP configure reject */ +#define IPCP_TERM_REQ LCP_TERM_REQ /* PPP IPCP terminate request */ +#define IPCP_TERM_ACK LCP_TERM_ACK /* PPP IPCP terminate acknowledge */ +#define IPCP_CODE_REJ LCP_CODE_REJ /* PPP IPCP code reject */ + +#define CISCO_MULTICAST 0x8f /* Cisco multicast address */ +#define CISCO_UNICAST 0x0f /* Cisco unicast address */ +#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */ +#define CISCO_ADDR_REQ 0 /* Cisco address request */ +#define CISCO_ADDR_REPLY 1 /* Cisco address reply */ +#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ + +struct ppp_header { + u8 address; + u8 control; + u16 protocol; +}; +#define PPP_HEADER_LEN sizeof (struct ppp_header) + +struct lcp_header { + u8 type; + u8 ident; + u16 len; +}; +#define LCP_HEADER_LEN sizeof (struct lcp_header) + +struct cisco_packet { + u32 type; + u32 par1; + u32 par2; + u16 rel; + u16 time0; + u16 time1; +}; +#define CISCO_PACKET_LEN 18 +#define CISCO_BIG_PACKET_LEN 20 + +static struct sppp *spppq; +static struct timer_list sppp_keepalive_timer; + +static void sppp_keepalive (unsigned long dummy); +static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, + u8 ident, u16 len, void *data); +static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2); +static void sppp_lcp_input (struct sppp *sp, struct sk_buff *m); +static void sppp_cisco_input (struct sppp *sp, struct sk_buff *m); +static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *m); +static void sppp_lcp_open (struct sppp *sp); +static void sppp_ipcp_open (struct sppp *sp); +static int sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, + int len, u32 *magic); +static void sppp_cp_timeout (unsigned long arg); +static char *sppp_lcp_type_name (u8 type); +static char *sppp_ipcp_type_name (u8 type); +static void sppp_print_bytes (u8 *p, u16 len); + +static int debug = 0; + +/* + * Interface down stub + */ + +static void if_down(struct net_device *dev) +{ + ; +} + +/* + * Timeout routine activations. + */ + +static void sppp_set_timeout(struct sppp *p,int s) +{ + if (! (p->pp_flags & PP_TIMO)) + { + init_timer(&p->pp_timer); + p->pp_timer.function=sppp_cp_timeout; + p->pp_timer.expires=jiffies+s*HZ; + p->pp_timer.data=(unsigned long)p; + p->pp_flags |= PP_TIMO; + add_timer(&p->pp_timer); + } +} + +static void sppp_clear_timeout(struct sppp *p) +{ + if (p->pp_flags & PP_TIMO) + { + del_timer(&p->pp_timer); + p->pp_flags &= ~PP_TIMO; + } +} + +/* + * Process the received packet. + */ + +void sppp_input (struct net_device *dev, struct sk_buff *skb) +{ + struct ppp_header *h; + struct sppp *sp = &((struct ppp_device *)dev)->sppp; + + skb->dev=dev; + skb->mac.raw=skb->data; + + if (dev->flags & IFF_UP) + { + /* Count received bytes, add FCS and one flag */ + sp->ibytes+= skb->len + 3; + sp->ipkts++; + } + + if (skb->len <= PPP_HEADER_LEN) { + /* Too small packet, drop it. */ + if (sp->pp_flags & PP_DEBUG) + printk (KERN_DEBUG "%s: input packet is too small, %d bytes\n", + dev->name, skb->len); +drop: kfree_skb(skb); + return; + } + + /* Get PPP header. */ + h = (struct ppp_header *)skb->data; + skb_pull(skb,sizeof(struct ppp_header)); + + switch (h->address) { + default: /* Invalid PPP packet. */ +invalid: if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: invalid input packet <0x%x 0x%x 0x%x>\n", + dev->name, + h->address, h->control, ntohs (h->protocol)); + goto drop; + case PPP_ALLSTATIONS: + if (h->control != PPP_UI) + goto invalid; + if (sp->pp_flags & PP_CISCO) { + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: PPP packet in Cisco mode <0x%x 0x%x 0x%x>\n", + dev->name, + h->address, h->control, ntohs (h->protocol)); + goto drop; + } + switch (ntohs (h->protocol)) { + default: + if (sp->lcp.state == LCP_STATE_OPENED) + sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ, + ++sp->pp_seq, skb->len + 2, + &h->protocol); + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: invalid input protocol <0x%x 0x%x 0x%x>\n", + dev->name, + h->address, h->control, ntohs (h->protocol)); + goto drop; + case PPP_LCP: + sppp_lcp_input (sp, skb); + kfree_skb(skb); + return; + case PPP_IPCP: + if (sp->lcp.state == LCP_STATE_OPENED) + sppp_ipcp_input (sp, skb); + else + printk(KERN_DEBUG "IPCP when still waiting LCP finish.\n"); + kfree_skb(skb); + return; + case PPP_IP: + if (sp->ipcp.state == IPCP_STATE_OPENED) { + if(sp->pp_flags&PP_DEBUG) + printk(KERN_DEBUG "Yow an IP frame.\n"); + skb->protocol=htons(ETH_P_IP); + netif_rx(skb); + return; + } + break; +#ifdef IPX + case PPP_IPX: + /* IPX IPXCP not implemented yet */ + if (sp->lcp.state == LCP_STATE_OPENED) { + skb->protocol=htons(ETH_P_IPX); + netif_rx(skb); + return; + } + break; +#endif + } + break; + case CISCO_MULTICAST: + case CISCO_UNICAST: + /* Don't check the control field here (RFC 1547). */ + if (! (sp->pp_flags & PP_CISCO)) { + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: Cisco packet in PPP mode <0x%x 0x%x 0x%x>\n", + dev->name, + h->address, h->control, ntohs (h->protocol)); + goto drop; + } + switch (ntohs (h->protocol)) { + default: + goto invalid; + case CISCO_KEEPALIVE: + sppp_cisco_input (sp, skb); + kfree_skb(skb); + return; +#ifdef CONFIG_INET + case ETH_P_IP: + skb->protocol=htons(ETH_P_IP); + netif_rx(skb); + return; +#endif +#ifdef CONFIG_IPX + case ETH_P_IPX: + skb->protocol=htons(ETH_P_IPX); + netif_rx(skb); + return; +#endif + } + break; + } + kfree_skb(skb); +} + +EXPORT_SYMBOL(sppp_input); + +/* + * Handle transmit packets. + */ + +static int sppp_hard_header(struct sk_buff *skb, struct net_device *dev, __u16 type, + void *daddr, void *saddr, unsigned int len) +{ + struct sppp *sp = &((struct ppp_device *)dev)->sppp; + struct ppp_header *h; + skb_push(skb,sizeof(struct ppp_header)); + h=(struct ppp_header *)skb->data; + if(sp->pp_flags&PP_CISCO) + { + h->address = CISCO_MULTICAST; + h->control = 0; + } + else + { + h->address = PPP_ALLSTATIONS; + h->control = PPP_UI; + } + if(sp->pp_flags & PP_CISCO) + { + h->protocol = htons(type); + } + else switch(type) + { + case ETH_P_IP: + h->protocol = htons(PPP_IP); + break; + case ETH_P_IPX: + h->protocol = htons(PPP_IPX); + break; + } + return sizeof(struct ppp_header); +} + +static int sppp_rebuild_header(struct sk_buff *skb) +{ + return 0; +} + +/* + * Send keepalive packets, every 10 seconds. + */ + +static void sppp_keepalive (unsigned long dummy) +{ + struct sppp *sp; + unsigned long flags; + save_flags(flags); + cli(); + + for (sp=spppq; sp; sp=sp->pp_next) + { + struct net_device *dev = sp->pp_if; + + /* Keepalive mode disabled or channel down? */ + if (! (sp->pp_flags & PP_KEEPALIVE) || + ! (dev->flags & IFF_RUNNING)) + continue; + + /* No keepalive in PPP mode if LCP not opened yet. */ + if (! (sp->pp_flags & PP_CISCO) && + sp->lcp.state != LCP_STATE_OPENED) + continue; + + if (sp->pp_alivecnt == MAXALIVECNT) { + /* No keepalive packets got. Stop the interface. */ + printk (KERN_WARNING "%s: down\n", dev->name); + if_down (dev); + if (! (sp->pp_flags & PP_CISCO)) { + /* Shut down the PPP link. */ + sp->lcp.magic = jiffies; + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + sppp_clear_timeout (sp); + /* Initiate negotiation. */ + sppp_lcp_open (sp); + } + } + if (sp->pp_alivecnt <= MAXALIVECNT) + ++sp->pp_alivecnt; + if (sp->pp_flags & PP_CISCO) + sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq, + sp->pp_rseq); + else if (sp->lcp.state == LCP_STATE_OPENED) { + long nmagic = htonl (sp->lcp.magic); + sp->lcp.echoid = ++sp->pp_seq; + sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ, + sp->lcp.echoid, 4, &nmagic); + } + } + restore_flags(flags); + sppp_keepalive_timer.expires=jiffies+10*HZ; + add_timer(&sppp_keepalive_timer); +} + +/* + * Handle incoming PPP Link Control Protocol packets. + */ + +static void sppp_lcp_input (struct sppp *sp, struct sk_buff *skb) +{ + struct lcp_header *h; + struct net_device *dev = sp->pp_if; + int len = skb->len; + u8 *p, opt[6]; + u32 rmagic; + + if (len < 4) { + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: invalid lcp packet length: %d bytes\n", + dev->name, len); + return; + } + h = (struct lcp_header *)skb->data; + skb_pull(skb,sizeof(struct lcp_header *)); + + if (sp->pp_flags & PP_DEBUG) + { + char state = '?'; + switch (sp->lcp.state) { + case LCP_STATE_CLOSED: state = 'C'; break; + case LCP_STATE_ACK_RCVD: state = 'R'; break; + case LCP_STATE_ACK_SENT: state = 'S'; break; + case LCP_STATE_OPENED: state = 'O'; break; + } + printk (KERN_WARNING "%s: lcp input(%c): %d bytes <%s id=%xh len=%xh", + dev->name, state, len, + sppp_lcp_type_name (h->type), h->ident, ntohs (h->len)); + if (len > 4) + sppp_print_bytes ((u8*) (h+1), len-4); + printk (">\n"); + } + if (len > ntohs (h->len)) + len = ntohs (h->len); + switch (h->type) { + default: + /* Unknown packet type -- send Code-Reject packet. */ + sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq, + skb->len, h); + break; + case LCP_CONF_REQ: + if (len < 4) { + if (sp->pp_flags & PP_DEBUG) + printk (KERN_DEBUG"%s: invalid lcp configure request packet length: %d bytes\n", + dev->name, len); + break; + } + if (len>4 && !sppp_lcp_conf_parse_options (sp, h, len, &rmagic)) + goto badreq; + if (rmagic == sp->lcp.magic) { + /* Local and remote magics equal -- loopback? */ + if (sp->pp_loopcnt >= MAXALIVECNT*5) { + printk (KERN_WARNING "%s: loopback\n", + dev->name); + sp->pp_loopcnt = 0; + if (dev->flags & IFF_UP) { + if_down (dev); + } + } else if (sp->pp_flags & PP_DEBUG) + printk (KERN_DEBUG "%s: conf req: magic glitch\n", + dev->name); + ++sp->pp_loopcnt; + + /* MUST send Conf-Nack packet. */ + rmagic = ~sp->lcp.magic; + opt[0] = LCP_OPT_MAGIC; + opt[1] = sizeof (opt); + opt[2] = rmagic >> 24; + opt[3] = rmagic >> 16; + opt[4] = rmagic >> 8; + opt[5] = rmagic; + sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK, + h->ident, sizeof (opt), &opt); +badreq: + switch (sp->lcp.state) { + case LCP_STATE_OPENED: + /* Initiate renegotiation. */ + sppp_lcp_open (sp); + /* fall through... */ + case LCP_STATE_ACK_SENT: + /* Go to closed state. */ + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + } + break; + } + /* Send Configure-Ack packet. */ + sp->pp_loopcnt = 0; + sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK, + h->ident, len-4, h+1); + /* Change the state. */ + switch (sp->lcp.state) { + case LCP_STATE_CLOSED: + sp->lcp.state = LCP_STATE_ACK_SENT; + break; + case LCP_STATE_ACK_RCVD: + sp->lcp.state = LCP_STATE_OPENED; + sppp_ipcp_open (sp); + break; + case LCP_STATE_OPENED: +#if 0 + /* Remote magic changed -- close session. */ + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + /* Initiate renegotiation. */ + sppp_lcp_open (sp); + /* An ACK has already been sent. */ + sp->lcp.state = LCP_STATE_ACK_SENT; +#endif + break; + } + break; + case LCP_CONF_ACK: + if (h->ident != sp->lcp.confid) + break; + sppp_clear_timeout (sp); + if (! (dev->flags & IFF_UP) && + (dev->flags & IFF_RUNNING)) { + /* Coming out of loopback mode. */ + dev->flags |= IFF_UP; + printk (KERN_INFO "%s: up\n", dev->name); + } + switch (sp->lcp.state) { + case LCP_STATE_CLOSED: + sp->lcp.state = LCP_STATE_ACK_RCVD; + sppp_set_timeout (sp, 5); + break; + case LCP_STATE_ACK_SENT: + sp->lcp.state = LCP_STATE_OPENED; + sppp_ipcp_open (sp); + break; + } + break; + case LCP_CONF_NAK: + if (h->ident != sp->lcp.confid) + break; + p = (u8*) (h+1); + if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) { + rmagic = (u32)p[2] << 24 | + (u32)p[3] << 16 | p[4] << 8 | p[5]; + if (rmagic == ~sp->lcp.magic) { + int newmagic; + if (sp->pp_flags & PP_DEBUG) + printk (KERN_DEBUG "%s: conf nak: magic glitch\n", + dev->name); + get_random_bytes(&newmagic, sizeof(newmagic)); + sp->lcp.magic += newmagic; + } else + sp->lcp.magic = rmagic; + } + if (sp->lcp.state != LCP_STATE_ACK_SENT) { + /* Go to closed state. */ + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + } + /* The link will be renegotiated after timeout, + * to avoid endless req-nack loop. */ + sppp_clear_timeout (sp); + sppp_set_timeout (sp, 2); + break; + case LCP_CONF_REJ: + if (h->ident != sp->lcp.confid) + break; + sppp_clear_timeout (sp); + /* Initiate renegotiation. */ + sppp_lcp_open (sp); + if (sp->lcp.state != LCP_STATE_ACK_SENT) { + /* Go to closed state. */ + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + } + break; + case LCP_TERM_REQ: + sppp_clear_timeout (sp); + /* Send Terminate-Ack packet. */ + sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, 0); + /* Go to closed state. */ + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + /* Initiate renegotiation. */ + sppp_lcp_open (sp); + break; + case LCP_TERM_ACK: + case LCP_CODE_REJ: + case LCP_PROTO_REJ: + /* Ignore for now. */ + break; + case LCP_DISC_REQ: + /* Discard the packet. */ + break; + case LCP_ECHO_REQ: + if (sp->lcp.state != LCP_STATE_OPENED) + break; + if (len < 8) { + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: invalid lcp echo request packet length: %d bytes\n", + dev->name, len); + break; + } + if (ntohl (*(long*)(h+1)) == sp->lcp.magic) { + /* Line loopback mode detected. */ + printk (KERN_WARNING "%s: loopback\n", dev->name); + if_down (dev); + + /* Shut down the PPP link. */ + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + sppp_clear_timeout (sp); + /* Initiate negotiation. */ + sppp_lcp_open (sp); + break; + } + *(long*)(h+1) = htonl (sp->lcp.magic); + sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REPLY, h->ident, len-4, h+1); + break; + case LCP_ECHO_REPLY: + if (h->ident != sp->lcp.echoid) + break; + if (len < 8) { + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: invalid lcp echo reply packet length: %d bytes\n", + dev->name, len); + break; + } + if (ntohl (*(long*)(h+1)) != sp->lcp.magic) + sp->pp_alivecnt = 0; + break; + } +} + +/* + * Handle incoming Cisco keepalive protocol packets. + */ + +static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb) +{ + struct cisco_packet *h; + struct net_device *dev = sp->pp_if; + + if (skb->len != CISCO_PACKET_LEN && skb->len != CISCO_BIG_PACKET_LEN) { + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: invalid cisco packet length: %d bytes\n", + dev->name, skb->len); + return; + } + h = (struct cisco_packet *)skb->data; + skb_pull(skb, sizeof(struct cisco_packet*)); + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: cisco input: %d bytes <%lxh %xh %xh %xh %xh-%xh>\n", + dev->name, skb->len, + ntohl (h->type), h->par1, h->par2, h->rel, + h->time0, h->time1); + switch (ntohl (h->type)) { + default: + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: unknown cisco packet type: 0x%lx\n", + dev->name, ntohl (h->type)); + break; + case CISCO_ADDR_REPLY: + /* Reply on address request, ignore */ + break; + case CISCO_KEEPALIVE_REQ: + sp->pp_alivecnt = 0; + sp->pp_rseq = ntohl (h->par1); + if (sp->pp_seq == sp->pp_rseq) { + /* Local and remote sequence numbers are equal. + * Probably, the line is in loopback mode. */ + int newseq; + if (sp->pp_loopcnt >= MAXALIVECNT) { + printk (KERN_WARNING "%s: loopback\n", + dev->name); + sp->pp_loopcnt = 0; + if (dev->flags & IFF_UP) { + if_down (dev); + } + } + ++sp->pp_loopcnt; + + /* Generate new local sequence number */ + get_random_bytes(&newseq, sizeof(newseq)); + sp->pp_seq ^= newseq; + break; + } + sp->pp_loopcnt = 0; + if (! (dev->flags & IFF_UP) && + (dev->flags & IFF_RUNNING)) { + dev->flags |= IFF_UP; + printk (KERN_INFO "%s: up\n", dev->name); + } + break; + case CISCO_ADDR_REQ: + /* Stolen from net/ipv4/devinet.c -- SIOCGIFADDR ioctl */ + { + struct in_device *in_dev; + struct in_ifaddr *ifa; + u32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */ + + if ((in_dev=in_dev_get(dev)) != NULL) + { + read_lock(&in_dev->lock); + for (ifa=in_dev->ifa_list; ifa != NULL; + ifa=ifa->ifa_next) { + if (strcmp(dev->name, ifa->ifa_label) == 0) + { + addr = ifa->ifa_local; + mask = ifa->ifa_mask; + break; + } + } + read_unlock(&in_dev->lock); + in_dev_put(in_dev); + } + /* I hope both addr and mask are in the net order */ + sppp_cisco_send (sp, CISCO_ADDR_REPLY, addr, mask); + break; + } + } +} + +/* + * Send PPP LCP packet. + */ + +static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, + u8 ident, u16 len, void *data) +{ + struct ppp_header *h; + struct lcp_header *lh; + struct sk_buff *skb; + struct net_device *dev = sp->pp_if; + + skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+LCP_HEADER_LEN+len, + GFP_ATOMIC); + if (skb==NULL) + return; + + skb_reserve(skb,dev->hard_header_len); + + h = (struct ppp_header *)skb_put(skb, sizeof(struct ppp_header)); + h->address = PPP_ALLSTATIONS; /* broadcast address */ + h->control = PPP_UI; /* Unnumbered Info */ + h->protocol = htons (proto); /* Link Control Protocol */ + + lh = (struct lcp_header *)skb_put(skb, sizeof(struct lcp_header)); + lh->type = type; + lh->ident = ident; + lh->len = htons (LCP_HEADER_LEN + len); + + if (len) + memcpy(skb_put(skb,len),data, len); + + if (sp->pp_flags & PP_DEBUG) { + printk (KERN_WARNING "%s: %s output <%s id=%xh len=%xh", + dev->name, + proto==PPP_LCP ? "lcp" : "ipcp", + proto==PPP_LCP ? sppp_lcp_type_name (lh->type) : + sppp_ipcp_type_name (lh->type), lh->ident, + ntohs (lh->len)); + if (len) + sppp_print_bytes ((u8*) (lh+1), len); + printk (">\n"); + } + sp->obytes += skb->len; + /* Control is high priority so it doesnt get queued behind data */ + skb->priority=TC_PRIO_CONTROL; + skb->dev = dev; + dev_queue_xmit(skb); +} + +/* + * Send Cisco keepalive packet. + */ + +static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2) +{ + struct ppp_header *h; + struct cisco_packet *ch; + struct sk_buff *skb; + struct net_device *dev = sp->pp_if; + u32 t = jiffies * 1000/HZ; + + skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+CISCO_PACKET_LEN, + GFP_ATOMIC); + + if(skb==NULL) + return; + + skb_reserve(skb, dev->hard_header_len); + h = (struct ppp_header *)skb_put (skb, sizeof(struct ppp_header)); + h->address = CISCO_MULTICAST; + h->control = 0; + h->protocol = htons (CISCO_KEEPALIVE); + + ch = (struct cisco_packet*)skb_put(skb, CISCO_PACKET_LEN); + ch->type = htonl (type); + ch->par1 = htonl (par1); + ch->par2 = htonl (par2); + ch->rel = -1; + ch->time0 = htons ((u16) (t >> 16)); + ch->time1 = htons ((u16) t); + + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: cisco output: <%lxh %xh %xh %xh %xh-%xh>\n", + dev->name, ntohl (ch->type), ch->par1, + ch->par2, ch->rel, ch->time0, ch->time1); + sp->obytes += skb->len; + skb->priority=TC_PRIO_CONTROL; + skb->dev = dev; + dev_queue_xmit(skb); +} + + +int sppp_close (struct net_device *dev) +{ + struct sppp *sp = &((struct ppp_device *)dev)->sppp; + dev->flags &= ~IFF_RUNNING; + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + sppp_clear_timeout (sp); + return 0; +} + +EXPORT_SYMBOL(sppp_close); + + +int sppp_open (struct net_device *dev) +{ + struct sppp *sp = &((struct ppp_device *)dev)->sppp; + sppp_close(dev); + dev->flags |= IFF_RUNNING; + if (!(sp->pp_flags & PP_CISCO)) + sppp_lcp_open (sp); + return 0; +} + +EXPORT_SYMBOL(sppp_open); + +int sppp_reopen (struct net_device *dev) +{ + struct sppp *sp = &((struct ppp_device *)dev)->sppp; + sppp_close(dev); + dev->flags |= IFF_RUNNING; + if (!(sp->pp_flags & PP_CISCO)) + { + sp->lcp.magic = jiffies; + ++sp->pp_seq; + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + /* Give it a moment for the line to settle then go */ + sppp_set_timeout (sp, 1); + } + return 0; +} + +EXPORT_SYMBOL(sppp_reopen); + +int sppp_change_mtu(struct net_device *dev, int new_mtu) +{ + if(new_mtu<128||new_mtu>PPP_MTU||(dev->flags&IFF_UP)) + return -EINVAL; + dev->mtu=new_mtu; + return 0; +} + +EXPORT_SYMBOL(sppp_change_mtu); + +int sppp_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct sppp *sp = &((struct ppp_device *)dev)->sppp; + + if(dev->flags&IFF_UP) + return -EBUSY; + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + + switch(cmd) + { + case SPPPIOCCISCO: + sp->pp_flags|=PP_CISCO; + dev->type = ARPHRD_HDLC; + break; + case SPPPIOCPPP: + sp->pp_flags&=~PP_CISCO; + dev->type = ARPHRD_PPP; + break; + case SPPPIOCDEBUG: + sp->pp_flags&=~PP_DEBUG; + if(ifr->ifr_flags) + sp->pp_flags|=PP_DEBUG; + break; + default: + return -EINVAL; + } + return 0; +} + +EXPORT_SYMBOL(sppp_do_ioctl); + +void sppp_attach(struct ppp_device *pd) +{ + struct net_device *dev=&pd->dev; + struct sppp *sp = &pd->sppp; + + /* Initialize keepalive handler. */ + if (! spppq) + { + init_timer(&sppp_keepalive_timer); + sppp_keepalive_timer.expires=jiffies+10*HZ; + sppp_keepalive_timer.function=sppp_keepalive; + add_timer(&sppp_keepalive_timer); + } + /* Insert new entry into the keepalive list. */ + sp->pp_next = spppq; + spppq = sp; + + sp->pp_loopcnt = 0; + sp->pp_alivecnt = 0; + sp->pp_seq = 0; + sp->pp_rseq = 0; + sp->pp_flags = PP_KEEPALIVE|PP_CISCO|debug;/*PP_DEBUG;*/ + sp->lcp.magic = 0; + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + sp->pp_if = dev; + + /* + * Device specific setup. All but interrupt handler and + * hard_start_xmit. + */ + + dev->hard_header = sppp_hard_header; + dev->rebuild_header = sppp_rebuild_header; + dev->tx_queue_len = 10; + dev->type = ARPHRD_HDLC; + dev->addr_len = 0; + dev->hard_header_len = sizeof(struct ppp_header); + dev->mtu = PPP_MTU; + /* + * These 4 are callers but MUST also call sppp_ functions + */ + dev->do_ioctl = sppp_do_ioctl; +#if 0 + dev->get_stats = NULL; /* Let the driver override these */ + dev->open = sppp_open; + dev->stop = sppp_close; +#endif + dev->change_mtu = sppp_change_mtu; + dev->hard_header_cache = NULL; + dev->header_cache_update = NULL; + dev->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP; + dev_init_buffers(dev); +} + +EXPORT_SYMBOL(sppp_attach); + +void sppp_detach (struct net_device *dev) +{ + struct sppp **q, *p, *sp = &((struct ppp_device *)dev)->sppp; + + + /* Remove the entry from the keepalive list. */ + for (q = &spppq; (p = *q); q = &p->pp_next) + if (p == sp) { + *q = p->pp_next; + break; + } + + /* Stop keepalive handler. */ + if (! spppq) + del_timer(&sppp_keepalive_timer); + sppp_clear_timeout (sp); +} + +EXPORT_SYMBOL(sppp_detach); + +/* + * Analyze the LCP Configure-Request options list + * for the presence of unknown options. + * If the request contains unknown options, build and + * send Configure-reject packet, containing only unknown options. + */ +static int +sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, + int len, u32 *magic) +{ + u8 *buf, *r, *p; + int rlen; + + len -= 4; + buf = r = kmalloc (len, GFP_ATOMIC); + if (! buf) + return (0); + + p = (void*) (h+1); + for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { + switch (*p) { + case LCP_OPT_MAGIC: + /* Magic number -- extract. */ + if (len >= 6 && p[1] == 6) { + *magic = (u32)p[2] << 24 | + (u32)p[3] << 16 | p[4] << 8 | p[5]; + continue; + } + break; + case LCP_OPT_ASYNC_MAP: + /* Async control character map -- check to be zero. */ + if (len >= 6 && p[1] == 6 && ! p[2] && ! p[3] && + ! p[4] && ! p[5]) + continue; + break; + case LCP_OPT_MRU: + /* Maximum receive unit -- always OK. */ + continue; + default: + /* Others not supported. */ + break; + } + /* Add the option to rejected list. */ + memcpy(r, p, p[1]); + r += p[1]; + rlen += p[1]; + } + if (rlen) + sppp_cp_send (sp, PPP_LCP, LCP_CONF_REJ, h->ident, rlen, buf); + kfree(buf); + return (rlen == 0); +} + +static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *skb) +{ + struct lcp_header *h; + struct net_device *dev = sp->pp_if; + int len = skb->len; + + if (len < 4) + { + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: invalid ipcp packet length: %d bytes\n", + dev->name, len); + return; + } + h = (struct lcp_header *)skb->data; + skb_pull(skb,sizeof(struct lcp_header)); + if (sp->pp_flags & PP_DEBUG) { + printk (KERN_WARNING "%s: ipcp input: %d bytes <%s id=%xh len=%xh", + dev->name, len, + sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len)); + if (len > 4) + sppp_print_bytes ((u8*) (h+1), len-4); + printk (">\n"); + } + if (len > ntohs (h->len)) + len = ntohs (h->len); + switch (h->type) { + default: + /* Unknown packet type -- send Code-Reject packet. */ + sppp_cp_send (sp, PPP_IPCP, IPCP_CODE_REJ, ++sp->pp_seq, len, h); + break; + case IPCP_CONF_REQ: + if (len < 4) { + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: invalid ipcp configure request packet length: %d bytes\n", + dev->name, len); + return; + } + if (len > 4) { + sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident, + len-4, h+1); + + switch (sp->ipcp.state) { + case IPCP_STATE_OPENED: + /* Initiate renegotiation. */ + sppp_ipcp_open (sp); + /* fall through... */ + case IPCP_STATE_ACK_SENT: + /* Go to closed state. */ + sp->ipcp.state = IPCP_STATE_CLOSED; + } + } else { + /* Send Configure-Ack packet. */ + sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident, + 0, 0); + /* Change the state. */ + if (sp->ipcp.state == IPCP_STATE_ACK_RCVD) + sp->ipcp.state = IPCP_STATE_OPENED; + else + sp->ipcp.state = IPCP_STATE_ACK_SENT; + } + break; + case IPCP_CONF_ACK: + if (h->ident != sp->ipcp.confid) + break; + sppp_clear_timeout (sp); + switch (sp->ipcp.state) { + case IPCP_STATE_CLOSED: + sp->ipcp.state = IPCP_STATE_ACK_RCVD; + sppp_set_timeout (sp, 5); + break; + case IPCP_STATE_ACK_SENT: + sp->ipcp.state = IPCP_STATE_OPENED; + break; + } + break; + case IPCP_CONF_NAK: + case IPCP_CONF_REJ: + if (h->ident != sp->ipcp.confid) + break; + sppp_clear_timeout (sp); + /* Initiate renegotiation. */ + sppp_ipcp_open (sp); + if (sp->ipcp.state != IPCP_STATE_ACK_SENT) + /* Go to closed state. */ + sp->ipcp.state = IPCP_STATE_CLOSED; + break; + case IPCP_TERM_REQ: + /* Send Terminate-Ack packet. */ + sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, 0); + /* Go to closed state. */ + sp->ipcp.state = IPCP_STATE_CLOSED; + /* Initiate renegotiation. */ + sppp_ipcp_open (sp); + break; + case IPCP_TERM_ACK: + /* Ignore for now. */ + case IPCP_CODE_REJ: + /* Ignore for now. */ + break; + } +} + +static void sppp_lcp_open (struct sppp *sp) +{ + char opt[6]; + + if (! sp->lcp.magic) + sp->lcp.magic = jiffies; + opt[0] = LCP_OPT_MAGIC; + opt[1] = sizeof (opt); + opt[2] = sp->lcp.magic >> 24; + opt[3] = sp->lcp.magic >> 16; + opt[4] = sp->lcp.magic >> 8; + opt[5] = sp->lcp.magic; + sp->lcp.confid = ++sp->pp_seq; + sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, sp->lcp.confid, + sizeof (opt), &opt); + sppp_set_timeout (sp, 2); +} + +static void sppp_ipcp_open (struct sppp *sp) +{ + sp->ipcp.confid = ++sp->pp_seq; + sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0, 0); + sppp_set_timeout (sp, 2); +} + +/* + * Process PPP control protocol timeouts. + */ + +static void sppp_cp_timeout (unsigned long arg) +{ + struct sppp *sp = (struct sppp*) arg; + unsigned long flags; + save_flags(flags); + cli(); + + sp->pp_flags &= ~PP_TIMO; + if (! (sp->pp_if->flags & IFF_RUNNING) || (sp->pp_flags & PP_CISCO)) { + restore_flags(flags); + return; + } + switch (sp->lcp.state) { + case LCP_STATE_CLOSED: + /* No ACK for Configure-Request, retry. */ + sppp_lcp_open (sp); + break; + case LCP_STATE_ACK_RCVD: + /* ACK got, but no Configure-Request for peer, retry. */ + sppp_lcp_open (sp); + sp->lcp.state = LCP_STATE_CLOSED; + break; + case LCP_STATE_ACK_SENT: + /* ACK sent but no ACK for Configure-Request, retry. */ + sppp_lcp_open (sp); + break; + case LCP_STATE_OPENED: + /* LCP is already OK, try IPCP. */ + switch (sp->ipcp.state) { + case IPCP_STATE_CLOSED: + /* No ACK for Configure-Request, retry. */ + sppp_ipcp_open (sp); + break; + case IPCP_STATE_ACK_RCVD: + /* ACK got, but no Configure-Request for peer, retry. */ + sppp_ipcp_open (sp); + sp->ipcp.state = IPCP_STATE_CLOSED; + break; + case IPCP_STATE_ACK_SENT: + /* ACK sent but no ACK for Configure-Request, retry. */ + sppp_ipcp_open (sp); + break; + case IPCP_STATE_OPENED: + /* IPCP is OK. */ + break; + } + break; + } + restore_flags(flags); +} + +static char *sppp_lcp_type_name (u8 type) +{ + static char buf [8]; + switch (type) { + case LCP_CONF_REQ: return ("conf-req"); + case LCP_CONF_ACK: return ("conf-ack"); + case LCP_CONF_NAK: return ("conf-nack"); + case LCP_CONF_REJ: return ("conf-rej"); + case LCP_TERM_REQ: return ("term-req"); + case LCP_TERM_ACK: return ("term-ack"); + case LCP_CODE_REJ: return ("code-rej"); + case LCP_PROTO_REJ: return ("proto-rej"); + case LCP_ECHO_REQ: return ("echo-req"); + case LCP_ECHO_REPLY: return ("echo-reply"); + case LCP_DISC_REQ: return ("discard-req"); + } + sprintf (buf, "%xh", type); + return (buf); +} + +static char *sppp_ipcp_type_name (u8 type) +{ + static char buf [8]; + switch (type) { + case IPCP_CONF_REQ: return ("conf-req"); + case IPCP_CONF_ACK: return ("conf-ack"); + case IPCP_CONF_NAK: return ("conf-nack"); + case IPCP_CONF_REJ: return ("conf-rej"); + case IPCP_TERM_REQ: return ("term-req"); + case IPCP_TERM_ACK: return ("term-ack"); + case IPCP_CODE_REJ: return ("code-rej"); + } + sprintf (buf, "%xh", type); + return (buf); +} + +static void sppp_print_bytes (u_char *p, u16 len) +{ + printk (" %x", *p++); + while (--len > 0) + printk ("-%x", *p++); +} + +/* + * Protocol glue. This drives the deferred processing mode the poorer + * cards use. + */ + +int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p) +{ + sppp_input(dev,skb); + return 0; +} + +EXPORT_SYMBOL(sppp_rcv); + +struct packet_type sppp_packet_type= +{ + 0, + NULL, + sppp_rcv, + NULL, + NULL +}; + + +void sync_ppp_init(void) +{ + printk(KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n"); + printk(KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & Jan \"Yenya\" Kasprzak.\n"); + sppp_packet_type.type=htons(ETH_P_WAN_PPP); + dev_add_pack(&sppp_packet_type); +} + +#ifdef MODULE + +int init_module(void) +{ + if(debug) + debug=PP_DEBUG; + sync_ppp_init(); + return 0; +} + +void cleanup_module(void) +{ + dev_remove_pack(&sppp_packet_type); +} + +#endif diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/syncppp.h linux/drivers/net/wan/syncppp.h --- v2.3.20/linux/drivers/net/wan/syncppp.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/syncppp.h Mon Oct 11 10:13:25 1999 @@ -0,0 +1,91 @@ +/* + * Defines for synchronous PPP/Cisco link level subroutines. + * + * Copyright (C) 1994 Cronyx Ltd. + * Author: Serge Vakulenko, + * + * This software is distributed with NO WARRANTIES, not even the implied + * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Authors grant any other persons or organizations permission to use + * or modify this software as long as this message is kept with the software, + * all derivative works or modified versions. + * + * Version 1.7, Wed Jun 7 22:12:02 MSD 1995 + * + * + * + */ + +#ifndef _SYNCPPP_H_ +#define _SYNCPPP_H_ 1 + +#ifdef __KERNEL__ +struct slcp { + u16 state; /* state machine */ + u32 magic; /* local magic number */ + u_char echoid; /* id of last keepalive echo request */ + u_char confid; /* id of last configuration request */ +}; + +struct sipcp { + u16 state; /* state machine */ + u_char confid; /* id of last configuration request */ +}; + +struct sppp +{ + struct sppp * pp_next; /* next interface in keepalive list */ + u32 pp_flags; /* use Cisco protocol instead of PPP */ + u16 pp_alivecnt; /* keepalive packets counter */ + u16 pp_loopcnt; /* loopback detection counter */ + u32 pp_seq; /* local sequence number */ + u32 pp_rseq; /* remote sequence number */ + struct slcp lcp; /* LCP params */ + struct sipcp ipcp; /* IPCP params */ + u32 ibytes,obytes; /* Bytes in/out */ + u32 ipkts,opkts; /* Packets in/out */ + struct timer_list pp_timer; + struct net_device *pp_if; +}; + +struct ppp_device +{ + struct net_device dev; /* Network device */ + struct sppp sppp; /* Synchronous PPP */ +}; + +#define PP_KEEPALIVE 0x01 /* use keepalive protocol */ +#define PP_CISCO 0x02 /* use Cisco protocol instead of PPP */ +#define PP_TIMO 0x04 /* cp_timeout routine active */ +#define PP_DEBUG 0x08 + +#define PPP_MTU 1500 /* max. transmit unit */ + +#define LCP_STATE_CLOSED 0 /* LCP state: closed (conf-req sent) */ +#define LCP_STATE_ACK_RCVD 1 /* LCP state: conf-ack received */ +#define LCP_STATE_ACK_SENT 2 /* LCP state: conf-ack sent */ +#define LCP_STATE_OPENED 3 /* LCP state: opened */ + +#define IPCP_STATE_CLOSED 0 /* IPCP state: closed (conf-req sent) */ +#define IPCP_STATE_ACK_RCVD 1 /* IPCP state: conf-ack received */ +#define IPCP_STATE_ACK_SENT 2 /* IPCP state: conf-ack sent */ +#define IPCP_STATE_OPENED 3 /* IPCP state: opened */ + +void sppp_attach (struct ppp_device *pd); +void sppp_detach (struct net_device *dev); +void sppp_input (struct net_device *dev, struct sk_buff *m); +int sppp_do_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd); +struct sk_buff *sppp_dequeue (struct net_device *dev); +int sppp_isempty (struct net_device *dev); +void sppp_flush (struct net_device *dev); +int sppp_open (struct net_device *dev); +int sppp_reopen (struct net_device *dev); +int sppp_close (struct net_device *dev); +#endif + +#define SPPPIOCCISCO (SIOCDEVPRIVATE) +#define SPPPIOCPPP (SIOCDEVPRIVATE+1) +#define SPPPIOCDEBUG (SIOCDEVPRIVATE+2) + +#endif /* _SYNCPPP_H_ */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/x25_asy.c linux/drivers/net/wan/x25_asy.c --- v2.3.20/linux/drivers/net/wan/x25_asy.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/x25_asy.c Mon Oct 11 10:13:25 1999 @@ -0,0 +1,943 @@ +/* + * Things to sort out: + * + * o tbusy handling + * o allow users to set the parameters + * o sync/async switching ? + * + * Note: This does _not_ implement CCITT X.25 asynchronous framing + * recommendations. Its primarily for testing purposes. If you wanted + * to do CCITT then in theory all you need is to nick the HDLC async + * checksum routines from ppp.c + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "x25_asy.h" + +typedef struct x25_ctrl { + char if_name[8]; /* "xasy0\0" .. "xasy99999\0" */ + struct x25_asy ctrl; /* X.25 things */ + struct net_device dev; /* the device */ +} x25_asy_ctrl_t; + +static x25_asy_ctrl_t **x25_asy_ctrls = NULL; + +int x25_asy_maxdev = SL_NRUNIT; /* Can be overridden with insmod! */ +MODULE_PARM(x25_asy_maxdev, "i"); + +static struct tty_ldisc x25_ldisc; + +static int x25_asy_esc(unsigned char *p, unsigned char *d, int len); +static void x25_asy_unesc(struct x25_asy *sl, unsigned char c); + +/* Find a free X.25 channel, and link in this `tty' line. */ +static inline struct x25_asy *x25_asy_alloc(void) +{ + x25_asy_ctrl_t *slp = NULL; + int i; + + if (x25_asy_ctrls == NULL) + return NULL; /* Master array missing ! */ + + for (i = 0; i < x25_asy_maxdev; i++) + { + slp = x25_asy_ctrls[i]; + /* Not allocated ? */ + if (slp == NULL) + break; + /* Not in use ? */ + if (!test_and_set_bit(SLF_INUSE, &slp->ctrl.flags)) + break; + } + /* SLP is set.. */ + + /* Sorry, too many, all slots in use */ + if (i >= x25_asy_maxdev) + return NULL; + + /* If no channels are available, allocate one */ + if (!slp && + (x25_asy_ctrls[i] = (x25_asy_ctrl_t *)kmalloc(sizeof(x25_asy_ctrl_t), + GFP_KERNEL)) != NULL) { + slp = x25_asy_ctrls[i]; + memset(slp, 0, sizeof(x25_asy_ctrl_t)); + + /* Initialize channel control data */ + set_bit(SLF_INUSE, &slp->ctrl.flags); + slp->ctrl.tty = NULL; + sprintf(slp->if_name, "x25asy%d", i); + slp->dev.name = slp->if_name; + slp->dev.base_addr = i; + slp->dev.priv = (void*)&(slp->ctrl); + slp->dev.next = NULL; + slp->dev.init = x25_asy_init; + } + if (slp != NULL) + { + + /* register device so that it can be ifconfig'ed */ + /* x25_asy_init() will be called as a side-effect */ + /* SIDE-EFFECT WARNING: x25_asy_init() CLEARS slp->ctrl ! */ + + if (register_netdev(&(slp->dev)) == 0) + { + /* (Re-)Set the INUSE bit. Very Important! */ + set_bit(SLF_INUSE, &slp->ctrl.flags); + slp->ctrl.dev = &(slp->dev); + slp->dev.priv = (void*)&(slp->ctrl); + return (&(slp->ctrl)); + } + else + { + clear_bit(SLF_INUSE,&(slp->ctrl.flags)); + printk("x25_asy_alloc() - register_netdev() failure.\n"); + } + } + return NULL; +} + + +/* Free an X.25 channel. */ + +static inline void x25_asy_free(struct x25_asy *sl) +{ + /* Free all X.25 frame buffers. */ + if (sl->rbuff) { + kfree(sl->rbuff); + } + sl->rbuff = NULL; + if (sl->xbuff) { + kfree(sl->xbuff); + } + sl->xbuff = NULL; + + if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) { + printk("%s: x25_asy_free for already free unit.\n", sl->dev->name); + } +} + +/* MTU has been changed by the IP layer. Unfortunately we are not told + about this, but we spot it ourselves and fix things up. We could be + in an upcall from the tty driver, or in an ip packet queue. */ + +static void x25_asy_changed_mtu(struct x25_asy *sl) +{ + struct net_device *dev = sl->dev; + unsigned char *xbuff, *rbuff, *oxbuff, *orbuff; + int len; + unsigned long flags; + + len = dev->mtu * 2; + + xbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC); + rbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC); + + if (xbuff == NULL || rbuff == NULL) + { + printk("%s: unable to grow X.25 buffers, MTU change cancelled.\n", + sl->dev->name); + dev->mtu = sl->mtu; + if (xbuff != NULL) + kfree(xbuff); + if (rbuff != NULL) + kfree(rbuff); + return; + } + + save_flags(flags); + cli(); + + oxbuff = sl->xbuff; + sl->xbuff = xbuff; + orbuff = sl->rbuff; + sl->rbuff = rbuff; + + if (sl->xleft) { + if (sl->xleft <= len) { + memcpy(sl->xbuff, sl->xhead, sl->xleft); + } else { + sl->xleft = 0; + sl->tx_dropped++; + } + } + sl->xhead = sl->xbuff; + + if (sl->rcount) { + if (sl->rcount <= len) { + memcpy(sl->rbuff, orbuff, sl->rcount); + } else { + sl->rcount = 0; + sl->rx_over_errors++; + set_bit(SLF_ERROR, &sl->flags); + } + } + sl->mtu = dev->mtu; + + sl->buffsize = len; + + restore_flags(flags); + + if (oxbuff != NULL) + kfree(oxbuff); + if (orbuff != NULL) + kfree(orbuff); +} + + +/* Set the "sending" flag. This must be atomic, hence the ASM. */ + +static inline void x25_asy_lock(struct x25_asy *sl) +{ + if (test_and_set_bit(0, (void *) &sl->dev->tbusy)) + printk("%s: trying to lock already locked device!\n", sl->dev->name); +} + + +/* Clear the "sending" flag. This must be atomic, hence the ASM. */ + +static inline void x25_asy_unlock(struct x25_asy *sl) +{ + if (!test_and_clear_bit(0, (void *)&sl->dev->tbusy)) + printk("%s: trying to unlock already unlocked device!\n", sl->dev->name); +} + +/* Send one completely decapsulated IP datagram to the IP layer. */ + +static void x25_asy_bump(struct x25_asy *sl) +{ + struct sk_buff *skb; + int count; + int err; + + count = sl->rcount; + sl->rx_bytes+=count; + + skb = dev_alloc_skb(count+1); + if (skb == NULL) + { + printk("%s: memory squeeze, dropping packet.\n", sl->dev->name); + sl->rx_dropped++; + return; + } + skb_push(skb,1); /* LAPB internal control */ + skb->dev = sl->dev; + memcpy(skb_put(skb,count), sl->rbuff, count); + skb->mac.raw=skb->data; + skb->protocol=htons(ETH_P_X25); + if((err=lapb_data_received(sl,skb))!=LAPB_OK) + { + kfree_skb(skb); + printk(KERN_DEBUG "x25_asy: data received err - %d\n",err); + } + else + { + netif_rx(skb); + sl->rx_packets++; + } +} + +/* Encapsulate one IP datagram and stuff into a TTY queue. */ +static void x25_asy_encaps(struct x25_asy *sl, unsigned char *icp, int len) +{ + unsigned char *p; + int actual, count; + + + if (sl->mtu != sl->dev->mtu) { /* Someone has been ifconfigging */ + + x25_asy_changed_mtu(sl); + } + + if (len > sl->mtu) + { /* Sigh, shouldn't occur BUT ... */ + len = sl->mtu; + printk ("%s: truncating oversized transmit packet!\n", sl->dev->name); + sl->tx_dropped++; + x25_asy_unlock(sl); + return; + } + + p = icp; + count = x25_asy_esc(p, (unsigned char *) sl->xbuff, len); + + /* Order of next two lines is *very* important. + * When we are sending a little amount of data, + * the transfer may be completed inside driver.write() + * routine, because it's running with interrupts enabled. + * In this case we *never* got WRITE_WAKEUP event, + * if we did not request it before write operation. + * 14 Oct 1994 Dmitry Gorodchanin. + */ + sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + actual = sl->tty->driver.write(sl->tty, 0, sl->xbuff, count); + sl->xleft = count - actual; + sl->xhead = sl->xbuff + actual; + /* VSV */ + clear_bit(SLF_OUTWAIT, &sl->flags); /* reset outfill flag */ +} + +/* + * Called by the driver when there's room for more data. If we have + * more packets to send, we send them here. + */ +static void x25_asy_write_wakeup(struct tty_struct *tty) +{ + int actual; + struct x25_asy *sl = (struct x25_asy *) tty->disc_data; + + /* First make sure we're connected. */ + if (!sl || sl->magic != X25_ASY_MAGIC || !sl->dev->start) + return; + + if (sl->xleft <= 0) + { + /* Now serial buffer is almost free & we can start + * transmission of another packet */ + sl->tx_packets++; + tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + x25_asy_unlock(sl); + mark_bh(NET_BH); + return; + } + + actual = tty->driver.write(tty, 0, sl->xhead, sl->xleft); + sl->xleft -= actual; + sl->xhead += actual; +} + +/* Encapsulate an IP datagram and kick it into a TTY queue. */ + +static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct x25_asy *sl = (struct x25_asy*)(dev->priv); + int err; + + if (!dev->start) + { + printk("%s: xmit call when iface is down\n", dev->name); + return 1; + } + + switch(skb->data[0]) + { + case 0x00:break; + case 0x01: /* Connection request .. do nothing */ + if((err=lapb_connect_request(sl))!=LAPB_OK) + printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err); + kfree_skb(skb); + return 0; + case 0x02: /* Disconnect request .. do nothing - hang up ?? */ + if((err=lapb_disconnect_request(sl))!=LAPB_OK) + printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err); + default: + kfree_skb(skb); + return 0; + } + skb_pull(skb,1); /* Remove control byte */ + /* + * If we are busy already- too bad. We ought to be able + * to queue things at this point, to allow for a little + * frame buffer. Oh well... + * ----------------------------------------------------- + * I hate queues in X.25 driver. May be it's efficient, + * but for me latency is more important. ;) + * So, no queues ! + * 14 Oct 1994 Dmitry Gorodchanin. + */ + if (dev->tbusy) { + /* May be we must check transmitter timeout here ? + * 14 Oct 1994 Dmitry Gorodchanin. + */ +#ifdef SL_CHECK_TRANSMIT + if (jiffies - dev->trans_start < 20 * HZ) { + /* 20 sec timeout not reached */ + return 1; + } + printk("%s: transmit timed out, %s?\n", dev->name, + (sl->tty->driver.chars_in_buffer(sl->tty) || sl->xleft) ? + "bad line quality" : "driver error"); + sl->xleft = 0; + sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + x25_asy_unlock(sl); +#else + return 1; +#endif + } + + if((err=lapb_data_request(sl,skb))!=LAPB_OK) + { + printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err); + kfree_skb(skb); + return 0; + } + return 0; +} + + +/* + * LAPB interface boilerplate + */ + +/* + * Called when I frame data arrives. We did the work above - throw it + * at the net layer. + */ + +static void x25_asy_data_indication(void *token, struct sk_buff *skb) +{ + netif_rx(skb); +} + +/* + * Data has emerged from the LAPB protocol machine. We don't handle + * busy cases too well. Its tricky to see how to do this nicely - + * perhaps lapb should allow us to bounce this ? + */ + +static void x25_asy_data_transmit(void *token, struct sk_buff *skb) +{ + struct x25_asy *sl=token; + if(sl->dev->tbusy) + { + printk(KERN_ERR "x25_asy: tbusy drop\n"); + kfree_skb(skb); + return; + } + /* We were not busy, so we are now... :-) */ + if (skb != NULL) + { + x25_asy_lock(sl); + sl->tx_bytes+=skb->len; + x25_asy_encaps(sl, skb->data, skb->len); + dev_kfree_skb(skb); + } +} + +/* + * LAPB connection establish/down information. + */ + +static void x25_asy_connected(void *token, int reason) +{ + struct x25_asy *sl = token; + struct sk_buff *skb; + unsigned char *ptr; + + if ((skb = dev_alloc_skb(1)) == NULL) { + printk(KERN_ERR "lapbeth: out of memory\n"); + return; + } + + ptr = skb_put(skb, 1); + *ptr = 0x01; + + skb->dev = sl->dev; + skb->protocol = htons(ETH_P_X25); + skb->mac.raw = skb->data; + skb->pkt_type = PACKET_HOST; + + netif_rx(skb); +} + +static void x25_asy_disconnected(void *token, int reason) +{ + struct x25_asy *sl = token; + struct sk_buff *skb; + unsigned char *ptr; + + if ((skb = dev_alloc_skb(1)) == NULL) { + printk(KERN_ERR "x25_asy: out of memory\n"); + return; + } + + ptr = skb_put(skb, 1); + *ptr = 0x02; + + skb->dev = sl->dev; + skb->protocol = htons(ETH_P_X25); + skb->mac.raw = skb->data; + skb->pkt_type = PACKET_HOST; + + netif_rx(skb); +} + + +/* Open the low-level part of the X.25 channel. Easy! */ + +static int x25_asy_open(struct net_device *dev) +{ + struct lapb_register_struct x25_asy_callbacks; + struct x25_asy *sl = (struct x25_asy*)(dev->priv); + unsigned long len; + int err; + + if (sl->tty == NULL) + return -ENODEV; + + /* + * Allocate the X.25 frame buffers: + * + * rbuff Receive buffer. + * xbuff Transmit buffer. + */ + + len = dev->mtu * 2; + + sl->rbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL); + if (sl->rbuff == NULL) { + goto norbuff; + } + sl->xbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL); + if (sl->xbuff == NULL) { + goto noxbuff; + } + sl->mtu = dev->mtu; + sl->buffsize = len; + sl->rcount = 0; + sl->xleft = 0; + sl->flags &= (1 << SLF_INUSE); /* Clear ESCAPE & ERROR flags */ + + dev->tbusy = 0; +/* dev->flags |= IFF_UP; */ + dev->start = 1; + + /* + * Now attach LAPB + */ + + x25_asy_callbacks.connect_confirmation=x25_asy_connected; + x25_asy_callbacks.connect_indication=x25_asy_connected; + x25_asy_callbacks.disconnect_confirmation=x25_asy_disconnected; + x25_asy_callbacks.disconnect_indication=x25_asy_disconnected; + x25_asy_callbacks.data_indication=x25_asy_data_indication; + x25_asy_callbacks.data_transmit=x25_asy_data_transmit; + + if((err=lapb_register(sl, &x25_asy_callbacks))==LAPB_OK) + return 0; + + /* Cleanup */ + kfree(sl->xbuff); +noxbuff: + kfree(sl->rbuff); +norbuff: + return -ENOMEM; +} + + +/* Close the low-level part of the X.25 channel. Easy! */ +static int x25_asy_close(struct net_device *dev) +{ + struct x25_asy *sl = (struct x25_asy*)(dev->priv); + int err; + + if (sl->tty == NULL) + return -EBUSY; + + sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + dev->tbusy = 1; + dev->start = 0; + if((err=lapb_unregister(sl))!=LAPB_OK) + printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",err); + +/* dev->flags &= ~IFF_UP; */ + return 0; +} + +static int x25_asy_receive_room(struct tty_struct *tty) +{ + return 65536; /* We can handle an infinite amount of data. :-) */ +} + +/* + * Handle the 'receiver data ready' interrupt. + * This function is called by the 'tty_io' module in the kernel when + * a block of X.25 data has been received, which can now be decapsulated + * and sent on to some IP layer for further processing. + */ + +static void x25_asy_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) +{ + struct x25_asy *sl = (struct x25_asy *) tty->disc_data; + + if (!sl || sl->magic != X25_ASY_MAGIC || !sl->dev->start) + return; + + /* + * Argh! mtu change time! - costs us the packet part received + * at the change + */ + if (sl->mtu != sl->dev->mtu) { + + x25_asy_changed_mtu(sl); + } + + /* Read the characters out of the buffer */ + while (count--) { + if (fp && *fp++) { + if (!test_and_set_bit(SLF_ERROR, &sl->flags)) { + sl->rx_errors++; + } + cp++; + continue; + } + x25_asy_unesc(sl, *cp++); + } +} + +/* + * Open the high-level part of the X.25 channel. + * This function is called by the TTY module when the + * X.25 line discipline is called for. Because we are + * sure the tty line exists, we only have to link it to + * a free X.25 channel... + */ + +static int x25_asy_open_tty(struct tty_struct *tty) +{ + struct x25_asy *sl = (struct x25_asy *) tty->disc_data; + int err; + + /* First make sure we're not already connected. */ + if (sl && sl->magic == X25_ASY_MAGIC) { + return -EEXIST; + } + + /* OK. Find a free X.25 channel to use. */ + if ((sl = x25_asy_alloc()) == NULL) { + return -ENFILE; + } + + sl->tty = tty; + tty->disc_data = sl; + if (tty->driver.flush_buffer) { + tty->driver.flush_buffer(tty); + } + if (tty->ldisc.flush_buffer) { + tty->ldisc.flush_buffer(tty); + } + + /* Restore default settings */ + sl->dev->type = ARPHRD_X25; + + /* Perform the low-level X.25 async init */ + if ((err = x25_asy_open(sl->dev))) + return err; + + MOD_INC_USE_COUNT; + + /* Done. We have linked the TTY line to a channel. */ + return sl->dev->base_addr; +} + + +/* + * Close down an X.25 channel. + * This means flushing out any pending queues, and then restoring the + * TTY line discipline to what it was before it got hooked to X.25 + * (which usually is TTY again). + */ +static void x25_asy_close_tty(struct tty_struct *tty) +{ + struct x25_asy *sl = (struct x25_asy *) tty->disc_data; + + /* First make sure we're connected. */ + if (!sl || sl->magic != X25_ASY_MAGIC) + return; + + if (sl->dev->flags & IFF_UP) + { + (void) dev_close(sl->dev); + } + + tty->disc_data = 0; + sl->tty = NULL; + x25_asy_free(sl); + unregister_netdev(sl->dev); + MOD_DEC_USE_COUNT; +} + + +static struct net_device_stats *x25_asy_get_stats(struct net_device *dev) +{ + static struct net_device_stats stats; + struct x25_asy *sl = (struct x25_asy*)(dev->priv); + + memset(&stats, 0, sizeof(struct net_device_stats)); + + stats.rx_packets = sl->rx_packets; + stats.tx_packets = sl->tx_packets; + stats.rx_bytes = sl->rx_bytes; + stats.tx_bytes = sl->tx_bytes; + stats.rx_dropped = sl->rx_dropped; + stats.tx_dropped = sl->tx_dropped; + stats.tx_errors = sl->tx_errors; + stats.rx_errors = sl->rx_errors; + stats.rx_over_errors = sl->rx_over_errors; + return (&stats); +} + + + /************************************************************************ + * STANDARD X.25 ENCAPSULATION * + ************************************************************************/ + +int x25_asy_esc(unsigned char *s, unsigned char *d, int len) +{ + unsigned char *ptr = d; + unsigned char c; + + /* + * Send an initial END character to flush out any + * data that may have accumulated in the receiver + * due to line noise. + */ + + *ptr++ = X25_END; /* Send 10111110 bit seq */ + + /* + * For each byte in the packet, send the appropriate + * character sequence, according to the X.25 protocol. + */ + + while (len-- > 0) + { + switch(c = *s++) + { + case X25_END: + *ptr++ = X25_ESC; + *ptr++ = X25_ESCAPE(X25_END); + break; + case X25_ESC: + *ptr++ = X25_ESC; + *ptr++ = X25_ESCAPE(X25_ESC); + break; + default: + *ptr++ = c; + break; + } + } + *ptr++ = X25_END; + return (ptr - d); +} + +static void x25_asy_unesc(struct x25_asy *sl, unsigned char s) +{ + + switch(s) + { + case X25_END: + if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) + { + x25_asy_bump(sl); + } + clear_bit(SLF_ESCAPE, &sl->flags); + sl->rcount = 0; + return; + + case X25_ESC: + set_bit(SLF_ESCAPE, &sl->flags); + return; + + case X25_ESCAPE(X25_ESC): + case X25_ESCAPE(X25_END): + if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) + s = X25_UNESCAPE(s); + break; + } + if (!test_bit(SLF_ERROR, &sl->flags)) + { + if (sl->rcount < sl->buffsize) + { + sl->rbuff[sl->rcount++] = s; + return; + } + sl->rx_over_errors++; + set_bit(SLF_ERROR, &sl->flags); + } +} + + +/* Perform I/O control on an active X.25 channel. */ +static int x25_asy_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg) +{ + struct x25_asy *sl = (struct x25_asy *) tty->disc_data; + + /* First make sure we're connected. */ + if (!sl || sl->magic != X25_ASY_MAGIC) { + return -EINVAL; + } + + switch(cmd) + { + case SIOCGIFNAME: + if(copy_to_user(arg, sl->dev->name, strlen(sl->dev->name) + 1)) + return -EFAULT; + return 0; + + case SIOCSIFHWADDR: + return -EINVAL; + + /* Allow stty to read, but not set, the serial port */ + case TCGETS: + case TCGETA: + return n_tty_ioctl(tty, (struct file *) file, cmd, (unsigned long) arg); + + default: + return -ENOIOCTLCMD; + } +} + +static int x25_asy_open_dev(struct net_device *dev) +{ + struct x25_asy *sl = (struct x25_asy*)(dev->priv); + if(sl->tty==NULL) + return -ENODEV; + return 0; +} + +/* Initialize X.25 control device -- register X.25 line discipline */ +#ifdef MODULE +static int x25_asy_init_ctrl_dev(void) +#else /* !MODULE */ +int __init x25_asy_init_ctrl_dev(struct net_device *dummy) +#endif /* !MODULE */ +{ + int status; + + if (x25_asy_maxdev < 4) x25_asy_maxdev = 4; /* Sanity */ + + printk(KERN_INFO "X.25 async: version 0.00 ALPHA (dynamic channels, max=%d).\n", + x25_asy_maxdev ); + x25_asy_ctrls = (x25_asy_ctrl_t **) kmalloc(sizeof(void*)*x25_asy_maxdev, GFP_KERNEL); + if (x25_asy_ctrls == NULL) + { + printk("X25 async: Can't allocate x25_asy_ctrls[] array! Uaargh! (-> No X.25 available)\n"); + return -ENOMEM; + } + + /* Clear the pointer array, we allocate devices when we need them */ + memset(x25_asy_ctrls, 0, sizeof(void*)*x25_asy_maxdev); /* Pointers */ + + /* Fill in our line protocol discipline, and register it */ + memset(&x25_ldisc, 0, sizeof(x25_ldisc)); + x25_ldisc.magic = TTY_LDISC_MAGIC; + x25_ldisc.name = "X.25"; + x25_ldisc.flags = 0; + x25_ldisc.open = x25_asy_open_tty; + x25_ldisc.close = x25_asy_close_tty; + x25_ldisc.read = NULL; + x25_ldisc.write = NULL; + x25_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, + unsigned int, unsigned long)) x25_asy_ioctl; + x25_ldisc.poll = NULL; + x25_ldisc.receive_buf = x25_asy_receive_buf; + x25_ldisc.receive_room = x25_asy_receive_room; + x25_ldisc.write_wakeup = x25_asy_write_wakeup; + if ((status = tty_register_ldisc(N_X25, &x25_ldisc)) != 0) { + printk("X.25 async: can't register line discipline (err = %d)\n", status); + } + +#ifdef MODULE + return status; +#else + /* Return "not found", so that dev_init() will unlink + * the placeholder device entry for us. + */ + return ENODEV; +#endif + } + + +/* Initialise the X.25 driver. Called by the device init code */ + +int x25_asy_init(struct net_device *dev) +{ + struct x25_asy *sl = (struct x25_asy*)(dev->priv); + + if (sl == NULL) /* Allocation failed ?? */ + return -ENODEV; + + /* Set up the control block. (And clear statistics) */ + + memset(sl, 0, sizeof (struct x25_asy)); + sl->magic = X25_ASY_MAGIC; + sl->dev = dev; + + /* + * Finish setting up the DEVICE info. + */ + + dev->mtu = SL_MTU; + dev->hard_start_xmit = x25_asy_xmit; + dev->open = x25_asy_open_dev; + dev->stop = x25_asy_close; + dev->get_stats = x25_asy_get_stats; + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->type = ARPHRD_X25; + dev->tx_queue_len = 10; + + dev_init_buffers(dev); + + /* New-style flags. */ + dev->flags = IFF_NOARP; + + return 0; +} +#ifdef MODULE + +int +init_module(void) +{ + return x25_asy_init_ctrl_dev(); +} + +void +cleanup_module(void) +{ + int i; + + if (x25_asy_ctrls != NULL) + { + for (i = 0; i < x25_asy_maxdev; i++) + { + if (x25_asy_ctrls[i]) + { + /* + * VSV = if dev->start==0, then device + * unregistered while close proc. + */ + if (x25_asy_ctrls[i]->dev.start) + unregister_netdev(&(x25_asy_ctrls[i]->dev)); + + kfree(x25_asy_ctrls[i]); + x25_asy_ctrls[i] = NULL; + } + } + kfree(x25_asy_ctrls); + x25_asy_ctrls = NULL; + } + if ((i = tty_register_ldisc(N_X25, NULL))) + { + printk("X.25 async: can't unregister line discipline (err = %d)\n", i); + } +} +#endif /* MODULE */ + diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/x25_asy.h linux/drivers/net/wan/x25_asy.h --- v2.3.20/linux/drivers/net/wan/x25_asy.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/x25_asy.h Mon Oct 11 10:13:25 1999 @@ -0,0 +1,58 @@ +#ifndef _LINUX_X25_ASY_H +#define _LINUX_X25_ASY_H + +/* X.25 asy configuration. */ +#define SL_NRUNIT 256 /* MAX number of X.25 channels; + This can be overridden with + insmod -ox25_asy_maxdev=nnn */ +#define SL_MTU 256 + +/* X25 async protocol characters. */ +#define X25_END 0x7E /* indicates end of frame */ +#define X25_ESC 0x7D /* indicates byte stuffing */ +#define X25_ESCAPE(x) ((x)^0x20) +#define X25_UNESCAPE(x) ((x)^0x20) + + +struct x25_asy { + int magic; + + /* Various fields. */ + struct tty_struct *tty; /* ptr to TTY structure */ + struct net_device *dev; /* easy for intr handling */ + + /* These are pointers to the malloc()ed frame buffers. */ + unsigned char *rbuff; /* receiver buffer */ + int rcount; /* received chars counter */ + unsigned char *xbuff; /* transmitter buffer */ + unsigned char *xhead; /* pointer to next byte to XMIT */ + int xleft; /* bytes left in XMIT queue */ + + /* X.25 interface statistics. */ + unsigned long rx_packets; /* inbound frames counter */ + unsigned long tx_packets; /* outbound frames counter */ + unsigned long rx_bytes; /* inbound byte counte */ + unsigned long tx_bytes; /* outbound byte counter */ + unsigned long rx_errors; /* Parity, etc. errors */ + unsigned long tx_errors; /* Planned stuff */ + unsigned long rx_dropped; /* No memory for skb */ + unsigned long tx_dropped; /* When MTU change */ + unsigned long rx_over_errors; /* Frame bigger then X.25 buf. */ + + int mtu; /* Our mtu (to spot changes!) */ + int buffsize; /* Max buffers sizes */ + + unsigned int flags; /* Flag values/ mode etc */ +#define SLF_INUSE 0 /* Channel in use */ +#define SLF_ESCAPE 1 /* ESC received */ +#define SLF_ERROR 2 /* Parity, etc. error */ +#define SLF_OUTWAIT 4 /* Waiting for output */ +}; + + + +#define X25_ASY_MAGIC 0x5303 + +extern int x25_asy_init(struct net_device *dev); + +#endif /* _LINUX_X25_ASY.H */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/z85230.c linux/drivers/net/wan/z85230.c --- v2.3.20/linux/drivers/net/wan/z85230.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/z85230.c Mon Oct 11 10:13:25 1999 @@ -0,0 +1,1470 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * (c) Copyright 1998 Building Number Three Ltd + * + * Development of this driver was funded by Equiinet Ltd + * http://www.equiinet.com + * + * ChangeLog: + * + * Asynchronous mode dropped for 2.2. For 2.3 we will attempt the + * unification of all the Z85x30 asynchronous drivers for real. + * + * To Do: + * + * Finish DMA mode support. + * + * Performance + * + * Z85230: + * Non DMA you want a 486DX50 or better to do 64Kbits. 9600 baud + * X.25 is not unrealistic on all machines. DMA mode can in theory + * handle T1/E1 quite nicely. In practice the limit seems to be about + * 512Kbit->1Mbit depending on motherboard. + * + * Z85C30: + * 64K will take DMA, 9600 baud X.25 should be ok. + * + * Z8530: + * Synchronous mode without DMA is unlikely to pass about 2400 baud. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define RT_LOCK +#define RT_UNLOCK +#include + +#include "z85230.h" +#include "syncppp.h" + + +static spinlock_t z8530_buffer_lock = SPIN_LOCK_UNLOCKED; + +/* + * Provided port access methods. The Comtrol SV11 requires no delays + * between accesses and uses PC I/O. Some drivers may need a 5uS delay + */ + +extern __inline__ int z8530_read_port(int p) +{ + u8 r=inb(Z8530_PORT_OF(p)); + if(p&Z8530_PORT_SLEEP) /* gcc should figure this out efficiently ! */ + udelay(5); + return r; +} + +extern __inline__ void z8530_write_port(int p, u8 d) +{ + outb(d,Z8530_PORT_OF(p)); + if(p&Z8530_PORT_SLEEP) + udelay(5); +} + + + +static void z8530_rx_done(struct z8530_channel *c); +static void z8530_tx_done(struct z8530_channel *c); + + +/* + * Port accesses + */ + +extern inline u8 read_zsreg(struct z8530_channel *c, u8 reg) +{ + u8 r; + unsigned long flags; + save_flags(flags); + cli(); + if(reg) + z8530_write_port(c->ctrlio, reg); + r=z8530_read_port(c->ctrlio); + restore_flags(flags); + return r; +} + +extern inline u8 read_zsdata(struct z8530_channel *c) +{ + u8 r; + r=z8530_read_port(c->dataio); + return r; +} + +extern inline void write_zsreg(struct z8530_channel *c, u8 reg, u8 val) +{ + unsigned long flags; + save_flags(flags); + cli(); + if(reg) + z8530_write_port(c->ctrlio, reg); + z8530_write_port(c->ctrlio, val); + restore_flags(flags); +} + +extern inline void write_zsctrl(struct z8530_channel *c, u8 val) +{ + z8530_write_port(c->ctrlio, val); +} + +extern inline void write_zsdata(struct z8530_channel *c, u8 val) +{ + z8530_write_port(c->dataio, val); +} + +/* + * Register loading parameters for a dead port + */ + +u8 z8530_dead_port[]= +{ + 255 +}; + +EXPORT_SYMBOL(z8530_dead_port); + +/* + * Register loading parameters for currently supported circuit types + */ + + +/* + * Data clocked by telco end. This is the correct data for the UK + * "kilostream" service, and most other similar services. + */ + +u8 z8530_hdlc_kilostream[]= +{ + 4, SYNC_ENAB|SDLC|X1CLK, + 2, 0, /* No vector */ + 1, 0, + 3, ENT_HM|RxCRC_ENAB|Rx8, + 5, TxCRC_ENAB|RTS|TxENAB|Tx8|DTR, + 9, 0, /* Disable interrupts */ + 6, 0xFF, + 7, FLAG, + 10, ABUNDER|NRZ|CRCPS,/*MARKIDLE ??*/ + 11, TCTRxCP, + 14, DISDPLL, + 15, DCDIE|SYNCIE|CTSIE|TxUIE|BRKIE, + 1, EXT_INT_ENAB|TxINT_ENAB|INT_ALL_Rx, + 9, NV|MIE|NORESET, + 255 +}; + +EXPORT_SYMBOL(z8530_hdlc_kilostream); + +/* + * As above but for enhanced chips. + */ + +u8 z8530_hdlc_kilostream_85230[]= +{ + 4, SYNC_ENAB|SDLC|X1CLK, + 2, 0, /* No vector */ + 1, 0, + 3, ENT_HM|RxCRC_ENAB|Rx8, + 5, TxCRC_ENAB|RTS|TxENAB|Tx8|DTR, + 9, 0, /* Disable interrupts */ + 6, 0xFF, + 7, FLAG, + 10, ABUNDER|NRZ|CRCPS, /* MARKIDLE?? */ + 11, TCTRxCP, + 14, DISDPLL, + 15, DCDIE|SYNCIE|CTSIE|TxUIE|BRKIE, + 1, EXT_INT_ENAB|TxINT_ENAB|INT_ALL_Rx, + 9, NV|MIE|NORESET, + 23, 3, /* Extended mode AUTO TX and EOM*/ + + 255 +}; + +EXPORT_SYMBOL(z8530_hdlc_kilostream_85230); + +/* + * Flush the FIFO + */ + +static void z8530_flush_fifo(struct z8530_channel *c) +{ + read_zsreg(c, R1); + read_zsreg(c, R1); + read_zsreg(c, R1); + read_zsreg(c, R1); + if(c->dev->type==Z85230) + { + read_zsreg(c, R1); + read_zsreg(c, R1); + read_zsreg(c, R1); + read_zsreg(c, R1); + } +} + +/* Sets or clears DTR/RTS on the requested line */ + +static void z8530_rtsdtr(struct z8530_channel *c, int set) +{ + if (set) + c->regs[5] |= (RTS | DTR); + else + c->regs[5] &= ~(RTS | DTR); + write_zsreg(c, R5, c->regs[5]); +} + +/* + * Receive handler. This is much like the async one but not quite the + * same or as complex + * + * Note: Its intended that this handler can easily be separated from + * the main code to run realtime. That'll be needed for some machines + * (eg to ever clock 64kbits on a sparc ;)). + * + * The RT_LOCK macros don't do anything now. Keep the code covered + * by them as short as possible in all circumstances - clocks cost + * baud. The interrupt handler is assumed to be atomic w.r.t. to + * other code - this is true in the RT case too. + * + * We only cover the sync cases for this. If you want 2Mbit async + * do it yourself but consider medical assistance first. + * + * This non DMA synchronous mode is portable code. + */ + +static void z8530_rx(struct z8530_channel *c) +{ + u8 ch,stat; + + while(1) + { + /* FIFO empty ? */ + if(!(read_zsreg(c, R0)&1)) + break; + ch=read_zsdata(c); + stat=read_zsreg(c, R1); + + /* + * Overrun ? + */ + if(c->count < c->max) + { + *c->dptr++=ch; + c->count++; + } + + if(stat&END_FR) + { + + /* + * Error ? + */ + if(stat&(Rx_OVR|CRC_ERR)) + { + /* Rewind the buffer and return */ + if(c->skb) + c->dptr=c->skb->data; + c->count=0; + if(stat&Rx_OVR) + { + printk(KERN_WARNING "%s: overrun\n", c->dev->name); + c->rx_overrun++; + } + if(stat&CRC_ERR) + { + c->rx_crc_err++; + /* printk("crc error\n"); */ + } + /* Shove the frame upstream */ + } + else + { + z8530_rx_done(c); + write_zsctrl(c, RES_Rx_CRC); + } + } + } + /* + * Clear irq + */ + write_zsctrl(c, ERR_RES); + write_zsctrl(c, RES_H_IUS); +} + + +/* + * Z8530 transmit interrupt handler + */ + +static void z8530_tx(struct z8530_channel *c) +{ + while(c->txcount) + { + /* FIFO full ? */ + if(!(read_zsreg(c, R0)&4)) + break; + c->txcount--; + /* + * Shovel out the byte + */ + write_zsreg(c, R8, *c->tx_ptr++); + write_zsctrl(c, RES_H_IUS); + /* We are about to underflow */ + if(c->txcount==0) + { + write_zsctrl(c, RES_EOM_L); + write_zsreg(c, R10, c->regs[10]&~ABUNDER); + } + return; + } + + /* + * End of frame TX - fire another one + */ + + write_zsctrl(c, RES_Tx_P); + + z8530_tx_done(c); +/* write_zsreg(c, R8, *c->tx_ptr++); */ + write_zsctrl(c, RES_H_IUS); +} + +static void z8530_status(struct z8530_channel *chan) +{ + u8 status=read_zsreg(chan, R0); + u8 altered=chan->status^status; + + chan->status=status; + + if(status&TxEOM) + { +/* printk("%s: Tx underrun.\n", chan->dev->name); */ + chan->stats.tx_fifo_errors++; + write_zsctrl(chan, ERR_RES); + z8530_tx_done(chan); + } + + if(altered&DCD) + { + if(status&DCD) + { + printk(KERN_INFO "%s: DCD raised\n", chan->dev->name); + write_zsreg(chan, R3, chan->regs[3]|RxENABLE); + if(chan->netdevice) + sppp_reopen(chan->netdevice); + } + else + { + printk(KERN_INFO "%s: DCD lost\n", chan->dev->name); + write_zsreg(chan, R3, chan->regs[3]&~RxENABLE); + z8530_flush_fifo(chan); + } + + } + write_zsctrl(chan, RES_EXT_INT); + write_zsctrl(chan, RES_H_IUS); +} + +struct z8530_irqhandler z8530_sync= +{ + z8530_rx, + z8530_tx, + z8530_status +}; + +EXPORT_SYMBOL(z8530_sync); + +/* + * Non bus mastering DMA interfaces for the Z8x30 devices. This + * is really pretty PC specific. + */ + +static void z8530_dma_rx(struct z8530_channel *chan) +{ + if(chan->rxdma_on) + { + /* Special condition check only */ + u8 status; + + read_zsreg(chan, R7); + read_zsreg(chan, R6); + + status=read_zsreg(chan, R1); + if(status&END_FR) + { + z8530_rx_done(chan); /* Fire up the next one */ + } + write_zsctrl(chan, ERR_RES); + write_zsctrl(chan, RES_H_IUS); + } + else + { + /* DMA is off right now, drain the slow way */ + z8530_rx(chan); + } +} + +static void z8530_dma_tx(struct z8530_channel *chan) +{ + if(!chan->dma_tx) + { + printk("Hey who turned the DMA off?\n"); + z8530_tx(chan); + return; + } + /* This shouldnt occur in DMA mode */ + printk(KERN_ERR "DMA tx ??\n"); + z8530_tx(chan); +} + +static void z8530_dma_status(struct z8530_channel *chan) +{ + unsigned long flags; + u8 status=read_zsreg(chan, R0); + u8 altered=chan->status^status; + + chan->status=status; + + if(chan->dma_tx) + { + if(status&TxEOM) + { + flags=claim_dma_lock(); + /* Transmit underrun */ + disable_dma(chan->txdma); + clear_dma_ff(chan->txdma); + chan->txdma_on=0; + release_dma_lock(flags); + z8530_tx_done(chan); + } + } + if(altered&DCD) + { + if(status&DCD) + { + printk(KERN_INFO "%s: DCD raised\n", chan->dev->name); + write_zsreg(chan, R3, chan->regs[3]|RxENABLE); + if(chan->netdevice) + sppp_reopen(chan->netdevice); + } + else + { + printk(KERN_INFO "%s:DCD lost\n", chan->dev->name); + write_zsreg(chan, R3, chan->regs[3]&~RxENABLE); + z8530_flush_fifo(chan); + } + } + write_zsctrl(chan, RES_EXT_INT); + write_zsctrl(chan, RES_H_IUS); +} + +struct z8530_irqhandler z8530_dma_sync= +{ + z8530_dma_rx, + z8530_dma_tx, + z8530_dma_status +}; + +EXPORT_SYMBOL(z8530_dma_sync); + +struct z8530_irqhandler z8530_txdma_sync= +{ + z8530_rx, + z8530_dma_tx, + z8530_dma_status +}; + +EXPORT_SYMBOL(z8530_txdma_sync); + +/* + * Interrupt vectors for a Z8530 that is in 'parked' mode. + * For machines with PCI Z85x30 cards, or level triggered interrupts + * (eg the MacII) we must clear the interrupt cause or die. + */ + + +static void z8530_rx_clear(struct z8530_channel *c) +{ + /* + * Data and status bytes + */ + u8 stat; + + read_zsdata(c); + stat=read_zsreg(c, R1); + + if(stat&END_FR) + write_zsctrl(c, RES_Rx_CRC); + /* + * Clear irq + */ + write_zsctrl(c, ERR_RES); + write_zsctrl(c, RES_H_IUS); +} + +static void z8530_tx_clear(struct z8530_channel *c) +{ + write_zsctrl(c, RES_Tx_P); + write_zsctrl(c, RES_H_IUS); +} + +static void z8530_status_clear(struct z8530_channel *chan) +{ + u8 status=read_zsreg(chan, R0); + if(status&TxEOM) + write_zsctrl(chan, ERR_RES); + write_zsctrl(chan, RES_EXT_INT); + write_zsctrl(chan, RES_H_IUS); +} + +struct z8530_irqhandler z8530_nop= +{ + z8530_rx_clear, + z8530_tx_clear, + z8530_status_clear +}; + + +EXPORT_SYMBOL(z8530_nop); + +/* + * A Z85[2]30 device has stuck its hand in the air for attention + */ + +void z8530_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct z8530_dev *dev=dev_id; + u8 intr; + static volatile int locker=0; + int work=0; + + if(locker) + { + printk(KERN_ERR "IRQ re-enter\n"); + return; + } + locker=1; + + while(++work<5000) + { + struct z8530_irqhandler *irqs=dev->chanA.irqs; + + intr = read_zsreg(&dev->chanA, R3); + if(!(intr & (CHARxIP|CHATxIP|CHAEXT|CHBRxIP|CHBTxIP|CHBEXT))) + break; + + /* This holds the IRQ status. On the 8530 you must read it from chan + A even though it applies to the whole chip */ + + /* Now walk the chip and see what it is wanting - it may be + an IRQ for someone else remember */ + + if(intr & (CHARxIP|CHATxIP|CHAEXT)) + { + if(intr&CHARxIP) + irqs->rx(&dev->chanA); + if(intr&CHATxIP) + irqs->tx(&dev->chanA); + if(intr&CHAEXT) + irqs->status(&dev->chanA); + } + + irqs=dev->chanB.irqs; + + if(intr & (CHBRxIP|CHBTxIP|CHBEXT)) + { + if(intr&CHBRxIP) + irqs->rx(&dev->chanB); + if(intr&CHBTxIP) + irqs->tx(&dev->chanB); + if(intr&CHBEXT) + irqs->status(&dev->chanB); + } + } + if(work==5000) + printk(KERN_ERR "%s: interrupt jammed - abort(0x%X)!\n", dev->name, intr); + /* Ok all done */ + locker=0; +} + +EXPORT_SYMBOL(z8530_interrupt); + +static char reg_init[16]= +{ + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0x55,0,0,0 +}; + + +int z8530_sync_open(struct net_device *dev, struct z8530_channel *c) +{ + c->sync = 1; + c->mtu = dev->mtu+64; + c->count = 0; + c->skb = NULL; + c->skb2 = NULL; + c->irqs = &z8530_sync; + /* This loads the double buffer up */ + z8530_rx_done(c); /* Load the frame ring */ + z8530_rx_done(c); /* Load the backup frame */ + z8530_rtsdtr(c,1); + c->dma_tx = 0; + c->regs[R1]|=TxINT_ENAB; + write_zsreg(c, R1, c->regs[R1]); + write_zsreg(c, R3, c->regs[R3]|RxENABLE); + return 0; +} + + +EXPORT_SYMBOL(z8530_sync_open); + +int z8530_sync_close(struct net_device *dev, struct z8530_channel *c) +{ + u8 chk; + c->irqs = &z8530_nop; + c->max = 0; + c->sync = 0; + + chk=read_zsreg(c,R0); + write_zsreg(c, R3, c->regs[R3]); + z8530_rtsdtr(c,0); + return 0; +} + +EXPORT_SYMBOL(z8530_sync_close); + +int z8530_sync_dma_open(struct net_device *dev, struct z8530_channel *c) +{ + unsigned long flags; + + c->sync = 1; + c->mtu = dev->mtu+64; + c->count = 0; + c->skb = NULL; + c->skb2 = NULL; + /* + * Load the DMA interfaces up + */ + c->rxdma_on = 0; + c->txdma_on = 0; + + /* + * Allocate the DMA flip buffers + */ + + c->rx_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA); + if(c->rx_buf[0]==NULL) + return -ENOBUFS; + c->rx_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA); + if(c->rx_buf[1]==NULL) + { + kfree(c->rx_buf[0]); + c->rx_buf[0]=NULL; + return -ENOBUFS; + } + + c->tx_dma_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA); + if(c->tx_dma_buf[0]==NULL) + { + kfree(c->rx_buf[0]); + kfree(c->rx_buf[1]); + c->rx_buf[0]=NULL; + return -ENOBUFS; + } + c->tx_dma_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA); + if(c->tx_dma_buf[1]==NULL) + { + kfree(c->tx_dma_buf[0]); + kfree(c->rx_buf[0]); + kfree(c->rx_buf[1]); + c->rx_buf[0]=NULL; + c->rx_buf[1]=NULL; + c->tx_dma_buf[0]=NULL; + return -ENOBUFS; + } + c->tx_dma_used=0; + c->dma_tx = 1; + c->dma_num=0; + c->dma_ready=1; + + /* + * Enable DMA control mode + */ + + /* + * TX DMA via DIR/REQ + */ + + c->regs[R14]|= DTRREQ; + write_zsreg(c, R14, c->regs[R14]); + + c->regs[R1]&= ~TxINT_ENAB; + write_zsreg(c, R1, c->regs[R1]); + + /* + * RX DMA via W/Req + */ + + c->regs[R1]|= WT_FN_RDYFN; + c->regs[R1]|= WT_RDY_RT; + c->regs[R1]|= INT_ERR_Rx; + c->regs[R1]&= ~TxINT_ENAB; + write_zsreg(c, R1, c->regs[R1]); + c->regs[R1]|= WT_RDY_ENAB; + write_zsreg(c, R1, c->regs[R1]); + + /* + * DMA interrupts + */ + + /* + * Set up the DMA configuration + */ + + flags=claim_dma_lock(); + + disable_dma(c->rxdma); + clear_dma_ff(c->rxdma); + set_dma_mode(c->rxdma, DMA_MODE_READ|0x10); + set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[0])); + set_dma_count(c->rxdma, c->mtu); + enable_dma(c->rxdma); + + disable_dma(c->txdma); + clear_dma_ff(c->txdma); + set_dma_mode(c->txdma, DMA_MODE_WRITE); + disable_dma(c->txdma); + + release_dma_lock(flags); + + /* + * Select the DMA interrupt handlers + */ + + c->rxdma_on = 1; + c->txdma_on = 1; + c->tx_dma_used = 1; + + c->irqs = &z8530_dma_sync; + z8530_rtsdtr(c,1); + write_zsreg(c, R3, c->regs[R3]|RxENABLE); + return 0; +} + +EXPORT_SYMBOL(z8530_sync_dma_open); + +int z8530_sync_dma_close(struct net_device *dev, struct z8530_channel *c) +{ + u8 chk; + unsigned long flags; + + c->irqs = &z8530_nop; + c->max = 0; + c->sync = 0; + + /* + * Disable the PC DMA channels + */ + + flags=claim_dma_lock(); + disable_dma(c->rxdma); + clear_dma_ff(c->rxdma); + + c->rxdma_on = 0; + + disable_dma(c->txdma); + clear_dma_ff(c->txdma); + release_dma_lock(flags); + + c->txdma_on = 0; + c->tx_dma_used = 0; + + /* + * Disable DMA control mode + */ + + c->regs[R1]&= ~WT_RDY_ENAB; + write_zsreg(c, R1, c->regs[R1]); + c->regs[R1]&= ~(WT_RDY_RT|WT_FN_RDYFN|INT_ERR_Rx); + c->regs[R1]|= INT_ALL_Rx; + write_zsreg(c, R1, c->regs[R1]); + c->regs[R14]&= ~DTRREQ; + write_zsreg(c, R14, c->regs[R14]); + + if(c->rx_buf[0]) + { + kfree(c->rx_buf[0]); + c->rx_buf[0]=NULL; + } + if(c->rx_buf[1]) + { + kfree(c->rx_buf[1]); + c->rx_buf[1]=NULL; + } + if(c->tx_dma_buf[0]) + { + kfree(c->tx_dma_buf[0]); + c->tx_dma_buf[0]=NULL; + } + if(c->tx_dma_buf[1]) + { + kfree(c->tx_dma_buf[1]); + c->tx_dma_buf[1]=NULL; + } + chk=read_zsreg(c,R0); + write_zsreg(c, R3, c->regs[R3]); + z8530_rtsdtr(c,0); + return 0; +} + +EXPORT_SYMBOL(z8530_sync_dma_close); + +int z8530_sync_txdma_open(struct net_device *dev, struct z8530_channel *c) +{ + unsigned long flags; + + printk("Opening sync interface for TX-DMA\n"); + c->sync = 1; + c->mtu = dev->mtu+64; + c->count = 0; + c->skb = NULL; + c->skb2 = NULL; + + /* + * Load the PIO receive ring + */ + + z8530_rx_done(c); + z8530_rx_done(c); + + /* + * Load the DMA interfaces up + */ + + c->rxdma_on = 0; + c->txdma_on = 0; + + c->tx_dma_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA); + if(c->tx_dma_buf[0]==NULL) + { + kfree(c->rx_buf[0]); + kfree(c->rx_buf[1]); + c->rx_buf[0]=NULL; + return -ENOBUFS; + } + c->tx_dma_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA); + if(c->tx_dma_buf[1]==NULL) + { + kfree(c->tx_dma_buf[0]); + kfree(c->rx_buf[0]); + kfree(c->rx_buf[1]); + c->rx_buf[0]=NULL; + c->rx_buf[1]=NULL; + c->tx_dma_buf[0]=NULL; + return -ENOBUFS; + } + c->tx_dma_used=0; + c->dma_num=0; + c->dma_ready=1; + c->dma_tx = 1; + + /* + * Enable DMA control mode + */ + + /* + * TX DMA via DIR/REQ + */ + c->regs[R14]|= DTRREQ; + write_zsreg(c, R14, c->regs[R14]); + + c->regs[R1]&= ~TxINT_ENAB; + write_zsreg(c, R1, c->regs[R1]); + + /* + * Set up the DMA configuration + */ + + flags = claim_dma_lock(); + + disable_dma(c->txdma); + clear_dma_ff(c->txdma); + set_dma_mode(c->txdma, DMA_MODE_WRITE); + disable_dma(c->txdma); + + release_dma_lock(flags); + + /* + * Select the DMA interrupt handlers + */ + + c->rxdma_on = 0; + c->txdma_on = 1; + c->tx_dma_used = 1; + + c->irqs = &z8530_txdma_sync; + printk("Loading RX\n"); + z8530_rtsdtr(c,1); + printk("Rx interrupts ON\n"); + write_zsreg(c, R3, c->regs[R3]|RxENABLE); + return 0; +} + +EXPORT_SYMBOL(z8530_sync_txdma_open); + +int z8530_sync_txdma_close(struct net_device *dev, struct z8530_channel *c) +{ + unsigned long flags; + u8 chk; + c->irqs = &z8530_nop; + c->max = 0; + c->sync = 0; + + /* + * Disable the PC DMA channels + */ + + flags = claim_dma_lock(); + + disable_dma(c->txdma); + clear_dma_ff(c->txdma); + c->txdma_on = 0; + c->tx_dma_used = 0; + + release_dma_lock(flags); + + /* + * Disable DMA control mode + */ + + c->regs[R1]&= ~WT_RDY_ENAB; + write_zsreg(c, R1, c->regs[R1]); + c->regs[R1]&= ~(WT_RDY_RT|WT_FN_RDYFN|INT_ERR_Rx); + c->regs[R1]|= INT_ALL_Rx; + write_zsreg(c, R1, c->regs[R1]); + c->regs[R14]&= ~DTRREQ; + write_zsreg(c, R14, c->regs[R14]); + + if(c->tx_dma_buf[0]) + { + kfree(c->tx_dma_buf[0]); + c->tx_dma_buf[0]=NULL; + } + if(c->tx_dma_buf[1]) + { + kfree(c->tx_dma_buf[1]); + c->tx_dma_buf[1]=NULL; + } + chk=read_zsreg(c,R0); + write_zsreg(c, R3, c->regs[R3]); + z8530_rtsdtr(c,0); + return 0; +} + + +EXPORT_SYMBOL(z8530_sync_txdma_close); + +/* + * Describe a Z8530 in a standard format. We must pass the I/O as + * the port offset isnt predictable. The main reason for this function + * is to try and get a common format of report. + */ + +static char *z8530_type_name[]={ + "Z8530", + "Z85C30", + "Z85230" +}; + +void z8530_describe(struct z8530_dev *dev, char *mapping, int io) +{ + printk(KERN_INFO "%s: %s found at %s 0x%X, IRQ %d.\n", + dev->name, + z8530_type_name[dev->type], + mapping, + Z8530_PORT_OF(io), + dev->irq); +} + +EXPORT_SYMBOL(z8530_describe); + +/* + * Configure up a Z8530 + */ + + +int z8530_init(struct z8530_dev *dev) +{ + /* NOP the interrupt handlers first - we might get a + floating IRQ transition when we reset the chip */ + dev->chanA.irqs=&z8530_nop; + dev->chanB.irqs=&z8530_nop; + /* Reset the chip */ + write_zsreg(&dev->chanA, R9, 0xC0); + udelay(200); + /* Now check its valid */ + write_zsreg(&dev->chanA, R12, 0xAA); + if(read_zsreg(&dev->chanA, R12)!=0xAA) + return -ENODEV; + write_zsreg(&dev->chanA, R12, 0x55); + if(read_zsreg(&dev->chanA, R12)!=0x55) + return -ENODEV; + + dev->type=Z8530; + + /* + * See the application note. + */ + + write_zsreg(&dev->chanA, R15, 0x01); + + /* + * If we can set the low bit of R15 then + * the chip is enhanced. + */ + + if(read_zsreg(&dev->chanA, R15)==0x01) + { + /* This C30 versus 230 detect is from Klaus Kudielka's dmascc */ + /* Put a char in the fifo */ + write_zsreg(&dev->chanA, R8, 0); + if(read_zsreg(&dev->chanA, R0)&Tx_BUF_EMP) + dev->type = Z85230; /* Has a FIFO */ + else + dev->type = Z85C30; /* Z85C30, 1 byte FIFO */ + } + + /* + * The code assumes R7' and friends are + * off. Use write_zsext() for these and keep + * this bit clear. + */ + + write_zsreg(&dev->chanA, R15, 0); + + /* + * At this point it looks like the chip is behaving + */ + + memcpy(dev->chanA.regs, reg_init, 16); + memcpy(dev->chanB.regs, reg_init ,16); + + return 0; +} + + +EXPORT_SYMBOL(z8530_init); + +int z8530_shutdown(struct z8530_dev *dev) +{ + /* Reset the chip */ + dev->chanA.irqs=&z8530_nop; + dev->chanB.irqs=&z8530_nop; + write_zsreg(&dev->chanA, R9, 0xC0); + udelay(100); + return 0; +} + +EXPORT_SYMBOL(z8530_shutdown); + +/* + * Load a Z8530 channel up from the system data + * We use +16 to indicate the 'prime' registers + */ + +int z8530_channel_load(struct z8530_channel *c, u8 *rtable) +{ + while(*rtable!=255) + { + int reg=*rtable++; + if(reg>0x0F) + write_zsreg(c, R15, c->regs[15]|1); + write_zsreg(c, reg&0x0F, *rtable); + if(reg>0x0F) + write_zsreg(c, R15, c->regs[15]&~1); + c->regs[reg]=*rtable++; + } + c->rx_function=z8530_null_rx; + c->skb=NULL; + c->tx_skb=NULL; + c->tx_next_skb=NULL; + c->mtu=1500; + c->max=0; + c->count=0; + c->status=0; /* Fixme - check DCD now */ + c->sync=1; + write_zsreg(c, R3, c->regs[R3]|RxENABLE); + return 0; +} + +EXPORT_SYMBOL(z8530_channel_load); + + +/* + * Higher level shovelling - transmit chains + */ + +static void z8530_tx_begin(struct z8530_channel *c) +{ + unsigned long flags; + if(c->tx_skb) + return; + + c->tx_skb=c->tx_next_skb; + c->tx_next_skb=NULL; + c->tx_ptr=c->tx_next_ptr; + + mark_bh(NET_BH); + if(c->tx_skb==NULL) + { + /* Idle on */ + if(c->dma_tx) + { + flags=claim_dma_lock(); + disable_dma(c->txdma); + /* + * Check if we crapped out. + */ + if(get_dma_residue(c->txdma)) + { + c->stats.tx_dropped++; + c->stats.tx_fifo_errors++; + } + release_dma_lock(flags); + } + c->txcount=0; + } + else + { + c->txcount=c->tx_skb->len; + + + if(c->dma_tx) + { + /* + * FIXME. DMA is broken for the original 8530, + * on the older parts we need to set a flag and + * wait for a further TX interrupt to fire this + * stage off + */ + + flags=claim_dma_lock(); + disable_dma(c->txdma); + + /* + * These two are needed by the 8530/85C30 + * and must be issued when idling. + */ + + if(c->dev->type!=Z85230) + { + write_zsctrl(c, RES_Tx_CRC); + write_zsctrl(c, RES_EOM_L); + } + write_zsreg(c, R10, c->regs[10]&~ABUNDER); + clear_dma_ff(c->txdma); + set_dma_addr(c->txdma, virt_to_bus(c->tx_ptr)); + set_dma_count(c->txdma, c->txcount); + enable_dma(c->txdma); + release_dma_lock(flags); + write_zsctrl(c, RES_EOM_L); + write_zsreg(c, R5, c->regs[R5]|TxENAB); + } + else + { + save_flags(flags); + cli(); + /* ABUNDER off */ + write_zsreg(c, R10, c->regs[10]); + write_zsctrl(c, RES_Tx_CRC); +//??? write_zsctrl(c, RES_EOM_L); + + while(c->txcount && (read_zsreg(c,R0)&Tx_BUF_EMP)) + { + write_zsreg(c, R8, *c->tx_ptr++); + c->txcount--; + } + restore_flags(flags); + } + } +} + + +static void z8530_tx_done(struct z8530_channel *c) +{ + unsigned long flags; + struct sk_buff *skb; + + spin_lock_irqsave(&z8530_buffer_lock, flags); + c->netdevice->tbusy=0; + /* Actually this can happen.*/ + if(c->tx_skb==NULL) + { + spin_unlock_irqrestore(&z8530_buffer_lock, flags); + return; + } + skb=c->tx_skb; + c->tx_skb=NULL; + z8530_tx_begin(c); + spin_unlock_irqrestore(&z8530_buffer_lock, flags); + c->stats.tx_packets++; + c->stats.tx_bytes+=skb->len; + dev_kfree_skb(skb); +} + +/* + * Higher level shovelling - receive chains + */ + +void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb) +{ + kfree_skb(skb); +} + +EXPORT_SYMBOL(z8530_null_rx); + +static void z8530_rx_done(struct z8530_channel *c) +{ + struct sk_buff *skb; + int ct; + + /* + * Is our receive engine in DMA mode + */ + + if(c->rxdma_on) + { + /* + * Save the ready state and the buffer currently + * being used as the DMA target + */ + + int ready=c->dma_ready; + unsigned char *rxb=c->rx_buf[c->dma_num]; + unsigned long flags; + + /* + * Complete this DMA. Neccessary to find the length + */ + + flags=claim_dma_lock(); + + disable_dma(c->rxdma); + clear_dma_ff(c->rxdma); + c->rxdma_on=0; + ct=c->mtu-get_dma_residue(c->rxdma); + if(ct<0) + ct=2; /* Shit happens.. */ + c->dma_ready=0; + + /* + * Normal case: the other slot is free, start the next DMA + * into it immediately. + */ + + if(ready) + { + c->dma_num^=1; + set_dma_mode(c->rxdma, DMA_MODE_READ|0x10); + set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[c->dma_num])); + set_dma_count(c->rxdma, c->mtu); + c->rxdma_on = 1; + enable_dma(c->rxdma); + /* Stop any frames that we missed the head of + from passing */ + write_zsreg(c, R0, RES_Rx_CRC); + } + else + /* Can't occur as we dont reenable the DMA irq until + after the flip is done */ + printk("DMA flip overrun!\n"); + + release_dma_lock(flags); + + /* + * Shove the old buffer into an sk_buff. We can't DMA + * directly into one on a PC - it might be above the 16Mb + * boundary. Optimisation - we could check to see if we + * can avoid the copy. Optimisation 2 - make the memcpy + * a copychecksum. + */ + + skb=dev_alloc_skb(ct); + if(skb==NULL) + { + c->stats.rx_dropped++; + printk(KERN_WARNING "%s: Memory squeeze.\n", c->netdevice->name); + } + else + { + skb_put(skb, ct); + memcpy(skb->data, rxb, ct); + c->stats.rx_packets++; + c->stats.rx_bytes+=ct; + } + c->dma_ready=1; + } + else + { + RT_LOCK; + skb=c->skb; + + /* + * The game we play for non DMA is similar. We want to + * get the controller set up for the next packet as fast + * as possible. We potentially only have one byte + the + * fifo length for this. Thus we want to flip to the new + * buffer and then mess around copying and allocating + * things. For the current case it doesn't matter but + * if you build a system where the sync irq isnt blocked + * by the kernel IRQ disable then you need only block the + * sync IRQ for the RT_LOCK area. + * + */ + ct=c->count; + + c->skb = c->skb2; + c->count = 0; + c->max = c->mtu; + if(c->skb) + { + c->dptr = c->skb->data; + c->max = c->mtu; + } + else + { + c->count= 0; + c->max = 0; + } + RT_UNLOCK; + + c->skb2 = dev_alloc_skb(c->mtu); + if(c->skb2==NULL) + printk(KERN_WARNING "%s: memory squeeze.\n", + c->netdevice->name); + else + { + skb_put(c->skb2,c->mtu); + } + c->stats.rx_packets++; + c->stats.rx_bytes+=ct; + + } + /* + * If we received a frame we must now process it. + */ + if(skb) + { + skb_trim(skb, ct); + c->rx_function(c,skb); + } + else + { + c->stats.rx_dropped++; + printk(KERN_ERR "%s: Lost a frame\n", c->netdevice->name); + } +} + +/* + * Cannot DMA over a 64K boundary on a PC + */ + +extern inline int spans_boundary(struct sk_buff *skb) +{ + unsigned long a=(unsigned long)skb->data; + a^=(a+skb->len); + if(a&0x00010000) /* If the 64K bit is different.. */ + { + printk("spanner\n"); + return 1; + } + return 0; +} + +/* + * Queue a packet for transmission. Because we have rather + * hard to hit interrupt latencies for the Z85230 per packet + * even in DMA mode we do the flip to DMA buffer if needed here + * not in the IRQ. + */ + +int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb) +{ + unsigned long flags; + if(c->tx_next_skb) + { + skb->dev->tbusy=1; + return 1; + } + + /* PC SPECIFIC - DMA limits */ + + /* + * If we will DMA the transmit and its gone over the ISA bus + * limit, then copy to the flip buffer + */ + + if(c->dma_tx && ((unsigned long)(virt_to_bus(skb->data+skb->len))>=16*1024*1024 || spans_boundary(skb))) + { + /* + * Send the flip buffer, and flip the flippy bit. + * We don't care which is used when just so long as + * we never use the same buffer twice in a row. Since + * only one buffer can be going out at a time the other + * has to be safe. + */ + c->tx_next_ptr=c->tx_dma_buf[c->tx_dma_used]; + c->tx_dma_used^=1; /* Flip temp buffer */ + memcpy(c->tx_next_ptr, skb->data, skb->len); + } + else + c->tx_next_ptr=skb->data; + RT_LOCK; + c->tx_next_skb=skb; + RT_UNLOCK; + + spin_lock_irqsave(&z8530_buffer_lock, flags); + z8530_tx_begin(c); + spin_unlock_irqrestore(&z8530_buffer_lock, flags); + return 0; +} + +EXPORT_SYMBOL(z8530_queue_xmit); + +struct net_device_stats *z8530_get_stats(struct z8530_channel *c) +{ + return &c->stats; +} + +EXPORT_SYMBOL(z8530_get_stats); + +#ifdef MODULE + +/* + * Module support + */ + +int init_module(void) +{ + printk(KERN_INFO "Generic Z85C30/Z85230 interface driver v0.02\n"); + return 0; +} + +void cleanup_module(void) +{ +} + +#endif diff -u --recursive --new-file v2.3.20/linux/drivers/net/wan/z85230.h linux/drivers/net/wan/z85230.h --- v2.3.20/linux/drivers/net/wan/z85230.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/z85230.h Mon Oct 11 10:13:25 1999 @@ -0,0 +1,446 @@ +/* + * Description of Z8530 Z85C30 and Z85230 communications chips + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1998 Alan Cox + */ + +#ifndef _Z8530_H +#define _Z8530_H + +/* Conversion routines to/from brg time constants from/to bits + * per second. + */ +#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2)) +#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2) + +/* The Zilog register set */ + +#define FLAG 0x7e + +/* Write Register 0 */ +#define R0 0 /* Register selects */ +#define R1 1 +#define R2 2 +#define R3 3 +#define R4 4 +#define R5 5 +#define R6 6 +#define R7 7 +#define R8 8 +#define R9 9 +#define R10 10 +#define R11 11 +#define R12 12 +#define R13 13 +#define R14 14 +#define R15 15 + +#define RPRIME 16 /* Indicate a prime register access on 230 */ + +#define NULLCODE 0 /* Null Code */ +#define POINT_HIGH 0x8 /* Select upper half of registers */ +#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */ +#define SEND_ABORT 0x18 /* HDLC Abort */ +#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */ +#define RES_Tx_P 0x28 /* Reset TxINT Pending */ +#define ERR_RES 0x30 /* Error Reset */ +#define RES_H_IUS 0x38 /* Reset highest IUS */ + +#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */ +#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */ +#define RES_EOM_L 0xC0 /* Reset EOM latch */ + +/* Write Register 1 */ + +#define EXT_INT_ENAB 0x1 /* Ext Int Enable */ +#define TxINT_ENAB 0x2 /* Tx Int Enable */ +#define PAR_SPEC 0x4 /* Parity is special condition */ + +#define RxINT_DISAB 0 /* Rx Int Disable */ +#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ +#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */ +#define INT_ERR_Rx 0x18 /* Int on error only */ + +#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */ +#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */ +#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */ + +/* Write Register #2 (Interrupt Vector) */ + +/* Write Register 3 */ + +#define RxENABLE 0x1 /* Rx Enable */ +#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */ +#define ADD_SM 0x4 /* Address Search Mode (SDLC) */ +#define RxCRC_ENAB 0x8 /* Rx CRC Enable */ +#define ENT_HM 0x10 /* Enter Hunt Mode */ +#define AUTO_ENAB 0x20 /* Auto Enables */ +#define Rx5 0x0 /* Rx 5 Bits/Character */ +#define Rx7 0x40 /* Rx 7 Bits/Character */ +#define Rx6 0x80 /* Rx 6 Bits/Character */ +#define Rx8 0xc0 /* Rx 8 Bits/Character */ + +/* Write Register 4 */ + +#define PAR_ENA 0x1 /* Parity Enable */ +#define PAR_EVEN 0x2 /* Parity Even/Odd* */ + +#define SYNC_ENAB 0 /* Sync Modes Enable */ +#define SB1 0x4 /* 1 stop bit/char */ +#define SB15 0x8 /* 1.5 stop bits/char */ +#define SB2 0xc /* 2 stop bits/char */ + +#define MONSYNC 0 /* 8 Bit Sync character */ +#define BISYNC 0x10 /* 16 bit sync character */ +#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */ +#define EXTSYNC 0x30 /* External Sync Mode */ + +#define X1CLK 0x0 /* x1 clock mode */ +#define X16CLK 0x40 /* x16 clock mode */ +#define X32CLK 0x80 /* x32 clock mode */ +#define X64CLK 0xC0 /* x64 clock mode */ + +/* Write Register 5 */ + +#define TxCRC_ENAB 0x1 /* Tx CRC Enable */ +#define RTS 0x2 /* RTS */ +#define SDLC_CRC 0x4 /* SDLC/CRC-16 */ +#define TxENAB 0x8 /* Tx Enable */ +#define SND_BRK 0x10 /* Send Break */ +#define Tx5 0x0 /* Tx 5 bits (or less)/character */ +#define Tx7 0x20 /* Tx 7 bits/character */ +#define Tx6 0x40 /* Tx 6 bits/character */ +#define Tx8 0x60 /* Tx 8 bits/character */ +#define DTR 0x80 /* DTR */ + +/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */ + +/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ + +/* Write Register 8 (transmit buffer) */ + +/* Write Register 9 (Master interrupt control) */ +#define VIS 1 /* Vector Includes Status */ +#define NV 2 /* No Vector */ +#define DLC 4 /* Disable Lower Chain */ +#define MIE 8 /* Master Interrupt Enable */ +#define STATHI 0x10 /* Status high */ +#define NORESET 0 /* No reset on write to R9 */ +#define CHRB 0x40 /* Reset channel B */ +#define CHRA 0x80 /* Reset channel A */ +#define FHWRES 0xc0 /* Force hardware reset */ + +/* Write Register 10 (misc control bits) */ +#define BIT6 1 /* 6 bit/8bit sync */ +#define LOOPMODE 2 /* SDLC Loop mode */ +#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */ +#define MARKIDLE 8 /* Mark/flag on idle */ +#define GAOP 0x10 /* Go active on poll */ +#define NRZ 0 /* NRZ mode */ +#define NRZI 0x20 /* NRZI mode */ +#define FM1 0x40 /* FM1 (transition = 1) */ +#define FM0 0x60 /* FM0 (transition = 0) */ +#define CRCPS 0x80 /* CRC Preset I/O */ + +/* Write Register 11 (Clock Mode control) */ +#define TRxCXT 0 /* TRxC = Xtal output */ +#define TRxCTC 1 /* TRxC = Transmit clock */ +#define TRxCBR 2 /* TRxC = BR Generator Output */ +#define TRxCDP 3 /* TRxC = DPLL output */ +#define TRxCOI 4 /* TRxC O/I */ +#define TCRTxCP 0 /* Transmit clock = RTxC pin */ +#define TCTRxCP 8 /* Transmit clock = TRxC pin */ +#define TCBR 0x10 /* Transmit clock = BR Generator output */ +#define TCDPLL 0x18 /* Transmit clock = DPLL output */ +#define RCRTxCP 0 /* Receive clock = RTxC pin */ +#define RCTRxCP 0x20 /* Receive clock = TRxC pin */ +#define RCBR 0x40 /* Receive clock = BR Generator output */ +#define RCDPLL 0x60 /* Receive clock = DPLL output */ +#define RTxCX 0x80 /* RTxC Xtal/No Xtal */ + +/* Write Register 12 (lower byte of baud rate generator time constant) */ + +/* Write Register 13 (upper byte of baud rate generator time constant) */ + +/* Write Register 14 (Misc control bits) */ +#define BRENABL 1 /* Baud rate generator enable */ +#define BRSRC 2 /* Baud rate generator source */ +#define DTRREQ 4 /* DTR/Request function */ +#define AUTOECHO 8 /* Auto Echo */ +#define LOOPBAK 0x10 /* Local loopback */ +#define SEARCH 0x20 /* Enter search mode */ +#define RMC 0x40 /* Reset missing clock */ +#define DISDPLL 0x60 /* Disable DPLL */ +#define SSBR 0x80 /* Set DPLL source = BR generator */ +#define SSRTxC 0xa0 /* Set DPLL source = RTxC */ +#define SFMM 0xc0 /* Set FM mode */ +#define SNRZI 0xe0 /* Set NRZI mode */ + +/* Write Register 15 (external/status interrupt control) */ +#define PRIME 1 /* R5' etc register access (Z85C30/230 only) */ +#define ZCIE 2 /* Zero count IE */ +#define FIFOE 4 /* Z85230 only */ +#define DCDIE 8 /* DCD IE */ +#define SYNCIE 0x10 /* Sync/hunt IE */ +#define CTSIE 0x20 /* CTS IE */ +#define TxUIE 0x40 /* Tx Underrun/EOM IE */ +#define BRKIE 0x80 /* Break/Abort IE */ + + +/* Read Register 0 */ +#define Rx_CH_AV 0x1 /* Rx Character Available */ +#define ZCOUNT 0x2 /* Zero count */ +#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ +#define DCD 0x8 /* DCD */ +#define SYNC_HUNT 0x10 /* Sync/hunt */ +#define CTS 0x20 /* CTS */ +#define TxEOM 0x40 /* Tx underrun */ +#define BRK_ABRT 0x80 /* Break/Abort */ + +/* Read Register 1 */ +#define ALL_SNT 0x1 /* All sent */ +/* Residue Data for 8 Rx bits/char programmed */ +#define RES3 0x8 /* 0/3 */ +#define RES4 0x4 /* 0/4 */ +#define RES5 0xc /* 0/5 */ +#define RES6 0x2 /* 0/6 */ +#define RES7 0xa /* 0/7 */ +#define RES8 0x6 /* 0/8 */ +#define RES18 0xe /* 1/8 */ +#define RES28 0x0 /* 2/8 */ +/* Special Rx Condition Interrupts */ +#define PAR_ERR 0x10 /* Parity error */ +#define Rx_OVR 0x20 /* Rx Overrun Error */ +#define CRC_ERR 0x40 /* CRC/Framing Error */ +#define END_FR 0x80 /* End of Frame (SDLC) */ + +/* Read Register 2 (channel b only) - Interrupt vector */ + +/* Read Register 3 (interrupt pending register) ch a only */ +#define CHBEXT 0x1 /* Channel B Ext/Stat IP */ +#define CHBTxIP 0x2 /* Channel B Tx IP */ +#define CHBRxIP 0x4 /* Channel B Rx IP */ +#define CHAEXT 0x8 /* Channel A Ext/Stat IP */ +#define CHATxIP 0x10 /* Channel A Tx IP */ +#define CHARxIP 0x20 /* Channel A Rx IP */ + +/* Read Register 8 (receive data register) */ + +/* Read Register 10 (misc status bits) */ +#define ONLOOP 2 /* On loop */ +#define LOOPSEND 0x10 /* Loop sending */ +#define CLK2MIS 0x40 /* Two clocks missing */ +#define CLK1MIS 0x80 /* One clock missing */ + +/* Read Register 12 (lower byte of baud rate generator constant) */ + +/* Read Register 13 (upper byte of baud rate generator constant) */ + +/* Read Register 15 (value of WR 15) */ + + +/* + * Interrupt handling functions for this SCC + */ + +struct z8530_channel; + +struct z8530_irqhandler +{ + void (*rx)(struct z8530_channel *); + void (*tx)(struct z8530_channel *); + void (*status)(struct z8530_channel *); +}; + +/* + * A channel of the Z8530 + */ + +struct z8530_channel +{ + struct z8530_irqhandler *irqs; /* IRQ handlers */ + /* + * Synchronous + */ + u16 count; /* Buyes received */ + u16 max; /* Most we can receive this frame */ + u16 mtu; /* MTU of the device */ + u8 *dptr; /* Pointer into rx buffer */ + struct sk_buff *skb; /* Buffer dptr points into */ + struct sk_buff *skb2; /* Pending buffer */ + u8 status; /* Current DCD */ + u8 sync; /* Set if in sync mode */ + + u8 regs[32]; /* Register map for the chip */ + u8 pendregs[32]; /* Pending register values */ + + struct sk_buff *tx_skb; /* Buffer being transmitted */ + struct sk_buff *tx_next_skb; /* Next transmit buffer */ + u8 *tx_ptr; /* Byte pointer into the buffer */ + u8 *tx_next_ptr; /* Next pointer to use */ + u8 *tx_dma_buf[2]; /* TX flip buffers for DMA */ + u8 tx_dma_used; /* Flip buffer usage toggler */ + u16 txcount; /* Count of bytes to transmit */ + + void (*rx_function)(struct z8530_channel *, struct sk_buff *); + + /* + * Sync DMA + */ + + u8 rxdma; /* DMA channels */ + u8 txdma; + u8 rxdma_on; /* DMA active if flag set */ + u8 txdma_on; + u8 dma_num; /* Buffer we are DMAing into */ + u8 dma_ready; /* Is the other buffer free */ + u8 dma_tx; /* TX is to use DMA */ + u8 *rx_buf[2]; /* The flip buffers */ + + /* + * System + */ + + struct z8530_dev *dev; /* Z85230 chip instance we are from */ + int ctrlio; /* I/O ports */ + int dataio; + + /* + * For PC we encode this way. + */ +#define Z8530_PORT_SLEEP 0x80000000 +#define Z8530_PORT_OF(x) ((x)&0xFFFF) + + u32 rx_overrun; /* Overruns - not done yet */ + u32 rx_crc_err; + + /* + * Bound device pointers + */ + + void *private; /* For our owner */ + struct net_device *netdevice; /* Network layer device */ + struct net_device_stats stats; /* Network layer statistics */ + + /* + * Async features + */ + + struct tty_struct *tty; /* Attached terminal */ + int line; /* Minor number */ + struct termios normal_termios; /* Terminal settings */ + struct termios callout_termios; + wait_queue_head_t open_wait; /* Tasks waiting to open */ + wait_queue_head_t close_wait; /* and for close to end */ + unsigned long event; /* Pending events */ + int fdcount; /* # of fd on device */ + int blocked_open; /* # of blocked opens */ + long session; /* Session of opening process */ + long pgrp; /* pgrp of opening process */ + int x_char; /* XON/XOF char */ + unsigned char *xmit_buf; /* Transmit pointer */ + int xmit_head; /* Transmit ring */ + int xmit_tail; + int xmit_cnt; + int flags; + int timeout; + int xmit_fifo_size; /* Transmit FIFO info */ + + int close_delay; /* Do we wait for drain on close ? */ + unsigned short closing_wait; + + /* We need to know the current clock divisor + * to read the bps rate the chip has currently + * loaded. + */ + + unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */ + int zs_baud; + + int magic; + int baud_base; /* Baud parameters */ + int custom_divisor; + + + unsigned char tx_active; /* character is being xmitted */ + unsigned char tx_stopped; /* output is suspended */ +}; + +/* + * Each Z853x0 device. + */ + +struct z8530_dev +{ + char *name; /* Device instance name */ + struct z8530_channel chanA; /* SCC channel A */ + struct z8530_channel chanB; /* SCC channel B */ + int type; +#define Z8530 0 /* NMOS dinosaur */ +#define Z85C30 1 /* CMOS - better */ +#define Z85230 2 /* CMOS with real FIFO */ + int irq; /* Interrupt for the device */ + int active; /* Soft interrupt enable - the Mac doesn't + always have a hard disable on its 8530s... */ +}; + + +/* + * Functions + */ + +extern u8 z8530_dead_port[]; +extern u8 z8530_hdlc_kilostream_85230[]; +extern u8 z8530_hdlc_kilostream[]; +extern void z8530_interrupt(int, void *, struct pt_regs *); +extern void z8530_describe(struct z8530_dev *, char *mapping,int io); +extern int z8530_init(struct z8530_dev *); +extern int z8530_shutdown(struct z8530_dev *); +extern int z8530_sync_open(struct net_device *, struct z8530_channel *); +extern int z8530_sync_close(struct net_device *, struct z8530_channel *); +extern int z8530_sync_dma_open(struct net_device *, struct z8530_channel *); +extern int z8530_sync_dma_close(struct net_device *, struct z8530_channel *); +extern int z8530_sync_txdma_open(struct net_device *, struct z8530_channel *); +extern int z8530_sync_txdma_close(struct net_device *, struct z8530_channel *); +extern int z8530_channel_load(struct z8530_channel *, u8 *); +extern int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb); +extern struct net_device_stats *z8530_get_stats(struct z8530_channel *c); +extern void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb); + + +/* + * Standard interrupt vector sets + */ + +struct z8530_irqhandler z8530_sync, z8530_async, z8530_nop; + +/* + * Asynchronous Interfacing + */ + +#define SERIAL_MAGIC 0x5301 + +/* + * The size of the serial xmit buffer is 1 page, or 4096 bytes + */ + +#define SERIAL_XMIT_SIZE 4096 +#define WAKEUP_CHARS 256 + +/* + * Events are used to schedule things to happen at timer-interrupt + * time, instead of at rs interrupt time. + */ +#define RS_EVENT_WRITE_WAKEUP 0 + +/* Internal flags used only by kernel/chr_drv/serial.c */ +#define ZILOG_INITIALIZED 0x80000000 /* Serial port was initialized */ +#define ZILOG_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ +#define ZILOG_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ +#define ZILOG_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ +#define ZILOG_CLOSING 0x08000000 /* Serial port is closing */ +#define ZILOG_CTS_FLOW 0x04000000 /* Do CTS flow control */ +#define ZILOG_CHECK_CD 0x02000000 /* i.e., CLOCAL */ + +#endif /* !(_Z8530_H) */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/x25_asy.c linux/drivers/net/x25_asy.c --- v2.3.20/linux/drivers/net/x25_asy.c Thu Aug 26 13:05:38 1999 +++ linux/drivers/net/x25_asy.c Wed Dec 31 16:00:00 1969 @@ -1,943 +0,0 @@ -/* - * Things to sort out: - * - * o tbusy handling - * o allow users to set the parameters - * o sync/async switching ? - * - * Note: This does _not_ implement CCITT X.25 asynchronous framing - * recommendations. Its primarily for testing purposes. If you wanted - * to do CCITT then in theory all you need is to nick the HDLC async - * checksum routines from ppp.c - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "x25_asy.h" - -typedef struct x25_ctrl { - char if_name[8]; /* "xasy0\0" .. "xasy99999\0" */ - struct x25_asy ctrl; /* X.25 things */ - struct net_device dev; /* the device */ -} x25_asy_ctrl_t; - -static x25_asy_ctrl_t **x25_asy_ctrls = NULL; - -int x25_asy_maxdev = SL_NRUNIT; /* Can be overridden with insmod! */ -MODULE_PARM(x25_asy_maxdev, "i"); - -static struct tty_ldisc x25_ldisc; - -static int x25_asy_esc(unsigned char *p, unsigned char *d, int len); -static void x25_asy_unesc(struct x25_asy *sl, unsigned char c); - -/* Find a free X.25 channel, and link in this `tty' line. */ -static inline struct x25_asy *x25_asy_alloc(void) -{ - x25_asy_ctrl_t *slp = NULL; - int i; - - if (x25_asy_ctrls == NULL) - return NULL; /* Master array missing ! */ - - for (i = 0; i < x25_asy_maxdev; i++) - { - slp = x25_asy_ctrls[i]; - /* Not allocated ? */ - if (slp == NULL) - break; - /* Not in use ? */ - if (!test_and_set_bit(SLF_INUSE, &slp->ctrl.flags)) - break; - } - /* SLP is set.. */ - - /* Sorry, too many, all slots in use */ - if (i >= x25_asy_maxdev) - return NULL; - - /* If no channels are available, allocate one */ - if (!slp && - (x25_asy_ctrls[i] = (x25_asy_ctrl_t *)kmalloc(sizeof(x25_asy_ctrl_t), - GFP_KERNEL)) != NULL) { - slp = x25_asy_ctrls[i]; - memset(slp, 0, sizeof(x25_asy_ctrl_t)); - - /* Initialize channel control data */ - set_bit(SLF_INUSE, &slp->ctrl.flags); - slp->ctrl.tty = NULL; - sprintf(slp->if_name, "x25asy%d", i); - slp->dev.name = slp->if_name; - slp->dev.base_addr = i; - slp->dev.priv = (void*)&(slp->ctrl); - slp->dev.next = NULL; - slp->dev.init = x25_asy_init; - } - if (slp != NULL) - { - - /* register device so that it can be ifconfig'ed */ - /* x25_asy_init() will be called as a side-effect */ - /* SIDE-EFFECT WARNING: x25_asy_init() CLEARS slp->ctrl ! */ - - if (register_netdev(&(slp->dev)) == 0) - { - /* (Re-)Set the INUSE bit. Very Important! */ - set_bit(SLF_INUSE, &slp->ctrl.flags); - slp->ctrl.dev = &(slp->dev); - slp->dev.priv = (void*)&(slp->ctrl); - return (&(slp->ctrl)); - } - else - { - clear_bit(SLF_INUSE,&(slp->ctrl.flags)); - printk("x25_asy_alloc() - register_netdev() failure.\n"); - } - } - return NULL; -} - - -/* Free an X.25 channel. */ - -static inline void x25_asy_free(struct x25_asy *sl) -{ - /* Free all X.25 frame buffers. */ - if (sl->rbuff) { - kfree(sl->rbuff); - } - sl->rbuff = NULL; - if (sl->xbuff) { - kfree(sl->xbuff); - } - sl->xbuff = NULL; - - if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) { - printk("%s: x25_asy_free for already free unit.\n", sl->dev->name); - } -} - -/* MTU has been changed by the IP layer. Unfortunately we are not told - about this, but we spot it ourselves and fix things up. We could be - in an upcall from the tty driver, or in an ip packet queue. */ - -static void x25_asy_changed_mtu(struct x25_asy *sl) -{ - struct net_device *dev = sl->dev; - unsigned char *xbuff, *rbuff, *oxbuff, *orbuff; - int len; - unsigned long flags; - - len = dev->mtu * 2; - - xbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC); - rbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC); - - if (xbuff == NULL || rbuff == NULL) - { - printk("%s: unable to grow X.25 buffers, MTU change cancelled.\n", - sl->dev->name); - dev->mtu = sl->mtu; - if (xbuff != NULL) - kfree(xbuff); - if (rbuff != NULL) - kfree(rbuff); - return; - } - - save_flags(flags); - cli(); - - oxbuff = sl->xbuff; - sl->xbuff = xbuff; - orbuff = sl->rbuff; - sl->rbuff = rbuff; - - if (sl->xleft) { - if (sl->xleft <= len) { - memcpy(sl->xbuff, sl->xhead, sl->xleft); - } else { - sl->xleft = 0; - sl->tx_dropped++; - } - } - sl->xhead = sl->xbuff; - - if (sl->rcount) { - if (sl->rcount <= len) { - memcpy(sl->rbuff, orbuff, sl->rcount); - } else { - sl->rcount = 0; - sl->rx_over_errors++; - set_bit(SLF_ERROR, &sl->flags); - } - } - sl->mtu = dev->mtu; - - sl->buffsize = len; - - restore_flags(flags); - - if (oxbuff != NULL) - kfree(oxbuff); - if (orbuff != NULL) - kfree(orbuff); -} - - -/* Set the "sending" flag. This must be atomic, hence the ASM. */ - -static inline void x25_asy_lock(struct x25_asy *sl) -{ - if (test_and_set_bit(0, (void *) &sl->dev->tbusy)) - printk("%s: trying to lock already locked device!\n", sl->dev->name); -} - - -/* Clear the "sending" flag. This must be atomic, hence the ASM. */ - -static inline void x25_asy_unlock(struct x25_asy *sl) -{ - if (!test_and_clear_bit(0, (void *)&sl->dev->tbusy)) - printk("%s: trying to unlock already unlocked device!\n", sl->dev->name); -} - -/* Send one completely decapsulated IP datagram to the IP layer. */ - -static void x25_asy_bump(struct x25_asy *sl) -{ - struct sk_buff *skb; - int count; - int err; - - count = sl->rcount; - sl->rx_bytes+=count; - - skb = dev_alloc_skb(count+1); - if (skb == NULL) - { - printk("%s: memory squeeze, dropping packet.\n", sl->dev->name); - sl->rx_dropped++; - return; - } - skb_push(skb,1); /* LAPB internal control */ - skb->dev = sl->dev; - memcpy(skb_put(skb,count), sl->rbuff, count); - skb->mac.raw=skb->data; - skb->protocol=htons(ETH_P_X25); - if((err=lapb_data_received(sl,skb))!=LAPB_OK) - { - kfree_skb(skb); - printk(KERN_DEBUG "x25_asy: data received err - %d\n",err); - } - else - { - netif_rx(skb); - sl->rx_packets++; - } -} - -/* Encapsulate one IP datagram and stuff into a TTY queue. */ -static void x25_asy_encaps(struct x25_asy *sl, unsigned char *icp, int len) -{ - unsigned char *p; - int actual, count; - - - if (sl->mtu != sl->dev->mtu) { /* Someone has been ifconfigging */ - - x25_asy_changed_mtu(sl); - } - - if (len > sl->mtu) - { /* Sigh, shouldn't occur BUT ... */ - len = sl->mtu; - printk ("%s: truncating oversized transmit packet!\n", sl->dev->name); - sl->tx_dropped++; - x25_asy_unlock(sl); - return; - } - - p = icp; - count = x25_asy_esc(p, (unsigned char *) sl->xbuff, len); - - /* Order of next two lines is *very* important. - * When we are sending a little amount of data, - * the transfer may be completed inside driver.write() - * routine, because it's running with interrupts enabled. - * In this case we *never* got WRITE_WAKEUP event, - * if we did not request it before write operation. - * 14 Oct 1994 Dmitry Gorodchanin. - */ - sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); - actual = sl->tty->driver.write(sl->tty, 0, sl->xbuff, count); - sl->xleft = count - actual; - sl->xhead = sl->xbuff + actual; - /* VSV */ - clear_bit(SLF_OUTWAIT, &sl->flags); /* reset outfill flag */ -} - -/* - * Called by the driver when there's room for more data. If we have - * more packets to send, we send them here. - */ -static void x25_asy_write_wakeup(struct tty_struct *tty) -{ - int actual; - struct x25_asy *sl = (struct x25_asy *) tty->disc_data; - - /* First make sure we're connected. */ - if (!sl || sl->magic != X25_ASY_MAGIC || !sl->dev->start) - return; - - if (sl->xleft <= 0) - { - /* Now serial buffer is almost free & we can start - * transmission of another packet */ - sl->tx_packets++; - tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - x25_asy_unlock(sl); - mark_bh(NET_BH); - return; - } - - actual = tty->driver.write(tty, 0, sl->xhead, sl->xleft); - sl->xleft -= actual; - sl->xhead += actual; -} - -/* Encapsulate an IP datagram and kick it into a TTY queue. */ - -static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct x25_asy *sl = (struct x25_asy*)(dev->priv); - int err; - - if (!dev->start) - { - printk("%s: xmit call when iface is down\n", dev->name); - return 1; - } - - switch(skb->data[0]) - { - case 0x00:break; - case 0x01: /* Connection request .. do nothing */ - if((err=lapb_connect_request(sl))!=LAPB_OK) - printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err); - kfree_skb(skb); - return 0; - case 0x02: /* Disconnect request .. do nothing - hang up ?? */ - if((err=lapb_disconnect_request(sl))!=LAPB_OK) - printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err); - default: - kfree_skb(skb); - return 0; - } - skb_pull(skb,1); /* Remove control byte */ - /* - * If we are busy already- too bad. We ought to be able - * to queue things at this point, to allow for a little - * frame buffer. Oh well... - * ----------------------------------------------------- - * I hate queues in X.25 driver. May be it's efficient, - * but for me latency is more important. ;) - * So, no queues ! - * 14 Oct 1994 Dmitry Gorodchanin. - */ - if (dev->tbusy) { - /* May be we must check transmitter timeout here ? - * 14 Oct 1994 Dmitry Gorodchanin. - */ -#ifdef SL_CHECK_TRANSMIT - if (jiffies - dev->trans_start < 20 * HZ) { - /* 20 sec timeout not reached */ - return 1; - } - printk("%s: transmit timed out, %s?\n", dev->name, - (sl->tty->driver.chars_in_buffer(sl->tty) || sl->xleft) ? - "bad line quality" : "driver error"); - sl->xleft = 0; - sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - x25_asy_unlock(sl); -#else - return 1; -#endif - } - - if((err=lapb_data_request(sl,skb))!=LAPB_OK) - { - printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err); - kfree_skb(skb); - return 0; - } - return 0; -} - - -/* - * LAPB interface boilerplate - */ - -/* - * Called when I frame data arrives. We did the work above - throw it - * at the net layer. - */ - -static void x25_asy_data_indication(void *token, struct sk_buff *skb) -{ - netif_rx(skb); -} - -/* - * Data has emerged from the LAPB protocol machine. We don't handle - * busy cases too well. Its tricky to see how to do this nicely - - * perhaps lapb should allow us to bounce this ? - */ - -static void x25_asy_data_transmit(void *token, struct sk_buff *skb) -{ - struct x25_asy *sl=token; - if(sl->dev->tbusy) - { - printk(KERN_ERR "x25_asy: tbusy drop\n"); - kfree_skb(skb); - return; - } - /* We were not busy, so we are now... :-) */ - if (skb != NULL) - { - x25_asy_lock(sl); - sl->tx_bytes+=skb->len; - x25_asy_encaps(sl, skb->data, skb->len); - dev_kfree_skb(skb); - } -} - -/* - * LAPB connection establish/down information. - */ - -static void x25_asy_connected(void *token, int reason) -{ - struct x25_asy *sl = token; - struct sk_buff *skb; - unsigned char *ptr; - - if ((skb = dev_alloc_skb(1)) == NULL) { - printk(KERN_ERR "lapbeth: out of memory\n"); - return; - } - - ptr = skb_put(skb, 1); - *ptr = 0x01; - - skb->dev = sl->dev; - skb->protocol = htons(ETH_P_X25); - skb->mac.raw = skb->data; - skb->pkt_type = PACKET_HOST; - - netif_rx(skb); -} - -static void x25_asy_disconnected(void *token, int reason) -{ - struct x25_asy *sl = token; - struct sk_buff *skb; - unsigned char *ptr; - - if ((skb = dev_alloc_skb(1)) == NULL) { - printk(KERN_ERR "x25_asy: out of memory\n"); - return; - } - - ptr = skb_put(skb, 1); - *ptr = 0x02; - - skb->dev = sl->dev; - skb->protocol = htons(ETH_P_X25); - skb->mac.raw = skb->data; - skb->pkt_type = PACKET_HOST; - - netif_rx(skb); -} - - -/* Open the low-level part of the X.25 channel. Easy! */ - -static int x25_asy_open(struct net_device *dev) -{ - struct lapb_register_struct x25_asy_callbacks; - struct x25_asy *sl = (struct x25_asy*)(dev->priv); - unsigned long len; - int err; - - if (sl->tty == NULL) - return -ENODEV; - - /* - * Allocate the X.25 frame buffers: - * - * rbuff Receive buffer. - * xbuff Transmit buffer. - */ - - len = dev->mtu * 2; - - sl->rbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL); - if (sl->rbuff == NULL) { - goto norbuff; - } - sl->xbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL); - if (sl->xbuff == NULL) { - goto noxbuff; - } - sl->mtu = dev->mtu; - sl->buffsize = len; - sl->rcount = 0; - sl->xleft = 0; - sl->flags &= (1 << SLF_INUSE); /* Clear ESCAPE & ERROR flags */ - - dev->tbusy = 0; -/* dev->flags |= IFF_UP; */ - dev->start = 1; - - /* - * Now attach LAPB - */ - - x25_asy_callbacks.connect_confirmation=x25_asy_connected; - x25_asy_callbacks.connect_indication=x25_asy_connected; - x25_asy_callbacks.disconnect_confirmation=x25_asy_disconnected; - x25_asy_callbacks.disconnect_indication=x25_asy_disconnected; - x25_asy_callbacks.data_indication=x25_asy_data_indication; - x25_asy_callbacks.data_transmit=x25_asy_data_transmit; - - if((err=lapb_register(sl, &x25_asy_callbacks))==LAPB_OK) - return 0; - - /* Cleanup */ - kfree(sl->xbuff); -noxbuff: - kfree(sl->rbuff); -norbuff: - return -ENOMEM; -} - - -/* Close the low-level part of the X.25 channel. Easy! */ -static int x25_asy_close(struct net_device *dev) -{ - struct x25_asy *sl = (struct x25_asy*)(dev->priv); - int err; - - if (sl->tty == NULL) - return -EBUSY; - - sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - dev->tbusy = 1; - dev->start = 0; - if((err=lapb_unregister(sl))!=LAPB_OK) - printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",err); - -/* dev->flags &= ~IFF_UP; */ - return 0; -} - -static int x25_asy_receive_room(struct tty_struct *tty) -{ - return 65536; /* We can handle an infinite amount of data. :-) */ -} - -/* - * Handle the 'receiver data ready' interrupt. - * This function is called by the 'tty_io' module in the kernel when - * a block of X.25 data has been received, which can now be decapsulated - * and sent on to some IP layer for further processing. - */ - -static void x25_asy_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) -{ - struct x25_asy *sl = (struct x25_asy *) tty->disc_data; - - if (!sl || sl->magic != X25_ASY_MAGIC || !sl->dev->start) - return; - - /* - * Argh! mtu change time! - costs us the packet part received - * at the change - */ - if (sl->mtu != sl->dev->mtu) { - - x25_asy_changed_mtu(sl); - } - - /* Read the characters out of the buffer */ - while (count--) { - if (fp && *fp++) { - if (!test_and_set_bit(SLF_ERROR, &sl->flags)) { - sl->rx_errors++; - } - cp++; - continue; - } - x25_asy_unesc(sl, *cp++); - } -} - -/* - * Open the high-level part of the X.25 channel. - * This function is called by the TTY module when the - * X.25 line discipline is called for. Because we are - * sure the tty line exists, we only have to link it to - * a free X.25 channel... - */ - -static int x25_asy_open_tty(struct tty_struct *tty) -{ - struct x25_asy *sl = (struct x25_asy *) tty->disc_data; - int err; - - /* First make sure we're not already connected. */ - if (sl && sl->magic == X25_ASY_MAGIC) { - return -EEXIST; - } - - /* OK. Find a free X.25 channel to use. */ - if ((sl = x25_asy_alloc()) == NULL) { - return -ENFILE; - } - - sl->tty = tty; - tty->disc_data = sl; - if (tty->driver.flush_buffer) { - tty->driver.flush_buffer(tty); - } - if (tty->ldisc.flush_buffer) { - tty->ldisc.flush_buffer(tty); - } - - /* Restore default settings */ - sl->dev->type = ARPHRD_X25; - - /* Perform the low-level X.25 async init */ - if ((err = x25_asy_open(sl->dev))) - return err; - - MOD_INC_USE_COUNT; - - /* Done. We have linked the TTY line to a channel. */ - return sl->dev->base_addr; -} - - -/* - * Close down an X.25 channel. - * This means flushing out any pending queues, and then restoring the - * TTY line discipline to what it was before it got hooked to X.25 - * (which usually is TTY again). - */ -static void x25_asy_close_tty(struct tty_struct *tty) -{ - struct x25_asy *sl = (struct x25_asy *) tty->disc_data; - - /* First make sure we're connected. */ - if (!sl || sl->magic != X25_ASY_MAGIC) - return; - - if (sl->dev->flags & IFF_UP) - { - (void) dev_close(sl->dev); - } - - tty->disc_data = 0; - sl->tty = NULL; - x25_asy_free(sl); - unregister_netdev(sl->dev); - MOD_DEC_USE_COUNT; -} - - -static struct net_device_stats *x25_asy_get_stats(struct net_device *dev) -{ - static struct net_device_stats stats; - struct x25_asy *sl = (struct x25_asy*)(dev->priv); - - memset(&stats, 0, sizeof(struct net_device_stats)); - - stats.rx_packets = sl->rx_packets; - stats.tx_packets = sl->tx_packets; - stats.rx_bytes = sl->rx_bytes; - stats.tx_bytes = sl->tx_bytes; - stats.rx_dropped = sl->rx_dropped; - stats.tx_dropped = sl->tx_dropped; - stats.tx_errors = sl->tx_errors; - stats.rx_errors = sl->rx_errors; - stats.rx_over_errors = sl->rx_over_errors; - return (&stats); -} - - - /************************************************************************ - * STANDARD X.25 ENCAPSULATION * - ************************************************************************/ - -int x25_asy_esc(unsigned char *s, unsigned char *d, int len) -{ - unsigned char *ptr = d; - unsigned char c; - - /* - * Send an initial END character to flush out any - * data that may have accumulated in the receiver - * due to line noise. - */ - - *ptr++ = X25_END; /* Send 10111110 bit seq */ - - /* - * For each byte in the packet, send the appropriate - * character sequence, according to the X.25 protocol. - */ - - while (len-- > 0) - { - switch(c = *s++) - { - case X25_END: - *ptr++ = X25_ESC; - *ptr++ = X25_ESCAPE(X25_END); - break; - case X25_ESC: - *ptr++ = X25_ESC; - *ptr++ = X25_ESCAPE(X25_ESC); - break; - default: - *ptr++ = c; - break; - } - } - *ptr++ = X25_END; - return (ptr - d); -} - -static void x25_asy_unesc(struct x25_asy *sl, unsigned char s) -{ - - switch(s) - { - case X25_END: - if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) - { - x25_asy_bump(sl); - } - clear_bit(SLF_ESCAPE, &sl->flags); - sl->rcount = 0; - return; - - case X25_ESC: - set_bit(SLF_ESCAPE, &sl->flags); - return; - - case X25_ESCAPE(X25_ESC): - case X25_ESCAPE(X25_END): - if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) - s = X25_UNESCAPE(s); - break; - } - if (!test_bit(SLF_ERROR, &sl->flags)) - { - if (sl->rcount < sl->buffsize) - { - sl->rbuff[sl->rcount++] = s; - return; - } - sl->rx_over_errors++; - set_bit(SLF_ERROR, &sl->flags); - } -} - - -/* Perform I/O control on an active X.25 channel. */ -static int x25_asy_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg) -{ - struct x25_asy *sl = (struct x25_asy *) tty->disc_data; - - /* First make sure we're connected. */ - if (!sl || sl->magic != X25_ASY_MAGIC) { - return -EINVAL; - } - - switch(cmd) - { - case SIOCGIFNAME: - if(copy_to_user(arg, sl->dev->name, strlen(sl->dev->name) + 1)) - return -EFAULT; - return 0; - - case SIOCSIFHWADDR: - return -EINVAL; - - /* Allow stty to read, but not set, the serial port */ - case TCGETS: - case TCGETA: - return n_tty_ioctl(tty, (struct file *) file, cmd, (unsigned long) arg); - - default: - return -ENOIOCTLCMD; - } -} - -static int x25_asy_open_dev(struct net_device *dev) -{ - struct x25_asy *sl = (struct x25_asy*)(dev->priv); - if(sl->tty==NULL) - return -ENODEV; - return 0; -} - -/* Initialize X.25 control device -- register X.25 line discipline */ -#ifdef MODULE -static int x25_asy_init_ctrl_dev(void) -#else /* !MODULE */ -int __init x25_asy_init_ctrl_dev(struct net_device *dummy) -#endif /* !MODULE */ -{ - int status; - - if (x25_asy_maxdev < 4) x25_asy_maxdev = 4; /* Sanity */ - - printk(KERN_INFO "X.25 async: version 0.00 ALPHA (dynamic channels, max=%d).\n", - x25_asy_maxdev ); - x25_asy_ctrls = (x25_asy_ctrl_t **) kmalloc(sizeof(void*)*x25_asy_maxdev, GFP_KERNEL); - if (x25_asy_ctrls == NULL) - { - printk("X25 async: Can't allocate x25_asy_ctrls[] array! Uaargh! (-> No X.25 available)\n"); - return -ENOMEM; - } - - /* Clear the pointer array, we allocate devices when we need them */ - memset(x25_asy_ctrls, 0, sizeof(void*)*x25_asy_maxdev); /* Pointers */ - - /* Fill in our line protocol discipline, and register it */ - memset(&x25_ldisc, 0, sizeof(x25_ldisc)); - x25_ldisc.magic = TTY_LDISC_MAGIC; - x25_ldisc.name = "X.25"; - x25_ldisc.flags = 0; - x25_ldisc.open = x25_asy_open_tty; - x25_ldisc.close = x25_asy_close_tty; - x25_ldisc.read = NULL; - x25_ldisc.write = NULL; - x25_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, - unsigned int, unsigned long)) x25_asy_ioctl; - x25_ldisc.poll = NULL; - x25_ldisc.receive_buf = x25_asy_receive_buf; - x25_ldisc.receive_room = x25_asy_receive_room; - x25_ldisc.write_wakeup = x25_asy_write_wakeup; - if ((status = tty_register_ldisc(N_X25, &x25_ldisc)) != 0) { - printk("X.25 async: can't register line discipline (err = %d)\n", status); - } - -#ifdef MODULE - return status; -#else - /* Return "not found", so that dev_init() will unlink - * the placeholder device entry for us. - */ - return ENODEV; -#endif - } - - -/* Initialise the X.25 driver. Called by the device init code */ - -int x25_asy_init(struct net_device *dev) -{ - struct x25_asy *sl = (struct x25_asy*)(dev->priv); - - if (sl == NULL) /* Allocation failed ?? */ - return -ENODEV; - - /* Set up the control block. (And clear statistics) */ - - memset(sl, 0, sizeof (struct x25_asy)); - sl->magic = X25_ASY_MAGIC; - sl->dev = dev; - - /* - * Finish setting up the DEVICE info. - */ - - dev->mtu = SL_MTU; - dev->hard_start_xmit = x25_asy_xmit; - dev->open = x25_asy_open_dev; - dev->stop = x25_asy_close; - dev->get_stats = x25_asy_get_stats; - dev->hard_header_len = 0; - dev->addr_len = 0; - dev->type = ARPHRD_X25; - dev->tx_queue_len = 10; - - dev_init_buffers(dev); - - /* New-style flags. */ - dev->flags = IFF_NOARP; - - return 0; -} -#ifdef MODULE - -int -init_module(void) -{ - return x25_asy_init_ctrl_dev(); -} - -void -cleanup_module(void) -{ - int i; - - if (x25_asy_ctrls != NULL) - { - for (i = 0; i < x25_asy_maxdev; i++) - { - if (x25_asy_ctrls[i]) - { - /* - * VSV = if dev->start==0, then device - * unregistered while close proc. - */ - if (x25_asy_ctrls[i]->dev.start) - unregister_netdev(&(x25_asy_ctrls[i]->dev)); - - kfree(x25_asy_ctrls[i]); - x25_asy_ctrls[i] = NULL; - } - } - kfree(x25_asy_ctrls); - x25_asy_ctrls = NULL; - } - if ((i = tty_register_ldisc(N_X25, NULL))) - { - printk("X.25 async: can't unregister line discipline (err = %d)\n", i); - } -} -#endif /* MODULE */ - diff -u --recursive --new-file v2.3.20/linux/drivers/net/x25_asy.h linux/drivers/net/x25_asy.h --- v2.3.20/linux/drivers/net/x25_asy.h Wed Aug 18 11:36:45 1999 +++ linux/drivers/net/x25_asy.h Wed Dec 31 16:00:00 1969 @@ -1,58 +0,0 @@ -#ifndef _LINUX_X25_ASY_H -#define _LINUX_X25_ASY_H - -/* X.25 asy configuration. */ -#define SL_NRUNIT 256 /* MAX number of X.25 channels; - This can be overridden with - insmod -ox25_asy_maxdev=nnn */ -#define SL_MTU 256 - -/* X25 async protocol characters. */ -#define X25_END 0x7E /* indicates end of frame */ -#define X25_ESC 0x7D /* indicates byte stuffing */ -#define X25_ESCAPE(x) ((x)^0x20) -#define X25_UNESCAPE(x) ((x)^0x20) - - -struct x25_asy { - int magic; - - /* Various fields. */ - struct tty_struct *tty; /* ptr to TTY structure */ - struct net_device *dev; /* easy for intr handling */ - - /* These are pointers to the malloc()ed frame buffers. */ - unsigned char *rbuff; /* receiver buffer */ - int rcount; /* received chars counter */ - unsigned char *xbuff; /* transmitter buffer */ - unsigned char *xhead; /* pointer to next byte to XMIT */ - int xleft; /* bytes left in XMIT queue */ - - /* X.25 interface statistics. */ - unsigned long rx_packets; /* inbound frames counter */ - unsigned long tx_packets; /* outbound frames counter */ - unsigned long rx_bytes; /* inbound byte counte */ - unsigned long tx_bytes; /* outbound byte counter */ - unsigned long rx_errors; /* Parity, etc. errors */ - unsigned long tx_errors; /* Planned stuff */ - unsigned long rx_dropped; /* No memory for skb */ - unsigned long tx_dropped; /* When MTU change */ - unsigned long rx_over_errors; /* Frame bigger then X.25 buf. */ - - int mtu; /* Our mtu (to spot changes!) */ - int buffsize; /* Max buffers sizes */ - - unsigned int flags; /* Flag values/ mode etc */ -#define SLF_INUSE 0 /* Channel in use */ -#define SLF_ESCAPE 1 /* ESC received */ -#define SLF_ERROR 2 /* Parity, etc. error */ -#define SLF_OUTWAIT 4 /* Waiting for output */ -}; - - - -#define X25_ASY_MAGIC 0x5303 - -extern int x25_asy_init(struct net_device *dev); - -#endif /* _LINUX_X25_ASY.H */ diff -u --recursive --new-file v2.3.20/linux/drivers/net/z85230.c linux/drivers/net/z85230.c --- v2.3.20/linux/drivers/net/z85230.c Fri Sep 10 23:57:30 1999 +++ linux/drivers/net/z85230.c Wed Dec 31 16:00:00 1969 @@ -1,1470 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * (c) Copyright 1998 Building Number Three Ltd - * - * Development of this driver was funded by Equiinet Ltd - * http://www.equiinet.com - * - * ChangeLog: - * - * Asynchronous mode dropped for 2.2. For 2.3 we will attempt the - * unification of all the Z85x30 asynchronous drivers for real. - * - * To Do: - * - * Finish DMA mode support. - * - * Performance - * - * Z85230: - * Non DMA you want a 486DX50 or better to do 64Kbits. 9600 baud - * X.25 is not unrealistic on all machines. DMA mode can in theory - * handle T1/E1 quite nicely. In practice the limit seems to be about - * 512Kbit->1Mbit depending on motherboard. - * - * Z85C30: - * 64K will take DMA, 9600 baud X.25 should be ok. - * - * Z8530: - * Synchronous mode without DMA is unlikely to pass about 2400 baud. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define RT_LOCK -#define RT_UNLOCK -#include - -#include "z85230.h" -#include "syncppp.h" - - -static spinlock_t z8530_buffer_lock = SPIN_LOCK_UNLOCKED; - -/* - * Provided port access methods. The Comtrol SV11 requires no delays - * between accesses and uses PC I/O. Some drivers may need a 5uS delay - */ - -extern __inline__ int z8530_read_port(int p) -{ - u8 r=inb(Z8530_PORT_OF(p)); - if(p&Z8530_PORT_SLEEP) /* gcc should figure this out efficiently ! */ - udelay(5); - return r; -} - -extern __inline__ void z8530_write_port(int p, u8 d) -{ - outb(d,Z8530_PORT_OF(p)); - if(p&Z8530_PORT_SLEEP) - udelay(5); -} - - - -static void z8530_rx_done(struct z8530_channel *c); -static void z8530_tx_done(struct z8530_channel *c); - - -/* - * Port accesses - */ - -extern inline u8 read_zsreg(struct z8530_channel *c, u8 reg) -{ - u8 r; - unsigned long flags; - save_flags(flags); - cli(); - if(reg) - z8530_write_port(c->ctrlio, reg); - r=z8530_read_port(c->ctrlio); - restore_flags(flags); - return r; -} - -extern inline u8 read_zsdata(struct z8530_channel *c) -{ - u8 r; - r=z8530_read_port(c->dataio); - return r; -} - -extern inline void write_zsreg(struct z8530_channel *c, u8 reg, u8 val) -{ - unsigned long flags; - save_flags(flags); - cli(); - if(reg) - z8530_write_port(c->ctrlio, reg); - z8530_write_port(c->ctrlio, val); - restore_flags(flags); -} - -extern inline void write_zsctrl(struct z8530_channel *c, u8 val) -{ - z8530_write_port(c->ctrlio, val); -} - -extern inline void write_zsdata(struct z8530_channel *c, u8 val) -{ - z8530_write_port(c->dataio, val); -} - -/* - * Register loading parameters for a dead port - */ - -u8 z8530_dead_port[]= -{ - 255 -}; - -EXPORT_SYMBOL(z8530_dead_port); - -/* - * Register loading parameters for currently supported circuit types - */ - - -/* - * Data clocked by telco end. This is the correct data for the UK - * "kilostream" service, and most other similar services. - */ - -u8 z8530_hdlc_kilostream[]= -{ - 4, SYNC_ENAB|SDLC|X1CLK, - 2, 0, /* No vector */ - 1, 0, - 3, ENT_HM|RxCRC_ENAB|Rx8, - 5, TxCRC_ENAB|RTS|TxENAB|Tx8|DTR, - 9, 0, /* Disable interrupts */ - 6, 0xFF, - 7, FLAG, - 10, ABUNDER|NRZ|CRCPS,/*MARKIDLE ??*/ - 11, TCTRxCP, - 14, DISDPLL, - 15, DCDIE|SYNCIE|CTSIE|TxUIE|BRKIE, - 1, EXT_INT_ENAB|TxINT_ENAB|INT_ALL_Rx, - 9, NV|MIE|NORESET, - 255 -}; - -EXPORT_SYMBOL(z8530_hdlc_kilostream); - -/* - * As above but for enhanced chips. - */ - -u8 z8530_hdlc_kilostream_85230[]= -{ - 4, SYNC_ENAB|SDLC|X1CLK, - 2, 0, /* No vector */ - 1, 0, - 3, ENT_HM|RxCRC_ENAB|Rx8, - 5, TxCRC_ENAB|RTS|TxENAB|Tx8|DTR, - 9, 0, /* Disable interrupts */ - 6, 0xFF, - 7, FLAG, - 10, ABUNDER|NRZ|CRCPS, /* MARKIDLE?? */ - 11, TCTRxCP, - 14, DISDPLL, - 15, DCDIE|SYNCIE|CTSIE|TxUIE|BRKIE, - 1, EXT_INT_ENAB|TxINT_ENAB|INT_ALL_Rx, - 9, NV|MIE|NORESET, - 23, 3, /* Extended mode AUTO TX and EOM*/ - - 255 -}; - -EXPORT_SYMBOL(z8530_hdlc_kilostream_85230); - -/* - * Flush the FIFO - */ - -static void z8530_flush_fifo(struct z8530_channel *c) -{ - read_zsreg(c, R1); - read_zsreg(c, R1); - read_zsreg(c, R1); - read_zsreg(c, R1); - if(c->dev->type==Z85230) - { - read_zsreg(c, R1); - read_zsreg(c, R1); - read_zsreg(c, R1); - read_zsreg(c, R1); - } -} - -/* Sets or clears DTR/RTS on the requested line */ - -static void z8530_rtsdtr(struct z8530_channel *c, int set) -{ - if (set) - c->regs[5] |= (RTS | DTR); - else - c->regs[5] &= ~(RTS | DTR); - write_zsreg(c, R5, c->regs[5]); -} - -/* - * Receive handler. This is much like the async one but not quite the - * same or as complex - * - * Note: Its intended that this handler can easily be separated from - * the main code to run realtime. That'll be needed for some machines - * (eg to ever clock 64kbits on a sparc ;)). - * - * The RT_LOCK macros don't do anything now. Keep the code covered - * by them as short as possible in all circumstances - clocks cost - * baud. The interrupt handler is assumed to be atomic w.r.t. to - * other code - this is true in the RT case too. - * - * We only cover the sync cases for this. If you want 2Mbit async - * do it yourself but consider medical assistance first. - * - * This non DMA synchronous mode is portable code. - */ - -static void z8530_rx(struct z8530_channel *c) -{ - u8 ch,stat; - - while(1) - { - /* FIFO empty ? */ - if(!(read_zsreg(c, R0)&1)) - break; - ch=read_zsdata(c); - stat=read_zsreg(c, R1); - - /* - * Overrun ? - */ - if(c->count < c->max) - { - *c->dptr++=ch; - c->count++; - } - - if(stat&END_FR) - { - - /* - * Error ? - */ - if(stat&(Rx_OVR|CRC_ERR)) - { - /* Rewind the buffer and return */ - if(c->skb) - c->dptr=c->skb->data; - c->count=0; - if(stat&Rx_OVR) - { - printk(KERN_WARNING "%s: overrun\n", c->dev->name); - c->rx_overrun++; - } - if(stat&CRC_ERR) - { - c->rx_crc_err++; - /* printk("crc error\n"); */ - } - /* Shove the frame upstream */ - } - else - { - z8530_rx_done(c); - write_zsctrl(c, RES_Rx_CRC); - } - } - } - /* - * Clear irq - */ - write_zsctrl(c, ERR_RES); - write_zsctrl(c, RES_H_IUS); -} - - -/* - * Z8530 transmit interrupt handler - */ - -static void z8530_tx(struct z8530_channel *c) -{ - while(c->txcount) - { - /* FIFO full ? */ - if(!(read_zsreg(c, R0)&4)) - break; - c->txcount--; - /* - * Shovel out the byte - */ - write_zsreg(c, R8, *c->tx_ptr++); - write_zsctrl(c, RES_H_IUS); - /* We are about to underflow */ - if(c->txcount==0) - { - write_zsctrl(c, RES_EOM_L); - write_zsreg(c, R10, c->regs[10]&~ABUNDER); - } - return; - } - - /* - * End of frame TX - fire another one - */ - - write_zsctrl(c, RES_Tx_P); - - z8530_tx_done(c); -/* write_zsreg(c, R8, *c->tx_ptr++); */ - write_zsctrl(c, RES_H_IUS); -} - -static void z8530_status(struct z8530_channel *chan) -{ - u8 status=read_zsreg(chan, R0); - u8 altered=chan->status^status; - - chan->status=status; - - if(status&TxEOM) - { -/* printk("%s: Tx underrun.\n", chan->dev->name); */ - chan->stats.tx_fifo_errors++; - write_zsctrl(chan, ERR_RES); - z8530_tx_done(chan); - } - - if(altered&DCD) - { - if(status&DCD) - { - printk(KERN_INFO "%s: DCD raised\n", chan->dev->name); - write_zsreg(chan, R3, chan->regs[3]|RxENABLE); - if(chan->netdevice) - sppp_reopen(chan->netdevice); - } - else - { - printk(KERN_INFO "%s: DCD lost\n", chan->dev->name); - write_zsreg(chan, R3, chan->regs[3]&~RxENABLE); - z8530_flush_fifo(chan); - } - - } - write_zsctrl(chan, RES_EXT_INT); - write_zsctrl(chan, RES_H_IUS); -} - -struct z8530_irqhandler z8530_sync= -{ - z8530_rx, - z8530_tx, - z8530_status -}; - -EXPORT_SYMBOL(z8530_sync); - -/* - * Non bus mastering DMA interfaces for the Z8x30 devices. This - * is really pretty PC specific. - */ - -static void z8530_dma_rx(struct z8530_channel *chan) -{ - if(chan->rxdma_on) - { - /* Special condition check only */ - u8 status; - - read_zsreg(chan, R7); - read_zsreg(chan, R6); - - status=read_zsreg(chan, R1); - if(status&END_FR) - { - z8530_rx_done(chan); /* Fire up the next one */ - } - write_zsctrl(chan, ERR_RES); - write_zsctrl(chan, RES_H_IUS); - } - else - { - /* DMA is off right now, drain the slow way */ - z8530_rx(chan); - } -} - -static void z8530_dma_tx(struct z8530_channel *chan) -{ - if(!chan->dma_tx) - { - printk("Hey who turned the DMA off?\n"); - z8530_tx(chan); - return; - } - /* This shouldnt occur in DMA mode */ - printk(KERN_ERR "DMA tx ??\n"); - z8530_tx(chan); -} - -static void z8530_dma_status(struct z8530_channel *chan) -{ - unsigned long flags; - u8 status=read_zsreg(chan, R0); - u8 altered=chan->status^status; - - chan->status=status; - - if(chan->dma_tx) - { - if(status&TxEOM) - { - flags=claim_dma_lock(); - /* Transmit underrun */ - disable_dma(chan->txdma); - clear_dma_ff(chan->txdma); - chan->txdma_on=0; - release_dma_lock(flags); - z8530_tx_done(chan); - } - } - if(altered&DCD) - { - if(status&DCD) - { - printk(KERN_INFO "%s: DCD raised\n", chan->dev->name); - write_zsreg(chan, R3, chan->regs[3]|RxENABLE); - if(chan->netdevice) - sppp_reopen(chan->netdevice); - } - else - { - printk(KERN_INFO "%s:DCD lost\n", chan->dev->name); - write_zsreg(chan, R3, chan->regs[3]&~RxENABLE); - z8530_flush_fifo(chan); - } - } - write_zsctrl(chan, RES_EXT_INT); - write_zsctrl(chan, RES_H_IUS); -} - -struct z8530_irqhandler z8530_dma_sync= -{ - z8530_dma_rx, - z8530_dma_tx, - z8530_dma_status -}; - -EXPORT_SYMBOL(z8530_dma_sync); - -struct z8530_irqhandler z8530_txdma_sync= -{ - z8530_rx, - z8530_dma_tx, - z8530_dma_status -}; - -EXPORT_SYMBOL(z8530_txdma_sync); - -/* - * Interrupt vectors for a Z8530 that is in 'parked' mode. - * For machines with PCI Z85x30 cards, or level triggered interrupts - * (eg the MacII) we must clear the interrupt cause or die. - */ - - -static void z8530_rx_clear(struct z8530_channel *c) -{ - /* - * Data and status bytes - */ - u8 stat; - - read_zsdata(c); - stat=read_zsreg(c, R1); - - if(stat&END_FR) - write_zsctrl(c, RES_Rx_CRC); - /* - * Clear irq - */ - write_zsctrl(c, ERR_RES); - write_zsctrl(c, RES_H_IUS); -} - -static void z8530_tx_clear(struct z8530_channel *c) -{ - write_zsctrl(c, RES_Tx_P); - write_zsctrl(c, RES_H_IUS); -} - -static void z8530_status_clear(struct z8530_channel *chan) -{ - u8 status=read_zsreg(chan, R0); - if(status&TxEOM) - write_zsctrl(chan, ERR_RES); - write_zsctrl(chan, RES_EXT_INT); - write_zsctrl(chan, RES_H_IUS); -} - -struct z8530_irqhandler z8530_nop= -{ - z8530_rx_clear, - z8530_tx_clear, - z8530_status_clear -}; - - -EXPORT_SYMBOL(z8530_nop); - -/* - * A Z85[2]30 device has stuck its hand in the air for attention - */ - -void z8530_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct z8530_dev *dev=dev_id; - u8 intr; - static volatile int locker=0; - int work=0; - - if(locker) - { - printk(KERN_ERR "IRQ re-enter\n"); - return; - } - locker=1; - - while(++work<5000) - { - struct z8530_irqhandler *irqs=dev->chanA.irqs; - - intr = read_zsreg(&dev->chanA, R3); - if(!(intr & (CHARxIP|CHATxIP|CHAEXT|CHBRxIP|CHBTxIP|CHBEXT))) - break; - - /* This holds the IRQ status. On the 8530 you must read it from chan - A even though it applies to the whole chip */ - - /* Now walk the chip and see what it is wanting - it may be - an IRQ for someone else remember */ - - if(intr & (CHARxIP|CHATxIP|CHAEXT)) - { - if(intr&CHARxIP) - irqs->rx(&dev->chanA); - if(intr&CHATxIP) - irqs->tx(&dev->chanA); - if(intr&CHAEXT) - irqs->status(&dev->chanA); - } - - irqs=dev->chanB.irqs; - - if(intr & (CHBRxIP|CHBTxIP|CHBEXT)) - { - if(intr&CHBRxIP) - irqs->rx(&dev->chanB); - if(intr&CHBTxIP) - irqs->tx(&dev->chanB); - if(intr&CHBEXT) - irqs->status(&dev->chanB); - } - } - if(work==5000) - printk(KERN_ERR "%s: interrupt jammed - abort(0x%X)!\n", dev->name, intr); - /* Ok all done */ - locker=0; -} - -EXPORT_SYMBOL(z8530_interrupt); - -static char reg_init[16]= -{ - 0,0,0,0, - 0,0,0,0, - 0,0,0,0, - 0x55,0,0,0 -}; - - -int z8530_sync_open(struct net_device *dev, struct z8530_channel *c) -{ - c->sync = 1; - c->mtu = dev->mtu+64; - c->count = 0; - c->skb = NULL; - c->skb2 = NULL; - c->irqs = &z8530_sync; - /* This loads the double buffer up */ - z8530_rx_done(c); /* Load the frame ring */ - z8530_rx_done(c); /* Load the backup frame */ - z8530_rtsdtr(c,1); - c->dma_tx = 0; - c->regs[R1]|=TxINT_ENAB; - write_zsreg(c, R1, c->regs[R1]); - write_zsreg(c, R3, c->regs[R3]|RxENABLE); - return 0; -} - - -EXPORT_SYMBOL(z8530_sync_open); - -int z8530_sync_close(struct net_device *dev, struct z8530_channel *c) -{ - u8 chk; - c->irqs = &z8530_nop; - c->max = 0; - c->sync = 0; - - chk=read_zsreg(c,R0); - write_zsreg(c, R3, c->regs[R3]); - z8530_rtsdtr(c,0); - return 0; -} - -EXPORT_SYMBOL(z8530_sync_close); - -int z8530_sync_dma_open(struct net_device *dev, struct z8530_channel *c) -{ - unsigned long flags; - - c->sync = 1; - c->mtu = dev->mtu+64; - c->count = 0; - c->skb = NULL; - c->skb2 = NULL; - /* - * Load the DMA interfaces up - */ - c->rxdma_on = 0; - c->txdma_on = 0; - - /* - * Allocate the DMA flip buffers - */ - - c->rx_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA); - if(c->rx_buf[0]==NULL) - return -ENOBUFS; - c->rx_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA); - if(c->rx_buf[1]==NULL) - { - kfree(c->rx_buf[0]); - c->rx_buf[0]=NULL; - return -ENOBUFS; - } - - c->tx_dma_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA); - if(c->tx_dma_buf[0]==NULL) - { - kfree(c->rx_buf[0]); - kfree(c->rx_buf[1]); - c->rx_buf[0]=NULL; - return -ENOBUFS; - } - c->tx_dma_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA); - if(c->tx_dma_buf[1]==NULL) - { - kfree(c->tx_dma_buf[0]); - kfree(c->rx_buf[0]); - kfree(c->rx_buf[1]); - c->rx_buf[0]=NULL; - c->rx_buf[1]=NULL; - c->tx_dma_buf[0]=NULL; - return -ENOBUFS; - } - c->tx_dma_used=0; - c->dma_tx = 1; - c->dma_num=0; - c->dma_ready=1; - - /* - * Enable DMA control mode - */ - - /* - * TX DMA via DIR/REQ - */ - - c->regs[R14]|= DTRREQ; - write_zsreg(c, R14, c->regs[R14]); - - c->regs[R1]&= ~TxINT_ENAB; - write_zsreg(c, R1, c->regs[R1]); - - /* - * RX DMA via W/Req - */ - - c->regs[R1]|= WT_FN_RDYFN; - c->regs[R1]|= WT_RDY_RT; - c->regs[R1]|= INT_ERR_Rx; - c->regs[R1]&= ~TxINT_ENAB; - write_zsreg(c, R1, c->regs[R1]); - c->regs[R1]|= WT_RDY_ENAB; - write_zsreg(c, R1, c->regs[R1]); - - /* - * DMA interrupts - */ - - /* - * Set up the DMA configuration - */ - - flags=claim_dma_lock(); - - disable_dma(c->rxdma); - clear_dma_ff(c->rxdma); - set_dma_mode(c->rxdma, DMA_MODE_READ|0x10); - set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[0])); - set_dma_count(c->rxdma, c->mtu); - enable_dma(c->rxdma); - - disable_dma(c->txdma); - clear_dma_ff(c->txdma); - set_dma_mode(c->txdma, DMA_MODE_WRITE); - disable_dma(c->txdma); - - release_dma_lock(flags); - - /* - * Select the DMA interrupt handlers - */ - - c->rxdma_on = 1; - c->txdma_on = 1; - c->tx_dma_used = 1; - - c->irqs = &z8530_dma_sync; - z8530_rtsdtr(c,1); - write_zsreg(c, R3, c->regs[R3]|RxENABLE); - return 0; -} - -EXPORT_SYMBOL(z8530_sync_dma_open); - -int z8530_sync_dma_close(struct net_device *dev, struct z8530_channel *c) -{ - u8 chk; - unsigned long flags; - - c->irqs = &z8530_nop; - c->max = 0; - c->sync = 0; - - /* - * Disable the PC DMA channels - */ - - flags=claim_dma_lock(); - disable_dma(c->rxdma); - clear_dma_ff(c->rxdma); - - c->rxdma_on = 0; - - disable_dma(c->txdma); - clear_dma_ff(c->txdma); - release_dma_lock(flags); - - c->txdma_on = 0; - c->tx_dma_used = 0; - - /* - * Disable DMA control mode - */ - - c->regs[R1]&= ~WT_RDY_ENAB; - write_zsreg(c, R1, c->regs[R1]); - c->regs[R1]&= ~(WT_RDY_RT|WT_FN_RDYFN|INT_ERR_Rx); - c->regs[R1]|= INT_ALL_Rx; - write_zsreg(c, R1, c->regs[R1]); - c->regs[R14]&= ~DTRREQ; - write_zsreg(c, R14, c->regs[R14]); - - if(c->rx_buf[0]) - { - kfree(c->rx_buf[0]); - c->rx_buf[0]=NULL; - } - if(c->rx_buf[1]) - { - kfree(c->rx_buf[1]); - c->rx_buf[1]=NULL; - } - if(c->tx_dma_buf[0]) - { - kfree(c->tx_dma_buf[0]); - c->tx_dma_buf[0]=NULL; - } - if(c->tx_dma_buf[1]) - { - kfree(c->tx_dma_buf[1]); - c->tx_dma_buf[1]=NULL; - } - chk=read_zsreg(c,R0); - write_zsreg(c, R3, c->regs[R3]); - z8530_rtsdtr(c,0); - return 0; -} - -EXPORT_SYMBOL(z8530_sync_dma_close); - -int z8530_sync_txdma_open(struct net_device *dev, struct z8530_channel *c) -{ - unsigned long flags; - - printk("Opening sync interface for TX-DMA\n"); - c->sync = 1; - c->mtu = dev->mtu+64; - c->count = 0; - c->skb = NULL; - c->skb2 = NULL; - - /* - * Load the PIO receive ring - */ - - z8530_rx_done(c); - z8530_rx_done(c); - - /* - * Load the DMA interfaces up - */ - - c->rxdma_on = 0; - c->txdma_on = 0; - - c->tx_dma_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA); - if(c->tx_dma_buf[0]==NULL) - { - kfree(c->rx_buf[0]); - kfree(c->rx_buf[1]); - c->rx_buf[0]=NULL; - return -ENOBUFS; - } - c->tx_dma_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA); - if(c->tx_dma_buf[1]==NULL) - { - kfree(c->tx_dma_buf[0]); - kfree(c->rx_buf[0]); - kfree(c->rx_buf[1]); - c->rx_buf[0]=NULL; - c->rx_buf[1]=NULL; - c->tx_dma_buf[0]=NULL; - return -ENOBUFS; - } - c->tx_dma_used=0; - c->dma_num=0; - c->dma_ready=1; - c->dma_tx = 1; - - /* - * Enable DMA control mode - */ - - /* - * TX DMA via DIR/REQ - */ - c->regs[R14]|= DTRREQ; - write_zsreg(c, R14, c->regs[R14]); - - c->regs[R1]&= ~TxINT_ENAB; - write_zsreg(c, R1, c->regs[R1]); - - /* - * Set up the DMA configuration - */ - - flags = claim_dma_lock(); - - disable_dma(c->txdma); - clear_dma_ff(c->txdma); - set_dma_mode(c->txdma, DMA_MODE_WRITE); - disable_dma(c->txdma); - - release_dma_lock(flags); - - /* - * Select the DMA interrupt handlers - */ - - c->rxdma_on = 0; - c->txdma_on = 1; - c->tx_dma_used = 1; - - c->irqs = &z8530_txdma_sync; - printk("Loading RX\n"); - z8530_rtsdtr(c,1); - printk("Rx interrupts ON\n"); - write_zsreg(c, R3, c->regs[R3]|RxENABLE); - return 0; -} - -EXPORT_SYMBOL(z8530_sync_txdma_open); - -int z8530_sync_txdma_close(struct net_device *dev, struct z8530_channel *c) -{ - unsigned long flags; - u8 chk; - c->irqs = &z8530_nop; - c->max = 0; - c->sync = 0; - - /* - * Disable the PC DMA channels - */ - - flags = claim_dma_lock(); - - disable_dma(c->txdma); - clear_dma_ff(c->txdma); - c->txdma_on = 0; - c->tx_dma_used = 0; - - release_dma_lock(flags); - - /* - * Disable DMA control mode - */ - - c->regs[R1]&= ~WT_RDY_ENAB; - write_zsreg(c, R1, c->regs[R1]); - c->regs[R1]&= ~(WT_RDY_RT|WT_FN_RDYFN|INT_ERR_Rx); - c->regs[R1]|= INT_ALL_Rx; - write_zsreg(c, R1, c->regs[R1]); - c->regs[R14]&= ~DTRREQ; - write_zsreg(c, R14, c->regs[R14]); - - if(c->tx_dma_buf[0]) - { - kfree(c->tx_dma_buf[0]); - c->tx_dma_buf[0]=NULL; - } - if(c->tx_dma_buf[1]) - { - kfree(c->tx_dma_buf[1]); - c->tx_dma_buf[1]=NULL; - } - chk=read_zsreg(c,R0); - write_zsreg(c, R3, c->regs[R3]); - z8530_rtsdtr(c,0); - return 0; -} - - -EXPORT_SYMBOL(z8530_sync_txdma_close); - -/* - * Describe a Z8530 in a standard format. We must pass the I/O as - * the port offset isnt predictable. The main reason for this function - * is to try and get a common format of report. - */ - -static char *z8530_type_name[]={ - "Z8530", - "Z85C30", - "Z85230" -}; - -void z8530_describe(struct z8530_dev *dev, char *mapping, int io) -{ - printk(KERN_INFO "%s: %s found at %s 0x%X, IRQ %d.\n", - dev->name, - z8530_type_name[dev->type], - mapping, - Z8530_PORT_OF(io), - dev->irq); -} - -EXPORT_SYMBOL(z8530_describe); - -/* - * Configure up a Z8530 - */ - - -int z8530_init(struct z8530_dev *dev) -{ - /* NOP the interrupt handlers first - we might get a - floating IRQ transition when we reset the chip */ - dev->chanA.irqs=&z8530_nop; - dev->chanB.irqs=&z8530_nop; - /* Reset the chip */ - write_zsreg(&dev->chanA, R9, 0xC0); - udelay(200); - /* Now check its valid */ - write_zsreg(&dev->chanA, R12, 0xAA); - if(read_zsreg(&dev->chanA, R12)!=0xAA) - return -ENODEV; - write_zsreg(&dev->chanA, R12, 0x55); - if(read_zsreg(&dev->chanA, R12)!=0x55) - return -ENODEV; - - dev->type=Z8530; - - /* - * See the application note. - */ - - write_zsreg(&dev->chanA, R15, 0x01); - - /* - * If we can set the low bit of R15 then - * the chip is enhanced. - */ - - if(read_zsreg(&dev->chanA, R15)==0x01) - { - /* This C30 versus 230 detect is from Klaus Kudielka's dmascc */ - /* Put a char in the fifo */ - write_zsreg(&dev->chanA, R8, 0); - if(read_zsreg(&dev->chanA, R0)&Tx_BUF_EMP) - dev->type = Z85230; /* Has a FIFO */ - else - dev->type = Z85C30; /* Z85C30, 1 byte FIFO */ - } - - /* - * The code assumes R7' and friends are - * off. Use write_zsext() for these and keep - * this bit clear. - */ - - write_zsreg(&dev->chanA, R15, 0); - - /* - * At this point it looks like the chip is behaving - */ - - memcpy(dev->chanA.regs, reg_init, 16); - memcpy(dev->chanB.regs, reg_init ,16); - - return 0; -} - - -EXPORT_SYMBOL(z8530_init); - -int z8530_shutdown(struct z8530_dev *dev) -{ - /* Reset the chip */ - dev->chanA.irqs=&z8530_nop; - dev->chanB.irqs=&z8530_nop; - write_zsreg(&dev->chanA, R9, 0xC0); - udelay(100); - return 0; -} - -EXPORT_SYMBOL(z8530_shutdown); - -/* - * Load a Z8530 channel up from the system data - * We use +16 to indicate the 'prime' registers - */ - -int z8530_channel_load(struct z8530_channel *c, u8 *rtable) -{ - while(*rtable!=255) - { - int reg=*rtable++; - if(reg>0x0F) - write_zsreg(c, R15, c->regs[15]|1); - write_zsreg(c, reg&0x0F, *rtable); - if(reg>0x0F) - write_zsreg(c, R15, c->regs[15]&~1); - c->regs[reg]=*rtable++; - } - c->rx_function=z8530_null_rx; - c->skb=NULL; - c->tx_skb=NULL; - c->tx_next_skb=NULL; - c->mtu=1500; - c->max=0; - c->count=0; - c->status=0; /* Fixme - check DCD now */ - c->sync=1; - write_zsreg(c, R3, c->regs[R3]|RxENABLE); - return 0; -} - -EXPORT_SYMBOL(z8530_channel_load); - - -/* - * Higher level shovelling - transmit chains - */ - -static void z8530_tx_begin(struct z8530_channel *c) -{ - unsigned long flags; - if(c->tx_skb) - return; - - c->tx_skb=c->tx_next_skb; - c->tx_next_skb=NULL; - c->tx_ptr=c->tx_next_ptr; - - mark_bh(NET_BH); - if(c->tx_skb==NULL) - { - /* Idle on */ - if(c->dma_tx) - { - flags=claim_dma_lock(); - disable_dma(c->txdma); - /* - * Check if we crapped out. - */ - if(get_dma_residue(c->txdma)) - { - c->stats.tx_dropped++; - c->stats.tx_fifo_errors++; - } - release_dma_lock(flags); - } - c->txcount=0; - } - else - { - c->txcount=c->tx_skb->len; - - - if(c->dma_tx) - { - /* - * FIXME. DMA is broken for the original 8530, - * on the older parts we need to set a flag and - * wait for a further TX interrupt to fire this - * stage off - */ - - flags=claim_dma_lock(); - disable_dma(c->txdma); - - /* - * These two are needed by the 8530/85C30 - * and must be issued when idling. - */ - - if(c->dev->type!=Z85230) - { - write_zsctrl(c, RES_Tx_CRC); - write_zsctrl(c, RES_EOM_L); - } - write_zsreg(c, R10, c->regs[10]&~ABUNDER); - clear_dma_ff(c->txdma); - set_dma_addr(c->txdma, virt_to_bus(c->tx_ptr)); - set_dma_count(c->txdma, c->txcount); - enable_dma(c->txdma); - release_dma_lock(flags); - write_zsctrl(c, RES_EOM_L); - write_zsreg(c, R5, c->regs[R5]|TxENAB); - } - else - { - save_flags(flags); - cli(); - /* ABUNDER off */ - write_zsreg(c, R10, c->regs[10]); - write_zsctrl(c, RES_Tx_CRC); -//??? write_zsctrl(c, RES_EOM_L); - - while(c->txcount && (read_zsreg(c,R0)&Tx_BUF_EMP)) - { - write_zsreg(c, R8, *c->tx_ptr++); - c->txcount--; - } - restore_flags(flags); - } - } -} - - -static void z8530_tx_done(struct z8530_channel *c) -{ - unsigned long flags; - struct sk_buff *skb; - - spin_lock_irqsave(&z8530_buffer_lock, flags); - c->netdevice->tbusy=0; - /* Actually this can happen.*/ - if(c->tx_skb==NULL) - { - spin_unlock_irqrestore(&z8530_buffer_lock, flags); - return; - } - skb=c->tx_skb; - c->tx_skb=NULL; - z8530_tx_begin(c); - spin_unlock_irqrestore(&z8530_buffer_lock, flags); - c->stats.tx_packets++; - c->stats.tx_bytes+=skb->len; - dev_kfree_skb(skb); -} - -/* - * Higher level shovelling - receive chains - */ - -void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb) -{ - kfree_skb(skb); -} - -EXPORT_SYMBOL(z8530_null_rx); - -static void z8530_rx_done(struct z8530_channel *c) -{ - struct sk_buff *skb; - int ct; - - /* - * Is our receive engine in DMA mode - */ - - if(c->rxdma_on) - { - /* - * Save the ready state and the buffer currently - * being used as the DMA target - */ - - int ready=c->dma_ready; - unsigned char *rxb=c->rx_buf[c->dma_num]; - unsigned long flags; - - /* - * Complete this DMA. Neccessary to find the length - */ - - flags=claim_dma_lock(); - - disable_dma(c->rxdma); - clear_dma_ff(c->rxdma); - c->rxdma_on=0; - ct=c->mtu-get_dma_residue(c->rxdma); - if(ct<0) - ct=2; /* Shit happens.. */ - c->dma_ready=0; - - /* - * Normal case: the other slot is free, start the next DMA - * into it immediately. - */ - - if(ready) - { - c->dma_num^=1; - set_dma_mode(c->rxdma, DMA_MODE_READ|0x10); - set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[c->dma_num])); - set_dma_count(c->rxdma, c->mtu); - c->rxdma_on = 1; - enable_dma(c->rxdma); - /* Stop any frames that we missed the head of - from passing */ - write_zsreg(c, R0, RES_Rx_CRC); - } - else - /* Can't occur as we dont reenable the DMA irq until - after the flip is done */ - printk("DMA flip overrun!\n"); - - release_dma_lock(flags); - - /* - * Shove the old buffer into an sk_buff. We can't DMA - * directly into one on a PC - it might be above the 16Mb - * boundary. Optimisation - we could check to see if we - * can avoid the copy. Optimisation 2 - make the memcpy - * a copychecksum. - */ - - skb=dev_alloc_skb(ct); - if(skb==NULL) - { - c->stats.rx_dropped++; - printk(KERN_WARNING "%s: Memory squeeze.\n", c->netdevice->name); - } - else - { - skb_put(skb, ct); - memcpy(skb->data, rxb, ct); - c->stats.rx_packets++; - c->stats.rx_bytes+=ct; - } - c->dma_ready=1; - } - else - { - RT_LOCK; - skb=c->skb; - - /* - * The game we play for non DMA is similar. We want to - * get the controller set up for the next packet as fast - * as possible. We potentially only have one byte + the - * fifo length for this. Thus we want to flip to the new - * buffer and then mess around copying and allocating - * things. For the current case it doesn't matter but - * if you build a system where the sync irq isnt blocked - * by the kernel IRQ disable then you need only block the - * sync IRQ for the RT_LOCK area. - * - */ - ct=c->count; - - c->skb = c->skb2; - c->count = 0; - c->max = c->mtu; - if(c->skb) - { - c->dptr = c->skb->data; - c->max = c->mtu; - } - else - { - c->count= 0; - c->max = 0; - } - RT_UNLOCK; - - c->skb2 = dev_alloc_skb(c->mtu); - if(c->skb2==NULL) - printk(KERN_WARNING "%s: memory squeeze.\n", - c->netdevice->name); - else - { - skb_put(c->skb2,c->mtu); - } - c->stats.rx_packets++; - c->stats.rx_bytes+=ct; - - } - /* - * If we received a frame we must now process it. - */ - if(skb) - { - skb_trim(skb, ct); - c->rx_function(c,skb); - } - else - { - c->stats.rx_dropped++; - printk(KERN_ERR "%s: Lost a frame\n", c->netdevice->name); - } -} - -/* - * Cannot DMA over a 64K boundary on a PC - */ - -extern inline int spans_boundary(struct sk_buff *skb) -{ - unsigned long a=(unsigned long)skb->data; - a^=(a+skb->len); - if(a&0x00010000) /* If the 64K bit is different.. */ - { - printk("spanner\n"); - return 1; - } - return 0; -} - -/* - * Queue a packet for transmission. Because we have rather - * hard to hit interrupt latencies for the Z85230 per packet - * even in DMA mode we do the flip to DMA buffer if needed here - * not in the IRQ. - */ - -int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb) -{ - unsigned long flags; - if(c->tx_next_skb) - { - skb->dev->tbusy=1; - return 1; - } - - /* PC SPECIFIC - DMA limits */ - - /* - * If we will DMA the transmit and its gone over the ISA bus - * limit, then copy to the flip buffer - */ - - if(c->dma_tx && ((unsigned long)(virt_to_bus(skb->data+skb->len))>=16*1024*1024 || spans_boundary(skb))) - { - /* - * Send the flip buffer, and flip the flippy bit. - * We don't care which is used when just so long as - * we never use the same buffer twice in a row. Since - * only one buffer can be going out at a time the other - * has to be safe. - */ - c->tx_next_ptr=c->tx_dma_buf[c->tx_dma_used]; - c->tx_dma_used^=1; /* Flip temp buffer */ - memcpy(c->tx_next_ptr, skb->data, skb->len); - } - else - c->tx_next_ptr=skb->data; - RT_LOCK; - c->tx_next_skb=skb; - RT_UNLOCK; - - spin_lock_irqsave(&z8530_buffer_lock, flags); - z8530_tx_begin(c); - spin_unlock_irqrestore(&z8530_buffer_lock, flags); - return 0; -} - -EXPORT_SYMBOL(z8530_queue_xmit); - -struct net_device_stats *z8530_get_stats(struct z8530_channel *c) -{ - return &c->stats; -} - -EXPORT_SYMBOL(z8530_get_stats); - -#ifdef MODULE - -/* - * Module support - */ - -int init_module(void) -{ - printk(KERN_INFO "Generic Z85C30/Z85230 interface driver v0.02\n"); - return 0; -} - -void cleanup_module(void) -{ -} - -#endif diff -u --recursive --new-file v2.3.20/linux/drivers/net/z85230.h linux/drivers/net/z85230.h --- v2.3.20/linux/drivers/net/z85230.h Wed Aug 18 11:36:45 1999 +++ linux/drivers/net/z85230.h Wed Dec 31 16:00:00 1969 @@ -1,446 +0,0 @@ -/* - * Description of Z8530 Z85C30 and Z85230 communications chips - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1998 Alan Cox - */ - -#ifndef _Z8530_H -#define _Z8530_H - -/* Conversion routines to/from brg time constants from/to bits - * per second. - */ -#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2)) -#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2) - -/* The Zilog register set */ - -#define FLAG 0x7e - -/* Write Register 0 */ -#define R0 0 /* Register selects */ -#define R1 1 -#define R2 2 -#define R3 3 -#define R4 4 -#define R5 5 -#define R6 6 -#define R7 7 -#define R8 8 -#define R9 9 -#define R10 10 -#define R11 11 -#define R12 12 -#define R13 13 -#define R14 14 -#define R15 15 - -#define RPRIME 16 /* Indicate a prime register access on 230 */ - -#define NULLCODE 0 /* Null Code */ -#define POINT_HIGH 0x8 /* Select upper half of registers */ -#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */ -#define SEND_ABORT 0x18 /* HDLC Abort */ -#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */ -#define RES_Tx_P 0x28 /* Reset TxINT Pending */ -#define ERR_RES 0x30 /* Error Reset */ -#define RES_H_IUS 0x38 /* Reset highest IUS */ - -#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */ -#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */ -#define RES_EOM_L 0xC0 /* Reset EOM latch */ - -/* Write Register 1 */ - -#define EXT_INT_ENAB 0x1 /* Ext Int Enable */ -#define TxINT_ENAB 0x2 /* Tx Int Enable */ -#define PAR_SPEC 0x4 /* Parity is special condition */ - -#define RxINT_DISAB 0 /* Rx Int Disable */ -#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ -#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */ -#define INT_ERR_Rx 0x18 /* Int on error only */ - -#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */ -#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */ -#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */ - -/* Write Register #2 (Interrupt Vector) */ - -/* Write Register 3 */ - -#define RxENABLE 0x1 /* Rx Enable */ -#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */ -#define ADD_SM 0x4 /* Address Search Mode (SDLC) */ -#define RxCRC_ENAB 0x8 /* Rx CRC Enable */ -#define ENT_HM 0x10 /* Enter Hunt Mode */ -#define AUTO_ENAB 0x20 /* Auto Enables */ -#define Rx5 0x0 /* Rx 5 Bits/Character */ -#define Rx7 0x40 /* Rx 7 Bits/Character */ -#define Rx6 0x80 /* Rx 6 Bits/Character */ -#define Rx8 0xc0 /* Rx 8 Bits/Character */ - -/* Write Register 4 */ - -#define PAR_ENA 0x1 /* Parity Enable */ -#define PAR_EVEN 0x2 /* Parity Even/Odd* */ - -#define SYNC_ENAB 0 /* Sync Modes Enable */ -#define SB1 0x4 /* 1 stop bit/char */ -#define SB15 0x8 /* 1.5 stop bits/char */ -#define SB2 0xc /* 2 stop bits/char */ - -#define MONSYNC 0 /* 8 Bit Sync character */ -#define BISYNC 0x10 /* 16 bit sync character */ -#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */ -#define EXTSYNC 0x30 /* External Sync Mode */ - -#define X1CLK 0x0 /* x1 clock mode */ -#define X16CLK 0x40 /* x16 clock mode */ -#define X32CLK 0x80 /* x32 clock mode */ -#define X64CLK 0xC0 /* x64 clock mode */ - -/* Write Register 5 */ - -#define TxCRC_ENAB 0x1 /* Tx CRC Enable */ -#define RTS 0x2 /* RTS */ -#define SDLC_CRC 0x4 /* SDLC/CRC-16 */ -#define TxENAB 0x8 /* Tx Enable */ -#define SND_BRK 0x10 /* Send Break */ -#define Tx5 0x0 /* Tx 5 bits (or less)/character */ -#define Tx7 0x20 /* Tx 7 bits/character */ -#define Tx6 0x40 /* Tx 6 bits/character */ -#define Tx8 0x60 /* Tx 8 bits/character */ -#define DTR 0x80 /* DTR */ - -/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */ - -/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ - -/* Write Register 8 (transmit buffer) */ - -/* Write Register 9 (Master interrupt control) */ -#define VIS 1 /* Vector Includes Status */ -#define NV 2 /* No Vector */ -#define DLC 4 /* Disable Lower Chain */ -#define MIE 8 /* Master Interrupt Enable */ -#define STATHI 0x10 /* Status high */ -#define NORESET 0 /* No reset on write to R9 */ -#define CHRB 0x40 /* Reset channel B */ -#define CHRA 0x80 /* Reset channel A */ -#define FHWRES 0xc0 /* Force hardware reset */ - -/* Write Register 10 (misc control bits) */ -#define BIT6 1 /* 6 bit/8bit sync */ -#define LOOPMODE 2 /* SDLC Loop mode */ -#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */ -#define MARKIDLE 8 /* Mark/flag on idle */ -#define GAOP 0x10 /* Go active on poll */ -#define NRZ 0 /* NRZ mode */ -#define NRZI 0x20 /* NRZI mode */ -#define FM1 0x40 /* FM1 (transition = 1) */ -#define FM0 0x60 /* FM0 (transition = 0) */ -#define CRCPS 0x80 /* CRC Preset I/O */ - -/* Write Register 11 (Clock Mode control) */ -#define TRxCXT 0 /* TRxC = Xtal output */ -#define TRxCTC 1 /* TRxC = Transmit clock */ -#define TRxCBR 2 /* TRxC = BR Generator Output */ -#define TRxCDP 3 /* TRxC = DPLL output */ -#define TRxCOI 4 /* TRxC O/I */ -#define TCRTxCP 0 /* Transmit clock = RTxC pin */ -#define TCTRxCP 8 /* Transmit clock = TRxC pin */ -#define TCBR 0x10 /* Transmit clock = BR Generator output */ -#define TCDPLL 0x18 /* Transmit clock = DPLL output */ -#define RCRTxCP 0 /* Receive clock = RTxC pin */ -#define RCTRxCP 0x20 /* Receive clock = TRxC pin */ -#define RCBR 0x40 /* Receive clock = BR Generator output */ -#define RCDPLL 0x60 /* Receive clock = DPLL output */ -#define RTxCX 0x80 /* RTxC Xtal/No Xtal */ - -/* Write Register 12 (lower byte of baud rate generator time constant) */ - -/* Write Register 13 (upper byte of baud rate generator time constant) */ - -/* Write Register 14 (Misc control bits) */ -#define BRENABL 1 /* Baud rate generator enable */ -#define BRSRC 2 /* Baud rate generator source */ -#define DTRREQ 4 /* DTR/Request function */ -#define AUTOECHO 8 /* Auto Echo */ -#define LOOPBAK 0x10 /* Local loopback */ -#define SEARCH 0x20 /* Enter search mode */ -#define RMC 0x40 /* Reset missing clock */ -#define DISDPLL 0x60 /* Disable DPLL */ -#define SSBR 0x80 /* Set DPLL source = BR generator */ -#define SSRTxC 0xa0 /* Set DPLL source = RTxC */ -#define SFMM 0xc0 /* Set FM mode */ -#define SNRZI 0xe0 /* Set NRZI mode */ - -/* Write Register 15 (external/status interrupt control) */ -#define PRIME 1 /* R5' etc register access (Z85C30/230 only) */ -#define ZCIE 2 /* Zero count IE */ -#define FIFOE 4 /* Z85230 only */ -#define DCDIE 8 /* DCD IE */ -#define SYNCIE 0x10 /* Sync/hunt IE */ -#define CTSIE 0x20 /* CTS IE */ -#define TxUIE 0x40 /* Tx Underrun/EOM IE */ -#define BRKIE 0x80 /* Break/Abort IE */ - - -/* Read Register 0 */ -#define Rx_CH_AV 0x1 /* Rx Character Available */ -#define ZCOUNT 0x2 /* Zero count */ -#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ -#define DCD 0x8 /* DCD */ -#define SYNC_HUNT 0x10 /* Sync/hunt */ -#define CTS 0x20 /* CTS */ -#define TxEOM 0x40 /* Tx underrun */ -#define BRK_ABRT 0x80 /* Break/Abort */ - -/* Read Register 1 */ -#define ALL_SNT 0x1 /* All sent */ -/* Residue Data for 8 Rx bits/char programmed */ -#define RES3 0x8 /* 0/3 */ -#define RES4 0x4 /* 0/4 */ -#define RES5 0xc /* 0/5 */ -#define RES6 0x2 /* 0/6 */ -#define RES7 0xa /* 0/7 */ -#define RES8 0x6 /* 0/8 */ -#define RES18 0xe /* 1/8 */ -#define RES28 0x0 /* 2/8 */ -/* Special Rx Condition Interrupts */ -#define PAR_ERR 0x10 /* Parity error */ -#define Rx_OVR 0x20 /* Rx Overrun Error */ -#define CRC_ERR 0x40 /* CRC/Framing Error */ -#define END_FR 0x80 /* End of Frame (SDLC) */ - -/* Read Register 2 (channel b only) - Interrupt vector */ - -/* Read Register 3 (interrupt pending register) ch a only */ -#define CHBEXT 0x1 /* Channel B Ext/Stat IP */ -#define CHBTxIP 0x2 /* Channel B Tx IP */ -#define CHBRxIP 0x4 /* Channel B Rx IP */ -#define CHAEXT 0x8 /* Channel A Ext/Stat IP */ -#define CHATxIP 0x10 /* Channel A Tx IP */ -#define CHARxIP 0x20 /* Channel A Rx IP */ - -/* Read Register 8 (receive data register) */ - -/* Read Register 10 (misc status bits) */ -#define ONLOOP 2 /* On loop */ -#define LOOPSEND 0x10 /* Loop sending */ -#define CLK2MIS 0x40 /* Two clocks missing */ -#define CLK1MIS 0x80 /* One clock missing */ - -/* Read Register 12 (lower byte of baud rate generator constant) */ - -/* Read Register 13 (upper byte of baud rate generator constant) */ - -/* Read Register 15 (value of WR 15) */ - - -/* - * Interrupt handling functions for this SCC - */ - -struct z8530_channel; - -struct z8530_irqhandler -{ - void (*rx)(struct z8530_channel *); - void (*tx)(struct z8530_channel *); - void (*status)(struct z8530_channel *); -}; - -/* - * A channel of the Z8530 - */ - -struct z8530_channel -{ - struct z8530_irqhandler *irqs; /* IRQ handlers */ - /* - * Synchronous - */ - u16 count; /* Buyes received */ - u16 max; /* Most we can receive this frame */ - u16 mtu; /* MTU of the device */ - u8 *dptr; /* Pointer into rx buffer */ - struct sk_buff *skb; /* Buffer dptr points into */ - struct sk_buff *skb2; /* Pending buffer */ - u8 status; /* Current DCD */ - u8 sync; /* Set if in sync mode */ - - u8 regs[32]; /* Register map for the chip */ - u8 pendregs[32]; /* Pending register values */ - - struct sk_buff *tx_skb; /* Buffer being transmitted */ - struct sk_buff *tx_next_skb; /* Next transmit buffer */ - u8 *tx_ptr; /* Byte pointer into the buffer */ - u8 *tx_next_ptr; /* Next pointer to use */ - u8 *tx_dma_buf[2]; /* TX flip buffers for DMA */ - u8 tx_dma_used; /* Flip buffer usage toggler */ - u16 txcount; /* Count of bytes to transmit */ - - void (*rx_function)(struct z8530_channel *, struct sk_buff *); - - /* - * Sync DMA - */ - - u8 rxdma; /* DMA channels */ - u8 txdma; - u8 rxdma_on; /* DMA active if flag set */ - u8 txdma_on; - u8 dma_num; /* Buffer we are DMAing into */ - u8 dma_ready; /* Is the other buffer free */ - u8 dma_tx; /* TX is to use DMA */ - u8 *rx_buf[2]; /* The flip buffers */ - - /* - * System - */ - - struct z8530_dev *dev; /* Z85230 chip instance we are from */ - int ctrlio; /* I/O ports */ - int dataio; - - /* - * For PC we encode this way. - */ -#define Z8530_PORT_SLEEP 0x80000000 -#define Z8530_PORT_OF(x) ((x)&0xFFFF) - - u32 rx_overrun; /* Overruns - not done yet */ - u32 rx_crc_err; - - /* - * Bound device pointers - */ - - void *private; /* For our owner */ - struct net_device *netdevice; /* Network layer device */ - struct net_device_stats stats; /* Network layer statistics */ - - /* - * Async features - */ - - struct tty_struct *tty; /* Attached terminal */ - int line; /* Minor number */ - struct termios normal_termios; /* Terminal settings */ - struct termios callout_termios; - wait_queue_head_t open_wait; /* Tasks waiting to open */ - wait_queue_head_t close_wait; /* and for close to end */ - unsigned long event; /* Pending events */ - int fdcount; /* # of fd on device */ - int blocked_open; /* # of blocked opens */ - long session; /* Session of opening process */ - long pgrp; /* pgrp of opening process */ - int x_char; /* XON/XOF char */ - unsigned char *xmit_buf; /* Transmit pointer */ - int xmit_head; /* Transmit ring */ - int xmit_tail; - int xmit_cnt; - int flags; - int timeout; - int xmit_fifo_size; /* Transmit FIFO info */ - - int close_delay; /* Do we wait for drain on close ? */ - unsigned short closing_wait; - - /* We need to know the current clock divisor - * to read the bps rate the chip has currently - * loaded. - */ - - unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */ - int zs_baud; - - int magic; - int baud_base; /* Baud parameters */ - int custom_divisor; - - - unsigned char tx_active; /* character is being xmitted */ - unsigned char tx_stopped; /* output is suspended */ -}; - -/* - * Each Z853x0 device. - */ - -struct z8530_dev -{ - char *name; /* Device instance name */ - struct z8530_channel chanA; /* SCC channel A */ - struct z8530_channel chanB; /* SCC channel B */ - int type; -#define Z8530 0 /* NMOS dinosaur */ -#define Z85C30 1 /* CMOS - better */ -#define Z85230 2 /* CMOS with real FIFO */ - int irq; /* Interrupt for the device */ - int active; /* Soft interrupt enable - the Mac doesn't - always have a hard disable on its 8530s... */ -}; - - -/* - * Functions - */ - -extern u8 z8530_dead_port[]; -extern u8 z8530_hdlc_kilostream_85230[]; -extern u8 z8530_hdlc_kilostream[]; -extern void z8530_interrupt(int, void *, struct pt_regs *); -extern void z8530_describe(struct z8530_dev *, char *mapping,int io); -extern int z8530_init(struct z8530_dev *); -extern int z8530_shutdown(struct z8530_dev *); -extern int z8530_sync_open(struct net_device *, struct z8530_channel *); -extern int z8530_sync_close(struct net_device *, struct z8530_channel *); -extern int z8530_sync_dma_open(struct net_device *, struct z8530_channel *); -extern int z8530_sync_dma_close(struct net_device *, struct z8530_channel *); -extern int z8530_sync_txdma_open(struct net_device *, struct z8530_channel *); -extern int z8530_sync_txdma_close(struct net_device *, struct z8530_channel *); -extern int z8530_channel_load(struct z8530_channel *, u8 *); -extern int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb); -extern struct net_device_stats *z8530_get_stats(struct z8530_channel *c); -extern void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb); - - -/* - * Standard interrupt vector sets - */ - -struct z8530_irqhandler z8530_sync, z8530_async, z8530_nop; - -/* - * Asynchronous Interfacing - */ - -#define SERIAL_MAGIC 0x5301 - -/* - * The size of the serial xmit buffer is 1 page, or 4096 bytes - */ - -#define SERIAL_XMIT_SIZE 4096 -#define WAKEUP_CHARS 256 - -/* - * Events are used to schedule things to happen at timer-interrupt - * time, instead of at rs interrupt time. - */ -#define RS_EVENT_WRITE_WAKEUP 0 - -/* Internal flags used only by kernel/chr_drv/serial.c */ -#define ZILOG_INITIALIZED 0x80000000 /* Serial port was initialized */ -#define ZILOG_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ -#define ZILOG_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ -#define ZILOG_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ -#define ZILOG_CLOSING 0x08000000 /* Serial port is closing */ -#define ZILOG_CTS_FLOW 0x04000000 /* Do CTS flow control */ -#define ZILOG_CHECK_CD 0x02000000 /* i.e., CLOCAL */ - -#endif /* !(_Z8530_H) */ diff -u --recursive --new-file v2.3.20/linux/drivers/pnp/Config.in linux/drivers/pnp/Config.in --- v2.3.20/linux/drivers/pnp/Config.in Sun Aug 15 11:50:35 1999 +++ linux/drivers/pnp/Config.in Mon Oct 11 10:13:24 1999 @@ -6,6 +6,6 @@ tristate 'Plug and Play support' CONFIG_PNP -dep_tristate 'ISA Plug and Play support' CONFIG_ISAPNP $CONFIG_PNP +dep_tristate ' ISA Plug and Play support' CONFIG_ISAPNP $CONFIG_PNP endmenu diff -u --recursive --new-file v2.3.20/linux/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c --- v2.3.20/linux/drivers/sbus/char/pcikbd.c Fri Sep 10 23:57:30 1999 +++ linux/drivers/sbus/char/pcikbd.c Mon Oct 11 10:13:25 1999 @@ -764,7 +764,7 @@ queue->head = head; aux_ready = 1; if (queue->fasync) - kill_fasync(queue->fasync, SIGIO); + kill_fasync(queue->fasync, SIGIO, POLL_IN); wake_up_interruptible(&queue->proc_list); } diff -u --recursive --new-file v2.3.20/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c --- v2.3.20/linux/drivers/sbus/char/sunkbd.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/sbus/char/sunkbd.c Mon Oct 11 10:13:25 1999 @@ -1273,7 +1273,7 @@ kbd_head = next; } if (kb_fasync) - kill_fasync (kb_fasync, SIGIO); + kill_fasync (kb_fasync, SIGIO, POLL_IN); wake_up_interruptible (&kbd_wait); } diff -u --recursive --new-file v2.3.20/linux/drivers/sbus/char/sunmouse.c linux/drivers/sbus/char/sunmouse.c --- v2.3.20/linux/drivers/sbus/char/sunmouse.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/sbus/char/sunmouse.c Mon Oct 11 10:13:25 1999 @@ -137,7 +137,7 @@ } sunmouse.ready = 1; if (sunmouse.fasync) - kill_fasync (sunmouse.fasync, SIGIO); + kill_fasync (sunmouse.fasync, SIGIO, POLL_IN); wake_up_interruptible (&sunmouse.proc_list); } @@ -334,7 +334,7 @@ */ sunmouse.ready = 1; if (sunmouse.fasync) - kill_fasync (sunmouse.fasync, SIGIO); + kill_fasync (sunmouse.fasync, SIGIO, POLL_IN); wake_up_interruptible(&sunmouse.proc_list); } return; diff -u --recursive --new-file v2.3.20/linux/drivers/sbus/char/uctrl.c linux/drivers/sbus/char/uctrl.c --- v2.3.20/linux/drivers/sbus/char/uctrl.c Fri Sep 10 23:57:30 1999 +++ linux/drivers/sbus/char/uctrl.c Mon Oct 11 10:13:25 1999 @@ -92,7 +92,7 @@ #ifdef MODULE int init_module(void) #else -__initfunc(int uctrl_init(void)) +int __init uctrl_init(void) #endif { struct uctrl_driver *driver = &drv; diff -u --recursive --new-file v2.3.20/linux/drivers/scsi/imm.c linux/drivers/scsi/imm.c --- v2.3.20/linux/drivers/scsi/imm.c Fri May 7 10:57:42 1999 +++ linux/drivers/scsi/imm.c Mon Oct 11 14:48:00 1999 @@ -166,15 +166,8 @@ */ imm_hosts[i].mode = IMM_NIBBLE; - if (modes & PARPORT_MODE_PCPS2) + if (modes & PARPORT_MODE_TRISTATE) imm_hosts[i].mode = IMM_PS2; - - if (modes & PARPORT_MODE_PCECPPS2) { - w_ecr(ppb, 0x20); - imm_hosts[i].mode = IMM_PS2; - } - if (modes & PARPORT_MODE_PCECPEPP) - w_ecr(ppb, 0x80); /* Done configuration */ imm_pb_release(i); diff -u --recursive --new-file v2.3.20/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c --- v2.3.20/linux/drivers/scsi/sg.c Sat Oct 9 11:47:50 1999 +++ linux/drivers/scsi/sg.c Mon Oct 11 10:13:25 1999 @@ -815,7 +815,7 @@ /* Now wake up any sg_read() that is waiting for this packet. */ wake_up_interruptible(&sfp->read_wait); if ((sfp->async_qp) && (! closed)) - kill_fasync(sfp->async_qp, SIGPOLL); + kill_fasync(sfp->async_qp, SIGPOLL, POLL_IN); } static void sg_debug_all(const Sg_fd * sfp) diff -u --recursive --new-file v2.3.20/linux/drivers/sgi/char/shmiq.c linux/drivers/sgi/char/shmiq.c --- v2.3.20/linux/drivers/sgi/char/shmiq.c Thu Aug 26 13:05:39 1999 +++ linux/drivers/sgi/char/shmiq.c Mon Oct 11 10:13:25 1999 @@ -118,7 +118,7 @@ s->tail = tail_next; shmiqs [device].tail = tail_next; if (shmiqs [device].fasync) - kill_fasync (shmiqs [device].fasync, SIGIO); + kill_fasync (shmiqs [device].fasync, SIGIO, POLL_IN); wake_up_interruptible (&shmiqs [device].proc_list); } diff -u --recursive --new-file v2.3.20/linux/drivers/usb/audio.c linux/drivers/usb/audio.c --- v2.3.20/linux/drivers/usb/audio.c Sat Oct 9 11:47:50 1999 +++ linux/drivers/usb/audio.c Mon Oct 11 10:21:34 1999 @@ -769,7 +769,7 @@ static int usbin_completed(int status, void *__buffer, int rval, void *dev_id) { -#if 0 +#if 1 struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id; struct usb_audiodev *as = (struct usb_audiodev *)id->context; #else @@ -777,10 +777,13 @@ struct usb_isoc_desc *id; #endif struct usbin *u = &as->usbin; + unsigned long flags; unsigned int next, idmask; +#if 0 printk(KERN_DEBUG "usbin_completed: status %d rval %d flags 0x%x\n", status, rval, u->flags); - spin_lock(&as->lock); +#endif + spin_lock_irqsave(&as->lock, flags); next = !(u->flags & FLG_NEXTID); idmask = FLG_ID1RUNNING >> next; u->flags = (u->flags & ~(FLG_NEXTID | idmask)) | next; @@ -794,7 +797,12 @@ u->flags &= ~FLG_RUNNING; printk(KERN_DEBUG "usbin_completed: descriptor not restarted\n"); } - spin_unlock(&as->lock); + if (!(u->flags & idmask)) { + printk(KERN_DEBUG "usbin_completed: killing id\n"); + usb_kill_isoc(id); + printk(KERN_DEBUG "usbin_completed: id killed\n"); + } + spin_unlock_irqrestore(&as->lock, flags); return 0; } @@ -833,7 +841,7 @@ static int usbin_sync_completed(int status, void *__buffer, int rval, void *dev_id) { -#if 0 +#if 1 struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id; struct usb_audiodev *as = (struct usb_audiodev *)id->context; #else @@ -841,13 +849,16 @@ struct usb_isoc_desc *id; #endif struct usbin *u = &as->usbin; + unsigned long flags; unsigned int next, idmask; +#if 0 printk(KERN_DEBUG "usbin_sync_completed: status %d rval %d flags 0x%x\n", status, rval, u->flags); - spin_lock(&as->lock); +#endif + spin_lock_irqsave(&as->lock, flags); next = !(u->flags & FLG_SYNCNEXTID); idmask = FLG_SYNC1RUNNING >> next; - u->flags = (u->flags & ~(FLG_SYNCNEXTID | idmask)) | (-next & FLG_SYNCNEXTID); + u->flags = (u->flags & ~(FLG_SYNCNEXTID | idmask)) | ((-next) & FLG_SYNCNEXTID); id = u->synciso[!next]; if (!usbin_sync_retire_desc(u, id) && u->flags & FLG_RUNNING && @@ -858,7 +869,12 @@ u->flags &= ~FLG_RUNNING; printk(KERN_DEBUG "usbin_sync_completed: descriptor not restarted\n"); } - spin_unlock(&as->lock); + if (!(u->flags & idmask)) { + printk(KERN_DEBUG "usbin_sync_completed: killing id\n"); + usb_kill_isoc(id); + printk(KERN_DEBUG "usbin_sync_completed: id killed\n"); + } + spin_unlock_irqrestore(&as->lock, flags); return 0; } @@ -870,8 +886,10 @@ unsigned long flags; unsigned int which, i; - printk(KERN_DEBUG "usbin_start: device %d ufmt %d dfmt %d srate %d\n", +#if 0 + printk(KERN_DEBUG "usbin_start: device %d ufmt 0x%08x dfmt 0x%08x srate %d\n", dev->devnum, u->format, u->dma.format, u->dma.srate); +#endif /* allocate USB storage if not already done */ /* UHCI wants the data to be page aligned - this is silly */ if (!u->data[0]) @@ -980,15 +998,18 @@ unsigned long flags; unsigned int i; +printk(KERN_DEBUG "usb_audio: usbout_stop (1) flags 0x%04x\n", u->flags); spin_lock_irqsave(&as->lock, flags); u->flags &= ~FLG_RUNNING; i = u->flags; spin_unlock_irqrestore(&as->lock, flags); +printk(KERN_DEBUG "usb_audio: usbout_stop (2) flags 0x%04x\n", i); while (i & (FLG_ID0RUNNING|FLG_ID1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) { schedule_timeout(1); spin_lock_irqsave(&as->lock, flags); i = u->flags; spin_unlock_irqrestore(&as->lock, flags); +printk(KERN_DEBUG "usb_audio: usbout_stop (3) flags 0x%04x\n", i); } if (u->dataiso[0]) usb_free_isoc(u->dataiso[0]); @@ -1219,7 +1240,7 @@ static int usbout_completed(int status, void *__buffer, int rval, void *dev_id) { -#if 0 +#if 1 struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id; struct usb_audiodev *as = (struct usb_audiodev *)id->context; #else @@ -1227,10 +1248,13 @@ struct usb_isoc_desc *id; #endif struct usbout *u = &as->usbout; + unsigned long flags; unsigned int next, idmask; +#if 0 printk(KERN_DEBUG "usbout_completed: status %d rval %d flags 0x%x\n", status, rval, u->flags); - spin_lock(&as->lock); +#endif + spin_lock_irqsave(&as->lock, flags); next = !(u->flags & FLG_NEXTID); idmask = FLG_ID1RUNNING >> next; u->flags = (u->flags & ~(FLG_NEXTID | idmask)) | next; @@ -1244,7 +1268,12 @@ u->flags &= ~FLG_RUNNING; printk(KERN_DEBUG "usbout_completed: descriptor not restarted\n"); } - spin_unlock(&as->lock); + if (!(u->flags & idmask)) { + printk(KERN_DEBUG "usbout_completed: killing id\n"); + usb_kill_isoc(id); + printk(KERN_DEBUG "usbout_completed: id killed\n"); + } + spin_unlock_irqrestore(&as->lock, flags); return 0; } @@ -1286,7 +1315,7 @@ static int usbout_sync_completed(int status, void *__buffer, int rval, void *dev_id) { -#if 0 +#if 1 struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id; struct usb_audiodev *as = (struct usb_audiodev *)id->context; #else @@ -1294,13 +1323,16 @@ struct usb_isoc_desc *id; #endif struct usbout *u = &as->usbout; + unsigned long flags; unsigned int next, idmask; +#if 0 printk(KERN_DEBUG "usbout_sync_completed: status %d rval %d flags 0x%x\n", status, rval, u->flags); - spin_lock(&as->lock); +#endif + spin_lock_irqsave(&as->lock, flags); next = !(u->flags & FLG_SYNCNEXTID); idmask = FLG_SYNC1RUNNING >> next; - u->flags = (u->flags & ~(FLG_SYNCNEXTID | idmask)) | (-next & FLG_SYNCNEXTID); + u->flags = (u->flags & ~(FLG_SYNCNEXTID | idmask)) | ((-next) & FLG_SYNCNEXTID); id = u->synciso[!next]; if (!usbout_sync_retire_desc(u, id) && u->flags & FLG_RUNNING && @@ -1311,7 +1343,12 @@ u->flags &= ~FLG_RUNNING; printk(KERN_DEBUG "usbout_sync_completed: descriptor not restarted\n"); } - spin_unlock(&as->lock); + if (!(u->flags & idmask)) { + printk(KERN_DEBUG "usbout_sync_completed: killing id\n"); + usb_kill_isoc(id); + printk(KERN_DEBUG "usbout_sync_completed: id killed\n"); + } + spin_unlock_irqrestore(&as->lock, flags); return 0; } @@ -1323,8 +1360,10 @@ unsigned long flags; unsigned int which, i; - printk(KERN_DEBUG "usbout_start: device %d ufmt %d dfmt %d srate %d\n", +#if 0 + printk(KERN_DEBUG "usbout_start: device %d ufmt 0x%08x dfmt 0x%08x srate %d\n", dev->devnum, u->format, u->dma.format, u->dma.srate); +#endif /* allocate USB storage if not already done */ /* UHCI wants the data to be page aligned - this is silly */ if (!u->data[0]) @@ -1459,7 +1498,7 @@ struct usbin *u = &as->usbin; struct dmabuf *d = &u->dma; struct audioformat *fmt; - unsigned int fmtnr; + unsigned int fmtnr, ep; unsigned char data[3]; if (u->interface < 0 || u->interface >= config->bNumInterfaces) @@ -1474,7 +1513,7 @@ if ((alts->endpoint[0].bmAttributes & 0x0c) == 0x08) { if (alts->bNumEndpoints < 2 || alts->endpoint[1].bmAttributes != 0x01 || - alts->endpoint[1].bSynchAddress == 0 || + alts->endpoint[1].bSynchAddress != 0 || alts->endpoint[1].bEndpointAddress != (alts->endpoint[0].bSynchAddress & 0x7f)) { printk(KERN_ERR "usb_audio: device %d interface %d altsetting %d invalid synch pipe\n", dev->devnum, u->interface, fmt->altsetting); @@ -1497,18 +1536,21 @@ data[0] = d->srate; data[1] = d->srate >> 8; data[2] = d->srate >> 16; + ep = usb_pipeendpoint(u->datapipe) | (u->datapipe & USB_DIR_IN); if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, - SAMPLING_FREQ_CONTROL << 8, usb_pipeendpoint(u->datapipe), data, 3, HZ) != 3) { - printk(KERN_ERR "usbaudio: failure to set sampling frequency device %d endpoint %d\n", - dev->devnum, usb_pipeendpoint(u->datapipe)); + SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ) < 0) { + printk(KERN_ERR "usbaudio: failure to set input sampling frequency device %d endpoint 0x%x to %u\n", + dev->devnum, ep, d->srate); return -1; } if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN, - SAMPLING_FREQ_CONTROL << 8, usb_pipeendpoint(u->datapipe), data, 3, HZ) != 3) { - printk(KERN_ERR "usbaudio: failure to get sampling frequency device %d endpoint %d\n", - dev->devnum, usb_pipeendpoint(u->datapipe)); + SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ) < 0) { + printk(KERN_ERR "usbaudio: failure to get input sampling frequency device %d endpoint 0x%x\n", + dev->devnum, ep); return -1; } + printk(KERN_DEBUG "usb_audio: set_format_in: device %d interface %d altsetting %d srate req: %u real %u\n", + dev->devnum, u->interface, fmt->altsetting, d->srate, data[0] | (data[1] << 8) | (data[2] << 16)); d->srate = data[0] | (data[1] << 8) | (data[2] << 16); return 0; } @@ -1522,7 +1564,7 @@ struct usbout *u = &as->usbout; struct dmabuf *d = &u->dma; struct audioformat *fmt; - unsigned int fmtnr; + unsigned int fmtnr, ep; unsigned char data[3]; if (u->interface < 0 || u->interface >= config->bNumInterfaces) @@ -1537,7 +1579,7 @@ if ((alts->endpoint[0].bmAttributes & 0x0c) == 0x04) { if (alts->bNumEndpoints < 2 || alts->endpoint[1].bmAttributes != 0x01 || - alts->endpoint[1].bSynchAddress == 0 || + alts->endpoint[1].bSynchAddress != 0 || alts->endpoint[1].bEndpointAddress != (alts->endpoint[0].bSynchAddress | 0x80)) { printk(KERN_ERR "usb_audio: device %d interface %d altsetting %d invalid synch pipe\n", dev->devnum, u->interface, fmt->altsetting); @@ -1560,18 +1602,21 @@ data[0] = d->srate; data[1] = d->srate >> 8; data[2] = d->srate >> 16; + ep = usb_pipeendpoint(u->datapipe) | (u->datapipe & USB_DIR_IN); if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, - SAMPLING_FREQ_CONTROL << 8, usb_pipeendpoint(u->datapipe), data, 3, HZ) != 3) { - printk(KERN_ERR "usbaudio: failure to set sampling frequency device %d endpoint %d\n", - dev->devnum, usb_pipeendpoint(u->datapipe)); + SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ) < 0) { + printk(KERN_ERR "usbaudio: failure to set output sampling frequency device %d endpoint 0x%x to %u\n", + dev->devnum, ep, d->srate); return -1; } if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN, - SAMPLING_FREQ_CONTROL << 8, usb_pipeendpoint(u->datapipe), data, 3, HZ) != 3) { - printk(KERN_ERR "usbaudio: failure to get sampling frequency device %d endpoint %d\n", - dev->devnum, usb_pipeendpoint(u->datapipe)); + SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ) < 0) { + printk(KERN_ERR "usbaudio: failure to get output sampling frequency device %d endpoint 0x%x\n", + dev->devnum, ep); return -1; } + printk(KERN_DEBUG "usb_audio: set_format_out: device %d interface %d altsetting %d srate req: %u real %u\n", + dev->devnum, u->interface, fmt->altsetting, d->srate, data[0] | (data[1] << 8) | (data[2] << 16)); d->srate = data[0] | (data[1] << 8) | (data[2] << 16); return 0; } @@ -1642,7 +1687,7 @@ data[0] = v1; data[1] = v1 >> 8; if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - (ch->chnum << 8) | 1, ms->iface | (ch->unitid << 8), data, 2, HZ) < 2) + (ch->chnum << 8) | 1, ms->iface | (ch->unitid << 8), data, 2, HZ) < 0) goto err; if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT))) return 0; @@ -1650,7 +1695,7 @@ data[1] = v2 >> 8; if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)), - ms->iface | (ch->unitid << 8), data, 2, HZ) < 2) + ms->iface | (ch->unitid << 8), data, 2, HZ) < 0) goto err; return 0; @@ -1659,14 +1704,14 @@ data[0] = v1; data[1] = v1 >> 8; if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 2, HZ) < 2) + (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 2, HZ) < 0) goto err; if (ch->chnum == 0) return 0; data[0] = v2; data[1] = v2 >> 8; if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 2, HZ) < 2) + (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 2, HZ) < 0) goto err; return 0; @@ -1675,13 +1720,13 @@ case TREBLE_CONTROL: data[0] = v1 >> 8; if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 1, HZ) < 1) + (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 1, HZ) < 0) goto err; if (ch->chnum == 0) return 0; data[0] = v2 >> 8; if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 1, HZ) < 1) + (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 1, HZ) < 0) goto err; return 0; @@ -1839,7 +1884,7 @@ for (val = i = 0; i < ms->numch; i++) if (ms->ch[i].flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) val |= 1 << ms->ch[i].osschannel; - return put_user(0, (int *)arg); + return put_user(val, (int *)arg); case SOUND_MIXER_CAPS: return put_user(0, (int *)arg); @@ -2778,26 +2823,26 @@ if ((state->termtype & 0xff00) == 0x0000 && !(state->mixchmask & SOUND_MASK_VOLUME)) return SOUND_MIXER_VOLUME; if ((state->termtype & 0xff00) == 0x0100) { - if (!(state->mixchmask & SOUND_MASK_PCM)) + if (state->mixchmask & SOUND_MASK_PCM) return SOUND_MIXER_PCM; - if (!(state->mixchmask & SOUND_MASK_ALTPCM)) + if (state->mixchmask & SOUND_MASK_ALTPCM) return SOUND_MIXER_ALTPCM; } - if ((state->termtype & 0xff00) == 0x0200 && !(state->mixchmask & SOUND_MASK_MIC)) + if ((state->termtype & 0xff00) == 0x0200 && (state->mixchmask & SOUND_MASK_MIC)) return SOUND_MIXER_MIC; - if ((state->termtype & 0xff00) == 0x0300 && !(state->mixchmask & SOUND_MASK_SPEAKER)) + if ((state->termtype & 0xff00) == 0x0300 && (state->mixchmask & SOUND_MASK_SPEAKER)) return SOUND_MIXER_SPEAKER; - if ((state->termtype & 0xff00) == 0x0300 && !(state->mixchmask & SOUND_MASK_SPEAKER)) + if ((state->termtype & 0xff00) == 0x0300 && (state->mixchmask & SOUND_MASK_SPEAKER)) return SOUND_MIXER_SPEAKER; if ((state->termtype & 0xff00) == 0x0500) { - if (!(state->mixchmask & SOUND_MASK_PHONEIN)) + if (state->mixchmask & SOUND_MASK_PHONEIN) return SOUND_MIXER_PHONEIN; - if (!(state->mixchmask & SOUND_MASK_PHONEOUT)) + if (state->mixchmask & SOUND_MASK_PHONEOUT) return SOUND_MIXER_PHONEOUT; } - if (state->termtype >= 0x710 && state->termtype <= 0x711 && !(state->mixchmask & SOUND_MASK_RADIO)) + if (state->termtype >= 0x710 && state->termtype <= 0x711 && (state->mixchmask & SOUND_MASK_RADIO)) return SOUND_MIXER_RADIO; - if (state->termtype >= 0x709 && state->termtype <= 0x70f && !(state->mixchmask & SOUND_MASK_VIDEO)) + if (state->termtype >= 0x709 && state->termtype <= 0x70f && (state->mixchmask & SOUND_MASK_VIDEO)) return SOUND_MIXER_VIDEO; u = ffs(state->mixchmask & (SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | SOUND_MASK_LINE3 | SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 | SOUND_MASK_DIGITAL3)); @@ -2818,18 +2863,18 @@ switch (ch->selector) { case 0: /* mixer unit request */ if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2) + (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0) goto err; ch->minval = buf[0] | (buf[1] << 8); if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2) + (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0) goto err; ch->maxval = buf[0] | (buf[1] << 8); v2 = ch->maxval - ch->minval; if (!v2) v2 = 1; if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2) + (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0) goto err; v1 = buf[0] | (buf[1] << 8); v3 = v1 - ch->minval; @@ -2840,7 +2885,7 @@ if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) { if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)), - state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2) + state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0) goto err; v1 = buf[0] | (buf[1] << 8); v3 = v1 - ch->minval; @@ -2854,15 +2899,15 @@ /* various feature unit controls */ case VOLUME_CONTROL: if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2) + (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0) goto err; ch->minval = buf[0] | (buf[1] << 8); if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2) + (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0) goto err; ch->maxval = buf[0] | (buf[1] << 8); if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2) + (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0) goto err; v1 = buf[0] | (buf[1] << 8); v2 = ch->maxval - ch->minval; @@ -2875,7 +2920,7 @@ ch->value = v3; if (ch->chnum != 0) { if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2) + (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0) goto err; v1 = buf[0] | (buf[1] << 8); v3 = v1 - ch->minval; @@ -2890,15 +2935,15 @@ case MID_CONTROL: case TREBLE_CONTROL: if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 1) + (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0) goto err; ch->minval = buf[0] << 8; if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 1) + (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0) goto err; ch->maxval = buf[0] << 8; if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 1) + (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0) goto err; v1 = buf[0] << 8; v2 = ch->maxval - ch->minval; @@ -2911,7 +2956,7 @@ ch->value = v3; if (ch->chnum != 0) { if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 1) + (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0) goto err; v1 = buf[0] << 8; v3 = v1 - ch->minval; @@ -2942,12 +2987,12 @@ unsigned int idx; idx = inidx*numoch; - if (!(bmap[idx >> 3] & (1 << (idx & 7)))) + if (!(bmap[-(idx >> 3)] & (0x80 >> (idx & 7)))) return 0; if (!(flg & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT))) return 1; idx = (inidx+!!(flg & MIXFLG_STEREOIN))*numoch+!!(flg & MIXFLG_STEREOOUT); - if (!(bmap[idx >> 3] & (1 << (idx & 7)))) + if (!(bmap[-(idx >> 3)] & (0x80 >> (idx & 7)))) return 0; return 1; } @@ -2958,6 +3003,8 @@ unsigned int chidx[SOUND_MIXER_NRDEVICES+1]; unsigned int termt[SOUND_MIXER_NRDEVICES]; unsigned char flg = (nroutch >= 2) ? MIXFLG_STEREOOUT : 0; + unsigned char *bmap = &mixer[9+mixer[4]]; + unsigned int bmapsize; struct mixerchannel *ch; unsigned int i; @@ -2977,7 +3024,9 @@ } state->termtype = 0; state->chconfig = mixer[6+mixer[4]] | (mixer[7+mixer[4]] << 8); - if (mixer[0] < 10+mixer[4]+((nroutch * chidx[mixer[4]] + 7) >> 3)) { + bmapsize = (nroutch * chidx[mixer[4]] + 7) >> 3; + bmap += bmapsize - 1; + if (mixer[0] < 10+mixer[4]+bmapsize) { printk(KERN_ERR "usb_audio: unit %u invalid MIXER_UNIT descriptor (bitmap too small)\n", mixer[3]); return; } @@ -2985,7 +3034,7 @@ state->termtype = termt[i]; if (chidx[i+1]-chidx[i] >= 2) { flg |= MIXFLG_STEREOIN; - if (checkmixbmap(&mixer[9+mixer[4]], flg, chidx[i], nroutch)) { + if (checkmixbmap(bmap, flg, chidx[i], nroutch)) { ch = getmixchannel(state, getvolchannel(state)); if (ch) { ch->unitid = mixer[3]; @@ -2998,7 +3047,7 @@ } } flg &= ~MIXFLG_STEREOIN; - if (checkmixbmap(&mixer[9+mixer[4]], flg, chidx[i], nroutch)) { + if (checkmixbmap(bmap, flg, chidx[i], nroutch)) { ch = getmixchannel(state, getvolchannel(state)); if (ch) { ch->unitid = mixer[3]; @@ -3134,6 +3183,7 @@ static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unitid) { unsigned char *p1; + unsigned int i, j; if (test_and_set_bit(unitid, &state->unitbitmap)) { printk(KERN_ERR "usb_audio: mixer path recursion detected, unit %d!\n", unitid); @@ -3195,15 +3245,16 @@ printk(KERN_ERR "usb_audio: unit %u: invalid EXTENSION_UNIT descriptor\n", unitid); return; } - { - unsigned int i; - - for (i = 0; i < p1[6]; i++) - usb_audio_recurseunit(state, p1[7+i]); + for (j = i = 0; i < p1[6]; i++) { + usb_audio_recurseunit(state, p1[7+i]); + if (!i) + j = state->termtype; + else if (j != state->termtype) + j = 0; } state->nrchannels = p1[7+p1[6]]; state->chconfig = p1[8+p1[6]] | (p1[9+p1[6]] << 8); - state->termtype = 0; + state->termtype = j; return; default: @@ -3378,6 +3429,10 @@ return -1; configfound: + if (usb_set_configuration(dev, config->bConfigurationValue) < 0) { + printk(KERN_ERR "usb_audio: set_configuration failed (ConfigValue 0x%x)\n", config->bConfigurationValue); + return -1; + } ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buf, 8); if (ret) { printk(KERN_ERR "usb_audio: cannot get first 8 bytes of config descriptor %d of device %d\n", i, dev->devnum); diff -u --recursive --new-file v2.3.20/linux/drivers/usb/mouse.c linux/drivers/usb/mouse.c --- v2.3.20/linux/drivers/usb/mouse.c Fri Sep 10 23:57:36 1999 +++ linux/drivers/usb/mouse.c Mon Oct 11 10:13:25 1999 @@ -120,7 +120,7 @@ wake_up_interruptible(&mouse->wait); if (mouse->fasync) - kill_fasync(mouse->fasync, SIGIO); + kill_fasync(mouse->fasync, SIGIO, POLL_IN); return 1; } diff -u --recursive --new-file v2.3.20/linux/drivers/video/Config.in linux/drivers/video/Config.in --- v2.3.20/linux/drivers/video/Config.in Fri Sep 10 23:57:36 1999 +++ linux/drivers/video/Config.in Mon Oct 11 10:30:42 1999 @@ -2,350 +2,362 @@ # Video configuration # +mainmenu_option next_comment +comment 'Frame-buffer support' + +bool 'Support for frame buffer devices (EXPERIMENTAL)' CONFIG_FB + if [ "$CONFIG_FB" = "y" ]; then - define_bool CONFIG_DUMMY_CONSOLE y - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_PCI" = "y" ]; then - tristate 'Cirrus Logic suport (experimental)' CONFIG_FB_CLGEN - tristate 'Permedia2 support (experimental)' CONFIG_FB_PM2 - if [ "$CONFIG_FB_PM2" = "y" ]; then - if [ "$CONFIG_PCI" = "y" ]; then - bool ' enable FIFO disconnect feature' CONFIG_FB_PM2_FIFO_DISCONNECT - bool ' generic Permedia2 PCI board support' CONFIG_FB_PM2_PCI - fi - if [ "$CONFIG_AMIGA" = "y" ]; then - bool ' Phase5 CVisionPPC/BVisionPPC support' CONFIG_FB_PM2_CVPPC - fi - fi - fi - fi - if [ "$CONFIG_ARCH_ACORN" = "y" ]; then - bool 'Acorn VIDC support' CONFIG_FB_ACORN - fi - if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then - tristate 'Cyber2000 support' CONFIG_FB_CYBER2000 - fi - if [ "$CONFIG_APOLLO" = "y" ]; then - define_bool CONFIG_FB_APOLLO y - fi - if [ "$CONFIG_Q40" = "y" ]; then - define_bool CONFIG_FB_Q40 y - fi - if [ "$CONFIG_AMIGA" = "y" ]; then - bool 'Amiga native chipset support' CONFIG_FB_AMIGA - if [ "$CONFIG_FB_AMIGA" != "n" ]; then - bool 'Amiga OCS chipset support' CONFIG_FB_AMIGA_OCS - bool 'Amiga ECS chipset support' CONFIG_FB_AMIGA_ECS - bool 'Amiga AGA chipset support' CONFIG_FB_AMIGA_AGA - fi - fi - if [ "$CONFIG_ZORRO" = "y" ]; then - tristate 'Amiga CyberVision support' CONFIG_FB_CYBER - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'Amiga CyberVision3D support (experimental)' CONFIG_FB_VIRGE - tristate 'Amiga RetinaZ3 support' CONFIG_FB_RETINAZ3 - bool 'Amiga FrameMaster II/Rainbow II support (experimental)' CONFIG_FB_FM2 - fi - fi - if [ "$CONFIG_ATARI" = "y" ]; then - bool 'Atari native chipset support' CONFIG_FB_ATARI - tristate 'ATI Mach64 display support' CONFIG_FB_ATY - fi - if [ "$CONFIG_PPC" = "y" ]; then - bool 'Open Firmware frame buffer device support' CONFIG_FB_OF - if [ "$CONFIG_FB_OF" = "y" ]; then - bool 'Apple "control" display support' CONFIG_FB_CONTROL - bool 'Apple "platinum" display support' CONFIG_FB_PLATINUM - bool 'Apple "valkyrie" display support' CONFIG_FB_VALKYRIE - tristate 'ATI Mach64 display support' CONFIG_FB_ATY - bool 'IMS Twin Turbo display support' CONFIG_FB_IMSTT - bool 'Chips 65550 display support' CONFIG_FB_CT65550 - bool 'S3 Trio display support' CONFIG_FB_S3TRIO - fi - tristate 'VGA 16-color graphics console' CONFIG_FB_VGA16 - fi - if [ "$CONFIG_MAC" = "y" ]; then - define_bool CONFIG_FB_MAC y - fi - if [ "$CONFIG_HP300" = "y" ]; then - define_bool CONFIG_FB_HP300 y - fi - if [ "$ARCH" = "alpha" ]; then - tristate 'TGA framebuffer support' CONFIG_FB_TGA - fi - if [ "$ARCH" = "i386" ]; then - bool 'VESA VGA graphics console' CONFIG_FB_VESA - tristate 'VGA 16-color graphics console' CONFIG_FB_VGA16 - define_bool CONFIG_VIDEO_SELECT y - fi - if [ "$CONFIG_VISWS" = "y" ]; then - tristate 'SGI Visual Workstation framebuffer support' CONFIG_FB_SGIVW - fi - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_PCI" != "n" ]; then - tristate 'Matrox acceleration' CONFIG_FB_MATROX - if [ "$CONFIG_FB_MATROX" != "n" ]; then - bool ' Millennium I/II support' CONFIG_FB_MATROX_MILLENIUM - bool ' Mystique support' CONFIG_FB_MATROX_MYSTIQUE - bool ' G100/G200/G400 support' CONFIG_FB_MATROX_G100 - bool ' Multihead support' CONFIG_FB_MATROX_MULTIHEAD - fi - tristate 'ATI Mach64 display support' CONFIG_FB_ATY - fi - fi - if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then - bool 'SBUS and UPA framebuffers' CONFIG_FB_SBUS - if [ "$CONFIG_FB_SBUS" != "n" ]; then - if [ "$ARCH" = "sparc64" ]; then - bool ' Creator/Creator3D support' CONFIG_FB_CREATOR - fi - bool ' CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX - bool ' BWtwo support' CONFIG_FB_BWTWO - bool ' CGthree support' CONFIG_FB_CGTHREE - if [ "$ARCH" = "sparc" ]; then - bool ' TCX (SS4/SS5 only) support' CONFIG_FB_TCX - bool ' CGfourteen (SX) support' CONFIG_FB_CGFOURTEEN - bool ' P9100 (Sparcbook 3 only) support' CONFIG_FB_P9100 - fi - bool ' Leo (ZX) support' CONFIG_FB_LEO - fi - fi - if [ "$ARCH" = "sparc" ]; then - if [ "$CONFIG_PCI" != "n" ]; then - bool 'PCI framebuffers' CONFIG_FB_PCI - if [ "$CONFIG_FB_PCI" != "n" ]; then - bool ' IGA 168x display support' CONFIG_FB_IGA - fi - fi - fi - if [ "$ARCH" = "sparc64" ]; then - if [ "$CONFIG_PCI" != "n" ]; then - bool 'PCI framebuffers' CONFIG_FB_PCI - if [ "$CONFIG_FB_PCI" != "n" ]; then - tristate ' ATI Mach64 display support' CONFIG_FB_ATY - fi - fi - fi - tristate 'Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL + define_bool CONFIG_DUMMY_CONSOLE y + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_PCI" = "y" ]; then + tristate ' Cirrus Logic suport (EXPERIMENTAL)' CONFIG_FB_CLGEN + tristate ' Permedia2 support (EXPERIMENTAL)' CONFIG_FB_PM2 + if [ "$CONFIG_FB_PM2" = "y" ]; then + if [ "$CONFIG_PCI" = "y" ]; then + bool ' enable FIFO disconnect feature' CONFIG_FB_PM2_FIFO_DISCONNECT + bool ' generic Permedia2 PCI board support' CONFIG_FB_PM2_PCI + fi + if [ "$CONFIG_AMIGA" = "y" ]; then + bool ' Phase5 CVisionPPC/BVisionPPC support' CONFIG_FB_PM2_CVPPC + fi + fi + fi + fi + if [ "$CONFIG_ARCH_ACORN" = "y" ]; then + bool ' Acorn VIDC support' CONFIG_FB_ACORN + fi + if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then + tristate ' Cyber2000 support' CONFIG_FB_CYBER2000 + fi + if [ "$CONFIG_APOLLO" = "y" ]; then + define_bool CONFIG_FB_APOLLO y + fi + if [ "$CONFIG_Q40" = "y" ]; then + define_bool CONFIG_FB_Q40 y + fi + if [ "$CONFIG_AMIGA" = "y" ]; then + bool ' Amiga native chipset support' CONFIG_FB_AMIGA + if [ "$CONFIG_FB_AMIGA" != "n" ]; then + bool ' Amiga OCS chipset support' CONFIG_FB_AMIGA_OCS + bool ' Amiga ECS chipset support' CONFIG_FB_AMIGA_ECS + bool ' Amiga AGA chipset support' CONFIG_FB_AMIGA_AGA + fi + fi + if [ "$CONFIG_ZORRO" = "y" ]; then + tristate ' Amiga CyberVision support' CONFIG_FB_CYBER + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' Amiga CyberVision3D support (EXPERIMENTAL)' CONFIG_FB_VIRGE + tristate ' Amiga RetinaZ3 support (EXPERIMENTAL)' CONFIG_FB_RETINAZ3 + bool ' Amiga FrameMaster II/Rainbow II support (EXPERIMENTAL)' CONFIG_FB_FM2 + fi + fi + if [ "$CONFIG_ATARI" = "y" ]; then + bool ' Atari native chipset support' CONFIG_FB_ATARI + tristate ' ATI Mach64 display support' CONFIG_FB_ATY + fi + if [ "$CONFIG_PPC" = "y" ]; then + bool ' Open Firmware frame buffer device support' CONFIG_FB_OF + if [ "$CONFIG_FB_OF" = "y" ]; then + bool ' Apple "control" display support' CONFIG_FB_CONTROL + bool ' Apple "platinum" display support' CONFIG_FB_PLATINUM + bool ' Apple "valkyrie" display support' CONFIG_FB_VALKYRIE + bool ' IMS Twin Turbo display support' CONFIG_FB_IMSTT + bool ' Chips 65550 display support' CONFIG_FB_CT65550 + bool ' S3 Trio display support' CONFIG_FB_S3TRIO + fi + tristate ' VGA 16-color graphics console' CONFIG_FB_VGA16 + fi + if [ "$CONFIG_MAC" = "y" ]; then + define_bool CONFIG_FB_MAC y + fi + if [ "$CONFIG_HP300" = "y" ]; then + define_bool CONFIG_FB_HP300 y + fi + if [ "$ARCH" = "alpha" ]; then + tristate ' TGA framebuffer support' CONFIG_FB_TGA + fi + if [ "$ARCH" = "i386" ]; then + bool ' VESA VGA graphics console' CONFIG_FB_VESA + tristate ' VGA 16-color graphics console' CONFIG_FB_VGA16 + define_bool CONFIG_VIDEO_SELECT y + fi + if [ "$CONFIG_VISWS" = "y" ]; then + tristate ' SGI Visual Workstation framebuffer support' CONFIG_FB_SGIVW + define_bool CONFIG_BUS_I2C y + fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_PCI" != "n" ]; then + tristate ' Matrox acceleration (EXPERIMENTAL)' CONFIG_FB_MATROX + if [ "$CONFIG_FB_MATROX" != "n" ]; then + bool ' Millennium I/II support' CONFIG_FB_MATROX_MILLENIUM + bool ' Mystique support' CONFIG_FB_MATROX_MYSTIQUE + bool ' G100/G200/G400 support' CONFIG_FB_MATROX_G100 + bool ' Multihead support' CONFIG_FB_MATROX_MULTIHEAD + fi + tristate ' ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY + bool ' 3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX + fi + fi + if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then + bool ' SBUS and UPA framebuffers' CONFIG_FB_SBUS + if [ "$CONFIG_FB_SBUS" != "n" ]; then + if [ "$ARCH" = "sparc64" ]; then + bool ' Creator/Creator3D support' CONFIG_FB_CREATOR + fi + bool ' CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX + bool ' BWtwo support' CONFIG_FB_BWTWO + bool ' CGthree support' CONFIG_FB_CGTHREE + if [ "$ARCH" = "sparc" ]; then + bool ' TCX (SS4/SS5 only) support' CONFIG_FB_TCX + bool ' CGfourteen (SX) support' CONFIG_FB_CGFOURTEEN + bool ' P9100 (Sparcbook 3 only) support' CONFIG_FB_P9100 + fi + bool ' Leo (ZX) support' CONFIG_FB_LEO + fi + fi + if [ "$ARCH" = "sparc" ]; then + if [ "$CONFIG_PCI" != "n" ]; then + bool ' PCI framebuffers' CONFIG_FB_PCI + if [ "$CONFIG_FB_PCI" != "n" ]; then + bool ' IGA 168x display support' CONFIG_FB_IGA + fi + fi + fi + if [ "$ARCH" = "sparc64" ]; then + if [ "$CONFIG_PCI" != "n" ]; then + bool ' PCI framebuffers' CONFIG_FB_PCI + if [ "$CONFIG_FB_PCI" != "n" ]; then + tristate ' ATI Mach64 display support' CONFIG_FB_ATY + fi + fi + fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate ' Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL + fi - bool 'Advanced low level driver options' CONFIG_FBCON_ADVANCED - if [ "$CONFIG_FBCON_ADVANCED" = "y" ]; then - tristate 'Monochrome support' CONFIG_FBCON_MFB - tristate '2 bpp packed pixels support' CONFIG_FBCON_CFB2 - tristate '4 bpp packed pixels support' CONFIG_FBCON_CFB4 - tristate '8 bpp packed pixels support' CONFIG_FBCON_CFB8 - tristate '16 bpp packed pixels support' CONFIG_FBCON_CFB16 - tristate '24 bpp packed pixels support' CONFIG_FBCON_CFB24 - tristate '32 bpp packed pixels support' CONFIG_FBCON_CFB32 - tristate 'Amiga bitplanes support' CONFIG_FBCON_AFB - tristate 'Amiga interleaved bitplanes support' CONFIG_FBCON_ILBM - tristate 'Atari interleaved bitplanes (2 planes) support' CONFIG_FBCON_IPLAN2P2 - tristate 'Atari interleaved bitplanes (4 planes) support' CONFIG_FBCON_IPLAN2P4 - tristate 'Atari interleaved bitplanes (8 planes) support' CONFIG_FBCON_IPLAN2P8 -# tristate 'Atari interleaved bitplanes (16 planes) support' CONFIG_FBCON_IPLAN2P16 - tristate 'Mac variable bpp packed pixels support' CONFIG_FBCON_MAC - tristate 'VGA 16-color planar support' CONFIG_FBCON_VGA_PLANES - tristate 'VGA characters/attributes support' CONFIG_FBCON_VGA - else - # Guess what we need - if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_AMIGA" = "y" -o \ - "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \ - "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_RETINAZ3" = "y" -o \ - "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ - "$CONFIG_FB_BWTWO" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then - define_bool CONFIG_FBCON_MFB y - else - if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_AMIGA" = "m" -o \ - "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \ - "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_RETINAZ3" = "m" -o \ - "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ - "$CONFIG_FB_BWTWO" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then - define_bool CONFIG_FBCON_MFB m - fi - fi - if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_MAC" = "y" -o \ - "$CONFIG_FB_VIRTUAL" = "y" ]; then - define_bool CONFIG_FBCON_CFB2 y - define_bool CONFIG_FBCON_CFB4 y - else - if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_MAC" = "m" -o \ - "$CONFIG_FB_VIRTUAL" = "m" ]; then - define_bool CONFIG_FBCON_CFB2 m - define_bool CONFIG_FBCON_CFB4 m - fi - fi - if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_ATARI" = "y" -o \ - "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \ - "$CONFIG_FB_OF" = "y" -o "$CONFIG_FB_TGA" = "y" -o \ - "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ - "$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \ - "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ - "$CONFIG_FB_CGFOURTEEN" = "y" -o "$CONFIG_FB_G364" = "y" -o \ - "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \ - "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ - "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \ - "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ - "$CONFIG_FB_P9100" = "y" -o \ - "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" ]; then - define_bool CONFIG_FBCON_CFB8 y - else - if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \ - "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_MAC" = "m" -o \ - "$CONFIG_FB_OF" = "m" -o "$CONFIG_FB_TGA" = "m" -o \ - "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ - "$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \ - "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ - "$CONFIG_FB_CGFOURTEEN" = "m" -o "$CONFIG_FB_G364" = "m" -o \ - "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \ - "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ - "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \ - "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ - "$CONFIG_FB_P9100" = "m" -o \ - "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" ]; then - define_bool CONFIG_FBCON_CFB8 m - fi - fi - if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \ - "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \ - "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \ - "$CONFIG_FB_Q40" = "y" -o \ - "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ - "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \ - "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ - "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \ - "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ - "$CONFIG_FB_CYBER2000" = "y" ]; then - define_bool CONFIG_FBCON_CFB16 y - else - if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ - "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VESA" = "m" -o \ - "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \ - "$CONFIG_FB_Q40" = "m" -o \ - "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ - "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \ - "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ - "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \ - "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "m" -o \ - "$CONFIG_FB_CYBER2000" = "m" ]; then - define_bool CONFIG_FBCON_CFB16 m - fi - fi - if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ - "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" -o \ - "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ - "$CONFIG_FB_CYBER2000" = "y" ]; then - define_bool CONFIG_FBCON_CFB24 y - else - if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ - "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" -o \ - "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ - "$CONFIG_FB_CYBER2000" = "m" ]; then - define_bool CONFIG_FBCON_CFB24 m - fi - fi - if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \ - "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ - "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ - "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ - "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ - "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" ]; then - define_bool CONFIG_FBCON_CFB32 y - else - if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ - "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ - "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ - "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ - "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ - "$CONFIG_FB_SGIVW" = "m" ]; then - define_bool CONFIG_FBCON_CFB32 m - fi - fi - if [ "$CONFIG_FB_AMIGA" = "y" ]; then - define_bool CONFIG_FBCON_AFB y - define_bool CONFIG_FBCON_ILBM y - else - if [ "$CONFIG_FB_AMIGA" = "m" ]; then - define_bool CONFIG_FBCON_AFB m - define_bool CONFIG_FBCON_ILBM m - fi - fi - if [ "$CONFIG_FB_ATARI" = "y" ]; then - define_bool CONFIG_FBCON_IPLAN2P2 y - define_bool CONFIG_FBCON_IPLAN2P4 y - define_bool CONFIG_FBCON_IPLAN2P8 y -# define_bool CONFIG_FBCON_IPLAN2P16 y - else - if [ "$CONFIG_FB_ATARI" = "m" ]; then - define_bool CONFIG_FBCON_IPLAN2P2 m - define_bool CONFIG_FBCON_IPLAN2P4 m - define_bool CONFIG_FBCON_IPLAN2P8 m -# define_bool CONFIG_FBCON_IPLAN2P16 m - fi - fi - if [ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then - define_bool CONFIG_FBCON_MAC y - else - if [ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then - define_bool CONFIG_FBCON_MAC m - fi - fi - if [ "$CONFIG_FB_VGA16" = "y" ]; then - define_bool CONFIG_FBCON_VGA_PLANES y - else - if [ "$CONFIG_FB_VGA16" = "m" ]; then - define_bool CONFIG_FBCON_VGA_PLANES m - fi - fi - if [ "$CONFIG_FB_MDA" = "y" -o "$CONFIG_FB_VGA" = "y" ]; then - define_bool CONFIG_FBCON_VGA y - else - if [ "$CONFIG_FB_MDA" = "m" -o "$CONFIG_FB_VGA" = "m" ]; then - define_bool CONFIG_FBCON_VGA m - fi - fi - fi - bool 'Support only 8 pixels wide fonts' CONFIG_FBCON_FONTWIDTH8_ONLY - if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then - bool 'Sparc console 8x16 font' CONFIG_FONT_SUN8x16 - if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then - bool 'Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22 - fi - bool 'Select other fonts' CONFIG_FBCON_FONTS - if [ "$CONFIG_FBCON_FONTS" = "y" ]; then - bool ' VGA 8x8 font' CONFIG_FONT_8x8 - bool ' VGA 8x16 font' CONFIG_FONT_8x16 - if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then - bool ' Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11 - fi - bool ' Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8 - bool ' Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8 - fi - else - bool 'Select compiled-in fonts' CONFIG_FBCON_FONTS - if [ "$CONFIG_FBCON_FONTS" = "y" ]; then - bool ' VGA 8x8 font' CONFIG_FONT_8x8 - bool ' VGA 8x16 font' CONFIG_FONT_8x16 + bool ' Advanced low level driver options' CONFIG_FBCON_ADVANCED + if [ "$CONFIG_FBCON_ADVANCED" = "y" ]; then + tristate ' Monochrome support' CONFIG_FBCON_MFB + tristate ' 2 bpp packed pixels support' CONFIG_FBCON_CFB2 + tristate ' 4 bpp packed pixels support' CONFIG_FBCON_CFB4 + tristate ' 8 bpp packed pixels support' CONFIG_FBCON_CFB8 + tristate ' 16 bpp packed pixels support' CONFIG_FBCON_CFB16 + tristate ' 24 bpp packed pixels support' CONFIG_FBCON_CFB24 + tristate ' 32 bpp packed pixels support' CONFIG_FBCON_CFB32 + tristate ' Amiga bitplanes support' CONFIG_FBCON_AFB + tristate ' Amiga interleaved bitplanes support' CONFIG_FBCON_ILBM + tristate ' Atari interleaved bitplanes (2 planes) support' CONFIG_FBCON_IPLAN2P2 + tristate ' Atari interleaved bitplanes (4 planes) support' CONFIG_FBCON_IPLAN2P4 + tristate ' Atari interleaved bitplanes (8 planes) support' CONFIG_FBCON_IPLAN2P8 +# tristate ' Atari interleaved bitplanes (16 planes) support' CONFIG_FBCON_IPLAN2P16 + tristate ' Mac variable bpp packed pixels support' CONFIG_FBCON_MAC + tristate ' VGA 16-color planar support' CONFIG_FBCON_VGA_PLANES + tristate ' VGA characters/attributes support' CONFIG_FBCON_VGA + else + # Guess what we need + if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_AMIGA" = "y" -o \ + "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \ + "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_RETINAZ3" = "y" -o \ + "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ + "$CONFIG_FB_BWTWO" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then + define_bool CONFIG_FBCON_MFB y + else + if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_AMIGA" = "m" -o \ + "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \ + "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_RETINAZ3" = "m" -o \ + "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ + "$CONFIG_FB_BWTWO" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then + define_bool CONFIG_FBCON_MFB m + fi + fi + if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_MAC" = "y" -o \ + "$CONFIG_FB_VIRTUAL" = "y" ]; then + define_bool CONFIG_FBCON_CFB2 y + define_bool CONFIG_FBCON_CFB4 y + else + if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_MAC" = "m" -o \ + "$CONFIG_FB_VIRTUAL" = "m" ]; then + define_bool CONFIG_FBCON_CFB2 m + define_bool CONFIG_FBCON_CFB4 m + fi + fi + if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_ATARI" = "y" -o \ + "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \ + "$CONFIG_FB_OF" = "y" -o "$CONFIG_FB_TGA" = "y" -o \ + "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ + "$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \ + "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ + "$CONFIG_FB_CGFOURTEEN" = "y" -o "$CONFIG_FB_G364" = "y" -o \ + "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \ + "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ + "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \ + "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ + "$CONFIG_FB_P9100" = "y" -o \ + "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \ + "$CONFIG_FB_3DFX" = "y" ]; then + define_bool CONFIG_FBCON_CFB8 y + else + if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \ + "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_MAC" = "m" -o \ + "$CONFIG_FB_OF" = "m" -o "$CONFIG_FB_TGA" = "m" -o \ + "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ + "$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \ + "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ + "$CONFIG_FB_CGFOURTEEN" = "m" -o "$CONFIG_FB_G364" = "m" -o \ + "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \ + "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ + "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \ + "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ + "$CONFIG_FB_P9100" = "m" -o \ + "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" ]; then + define_bool CONFIG_FBCON_CFB8 m + fi + fi + if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \ + "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \ + "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \ + "$CONFIG_FB_Q40" = "y" -o \ + "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ + "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \ + "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ + "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \ + "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ + "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y" ]; then + define_bool CONFIG_FBCON_CFB16 y + else + if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ + "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VESA" = "m" -o \ + "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \ + "$CONFIG_FB_Q40" = "m" -o \ + "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ + "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \ + "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ + "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \ + "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "m" -o \ + "$CONFIG_FB_CYBER2000" = "m" ]; then + define_bool CONFIG_FBCON_CFB16 m + fi + fi + if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ + "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" -o \ + "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ + "$CONFIG_FB_CYBER2000" = "y" ]; then + define_bool CONFIG_FBCON_CFB24 y + else + if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ + "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" -o \ + "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ + "$CONFIG_FB_CYBER2000" = "m" ]; then + define_bool CONFIG_FBCON_CFB24 m + fi + fi + if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \ + "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ + "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ + "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ + "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ + "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ + "$CONFIG_FB_3DFX" = "y" ]; then + define_bool CONFIG_FBCON_CFB32 y + else + if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ + "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ + "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ + "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ + "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ + "$CONFIG_FB_SGIVW" = "m" ]; then + define_bool CONFIG_FBCON_CFB32 m + fi + fi + if [ "$CONFIG_FB_AMIGA" = "y" ]; then + define_bool CONFIG_FBCON_AFB y + define_bool CONFIG_FBCON_ILBM y + else + if [ "$CONFIG_FB_AMIGA" = "m" ]; then + define_bool CONFIG_FBCON_AFB m + define_bool CONFIG_FBCON_ILBM m + fi + fi + if [ "$CONFIG_FB_ATARI" = "y" ]; then + define_bool CONFIG_FBCON_IPLAN2P2 y + define_bool CONFIG_FBCON_IPLAN2P4 y + define_bool CONFIG_FBCON_IPLAN2P8 y +# define_bool CONFIG_FBCON_IPLAN2P16 y + else + if [ "$CONFIG_FB_ATARI" = "m" ]; then + define_bool CONFIG_FBCON_IPLAN2P2 m + define_bool CONFIG_FBCON_IPLAN2P4 m + define_bool CONFIG_FBCON_IPLAN2P8 m +# define_bool CONFIG_FBCON_IPLAN2P16 m + fi + fi + if [ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then + define_bool CONFIG_FBCON_MAC y + else + if [ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then + define_bool CONFIG_FBCON_MAC m + fi + fi + if [ "$CONFIG_FB_VGA16" = "y" ]; then + define_bool CONFIG_FBCON_VGA_PLANES y + else + if [ "$CONFIG_FB_VGA16" = "m" ]; then + define_bool CONFIG_FBCON_VGA_PLANES m + fi + fi + if [ "$CONFIG_FB_MDA" = "y" -o "$CONFIG_FB_VGA" = "y" ]; then + define_bool CONFIG_FBCON_VGA y + else + if [ "$CONFIG_FB_MDA" = "m" -o "$CONFIG_FB_VGA" = "m" ]; then + define_bool CONFIG_FBCON_VGA m + fi + fi + fi + bool ' Support only 8 pixels wide fonts' CONFIG_FBCON_FONTWIDTH8_ONLY + if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then bool ' Sparc console 8x16 font' CONFIG_FONT_SUN8x16 if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then - bool ' Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22 - bool ' Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11 + bool ' Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22 fi - bool ' Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8 - bool ' Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8 - else - define_bool CONFIG_FONT_8x8 y - define_bool CONFIG_FONT_8x16 y - if [ "$CONFIG_MAC" = "y" ]; then - if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then - define_bool CONFIG_FONT_6x11 y - fi + bool ' Select other fonts' CONFIG_FBCON_FONTS + if [ "$CONFIG_FBCON_FONTS" = "y" ]; then + bool ' VGA 8x8 font' CONFIG_FONT_8x8 + bool ' VGA 8x16 font' CONFIG_FONT_8x16 + if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then + bool ' Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11 + fi + bool ' Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8 + bool ' Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8 + fi + else + bool ' Select compiled-in fonts' CONFIG_FBCON_FONTS + if [ "$CONFIG_FBCON_FONTS" = "y" ]; then + bool ' VGA 8x8 font' CONFIG_FONT_8x8 + bool ' VGA 8x16 font' CONFIG_FONT_8x16 + bool ' Sparc console 8x16 font' CONFIG_FONT_SUN8x16 + if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then + bool ' Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22 + bool ' Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11 + fi + bool ' Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8 + bool ' Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8 + else + define_bool CONFIG_FONT_8x8 y + define_bool CONFIG_FONT_8x16 y + if [ "$CONFIG_MAC" = "y" ]; then + if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then + define_bool CONFIG_FONT_6x11 y + fi + fi + if [ "$CONFIG_AMIGA" = "y" ]; then + define_bool CONFIG_FONT_PEARL_8x8 y + fi + if [ "$CONFIG_ARM" = "y" -a "$CONFIG_ARCH_ACORN" = "y" ]; then + define_bool CONFIG_FONT_ACORN_8x8 y + fi fi - if [ "$CONFIG_AMIGA" = "y" ]; then - define_bool CONFIG_FONT_PEARL_8x8 y - fi - if [ "$CONFIG_ARM" = "y" -a "$CONFIG_ARCH_ACORN" = "y" ]; then - define_bool CONFIG_FONT_ACORN_8x8 y - fi - fi - fi + fi fi + +endmenu diff -u --recursive --new-file v2.3.20/linux/drivers/video/Makefile linux/drivers/video/Makefile --- v2.3.20/linux/drivers/video/Makefile Fri Sep 10 23:57:36 1999 +++ linux/drivers/video/Makefile Mon Oct 11 10:26:52 1999 @@ -150,11 +150,15 @@ endif ifeq ($(CONFIG_FB_SGIVW),y) -L_OBJS += sgivwfb.o +LX_OBJS += sgivwfb.o else ifeq ($(CONFIG_FB_SGIVW),m) - M_OBJS += sgivwfb.o + MX_OBJS += sgivwfb.o endif +endif + +ifeq ($(CONFIG_FB_3DFX),y) +L_OBJS += tdfxfb.o endif ifeq ($(CONFIG_FB_MAC),y) diff -u --recursive --new-file v2.3.20/linux/drivers/video/amifb.c linux/drivers/video/amifb.c --- v2.3.20/linux/drivers/video/amifb.c Thu Aug 26 13:05:40 1999 +++ linux/drivers/video/amifb.c Mon Oct 11 10:26:52 1999 @@ -1736,6 +1736,7 @@ fb_info.updatevar = &amifbcon_updatevar; fb_info.blank = &amifbcon_blank; fb_info.flags = FBINFO_FLAG_DEFAULT; + memset(&var, 0, sizeof(var)); if (!fb_find_mode(&var, &fb_info, mode_option, ami_modedb, NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) diff -u --recursive --new-file v2.3.20/linux/drivers/video/aty.h linux/drivers/video/aty.h --- v2.3.20/linux/drivers/video/aty.h Mon Aug 9 11:39:37 1999 +++ linux/drivers/video/aty.h Mon Oct 11 10:26:52 1999 @@ -103,6 +103,8 @@ #define CUSTOM_MACRO_CNTL 0x00D4 /* Dword offset 0_35 */ +#define POWER_MANAGEMENT 0x00D8 /* Dword offset 0_36 (LG) */ + #define CONFIG_CNTL 0x00DC /* Dword offset 0_37 (CT, ET, VT) */ #define CONFIG_CHIP_ID 0x00E0 /* Dword offset 0_38 */ #define CONFIG_STAT0 0x00E4 /* Dword offset 0_39 */ @@ -950,5 +952,16 @@ #define MACH64_NUM_CLOCKS 16 #define MACH64_NUM_FREQS 50 + +/* Power Management register constants (LTG and LT Pro) */ +#define PWR_MGT_ON 0x00000001 +#define PWR_MGT_MODE_MASK 0x00000006 +#define AUTO_PWR_UP 0x00000008 +#define SELF_REFRESH 0x00000080 +#define PWR_BLON 0x02000000 +#define STANDBY_NOW 0x10000000 +#define SUSPEND_NOW 0x20000000 +#define PWR_MGT_STATUS_MASK 0xC0000000 +#define PWR_MGT_STATUS_SUSPEND 0x80000000 #endif /* REGMACH64_H */ diff -u --recursive --new-file v2.3.20/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c --- v2.3.20/linux/drivers/video/atyfb.c Fri Sep 10 23:57:36 1999 +++ linux/drivers/video/atyfb.c Mon Oct 11 10:26:52 1999 @@ -1,4 +1,4 @@ -/* $Id: atyfb.c,v 1.122 1999/09/06 20:44:08 geert Exp $ +/* $Id: atyfb.c,v 1.126 1999/09/16 18:46:23 geert Exp $ * linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64 * * Copyright (C) 1997-1998 Geert Uytterhoeven @@ -52,7 +52,6 @@ #include #include #include -#include #include #include @@ -62,12 +61,15 @@ #include -#if defined(CONFIG_PPC) +#ifdef __powerpc__ +#include +#include #include #include #include