diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/Configure.help linux.ac/Documentation/Configure.help --- linux.vanilla/Documentation/Configure.help Tue Jun 15 16:49:44 1999 +++ linux.ac/Documentation/Configure.help Tue Jun 15 17:11:14 1999 @@ -87,13 +87,13 @@ a system with only one CPU, like most personal computers, say N. If you have a system with more than one CPU, say Y. - If you say N here, the kernel will run on single and multiprocessor - machines, but will use only one CPU of a multiprocessor machine. If + If you say N here, the kernel will run on single and multi-processor + machines, but will use only one CPU of a multi-processor machine. If you say Y here, the kernel will run on many, but not all, - singleprocessor machines. On a singleprocessor machine, the kernel + single-processor machines. On a single-processor machine, the kernel will run faster if you say N here. - Note that if you say Y here and choose architecture "586" or + Note that if you say Y here and choose architectures "586" or "Pentium" under "Processor family", the kernel will not work on 486 architectures. Similarly, multiprocessor kernels for the "PPro" architecture may not work on all Pentium based boards. @@ -136,7 +136,7 @@ If you are not sure, say Y; apart from resulting in a 45 KB bigger kernel, it won't hurt. - + Timer and CPU usage LEDs CONFIG_LEDS If you define this option, the LEDs on your machine will be used @@ -1844,6 +1844,11 @@ You will get a boot time penguin logo at no additional cost. Please read Documentation/fb/vesafb.txt. If unsure, say Y. +VGA 16-color graphics console +CONFIG_FB_VGA16 + This is the frame buffer device driver for VGA 16 color graphic + cards. Say Y if you have such a card. + Backward compatibility mode for Xpmac CONFIG_FB_COMPAT_XPMAC If you use the Xpmac X server (common with mklinux), you'll need to @@ -4989,6 +4994,17 @@ module, say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. +Aironet Arlan 655 & IC2200 DS support +CONFIG_ARLAN + Aironet makes Arlan. www.aironet.com. Uses www.Telxon.com chip, which is + used on several similar cards. Driver is tested on 655 and IC2200 series. + Look for http://www.ylenurme.ee/~elmer/655/ for latest information. + Driver is build as two modules, arlan and arlan-proc. The later is /proc + interface and not needed most of time. + On some computers the card ends up in non-valid state after some time. + Use a ping-reset script to clear it. + + LAPB over Ethernet driver CONFIG_LAPBETHER This is a driver for a pseudo device (typically called /dev/lapb0) @@ -5115,6 +5131,15 @@ module, say M here and read Documentation/modules.txt. If you don't know what to use this for, you don't need it. +Sealevel Systems 4021 support +CONFIG_SEALEVEL_4021 + This is a driver for the Sealevel Systems ACB 56 serial I/O adapter. + + This driver can only be compiled as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to do that, say M here. The module will be called + sealevel.o. + Frame Relay (DLCI) support CONFIG_DLCI This is support for the frame relay protocol; frame relay is a fast @@ -5478,9 +5503,12 @@ that has a program like lynx or netscape) is a family of intelligent multiprotocol WAN adapters with data transfer rates up to T1 (1.544 Mbps). They are also known as Synchronous Data Link Adapters (SDLA) - and designated S502E(A), S503 or S508. These cards support the X.25, - Frame Relay, and PPP protocols. If you have one or more of these - cards, say Y to this option; you may then also want to read the file + and designated S503 or S508. These cards support the X.25, Frame + Relay, PPP, Cisco HDLC protocols. The driver also offers API support + for protocols like HDLC (LAPB), HDLC Streaming and BiSync. + + If you have one or more of these cards, say Y to this option; you + may then also want to read the file Documentation/networking/wanpipe.txt. The next questions will ask you about the protocols you want the driver to support. @@ -5500,26 +5528,48 @@ WANPIPE X.25 support CONFIG_WANPIPE_X25 Say Y to this option if you are planning to connect a WANPIPE card - to an X.25 network. You should then also have said Y to "CCITT X.25 - Packet Layer" and "LAPB Data Link Driver", above. If you say N, the - X.25 support will not be included in the driver (saves about 16 KB - of kernel memory). + to an X.25 network. If you say N, the X.25 support will not be + included in the driver. The X.25 option is ONLY supported on S508 + cards. WANPIPE Frame Relay support CONFIG_WANPIPE_FR Say Y to this option if you are planning to connect a WANPIPE card - to a frame relay network. You should then also have said Y to "Frame - Relay (DLCI) support", above. If you say N, the frame relay - support will not be included in the driver (saves about 16 KB of - kernel memory). + to a frame relay network. If you say N, the frame relay support will + not be included in the driver. The Frame Relay option is ONLY + supported on S508 cards. WANPIPE PPP support CONFIG_WANPIPE_PPP Say Y to this option if you are planning to connect a WANPIPE card - to a leased line using Point-to-Point protocol (PPP). You should - then also have said Y to "PPP (point-to-point) support", above. If - you say N, the PPP support will not be included in the driver (saves - about 16 KB of kernel memory). + to a leased line using Point-to-Point protocol (PPP). If you say N, + the PPP support will not be included in the driver. The PPP option + is ONLY supported on S508 cards. + +WANPIPE Cisco HDLC support +CONFIG_WANPIPE_CHDLC + Say Y to this option if you are planning to connect a WANPIPE card + to a leased line using the Cisco HDLC protocol. This now supports + Dual Port Cisco HDLC on the S508 card ONLY. This support also allows + user to build applications using the HDLC streaming API. If you say + N, the Cisco HDLC support and HDLC streaming API will not be + included in the driver. + +WANPIPE BiSync Streaming API support +CONFIG_WANPIPE_BSTRM + Say Y to this option if you are planning to use a WANPIPE card to + develop user applications to send RAW BiSync data. This option + provides an API support for customers to build their own + applications. This API ONLY supports S503 cards. If you say N, then + BiSync API support will not be included in the driver. + +WANPIPE HDLC (LAPB) API support +CONFIG_WANPIPE_HDLC + Say Y to this option if you are planning to use a WANPIPE card to + develop user application to send HDLC (LAPB) data. This option + provides an API support for customers to build their own + applications. This API ONLY supports the S508 cards. If you say N, + then HDLC (LAPB) API support will not be included in the driver. Ethernet (10 or 100Mbit) CONFIG_NET_ETHERNET @@ -5734,7 +5784,7 @@ say M here and read Documentation/modules.txt. This is recommended. The module will be called yellowfin.o. -Alteon AceNIC / 3Com 3C985 Gigabit Ethernet support. +Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support CONFIG_ACENIC Say Y here if you have an Alteon AceNIC or 3Com 3C985 PCI Gigabit Ethernet adapter. The driver allows for using the Jumbo Frame @@ -6492,6 +6542,25 @@ The module will be called ibmtr.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +IBM Olympic chipset PCI adapter support +CONFIG_IBMOL + This is support for all non-Lanstreamer IBM PCI Token Ring Cards. + Specifically this is all IBM PCI, PCI Wake On Lan, PCI II, PCI II + Wake On Lan, and PCI 100/16/4 adapters. + + If you have such an adapter, say Y and read the Token-Ring mini-HOWTO, + available via FTP (user:anonymous) from + ftp://metalab.unc/edu/pub/Linux/docs/HOWTO. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will will be called olympic.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + + Also read the linux/Documentation/networking/olympic.txt or check the + Linux Token Ring Project site for the latest information at + http://www.linuxtr.net + SysKonnect adapter support CONFIG_SKTR This is support for all SysKonnect Token Ring cards, specifically @@ -7204,11 +7273,12 @@ If unsure, say N. -System V and Coherent filesystem support +System V, Version 7 and Coherent filesystem support CONFIG_SYSV_FS SCO, Xenix and Coherent are commercial Unix systems for Intel - machines. Saying Y here would allow you to read to and write from - their floppies and hard disk partitions. + machines, and Version 7 was used on the DEC PDP-11. Saying Y here + would allow you to read to and write from their floppies and hard + disk partitions. If you have floppies or hard disk partitions like that, it is likely that they contain binaries from those other Unix systems; in order @@ -7360,6 +7430,18 @@ Say Y here if you want to try writing to UFS partitions. This is experimental, so you should back up your UFS partitions beforehand. +EFS filesystem support (experimental) +CONFIG_EFS_FS + EFS is the filesystem used for CDROMs and filesystems by SGI's IRIX. + This implementation only offers read-only access. If you don't know + what all this is about, it's safe to say N. For more information + about EFS see it's homepage at http://aeschi.ch.eu.org/efs. + +SGI disklabel support +CONFIG_SGI_DISKLABEL + Say Y to this only if you plan on mounting disks with SGI disklabels. + This is not required to mount EFS-format CDROMs. + BSD disklabel (FreeBSD partition tables) support CONFIG_BSD_DISKLABEL FreeBSD uses its own hard disk partition scheme on your PC. It @@ -8731,9 +8813,15 @@ APM is a BIOS specification for saving power using several different techniques. This is mostly useful for battery powered laptops with APM compliant BIOSes. If you say Y here, the system time will be - reset after a USER RESUME operation, the /proc/apm device will - provide battery status information, and user-space programs will - receive notification of APM "events" (e.g., battery status change). + reset after a RESUME operation, the /proc/apm device will provide + battery status information, and user-space programs will receive + notification of APM "events" (e.g., battery status change). + + If you select "Y" here, you can disable actual use of the APM + BIOS by passing the "apm=off" option to the kernel at boot time. + + Note that the APM support is almost completely disabled for + machines with more than one CPU. Supporting software is available; for more information, read the Battery Powered Linux mini-HOWTO, available via FTP (user: @@ -8746,9 +8834,7 @@ This driver does not support the TI 4000M TravelMate and the ACER 486/DX4/75 because they don't have compliant BIOSes. Many "green" desktop machines also don't have compliant BIOSes, and this driver - will cause those machines to panic during the boot phase (typically, - these machines are using a data segment of 0040, which is reserved - for the Linux kernel). + may cause those machines to panic during the boot phase. If you are running Linux on a laptop, you may also want to read the Linux Laptop home page on the WWW at @@ -8825,18 +8911,6 @@ backlight at all, or it might print a lot of errors to the console, especially if you are using gpm. -Power off on shutdown -CONFIG_APM_POWER_OFF - Enable the ability to power off the computer after the Linux kernel - is halted. You will need software (e.g., a suitable version of the - halt(8) command ("man 8 halt")) to cause the computer to power down. - Recent versions of the sysvinit package available from - ftp://metalab.unc.edu/pub/Linux/system/daemons/init/ (user: - anonymous) contain support for this ("halt -p" shuts down Linux and - powers off the computer, if executed from runlevel 0). As with the - other APM options, this option may not work reliably with some APM - BIOS implementations. - Ignore multiple suspend/standby events CONFIG_APM_IGNORE_MULTIPLE_SUSPEND This option is necessary on the IBM Thinkpad 560, but should work on @@ -9268,6 +9342,15 @@ You can say M here to compile this driver as a module; the module is called sb.o. +### +### Don't know what this is +### +#PCI Legacy soundblaster enabler +#CONFIG_SOUND_PCISB +# +#ESS-Tech Maestro support +#CONFIG_SOUND_ESSMAESTRO + Generic OPL2/OPL3 FM synthesizer support CONFIG_SOUND_ADLIB Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). @@ -9764,6 +9847,11 @@ ISDN subsystem CONFIG_ISDN + CAUTION: the ISDN driver shipped with this kernel distribution + is outdated and might not work without problems. An updated driver + is available for download. Please read http://www.isdn4linux.de + on the WWW for a list of servers. + ISDN ("Integrated Services Digital Networks", called RNIS in France) is a special type of fully digital telephone service; it's mostly used to connect to your Internet service provider (with SLIP or diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/filesystems/dcache.txt linux.ac/Documentation/filesystems/dcache.txt --- linux.vanilla/Documentation/filesystems/dcache.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/filesystems/dcache.txt Fri Jun 4 23:52:54 1999 @@ -0,0 +1,173 @@ +Some dcache details + +A traditional Unix system has inodes (`index nodes') as in-core +descriptors of files. An inode refers to the actual file, not +to a directory entry naming it. Linux v2.1.43 introduced dentries +(`directory entries') as in-core descriptors of file names. + +The entire purpose of dentries is to make the map +filename -> inode fast. An interesting side effect +is that the kernel knows what name was used to open a file +and that a system call getcwd() is possible. + +Thus, the central part of the dcache code are the lines + dentry = reserved_lookup(base, &this); + if (!dentry) { + dentry = cached_lookup(base, &this); + if (!dentry) + dentry = real_lookup(base, &this); + } +in namei.c. The reserved_lookup() takes care of . and ..; +the cached_lookup() is what we have the dcache for, +and the real_lookup() goes to the filesystem. + +The cached_lookup() returns the value of d_lookup(), +but does a d_revalidate() before returning, and if that fails +and the dentry has no children, it returns NULL. + [This is a rather obscure part. The d_revalidate() + is allowed to fail for any reason - for example, + autofs uses a timeout to make d_revalidate fail - + which means that the final dentry we come up with + need not be the dentry that d_lookup() found. + This causes bugs in the vfat filesystem. + Moreover, if d_revalidate(D) fails but D still has + children, then D is used anyway. + This also causes bugs in the vfat filesystem. + I think also nfs has problems.] + + + + +A struct dentry has five members of type struct list_head: + struct list_head d_hash; /* lookup hash list */ + struct list_head d_lru; /* d_count = 0 LRU list */ + struct list_head d_child; /* child of parent list */ + struct list_head d_subdirs; /* our children */ + struct list_head d_alias; /* inode alias list */ + + [Some of these names were very badly chosen, and lead + to confusion all the time. We should do a global replace + changing d_subdirs into d_children and d_child into d_sister.] + + + +1. d_hash + +The d_hash field of a dentry links the dentry into +the list of dentries for filenames with a given hash value +with list head dentry_hashtable[hashvalue] defined in dcache.c. +This list is used in d_lookup() to find a dentry with given name +and parent. It is used in d_validate() to find a dentry with +known hash and parent. + [The present code takes the parent into account when + computing a hash. Not doing this would make the code + simpler and faster, possibly at the expense of a few + more collisions. Has anyone investigated this?] +The d_hash field is an empty list when the file is a mount point +(cf. d_validate) or has been deleted, or when the dentry was +dropped for some other reason. + + +d_add(D,I) will put D into its hash chain and provide it +with the inode I. It is called by all filesystem lookup routines. + +d_drop(D) will remove D from its hash chain. A dentry is called +`unhashed' when its d_hash field is an empty list. +Sometimes dentries are dropped temporarily to make sure +no lookup will find them. The general routine vfs_rmdir(I,D) +will drop D if d_count=2, so that all filesystem rmdir() +routines can return -EBUSY when D still occurs in the hash list. +The filesystem routines for unlink and rmdir call d_delete() +which again calls d_drop(). + +[The d_hash field is referred to in many places that should +not know about its existence, in the phrase + if (list_empty(&dentry->d_hash)) ... +No doubt there should be a line + #define unhashed(d) (list_empty(&(d)->d_hash)) +in dcache.h, together with a comment describing the semantics +of being unhashed. Then all these occurrences of d_hash can +be removed. Next, d_drop() should be renamed d_unhash().] + +The dentry for the root of a mounted filesystem is returned by +d_alloc_root() and is unhashed. + + + +2. d_lru +The simplest list is the one joining the d_lru fields of +dentries that had d_count = 0 at some point in time. +The list head is the variable dentry_unused defined in dcache.c. +The number of elements in this list is dentry_stat.nr_unused. +There are no references to the d_lru field outside dcache.[ch]. + +Note that d_count is incremented by dget(), invoked by d_lookup(), +without removing the dentry from the LRU list. Thus, anyone hoping +to find unused dentries on this list must first check d_count. +If a dentry is not on the LRU list, its d_lru field is an +empty list (initialized by d_alloc()). + +dput(D) tries to get rid of D altogether when d_count = 0, but +puts D at the head of the LRU list if it is still on the hash list. +Thus, every D with d_count = 0 will be on the LRU list. + +select_dcache(ict,pct) removes D with d_count > 0 from the +LRU list, and moves D that are ready to be sacrificed for memory +to the end of the list. (If ict and/or pct is given, then we are +satisfied when the selected D's involve ict inodes or pct pages.) + +prune_dcache(ct) removes D with d_count > 0 from the LRU list, +and frees unused D, stopping when ct of them have been freed. + +shrink_dcache_sb(sb) removes all unused D with given superblock +from the LRU list. + +select_parent(D) move all unused descendants of D to the end +of the LRU list. + + + +3. d_child and d_subdirs +As already noted, the names are terrible. The d_child field +does not refer to a child but to a sibling, and the d_subdirs +field does not refer to a subdirectory but to a child, directory +or not. These two fields form a threaded tree: the d_subdirs field +points to the first child, and the d_child field is member of the +circularly linked list of all children of one parent. + +To be more precise: this circularly linked list of all children +of one parent P passes through the d_child fields of all children +and through the d_subdirs field of the parent P. + + + +4. d_alias +Somewhat similar to the above, where we had a circularly linked list +with one special element, we here have a circularly linked list +passing through the d_alias field of all dentries that are aliases +of one inode, and through the i_dentry field of the inode. + +The dentry is added to this list by d_instantiate(). +It is removed again by dentry_iput() which is called by dput() +and d_delete(). + + + + +So far about the lists in the dentry structure. +Some of the routines in dcache.c have been mentioned already. +Let me describe one of the more obscure ones. + +d_move(D,T) is the routine called by the filesystem code +just before finishing the rename(D,T) call. Since both +dentries D and T may be busy we cannot just throw one away. +Instead they are partially interchanged: +D and T interchange names, and D is put into T's hash queue, +and T is unhashed; D and T interchange parents, and are put +on the list of children of their new parent. +The result is that the file D that got renamed is now in perfect +shape again - it has been renamed. T, if it existed, lost its +name string, if it was short, but perhaps this is harmless - +let us hope no-one will ever ask for T's name anymore. + + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/filesystems/sysv-fs.txt linux.ac/Documentation/filesystems/sysv-fs.txt --- linux.vanilla/Documentation/filesystems/sysv-fs.txt Sun Nov 8 15:08:46 1998 +++ linux.ac/Documentation/filesystems/sysv-fs.txt Fri Jun 4 23:52:54 1999 @@ -2,20 +2,22 @@ It implements all of - Xenix FS, - SystemV/386 FS, + - Version 7 FS - Coherent FS. This is version beta 4. To install: -* Answer the 'System V and Coherent filesystem support' question with 'y' - when configuring the kernel. +* Answer the 'System V, Version 7 and Coherent filesystem support' question + with a 'y' when configuring the kernel. * To mount a disk or a partition, use mount [-r] -t sysv device mountpoint The file system type names -t sysv -t xenix + -t v7 -t coherent - may be used interchangeably, but the last two will eventually disappear. + the xenix and coherent options will eventually disappear. Bugs in the present implementation: - Coherent FS: diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/locks.txt linux.ac/Documentation/locks.txt --- linux.vanilla/Documentation/locks.txt Sat Jan 9 21:50:34 1999 +++ linux.ac/Documentation/locks.txt Fri Jun 4 23:52:55 1999 @@ -13,12 +13,11 @@ The old flock(2) emulation in the kernel was swapped for proper BSD compatible flock(2) support in the 1.3.x series of kernels. With the -release of the 2.1.x kernel series, support for the old emulation has -been totally removed, so that we don't need to carry this baggage -forever. +release of the 2.1.x kernel series, support for the old emulation was +totally removed, so that we don't need to carry this baggage forever. -This should not cause problems for anybody, since everybody using a -2.1.x kernel should have updated their C library to a suitable version +This should not cause problems for anybody, since everybody using a 2.1.x +or 2.2.x kernel should have updated their C library to a suitable version anyway (see the file "linux/Documentation/Changes".) 1.2 Allow Mixed Locks Again @@ -31,9 +30,9 @@ for example. This gave rise to some other subtle problems if sendmail was configured to rebuild the alias file. Sendmail tried to lock the aliases.dir file with fcntl() at the same time as the GDBM routines tried to lock this -file with flock(). With pre 1.3.96 kernels this could result in deadlocks that, -over time, or under a very heavy mail load, would eventually cause the kernel -to lock solid with deadlocked processes. +file with flock(). With kernels before 1.3.96 this could result in deadlocks +that, over time or under a very heavy mail load, would eventually cause the +kernel to lock solid with deadlocked processes. 1.2.2 The Solution @@ -60,7 +59,7 @@ file for which a mandatory lock existed. From this release of the kernel, mandatory locking can be turned on and off -on a per-filesystem basis, using the mount options 'mand' and 'nomand'. +on a per-file-system basis, using the mount options 'mand' and 'nomand'. The default is to disallow mandatory locking. The intention is that mandatory locking only be enabled on a local filesystem as the specific need arises. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/m68k/kernel-options.txt linux.ac/Documentation/m68k/kernel-options.txt --- linux.vanilla/Documentation/m68k/kernel-options.txt Thu May 27 22:11:47 1999 +++ linux.ac/Documentation/m68k/kernel-options.txt Fri Jun 4 23:52:55 1999 @@ -1,5 +1,3 @@ - - Command Line Options for Linux/m68k =================================== @@ -14,7 +12,7 @@ Often I've been asked which command line options the Linux/m68k kernel understands, or how the exact syntax for the ... option is, or ... about the option ... . I hope, this document supplies all the -answers... +answers. Note that some options might be outdated, their descriptions being incomplete or missing. Please update the information and send in the @@ -110,20 +108,19 @@ [Strange and maybe uninteresting stuff ON] This unusual translation of device names has some strange -consequences: If, for example, you have a symbolic link from /dev/fd +consequences: if, for example, you have a symbolic link from /dev/fd to /dev/fd0D720 as an abbreviation for floppy driver #0 in DD format, you cannot use this name for specifying the root device, because the kernel cannot see this symlink before mounting the root FS and it isn't in the table above. If you use it, the root device will not be -set at all, without an error message. Another example: You cannot use a +set at all, without an error message. Another example: you cannot use a partition on e.g. the sixth SCSI disk as the root filesystem, if you want to specify it by name. This is, because only the devices up to -/dev/sde are in the table above, but not /dev/sdf. Although, you can -use the sixth SCSI disk for the root FS, but you have to specify the -device by number... (see below). Or, even more strange, you can use the -fact that there is no range checking of the partition number, and your -knowledge that each disk uses 16 minors, and write "root=/dev/sde17" -(for /dev/sdf1). +/dev/sde are in the table above, but not /dev/sdf. You can use the sixth +SCSI disk for the root filesystem, but you have to specify the device by +number (see below). Even more strange, you can use the fact that there is +no range checking of the partition number, and your knowledge that each +disk uses 16 minors, and write "root=/dev/sde17" (for /dev/sdf1). [Strange and maybe uninteresting stuff OFF] @@ -181,7 +178,7 @@ Devices possible for Amiga: - "ser": built-in serial port; parameters: 9600bps, 8N1 - - "mem": Save the messages to a reserved area in chip mem. After + - "mem": Save the messages to a reserved area in chip memory. After rebooting, they can be read under AmigaOS with the tool 'dmesg'. @@ -205,7 +202,7 @@ Syntax: ramdisk= This option instructs the kernel to set up a ramdisk of the given -size in KBytes. Do not use this option if the ramdisk contents are +size in kilobytes. Do not use this option if the ramdisk contents are passed by bootstrap! In this case, the size is selected automatically and should not be overwritten. @@ -234,10 +231,10 @@ drivers/net/Space.c in the Linux source. Most prominent are eth0, ... eth3, sl0, ... sl3, ppp0, ..., ppp3, dummy, and lo. - The non-ethernet drivers (sl, ppp, dummy, lo) obviously ignore the -settings by this options. Also, the existing ethernet drivers for + The non-Ethernet drivers (sl, ppp, dummy, lo) obviously ignore the +settings by this options. Also, the existing Ethernet drivers for Linux/m68k (ariadne, a2065, hydra) don't use them because Zorro boards -are really Plug-'n-Play, so the "ether=" option is useless altogether +are really Plug-'n'-Play, so the "ether=" option is useless altogether for Linux/m68k. @@ -288,8 +285,8 @@ to use (minimum 4, default 4), is the size of each buffer in kilobytes (minimum 4, default 32) and says how much percent of error will be tolerated when setting a frequency -(maximum 10, default 0). For example with 3% you can play 8000Hz -AU-Files on the Falcon with its hardware frequency of 8195Hz and thus +(maximum 10, default 0). For example, with 3% you can play 8000 Hz Sun +audio files on the Falcon with its hardware frequency of 8195 Hz and thus don't need to expand the sound. @@ -482,7 +479,7 @@ xres_virtual must be set to 2048. For ET4000, xres_virtual depends on the initialisation of the video-card. If you're missing a corresponding yres_virtual: the external part is legacy, -therefore we don't support hardware-dependend functions like hardware-scroll, +therefore we don't support hardware-dependent functions like hardware scroll, panning or blanking. 4.1.7) eclock: @@ -653,7 +650,7 @@ "ov_midi", ... These options are meant for switching on an OverScan video extension. The difference to the bare option is that the switch-on is done after video initialization, and somehow synchronized -to the HBLANK. A speciality is that ov_ikbd and ov_midi are switched +to the HBLANK. A specialty is that ov_ikbd and ov_midi are switched off before rebooting, so that OverScan is disabled and TOS boots correctly. @@ -737,8 +734,8 @@ - vga70 : 640x400, 31 kHz, 70 Hz Please notice that the ECS and VGA modes require either an ECS or AGA -chipset, and that these modes are limited to 2-bit color for the ECS -chipset and 8-bit color for the AGA chipset. +chip set, and that these modes are limited to 2-bit color for the ECS +chip set and 8-bit color for the AGA chip set. 5.1.2) depth ------------ @@ -842,11 +839,11 @@ Syntax: clock:x x = clock input in MHz for WD33c93 chip. Normal values would be from -8 through 20. The default value depends on your hostadapter(s), +8 through 20. The default value depends on your host adapter(s), default for the A3000 internal controller is 14, for the A2091 it's 8 -and for the GVP hostadapters it's either 8 or 14, depending on the -hostadapter and the SCSI-clock jumper present on some GVP -hostadapters. +and for the GVP host adapters it's either 8 or 14, depending on the +host adapter and the SCSI-clock jumper present on some GVP +host adapters. 5.3.6) next ----------- @@ -875,8 +872,8 @@ The earlier versions of the GVP driver did not handle DMA address-mask settings correctly which made it necessary for some people to use this option, in order to get their GVP controller -running under Linux. These problems have hopefully been solved and the -use of this option is now highly unrecommended! +running under Linux. These problems should now be solved and +further use of this option is highly discouraged! Incorrect use can lead to unpredictable behavior, so please only use this option if you *know* what you are doing and have a reason to do diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/modules.txt linux.ac/Documentation/modules.txt --- linux.vanilla/Documentation/modules.txt Sun Nov 8 15:08:46 1998 +++ linux.ac/Documentation/modules.txt Fri Jun 4 23:52:54 1999 @@ -59,7 +59,7 @@ Most low-level SCSI drivers: (i.e. aha1542, in2000) All SCSI high-level drivers: disk, tape, cdrom, generic. - Most ethernet drivers: (too many to list, please see the file + Most Ethernet drivers: (too many to list, please see the file ./Documentation/networking/net-modules.txt) Most CDROM drivers: diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/mtrr.txt linux.ac/Documentation/mtrr.txt --- linux.vanilla/Documentation/mtrr.txt Thu May 27 22:11:47 1999 +++ linux.ac/Documentation/mtrr.txt Fri Jun 4 23:52:56 1999 @@ -40,7 +40,7 @@ reg01: base=0x08000000 ( 128MB), size= 64MB: write-back, count=1 reg02: base=0xf8000000 (3968MB), size= 4MB: write-combining, count=1 -This is for videoram at base address 0xf8000000 and size 4 MBytes. To +This is for video RAM at base address 0xf8000000 and size 4 megabytes. To find out your base address, you need to look at the output of your X server, which tells you where the linear framebuffer address is. A typical line that you may get is: @@ -56,7 +56,7 @@ (--) S3: videoram: 4096k -That's 4 MBytes, which is 0x400000 bytes (in hexadecimal). +That's 4 megabytes, which is 0x400000 bytes (in hexadecimal). A patch is being written for XFree86 which will make this automatic: in other words the X server will manipulate /proc/mtrr using the ioctl() interface, so users won't have to do anything. If you use a diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/nbd.txt linux.ac/Documentation/nbd.txt --- linux.vanilla/Documentation/nbd.txt Sun Nov 8 15:08:49 1998 +++ linux.ac/Documentation/nbd.txt Fri Jun 4 23:52:55 1999 @@ -4,11 +4,11 @@ means, that it works on my computer, and it worked on one of school computers. - What is it: With this compiled in the kernel, linux can use a remote + What is it: With this compiled in the kernel, Linux can use a remote server as one of its block devices. So every time the client computer wants to read /dev/nd0, it sends a request over TCP to the server, which will reply with the data read. This can be used for stations with - low-disk space (or even diskless - if you boot from floppy) to + low disk space (or even diskless - if you boot from floppy) to borrow disk space from another computer. Unlike NFS, it is possible to put any filesystem on it etc. It is impossible to use NBD as a root filesystem, since it requires a user-level program to start. It also diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/00-INDEX linux.ac/Documentation/networking/00-INDEX --- linux.vanilla/Documentation/networking/00-INDEX Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/00-INDEX Fri Jun 4 23:52:54 1999 @@ -13,9 +13,9 @@ alias.txt - info on using alias network devices arcnet-hardware.txt - - tons of info on arcnet, hubs, arcnet card jumper settings, etc. + - tons of info on ARCnet, hubs, jumper settings for ARCnet cards, etc. arcnet.txt - - info on the using the arcnet driver itself. + - info on the using the ARCnet driver itself. ax25.txt - info on using AX.25 and NET/ROM code for Linux baycom.txt @@ -69,13 +69,13 @@ smc9.txt - the driver for SMC's 9000 series of Ethernet cards soundmodem.txt - - Linux driver for soundcards as AX.25 modems + - Linux driver for sound cards as AX.25 modems tcp.txt - short blurb on how TCP output takes place. tulip.txt - info on using DEC 21040/21041/21140 based PCI Ethernet cards. vortex.txt - - info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) e'net cards. + - info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) Ethernet cards. wan-router.txt - Wan router documentation wanpipe.txt diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/Configurable linux.ac/Documentation/networking/Configurable --- linux.vanilla/Documentation/networking/Configurable Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/Configurable Fri Jun 4 23:52:54 1999 @@ -20,11 +20,11 @@ 7000 Others are already accessible via the related user space programs. -For example, MAX_WINDOW has a default of 32k which is a good choice for -modern hardware, but if you have a slow (8 bit) ethercard and/or a slow +For example, MAX_WINDOW has a default of 32 k which is a good choice for +modern hardware, but if you have a slow (8 bit) Ethernet card and/or a slow machine, then this will be far too big for the card to keep up with fast -Tx'ing machines on the same net, resulting in overruns and receive errors. -A value of about 4k would be more appropriate, which can be set via: +machines transmitting on the same net, resulting in overruns and receive errors. +A value of about 4 k would be more appropriate, which can be set via: # route add -net 192.168.3.0 window 4096 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/DLINK.txt linux.ac/Documentation/networking/DLINK.txt --- linux.vanilla/Documentation/networking/DLINK.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/DLINK.txt Fri Jun 4 23:52:54 1999 @@ -18,8 +18,8 @@ pocket adapters, for the parallel port on a Linux based machine. Some adapter "clones" will also work. Xircom is _not_ a clone... These drivers _can_ be used as loadable modules, - and were developed for use on Linux v1.1.13 and above. - For use on Linux v1.0.X, or earlier releases, see below. + and were developed for use on Linux 1.1.13 and above. + For use on Linux 1.0.X, or earlier releases, see below. I have used these drivers for NFS, ftp, telnet and X-clients on remote machines. Transmissions with ftp seems to work as @@ -57,7 +57,7 @@ de620.h Macros for de620.c If you are upgrading from the d-link tar release, there will - also be a "dlink-patches" file that will patch Linux v1.1.18: + also be a "dlink-patches" file that will patch Linux 1.1.18: linux/drivers/net/Makefile linux/drivers/net/CONFIG linux/drivers/net/MODULES @@ -162,10 +162,10 @@ 6. USING THE DRIVERS WITH EARLIER RELEASES. - The later v1.1.X releases of the Linux kernel include some + The later 1.1.X releases of the Linux kernel include some changes in the networking layer (a.k.a. NET3). This affects these drivers in a few places. The hints that follow are - _not_ tested by me, since I don't have the diskspace to keep + _not_ tested by me, since I don't have the disk space to keep all releases on-line. Known needed changes to date: - release patchfile: some patches will fail, but they should diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/arcnet-hardware.txt linux.ac/Documentation/networking/arcnet-hardware.txt --- linux.vanilla/Documentation/networking/arcnet-hardware.txt Sat Jan 9 21:50:35 1999 +++ linux.ac/Documentation/networking/arcnet-hardware.txt Fri Jun 4 23:52:54 1999 @@ -20,14 +20,14 @@ ARCnet is a network type which works in a way similar to popular Ethernet networks but which is also different in some very important ways. -First of all, you can get ARCnet cards in at least two speeds: 2.5Mbps -(slower than Ethernet) and 100Mbps (faster than normal Ethernet). In fact, +First of all, you can get ARCnet cards in at least two speeds: 2.5 Mbps +(slower than Ethernet) and 100 Mbps (faster than normal Ethernet). In fact, there are others as well, but these are less common. The different hardware types, as far as I'm aware, are not compatible and so you cannot wire a -100Mbps card to a 2.5Mbps card, and so on. From what I hear, my driver does -work with 100Mbps cards, but I haven't been able to verify this myself, -since I only have the 2.5Mbps variety. It is probably not going to saturate -your 100Mbps card. Stop complaining :) +100 Mbps card to a 2.5 Mbps card, and so on. From what I hear, my driver does +work with 100 Mbps cards, but I haven't been able to verify this myself, +since I only have the 2.5 Mbps variety. It is probably not going to saturate +your 100 Mbps card. Stop complaining. :) You also cannot connect an ARCnet card to any kind of Ethernet card and expect it to work. @@ -52,17 +52,17 @@ useful for realtime networks. In addition, all known ARCnet cards have an (almost) identical programming -interface. This means that with one "arcnet" driver you can support any -card; whereas, with Ethernet, each manufacturer uses what is sometimes a +interface. This means that with one ARCnet driver you can support any +card, whereas with Ethernet each manufacturer uses what is sometimes a completely different programming interface, leading to a lot of different, sometimes very similar, Ethernet drivers. Of course, always using the same programming interface also means that when high-performance hardware -facilities like PCI busmastering DMA appear, it's hard to take advantage of +facilities like PCI bus mastering DMA appear, it's hard to take advantage of them. Let's not go into that. One thing that makes ARCnet cards difficult to program for, however, is the limit on their packet sizes; standard ARCnet can only send packets that are -up to 508 bytes in length. This is smaller than the internet "bare minimum" +up to 508 bytes in length. This is smaller than the Internet "bare minimum" of 576 bytes, let alone the Ethernet MTU of 1500. To compensate, an extra level of encapsulation is defined by RFC1201, which I call "packet splitting," that allows "virtual packets" to grow as large as 64K each, @@ -1005,9 +1005,9 @@ only (the JP0 jumper is hardwired), and BNC only. This is a LCS-8830-T made by SMC, I think ('SMC' only appears on one PLCC, -nowhere else, not even on the few xeroxed sheets from the manual). +nowhere else, not even on the few Xeroxed sheets from the manual). -SMC Arcnet Board Type LCS-8830-T +SMC ARCnet Board Type LCS-8830-T ------------------------------------ | | @@ -1070,7 +1070,7 @@ DIP Switches 1-5 of SW2 encode the RAM and ROM Address Range: -Switches Ram Rom +Switches RAM ROM 12345 Address Range Address Range 00000 C:0000-C:07ff C:2000-C:3fff 10000 C:0800-C:0fff @@ -1170,11 +1170,11 @@ DIP Switches: The DIP switches accessible on the accessible end of the card while - it is installed, is used to set the arcnet address. There are 8 + it is installed, is used to set the ARCnet address. There are 8 switches. Use an address from 1 to 254. Switch No. - 12345678 Arcnet address + 12345678 ARCnet address ----------------------------------------- 00000000 FF (Don't use this!) 00000001 FE @@ -1222,7 +1222,7 @@ from the upper memory regions, and then attempting to load ARCETHER using these addresses. - I recommend using an arcnet memory address of 0xD000, and putting + I recommend using an ARCnet memory address of 0xD000, and putting the EMS page frame at 0xC000 while using QEMM stealth mode. That way, you get contiguous high memory from 0xD100 almost all the way the end of the megabyte. @@ -1687,7 +1687,7 @@ |____________________________________________| |__| -UM9065L : Arcnet Controller +UM9065L : ARCnet Controller SW 1 : Shared Memory Address and I/O Base @@ -1800,7 +1800,7 @@ J1-J5 IRQ Select J6-J21 Unknown (Probably extra timeouts & ROM enable ...) LED1 Activity LED -BNC Coax connector (STAR arcnet) +BNC Coax connector (STAR ARCnet) RAM 2k of SRAM ROM Boot ROM socket UFS Unidentified Flying Sockets @@ -1905,7 +1905,7 @@ ------------------------ - from Vojtech Pavlik -This is another SMC 90C65 based arcnet card. I couldn't identify the +This is another SMC 90C65-based ARCnet card. I couldn't identify the manufacturer, but it might be DataPoint, because the card has the original arcNet logo in its upper right corner. @@ -1942,9 +1942,9 @@ SW2 1-8: Node ID Select SW3 1-5: IRQ Select 6-7: Extra Timeout - 8 : Rom Enable + 8 : ROM Enable BNC Coax connector -XTAL 20MHz Crystal +XTAL 20 MHz Crystal Setting the Node ID @@ -2081,11 +2081,11 @@ 6-8 Base I/O Address Select SW2 1-8 Node ID Select (ID0-ID7) J1 IRQ Select -J2 Rom Enable +J2 ROM Enable J3 Extra Timeout LED1 Activity LED -BNC Coax connector (BUS arcnet) -RJ Twisted Pair Connector (daisychain) +BNC Coax connector (BUS ARCnet) +RJ Twisted Pair Connector (daisy chain) Setting the Node ID @@ -2419,7 +2419,7 @@ Legend: -COM90C65: Arcnet Probe +COM90C65: ARCnet Probe S1 1-8: Node ID Select S2 1-3: I/O Base Address Select 4-6: Memory Base Address Select @@ -2791,7 +2791,7 @@ SW2 1-8: Node ID Select (ID0-ID7) SW3 1-5: IRQ Select 6-7: Extra Timeout - 8 : Rom Enable + 8 : ROM Enable JP1 Led connector BNC Coax connector @@ -3089,7 +3089,7 @@ 0 = Jumper Installed 1 = Open -Top Jumper line Bit 7 = Rom Enable 654=Memory location 321=I/O +Top Jumper line Bit 7 = ROM Enable 654=Memory location 321=I/O Settings for Memory Location (Top Jumper Line) 456 Address selected diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/arcnet.txt linux.ac/Documentation/networking/arcnet.txt --- linux.vanilla/Documentation/networking/arcnet.txt Sun Nov 8 15:08:46 1998 +++ linux.ac/Documentation/networking/arcnet.txt Fri Jun 4 23:52:54 1999 @@ -1,4 +1,3 @@ - ---------------------------------------------------------------------------- NOTE: See also arcnet-hardware.txt in this directory for jumper-setting and cabling information if you're like many of us and didn't happen to get a @@ -92,10 +91,10 @@ http://www.perftech.com/ or ftp to ftp.perftech.com. Novell makes a networking stack for DOS which includes ARCnet drivers. Try -ftp'ing to ftp.novell.com. +FTPing to ftp.novell.com. You can get the Crynwr packet driver collection (including arcether.com, the -one you'll want to use with arcnet cards) from +one you'll want to use with ARCnet cards) from oak.oakland.edu:/simtel/msdos/pktdrvr. It won't work perfectly on a 386+ without patches, though, and also doesn't like several cards. Fixed versions are available on my WWW page, or via e-mail if you don't have WWW @@ -183,7 +182,7 @@ ----------------------- Configure and rebuild Linux. When asked, answer 'm' to "Generic ARCnet -support" and to support for your ARcnet chipset if you want to use the +support" and to support for your ARCnet chipset if you want to use the loadable module. You can also say 'y' to "Generic ARCnet support" and 'm' to the chipset support if you wish. @@ -269,7 +268,7 @@ Arcether client, assuming you remember to load winpkt of course. LAN Manager and Windows for Workgroups: These programs use protocols that - are incompatible with the internet standard. They try to pretend + are incompatible with the Internet standard. They try to pretend the cards are Ethernet, and confuse everyone else on the network. However, v2.00 and higher of the Linux ARCnet driver supports this @@ -288,7 +287,7 @@ you're completely insane, and/or you need to build some kind of hybrid network that uses both encapsulation types. -OS2: I've been told it works under Warp Connect with an ARCnet driver from +OS/2: I've been told it works under Warp Connect with an ARCnet driver from SMC. You need to use the 'arc0e' interface for this. If you get the SMC driver to work with the TCP/IP stuff included in the "normal" Warp Bonus Pack, let me know. @@ -309,7 +308,7 @@ The ARCnet driver v2.10 ALPHA supports three protocols, each on its own "virtual network device": - arc0 - RFC1201 protocol, the official internet standard which just + arc0 - RFC1201 protocol, the official Internet standard which just happens to be 100% compatible with Novell's TRXNET driver. Version 1.00 of the ARCnet driver supported _only_ this protocol. arc0 is the fastest of the three protocols (for @@ -331,13 +330,13 @@ reasons yet to be determined. (Probably it's the smaller MTU that does it.) - arc0s - The "[s]imple" RFC1051 protocol is the "previous" internet + arc0s - The "[s]imple" RFC1051 protocol is the "previous" Internet standard that is completely incompatible with the new standard. Some software today, however, continues to support the old standard (and only the old standard) including NetBSD and AmiTCP. RFC1051 also does not support RFC1201's packet splitting, and the MTU of 507 is still - smaller than the internet "requirement," so it's quite + smaller than the Internet "requirement," so it's quite possible that you may run into problems. It's also slower than RFC1201 by about 25%, for the same reason as arc0e. @@ -388,16 +387,16 @@ Linux but runs the free Microsoft LANMAN Client instead. Worse, one of the Linux computers (freedom) also has a modem and acts as - a router to my internet provider. The other Linux box (insight) also has + a router to my Internet provider. The other Linux box (insight) also has its own IP address and needs to use freedom as its default gateway. The - XT (patience), however, does not have its own internet IP address and so + XT (patience), however, does not have its own Internet IP address and so I assigned it one on a "private subnet" (as defined by RFC1597). To start with, take a simple network with just insight and freedom. Insight needs to: - talk to freedom via RFC1201 (arc0) protocol, because I like it more and it's faster. - - use freedom as its internet gateway. + - use freedom as its Internet gateway. That's pretty easy to do. Set up insight like this: ifconfig arc0 insight @@ -417,20 +416,20 @@ /* and default gateway is configured by pppd */ Great, now insight talks to freedom directly on arc0, and sends packets - to the internet through freedom. If you didn't know how to do the above, + to the Internet through freedom. If you didn't know how to do the above, you should probably stop reading this section now because it only gets worse. Now, how do I add patience into the network? It will be using LANMAN Client, which means I need the arc0e device. It needs to be able to talk to both insight and freedom, and also use freedom as a gateway to the - internet. (Recall that patience has a "private IP address" which won't - work on the internet; that's okay, I configured Linux IP masquerading on + Internet. (Recall that patience has a "private IP address" which won't + work on the Internet; that's okay, I configured Linux IP masquerading on freedom for this subnet). So patience (necessarily; I don't have another IP number from my provider) has an IP address on a different subnet than freedom and - insight, but needs to use freedom as an internet gateway. Worse, most + insight, but needs to use freedom as an Internet gateway. Worse, most DOS networking programs, including LANMAN, have braindead networking schemes that rely completely on the netmask and a 'default gateway' to determine how to route packets. This means that to get to freedom or @@ -449,7 +448,7 @@ This way, freedom will send all packets for patience through arc0e, giving its IP address as gatekeeper (on the private subnet). When it - talks to insight or the internet, it will use its "freedom" internet IP + talks to insight or the Internet, it will use its "freedom" Internet IP address. You will notice that we haven't configured the arc0e device on insight. @@ -473,7 +472,7 @@ [RFC1201 NETWORK] [ETHER-ENCAP NETWORK] - (registered internet subnet) (RFC1597 private subnet) + (registered Internet subnet) (RFC1597 private subnet) (IP Masquerade) /---------------\ * /---------------\ @@ -523,7 +522,7 @@ Once the driver is running, you can run the arcdump shell script (available from me or in the full ARCnet package, if you have it) as root to list the contents of the arcnet buffers at any time. To make any sense at all out of -this, you should grab the pertinent RFC's. (some are listed near the top of +this, you should grab the pertinent RFCs. (some are listed near the top of arcnet.c). arcdump assumes your card is at 0xD0000. If it isn't, edit the script. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/baycom.txt linux.ac/Documentation/networking/baycom.txt --- linux.vanilla/Documentation/networking/baycom.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/baycom.txt Fri Jun 4 23:52:54 1999 @@ -31,7 +31,7 @@ Its devices are called bcp0 through bcp3. baycom_epp: - This driver supports the epp modem. + This driver supports the EPP modem. Its devices are called bce0 through bce3. This driver is work-in-progress. @@ -60,10 +60,10 @@ an additional power supply. Furthermore, it incorporates a carrier detect circuitry. -epp: This is a high speed modem adaptor that connects to an enhanced parallel port. +EPP: This is a high-speed modem adaptor that connects to an enhanced parallel port. Its target audience is users working over a high speed hub (76.8kbit/s). -eppfpga: This is a redesign of the epp adaptor. +eppfpga: This is a redesign of the EPP adaptor. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/cs89x0.txt linux.ac/Documentation/networking/cs89x0.txt --- linux.vanilla/Documentation/networking/cs89x0.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/cs89x0.txt Fri Jun 4 23:52:54 1999 @@ -203,7 +203,7 @@ * io=### - specify IO address (200h-360h) * irq=## - specify interrupt level * mmode=##### - specify memory base address -* dma=# - specify dma channel +* dma=# - specify DMA channel * media=rj45 - specify media type or media=2 or media=aui @@ -412,33 +412,33 @@ assigned during hardware configuration. The following tests are performed: * IO Register Read/Write Test - The IO Register Read/Write test insures that the CS8900/20 can be + The IO Register Read/Write test ensures that the CS8900/20 can be accessed in IO mode, and that the IO base address is correct. * Shared Memory Test - The Shared Memory test insures the CS8900/20 can be accessed in memory + The Shared Memory test ensures the CS8900/20 can be accessed in memory mode and that the range of memory addresses assigned does not conflict with other devices in the system. * Interrupt Test - The Interrupt test insures there are no conflicts with the assigned IRQ + The Interrupt test ensures there are no conflicts with the assigned IRQ signal. * EEPROM Test - The EEPROM test insures the EEPROM can be read. + The EEPROM test ensures the EEPROM can be read. * Chip RAM Test - The Chip RAM test insures the 4K of memory internal to the CS8900/20 is + The Chip RAM test ensures the 4 K of memory internal to the CS8900/20 is working properly. * Internal Loop-back Test - The Internal Loop Back test insures the adapter's transmitter and + The Internal Loop Back test ensures the adapter's transmitter and receiver are operating properly. If this test fails, make sure the adapter's cable is connected to the network (check for LED activity for example). * Boot PROM Test - The Boot PROM test insures the Boot PROM is present, and can be read. + The Boot PROM test ensures the Boot PROM is present, and can be read. Failure indicates the Boot PROM was not successfully read due to a hardware problem or due to a conflicts on the Boot PROM address assignment. (Test only applies if the adapter is configured to use the @@ -564,7 +564,7 @@ Telephone :(800) 888-5016 (from inside U.S. and Canada) :(512) 442-7555 (from outside the U.S. and Canada) Fax :(512) 912-3871 -Email :ethernet@crystal.cirrus.com +E-mail :ethernet@crystal.cirrus.com WWW :http://www.crystal.com diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/dgrs.txt linux.ac/Documentation/networking/dgrs.txt --- linux.vanilla/Documentation/networking/dgrs.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/dgrs.txt Fri Jun 4 23:52:54 1999 @@ -1,4 +1,4 @@ - The Digi Intl. RightSwitch SE-X (dgrs) Device Driver + The Digi International RightSwitch SE-X (dgrs) Device Driver This is a Linux driver for the Digi International RightSwitch SE-X EISA and PCI boards. These are 4 (EISA) or 6 (PCI) port Ethernet diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/eql.txt linux.ac/Documentation/networking/eql.txt --- linux.vanilla/Documentation/networking/eql.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/eql.txt Fri Jun 4 23:52:54 1999 @@ -471,58 +471,3 @@ able to data at over 48Kb/s [ISDN link -Simon]. I managed a transfer of up to 7.5 Kbyte/s on one go, but averaged around 6.4 Kbyte/s, which I think is pretty cool. :) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/load-balancing.txt linux.ac/Documentation/networking/load-balancing.txt --- linux.vanilla/Documentation/networking/load-balancing.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/networking/load-balancing.txt Fri Jun 4 23:52:54 1999 @@ -0,0 +1,122 @@ +Load balancing using multipaths (patch version: 4) +================================================== + +Contact Guus Sliepen if you need help, want to know +more, have remarks or further idea's with relation to this. + +Intro +----- + +If you have multiple physical network links to another computer, and you want +some kind of load balancing, you can now do so. Please note that this only +applies to IPv4 traffic, not for IPX, IPv6 or any other protocol (yet). + +Needed +----- + +* LATEST iproute package from ftp://ftp.inr.ac.ru/ip-routing/ +* CONFIG_IP_ROUTE_MULTIPATH enabled in kernel configuration (it's in + Networking options, below the Advanced Router option you'll have to enable + too) +* Ofcourse you must also have patched your kernel and recompiled it for this + feature to be enabled. + +To do +----- + +* Make sure the devices you want to combine are up, they all accept the + packets you want to send (ie, they must all have the same IP address/netmask + or something clever to get the same result) +* Just to make sure, remove any routes via those devices (route del ...) +* Now add all routes via one iproute command using the 'nexthops' statement: + + ip route add / equalize \\ + nexthop dev \\ + nexthop dev \\ + nexthop ... + +* Just to make sure, flush route cache: + + echo 1 >/proc/sys/net/ipv4/route/flush + +Example +------- + +This is an example showing how to make a 20 Mbit connection between two +computers using 2 10 Mbit ethernet cards per computer. Computer 1 has IP +192.168.1.1 and computer 2 has IP 192.168.1.2. We start from scratch: + +[computer1]~/>ifconfig eth0 192.168.1.1 netmask 255.255.255.0 +[computer1]~/>route del -net 192.168.1.0 netmask 255.255.255.0 +[computer1]~/>ifconfig eth1 192.168.1.1 netmask 255.255.255.0 +[computer1]~/>route del -net 192.168.1.0 netmask 255.255.255.0 +[computer1]~/>ip route add 192.168.1.0/24 equalize nexthop dev eth0 nexthop dev eth1 +[computer1]~/>echo 1 >/proc/sys/net/ipv4/route/flush + +[computer2]~/>ifconfig eth0 192.168.1.2 netmask 255.255.255.0 +[computer2]~/>route del -net 192.168.1.0 netmask 255.255.255.0 +[computer2]~/>ifconfig eth1 192.168.1.2 netmask 255.255.255.0 +[computer2]~/>route del -net 192.168.1.0 netmask 255.255.255.0 +[computer2]~/>ip route add 192.168.1.0/24 equalize nexthop dev eth0 nexthop dev eth1 +[computer2]~/>echo 1 >/proc/sys/net/ipv4/route/flush + +You can even add more computers, just replace the x in 192.168.1.x with the +number of your computer, and make sure all eth0's are connected to each other +and all eth1's. You can also use more devices, just ifconfig them all and +remove the default routes that are generated, and add extra nexthops. + +Notes +----- + +If you want to add a gateway entry in your routing table, and want it to be +balanced too, you first have to make singlepath entries for every network +interface you want to use, after that add the gateway with all the nexthops +filled in, then delete the singlepath routes and then add the normal +multipath route. + +Older patch versions used a /proc entry to control load-balancing. This does +not work anymore. You should use the 'equalize' flag instead while adding new +routes. You need a fresh version of iproute for that. + +Status +------ + +Packet type: Balanced? Note +---------------------------------------------------------------------- +ARP no But we don't want them to ;) +ICMP yes +Connectionless UDP yes +Connected UDP yes +Broadcast UDP no Would be nice if it would, + but this is rarely used for + high bandwith data transfers. +TCP yes At least all data packets are, + maybe some control packets are + not. + +Bugs +---- + +It is possible that under extreme conditions the kernel will run out of +memory for network buffers. This might be temporarily, but if you're unlucky +it is permanent and then your network will be dead. However, completely +flooding my 486/66 with 2.5 megabyte per second random traffic only gave an +occasional 'Couldn't allocate a sk_buff of size 1514' message, but that was +not permanent, and there were no crashes. + +Technically +----------- + +Load balancing needed a slight adjustment to the unpatched linux kernel, +because of the route cache. Multipath is an option already found in the old +2.1.x kernels. However, once a packet arrives, and it matches a multipath +route, a (quasi random) device out of the list of nexthops is taken for its +destination. That's okay, but after that the kernel puts everything into a +hash table, and the next time a packet with the same source/dest/tos arrives, +it finds it is in the hash table, and routes it via the same device as last +time. The adjustment I made is as follows: If the kernel sees that the route +to be taken has got the 'equalize' flag set, it not only selects the random +device, but also tags the packet with the RTCF_EQUALIZE flag. If another +packet of the same kind arrives, it is looked up in the hash table. It then +checks if our flag is set, and if so, it deletes the entry in the cache and +has to recalculate the destination again. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/multicast.txt linux.ac/Documentation/networking/multicast.txt --- linux.vanilla/Documentation/networking/multicast.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/multicast.txt Fri Jun 4 23:52:54 1999 @@ -1,11 +1,13 @@ -Behaviour of cards under Multicast. This is how they currently -behave not what the hardware can do - i.e. the lance driver doesn't -use its filter, even though the code for loading it is in the DEC -lance based driver. +Behaviour of Cards Under Multicast +================================== -The following multicast requirements are needed +This is how they currently behave, not what the hardware can do--for example, +the Lance driver doesn't use its filter, even though the code for loading +it is in the DEC Lance-based driver. + +The following are requirements for multicasting ----------------------------------------------- -Appletalk Multicast hardware filtering not important but +AppleTalk Multicast hardware filtering not important but avoid cards only doing promisc IP-Multicast Multicast hardware filters really help IP-MRoute AllMulti hardware filters are of no help diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/olympic.txt linux.ac/Documentation/networking/olympic.txt --- linux.vanilla/Documentation/networking/olympic.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/networking/olympic.txt Wed Jun 9 20:08:19 1999 @@ -0,0 +1,75 @@ + +IBM PCI Pit/Pit-Phy/Olympic CHIPSET BASED TOKEN RING CARDS README + +Release 0.2.0 - Release + June 8th 1999 Peter De Schrijver & Mike Phillips + + +Thanks: +Erik De Cock, Adrian Bridgett and Frank Fiene for their +patience and testing. +Paul Norton without whose tr.c code we would have had +a lot more work to do. + +Options: + +The driver accepts three options: ringspeed, pkt_buf_sz, and +message_level. + +These options can be specified differently for each card found. + +ringspeed: Has one of three settings 0 (default), 4 or 16. 0 will +make the card autosense the ringspeed and join at the appropriate speed, +this will be the default option for most people. 4 or 16 allow you to +explicitly force the card to operate at a certain speed. The card will fail +if you try to insert it at the wrong speed. (Although some hubs will allow +this so be *very* careful). The main purpose for explicitly setting the ring +speed is for when the card is first on the ring. In autosense mode, if the card +cannot detect any active monitors on the ring it will not open, so you must +re-init the card at the appropriate speed. Unfortunately at present the only +way of doing this is rmmod and insmod which is a bit tough if it is compiled +in the kernel. + +pkt_buf_sz: This is this initial receive buffer allocation size. This will +default to 4096 if no value is entered. You may increase performance of the +driver by setting this to a value larger than the network packet size, although +the driver now re-sizes buffers based on MTU settings as well. + +message_level: Controls level of messages created by the driver. Defaults to 0: +which only displays start-up and critical messages. Presently any non-zero +value will display all soft messages as well. NB This does not turn +debuging messages on, that must be done by modified the source code. + +Multi-card: + +The driver will detect multiple cards and will work with shared interrupts, +each card is assigned the next token ring device, i.e. tr0 , tr1, tr2. The +driver should also happily reside in the system with other drivers. It has +been tested with ibmtr.c running, and I personnally have had one Olicom PCI +card and two IBM olympic cards (all on the same interrupt), all running +together. + +Variable MTU size: + +The driver can handle a MTU size upto either 4500 or 18000 depending upon +ring speed. The driver also changes the size of the receive buffers as part +of the mtu re-sizing, so if you set mtu = 18000, you will need to be able +to allocate 16 * (sk_buff with 18000 buffer size) call it 18500 bytes per ring +position = 296,000 bytes of memory space, plus of course anything +necessary for the tx sk_buff's. Remember this is per card, so if you are +building routers, gateway's etc, you could start to use a lot of memory +real fast. + +Network Monitor Mode: + +By modifying the #define OLYMPIC_NETWORK_MONITOR from 0 to 1 in the +source code the driver will implement a quasi network monitoring +mode. All unexpected MAC frames (beaconing etc.) will be received +by the driver and the source and destination addresses printed. +Also an entry will be added in /proc/net called olympic_tr. This +displays low level information about the configuration of the ring and +the adapter. This feature has been designed for network adiministrators +to assist in the diagnosis of network / ring problems. + +6/8/99 Peter De Schrijver and Mike Phillips + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/policy-routing.txt linux.ac/Documentation/networking/policy-routing.txt --- linux.vanilla/Documentation/networking/policy-routing.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/policy-routing.txt Fri Jun 4 23:52:54 1999 @@ -83,7 +83,7 @@ 2. Opposite case. Just forget all that you know about routing tables. Every rule is supplied with its own gateway, device info. record. This approach is not appropriate for automated - route maintanance, but it is ideal for manual configuration. + route maintenance, but it is ideal for manual configuration. HOWTO: iproute addrule [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ dev INPUTDEV] [ pref PREFERENCE ] route [ gw GATEWAY ] diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/wan-router.txt linux.ac/Documentation/networking/wan-router.txt --- linux.vanilla/Documentation/networking/wan-router.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/wan-router.txt Fri Jun 4 23:52:54 1999 @@ -1,19 +1,21 @@ ------------------------------------------------------------------------------ WAN Router for Linux Operating System ------------------------------------------------------------------------------ +Version 2.0.4 - Nov 26, 1998 +Version 2.0.3 - Aug 25, 1998 +Version 2.0.2 - Dec 09, 1997 Version 2.0.1 - Nov 28, 1997 Version 2.0.0 - Nov 06, 1997 Version 1.0.3 - June 3, 1997 Version 1.0.1 - January 30, 1997 Author: Jaspreet Singh - Gene Kozin Copyright (c) 1995-1997 Sangoma Technologies Inc. ------------------------------------------------------------------------------ WARNING: This Version of WANPIPE supports only the S508 and S508/FT1 cards. IF YOU OWN A S502E OR A S508 CARD THEN PLEASE CONTACT SANGOMA TECHNOLOGIES FOR -AN UPGRADE. +AN UPGRADE. ONLY THE BiSYNC STREAMING CODE IS SUPPORTED ON S502E/S503 cards. INTRODUCTION @@ -121,6 +123,9 @@ were given by Mike McLagan and his implementation of the Frame Relay router and drivers for Sangoma cards (dlci/sdla). +With the new implementation of the APIs being incorporated into the WANPIPE, +a special thank goes to Alan Cox in providing insight into BSD sockets. + Special thanks to all the WANPIPE users who performed field-testing, reported bugs and made valuable comments and suggestions that help us to improve this product. @@ -128,6 +133,27 @@ REVISION HISTORY + +2.0.4 Nov 26, 1998 - NEW Cisco Dual Port support. + - NEW support for BiSync Streaming API. + - NEW support for HDLC (LAPB) API. + - WANPIPE provides an API for application + development using the BSD socket interface. + +2.0.3 Aug 25, 1998 - NEW support for Cisco HDLC, with cpipemon + utility for monitoring + - CIR support for Frame-relay + - Support for PAP and CHAP for ppp has been + implemented + - Dynamic IP assignment for PPP + - Multiple channel IPX support for Frame-relay + and X25 + - Inverse Arp support for Frame-relay + - FT1 Configuration utility for linux + - Man Pages for router.conf, router, sdladump, + cfgft1, fpipemon, ppipemon and cpipemon + +2.0.2 Dev 09, 1997 - Implemented PAP and CHAP for ppp. 2.0.1 Nov 28, 1997 - Protection of "enable_irq()" while "disable_irq()" has been enabled from any other diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/wanpipe.txt linux.ac/Documentation/networking/wanpipe.txt --- linux.vanilla/Documentation/networking/wanpipe.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/wanpipe.txt Fri Jun 4 23:52:54 1999 @@ -1,8 +1,8 @@ ------------------------------------------------------------------------------ WANPIPE(tm) Multiprotocol WAN Driver for Linux WAN Router ------------------------------------------------------------------------------ -Release 4.1 -November 17, 1997 +VERSION 5.0 +August 25, 1998 Author: Jaspreet Singh Copyright (c) 1995-1997 Sangoma Technologies Inc. ------------------------------------------------------------------------------ @@ -13,11 +13,11 @@ for personal computers (ISA bus) designed to provide PC connectivity to various communication links, such as leased lines and public data networks, at speeds up to T1/E1 using a variety of synchronous communications protocols, -including frame relay, PPP, X.25, SDLC, etc. +including frame relay, PPP, Cisco HDLC, X.25, SDLC, etc. -WANPIPE driver together with Linux WAN Router module allows you to build a -relatively inexpensive, yet high-performance multiprotocol WAN router. For -more information about the Linux WAN Router please read the file +The WANPIPE driver together with the Linux WAN Router module allows you to +build a relatively inexpensive, yet high-prformance multiprotocol WAN +router. For more information about Linux WAN Router please read file Documentation/networking/wan-router.txt. You must also obtain the WAN Tools package to be able to use the Linux WAN Router and WANPIPE driver. The package is available via the Internet from Sangoma Technologies' anonymous FTP server: @@ -26,7 +26,7 @@ or ftp.sangoma.com/pub/linux/wanpipe-X.Y.Z.tgz -The names of the packages differ only due to naming convention. The +The name of the package differs only due to naming convention. The functionality of wantools and wanpipe packages are the same. The latest version of the WAN Drivers is wanpipe-2.0.0. @@ -59,13 +59,11 @@ NEW IN THIS RELEASE - o This Version of WANPIPE supports only the S508 and S508/FT1 cards. IF YOU - OWN A S502E OR A S508 CARD THEN PLEASE CONTACT SANGOMA TECHNOLOGIES FOR AN - UPGRADE. - o Protection of "enable_irq()" while "disable_irq()" has been enabled from - any other routine (for Frame Relay, PPP and X25). - o Added additional Stats for Fpipemon and Ppipemon. - o Improved Load Sharing for multiple boards +o Supports DUAL PORT Cisco HDLC. +o Supports HDLC (LAPB) API +o Supports BiSync Streaming code for S502E and S503 cards ONLY. +o Provides a BSD socket interface for creating applications using BiSync + streaming and HDLC LAPB. FILE LIST @@ -76,12 +74,18 @@ sdla_fr.c SDLA Frame Relay source code sdla_ppp.c SDLA PPP source code sdla_x25.c SDLA X.25 source code + sdla_chdlc.c SDLA Cisco HDLC source code + sdla_bstrm.c SDLA BiSync Streaming API source code + sdla_hdlc.c SDLA HDLC (LAPB) API source code sdlamain.c SDLA support source code include/linux: sdla_x25.h SDLA X.25 firmware API definitions sdla_fr.h SDLA frame relay firmware API definitions sdla_ppp.h SDLA PPP firmware API definitions + sdla_chdlc.h SDLA Cisco HDLC firmware API definitions + sdla_bstrm.h SDLA BiSync Streaming firmware API definitions + sdla_hdlc.h SDLA HDLC LAPB firmware API definitions wanpipe.h WANPIPE API definitions sdladrv.h SDLA support module API definitions sdlasfm.h SDLA firmware module definitions @@ -89,6 +93,20 @@ REVISION HISTORY + +5.0 August 25, 1998 + o This Version of WANPIPE supports only the S508 and S508/FT1 cards. + IF YOU OWN A S502E OR A S508 CARD THEN PLEASE CONTACT SANGOMA + TECHNOLOGIES FOR AN UPGRADE. + o NEW support for Cisco HDLC, with cpipemon utility for monitoring + o CIR support for Frame-relay + o Support for PAP and CHAP for ppp has been implemented + o Dynamic IP assignment for PPP + o Multiple channel IPX support for Frame-relay and X25 + o Inverse Arp support for Frame-relay + o FT1 Configuration utility for linux + o Man Pages for router.conf, router, sdladump, cfgft1, fpipemon, + ppipemon and cpipemon 4.1 November 28, 1997 o Protection of "enable_irq()" while "disable_irq()" has been enabled diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/z8530drv.txt linux.ac/Documentation/networking/z8530drv.txt --- linux.vanilla/Documentation/networking/z8530drv.txt Sun Nov 8 15:08:46 1998 +++ linux.ac/Documentation/networking/z8530drv.txt Fri Jun 4 23:52:54 1999 @@ -252,7 +252,7 @@ speed 1200 # the default baudrate clock dpll # clock source: - # dpll = normal halfduplex operation + # dpll = normal half duplex operation # external = MODEM provides own Rx/Tx clock # divider = use full duplex divider if # installed (1) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/sound/OPL3-SA2 linux.ac/Documentation/sound/OPL3-SA2 --- linux.vanilla/Documentation/sound/OPL3-SA2 Tue Jan 19 02:57:22 1999 +++ linux.ac/Documentation/sound/OPL3-SA2 Sat Jun 12 20:06:07 1999 @@ -46,6 +46,21 @@ then email me if you are willing to experiment in an effort to make it work. +************************************************************************ +* I have now had two such machines, and I have fixed this to work +* properly when built into the kernel. The Toshiba Libretto series, or +* at least models 70CT and 110CT which I have owned, use a Yamaha +* OPL3-SAx (OPL3-SA3 according to documentation) sound chip, IRQ 5, +* IO addresses 220/530/388/330/370 and DMA 1,0 (_not_ 0,1). All these +* configuration settings can be gathered by booting another OS which +* recognizes the card already. +* +* I have made things 'just work' for the non-modular case on such +* machines when configured properly. +* +* David Luyer +************************************************************************ + If you are using isapnp, follow the directions in its documentation to produce a configuration file. Here is the relevant excerpt I use for my SAx card from my isapnp.conf: diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/sysrq.txt linux.ac/Documentation/sysrq.txt --- linux.vanilla/Documentation/sysrq.txt Sun Nov 8 15:08:50 1998 +++ linux.ac/Documentation/sysrq.txt Fri Jun 4 23:52:56 1999 @@ -9,8 +9,8 @@ * How do I enable the magic SysRQ key? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You need to say yes to 'Magic SysRq key (CONFIG_MAGIC_SYSRQ)' when -configuring the kernel. This option is only available it 2.1.x or later +You need to say "yes" to 'Magic SysRq key (CONFIG_MAGIC_SYSRQ)' when +configuring the kernel. This option is only available in 2.1.x or later kernels. * How do I use the magic SysRQ key? diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/MAINTAINERS linux.ac/MAINTAINERS --- linux.vanilla/MAINTAINERS Tue Jun 15 16:49:45 1999 +++ linux.ac/MAINTAINERS Mon Jun 14 13:51:28 1999 @@ -16,8 +16,8 @@ SMC etherpower for that.) 3. Make sure your changes compile correctly in multiple - configurations. In paticular check changes work both as a module - and built into the kernel. + configurations. In particular check that changes work both as a + module and built into the kernel. 4. When you are happy with a change make it generally available for testing and await feedback. @@ -28,7 +28,7 @@ and variable names. These aren't as silly as they seem. One job the maintainers (and especially Linus) do is to keep things looking the same. Sometimes this means that the clever hack in - your driver to get around a problem actual needs to become a + your driver to get around a problem actually needs to become a generalized kernel feature ready for next time. See Documentation/CodingStyle for guidance here. @@ -49,8 +49,8 @@ Maintainers List (try to look for most precise areas first) -Note: For the hard of thinking, this list is meant to remain in Alphabetical -order. If you could add yourselves to it in Alphabetical order that would +Note: For the hard of thinking, this list is meant to remain in alphabetical +order. If you could add yourselves to it in alphabetical order that would so much easier [Ed] P: Person @@ -560,6 +560,16 @@ L: linux-kernel@vger.rutgers.edu S: Maintained +OLYMPIC NETWORK DRIVER +P: Peter De Shrijver +M: p2@ace.ulyssis.sutdent.kuleuven.ac.be +P: Mike Phillips +M: phillim@amtrak.com +L: linux-net@vger.rutgers.edu +L: linux-tr@emissary.aus-etc.com +W: http://www.linuxtr.net +S: Maintained + OPL3-SA2, SA3, and SAx DRIVER P: Scott Murray M: scottm@interlog.com @@ -626,7 +636,7 @@ REAL TIME CLOCK DRIVER P: Paul Gortmaker -M gpg109@rsphy1.anu.edu.au +M: gpg109@rsphy1.anu.edu.au L: linux-kernel@vger.rutgers.edu S: Maintained @@ -655,11 +665,6 @@ W: http://www.torque.net/sg S: Maintained -SCSI GENERIC -L: linux-scsi@vger.rutgers.edu -M: douglas.gilbert@rbcds.com -S: Maintained - SCSI SUBSYSTEM L: linux-scsi@vger.rutgers.edu S: Unmaintained @@ -678,9 +683,10 @@ S: Maintained SMB FILESYSTEM -P: Volker Lendecke -M: vl@kki.org -L: samba@listproc.anu.edu.au +P: Andrew Tridgell +M: tridge@samba.org +W: http://samba.org/ +L: samba@samba.org S: Maintained SMP: (except SPARC) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Makefile linux.ac/Makefile --- linux.vanilla/Makefile Tue Jun 15 16:49:45 1999 +++ linux.ac/Makefile Tue Jun 15 17:32:43 1999 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 2 SUBLEVEL = 10 -EXTRAVERSION = +EXTRAVERSION = -ac1 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -65,12 +65,12 @@ # INSTALL_PATH specifies where to place the updated kernel and system map # images. Uncomment if you want to place them anywhere other than root. -#INSTALL_PATH=/boot +INSTALL_PATH=/boot # # INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory # relocations required by build roots. This is not defined in the -# makefile but the arguement can be passed to make if needed. +# makefile but the argument can be passed to make if needed. # # @@ -323,7 +323,7 @@ if [ -f FC4_MODULES ]; then inst_mod FC4_MODULES fc4; fi; \ if [ -f IRDA_MODULES ]; then inst_mod IRDA_MODULES net; fi; \ \ - ls *.o > $$MODLIB/.allmods; \ + for f in *.o; do [ -r $$f ] && echo $$f; done > $$MODLIB/.allmods; \ echo $$MODULES | tr ' ' '\n' | sort | comm -23 $$MODLIB/.allmods - > $$MODLIB/.misc; \ if [ -s $$MODLIB/.misc ]; then inst_mod $$MODLIB/.misc misc; fi; \ rm -f $$MODLIB/.misc $$MODLIB/.allmods; \ @@ -343,8 +343,8 @@ clean: archclean rm -f kernel/ksyms.lst include/linux/compile.h - rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' \ - ! -regex '.*ksymoops/.*' -print` + rm -f core `find . -name '*.[oas]' ! \( -regex '.*lxdialog/.*' \ + -o -regex '.*ksymoops/.*' \) -print` rm -f core `find . -type f -name 'core' -print` rm -f core `find . -name '.*.flags' -print` rm -f vmlinux System.map @@ -391,7 +391,7 @@ sums: find . -type f -print | sort | xargs sum > .SUMS -dep-files: scripts/mkdep archdep include/linux/version.h +dep-files: scripts/mkdep archdep include/linux/version.h new-genksyms scripts/mkdep init/*.c > .depend scripts/mkdep `find $(FINDHPATH) -follow -name \*.h ! -name modversions.h -print` > .hdepend # set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i fastdep ;done @@ -401,7 +401,19 @@ MODVERFILE := ifdef CONFIG_MODVERSIONS + MODVERFILE := $(TOPDIR)/include/linux/modversions.h + +new-genksyms: + @$(GENKSYMS) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) /dev/null || ( echo -e "\nYou need a new version of the genksyms\ + program, which is part of\nthe modutils package. Please read the file\ + Documentation/Changes\nfor more information.\n"; exit 1 ) + +else + +new-genksyms: + endif depend dep: dep-files $(MODVERFILE) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/alpha_ksyms.c linux.ac/arch/alpha/kernel/alpha_ksyms.c --- linux.vanilla/arch/alpha/kernel/alpha_ksyms.c Tue Jun 15 16:49:45 1999 +++ linux.ac/arch/alpha/kernel/alpha_ksyms.c Mon Jun 7 01:13:17 1999 @@ -71,6 +71,10 @@ EXPORT_SYMBOL(_writel); EXPORT_SYMBOL(_memcpy_fromio); EXPORT_SYMBOL(_memcpy_toio); +#ifdef CONFIG_ALPHA_JENSEN +EXPORT_SYMBOL (_memcpy_fromio_g32a); +EXPORT_SYMBOL (_memcpy_toio_g32a); +#endif EXPORT_SYMBOL(_memset_c_io); EXPORT_SYMBOL(insb); EXPORT_SYMBOL(insw); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/core_cia.c linux.ac/arch/alpha/kernel/core_cia.c --- linux.vanilla/arch/alpha/kernel/core_cia.c Tue Jun 15 16:49:45 1999 +++ linux.ac/arch/alpha/kernel/core_cia.c Fri Jun 4 23:52:48 1999 @@ -535,8 +535,6 @@ * Set up the PCI->physical memory translation windows. * For now, windows 1,2 and 3 are disabled. In the future, * we may want to use them to do scatter/gather DMA. - * - * Window 0 goes at 1 GB and is 1 GB large. */ *(vuip)CIA_IOC_PCI_W0_BASE = 1U | (CIA_DMA_WIN_BASE_DEFAULT & 0xfff00000U); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/core_pyxis.c linux.ac/arch/alpha/kernel/core_pyxis.c --- linux.vanilla/arch/alpha/kernel/core_pyxis.c Sun Nov 8 15:08:25 1998 +++ linux.ac/arch/alpha/kernel/core_pyxis.c Fri Jun 4 23:52:48 1999 @@ -427,8 +427,6 @@ * Set up the PCI->physical memory translation windows. * For now, windows 1,2 and 3 are disabled. In the future, we may * want to use them to do scatter/gather DMA. - * - * Window 0 goes at 1 GB and is 1 GB large. */ *(vuip)PYXIS_W0_BASE = 1U | (PYXIS_DMA_WIN_BASE_DEFAULT & 0xfff00000U); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/entry.S linux.ac/arch/alpha/kernel/entry.S --- linux.vanilla/arch/alpha/kernel/entry.S Thu May 27 22:11:48 1999 +++ linux.ac/arch/alpha/kernel/entry.S Fri Jun 4 23:52:48 1999 @@ -527,6 +527,8 @@ call_pal PAL_swpctx unop bsr $1,undo_switch_stack + lda $8,0x3fff + bic $30,$8,$8 mov $17,$0 ret $31,($26),1 .end alpha_switch_to diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/process.c linux.ac/arch/alpha/kernel/process.c --- linux.vanilla/arch/alpha/kernel/process.c Tue Jun 15 16:49:45 1999 +++ linux.ac/arch/alpha/kernel/process.c Fri Jun 4 23:52:48 1999 @@ -55,7 +55,6 @@ unsigned long init_user_stack[1024] = { STACK_MAGIC, }; static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/proto.h linux.ac/arch/alpha/kernel/proto.h --- linux.vanilla/arch/alpha/kernel/proto.h Tue Jun 15 16:49:45 1999 +++ linux.ac/arch/alpha/kernel/proto.h Sun Jun 13 19:58:21 1999 @@ -193,7 +193,7 @@ /* process.c */ extern void generic_kill_arch (int mode, char *reboot_cmd); -extern void cpu_idle(void *) __attribute__((noreturn)); +extern int cpu_idle(void *) __attribute__((noreturn)); /* ptrace.c */ extern int ptrace_set_bpt (struct task_struct *child); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/lib/io.c linux.ac/arch/alpha/lib/io.c --- linux.vanilla/arch/alpha/lib/io.c Fri Apr 16 22:10:51 1999 +++ linux.ac/arch/alpha/lib/io.c Mon Jun 7 01:13:17 1999 @@ -452,6 +452,48 @@ } } +#ifdef CONFIG_ALPHA_JENSEN +/* Special memcopy for EISA-Cards that permit only + * 32-bit accesses. Two 16-bit words are combined and + * written as one 32-bit word to the IO space. + */ + +void _memcpy_fromio_g32a(void * to, unsigned long from, long count) +{ + + if ((((long)to&1)!=0)&&((from&3)!=0)&&((count&3)!=0)) + { + printk ("memcpy_fromio_g32: Unaligned Data!\n"); + return; + } + + count-=4; + do { + __readlua((u16 *)to, (u16 *)(to+2), from); + count -= 4; + to += 4; + from += 4; + } while (count >= 0); +} + +void _memcpy_toio_g32a(unsigned long to, void * from, long count) +{ + if ((((long)from&1)!=0)&&((to&3)!=0)&&((count&3)!=0)) + { + printk ("memcpy_toio_g32: Unaligned Data!\n"); + return; + } + + count-=4; + do { + __writelua(*(u16 *)from, *(u16 *)(from+2), to); + count -= 4; + to += 4; + from += 4; + } while (count >= 0); +} +#endif + /* * "memset" on IO memory space. */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/sys_arm.c linux.ac/arch/arm/kernel/sys_arm.c --- linux.vanilla/arch/arm/kernel/sys_arm.c Thu May 27 22:11:49 1999 +++ linux.ac/arch/arm/kernel/sys_arm.c Fri Jun 4 23:52:53 1999 @@ -77,14 +77,12 @@ goto out; if (!(a.flags & MAP_ANONYMOUS)) { error = -EBADF; - file = fget(a.fd); - if (!file) + if (a.fd >= current->files->max_fds || + !(file = current->files->fd[a.fd])) goto out; } a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset); - if (file) - fput(file); out: unlock_kernel(); return error; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/Makefile linux.ac/arch/i386/Makefile --- linux.vanilla/arch/i386/Makefile Thu Dec 31 18:10:39 1998 +++ linux.ac/arch/i386/Makefile Sun Jun 6 02:46:05 1999 @@ -62,6 +62,13 @@ MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot +vmlinux: arch/i386/vmlinux.lds + +arch/i386/vmlinux.lds: arch/i386/vmlinux.lds.S FORCE + gcc -E -C -P -I$(HPATH) -imacros $(HPATH)/asm-i386/page_offset.h -Ui386 arch/i386/vmlinux.lds.S >arch/i386/vmlinux.lds + +FORCE: ; + zImage: vmlinux @$(MAKEBOOT) zImage diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/config.in linux.ac/arch/i386/config.in --- linux.vanilla/arch/i386/config.in Wed Apr 28 19:14:24 1999 +++ linux.ac/arch/i386/config.in Mon Jun 7 00:10:09 1999 @@ -33,6 +33,10 @@ define_bool CONFIG_X86_GOOD_APIC y fi +choice 'Maximum Physical Memory' \ + "1GB CONFIG_1GB \ + 2GB CONFIG_2GB" 1GB + bool 'Math emulation' CONFIG_MATH_EMULATION bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR bool 'Symmetric multi-processing support' CONFIG_SMP @@ -105,7 +109,6 @@ bool ' Enable PM at boot time' CONFIG_APM_DO_ENABLE bool ' Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE bool ' Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK - bool ' Power off on shutdown' CONFIG_APM_POWER_OFF bool ' Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND bool ' Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE bool ' RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/apm.c linux.ac/arch/i386/kernel/apm.c --- linux.vanilla/arch/i386/kernel/apm.c Tue Jan 19 02:57:23 1999 +++ linux.ac/arch/i386/kernel/apm.c Mon Jun 7 00:10:10 1999 @@ -1,6 +1,6 @@ /* -*- linux-c -*- * APM BIOS driver for Linux - * Copyright 1994-1998 Stephen Rothwell + * Copyright 1994-1999 Stephen Rothwell * (Stephen.Rothwell@canb.auug.org.au) * Development of this driver was funded by NEC Australia P/L * and NEC Corporation @@ -33,6 +33,7 @@ * Nov 1998, Version 1.7 * Jan 1999, Version 1.8 * Jan 1999, Version 1.9 + * Jun 1999, Version 1.10 * * History: * 0.6b: first version in official kernel, Linux 1.3.46 @@ -90,6 +91,12 @@ * Use CONFIG_SMP instead of __SMP__ * Ignore BOUNCES for three seconds. * Stephen Rothwell + * 1.10: Reset time across standby. + * Allow more inititialisation on SMP. + * Remove CONFIG_APM_POWER_OFF and make it boot time + * configurable (default on). + * Make debug only a boot time parameter (remove APM_DEBUG). + * Try to blank all devices on any error. * * APM 1.1 Reference: * @@ -144,51 +151,14 @@ */ #define APM_MINOR_DEV 134 -/* Configurable options: - * - * CONFIG_APM_IGNORE_USER_SUSPEND: define to ignore USER SUSPEND requests. - * This is necessary on the NEC Versa M series, which generates these when - * resuming from SYSTEM SUSPEND. However, enabling this on other laptops - * will cause the laptop to generate a CRITICAL SUSPEND when an appropriate - * USER SUSPEND is ignored -- this may prevent the APM driver from updating - * the system time on a RESUME. - * - * CONFIG_APM_DO_ENABLE: enable APM features at boot time. From page 36 of - * the specification: "When disabled, the APM BIOS does not automatically - * power manage devices, enter the Standby State, enter the Suspend State, - * or take power saving steps in response to CPU Idle calls." This driver - * will make CPU Idle calls when Linux is idle (unless this feature is - * turned off -- see below). This should always save battery power, but - * more complicated APM features will be dependent on your BIOS - * implementation. You may need to turn this option off if your computer - * hangs at boot time when using APM support, or if it beeps continuously - * instead of suspending. Turn this off if you have a NEC UltraLite Versa - * 33/C or a Toshiba T400CDT. This is off by default since most machines - * do fine without this feature. - * - * CONFIG_APM_CPU_IDLE: enable calls to APM CPU Idle/CPU Busy inside the - * idle loop. On some machines, this can activate improved power savings, - * such as a slowed CPU clock rate, when the machine is idle. These idle - * call is made after the idle loop has run for some length of time (e.g., - * 333 mS). On some machines, this will cause a hang at boot time or - * whenever the CPU becomes idle. - * - * CONFIG_APM_DISPLAY_BLANK: enable console blanking using the APM. Some - * laptops can use this to turn of the LCD backlight when the VC screen - * blanker blanks the screen. Note that this is only used by the VC screen - * blanker, and probably won't turn off the backlight when using X11. Some - * problems have been reported when using this option with gpm (if you'd - * like to debug this, please do so). - * - * CONFIG_APM_IGNORE_MULTIPLE_SUSPEND: The IBM TP560 bios seems to insist - * on returning multiple suspend/standby events whenever one occurs. We - * really only need one at a time, so just ignore any beyond the first. - * This is probably safe on most laptops. - * - * If you are debugging the APM support for your laptop, note that code for - * all of these options is contained in this file, so you can #define or - * #undef these on the next line to avoid recompiling the whole kernel. +/* + * See Documentation/Config.help for the configuration options. * + * Various options can be changed at boot time as follows: + * apm=on/off enable/disable APM + * [no-]debug log some debugging messages + * [no-]power-off power off on shutdown + * [no-]smp-power-off allow power off even for SMP */ /* KNOWN PROBLEM MACHINES: @@ -207,11 +177,6 @@ */ /* - * Define to have debug messages. - */ -#undef APM_DEBUG - -/* * Define to always call the APM BIOS busy routine even if the clock was * not slowed by the idle routine. */ @@ -266,27 +231,6 @@ __asm__ __volatile__("movl %%" #seg ",%0" : "=m" (where)) /* - * Forward declarations - */ -static void suspend(void); -static void standby(void); -static void set_time(void); - -static void check_events(void); -static void do_apm_timer(unsigned long); - -static int do_open(struct inode *, struct file *); -static int do_release(struct inode *, struct file *); -static ssize_t do_read(struct file *, char *, size_t , loff_t *); -static unsigned int do_poll(struct file *, poll_table *); -static int do_ioctl(struct inode *, struct file *, u_int, u_long); - -static int apm_get_info(char *, char **, off_t, int, int); - -extern int apm_register_callback(int (*)(apm_event_t)); -extern void apm_unregister_callback(int (*)(apm_event_t)); - -/* * Local variables */ static asmlinkage struct { @@ -313,15 +257,15 @@ #endif static int debug = 0; static int apm_disabled = 0; +static int power_off_enabled = 1; static struct wait_queue * process_list = NULL; static struct apm_bios_struct * user_list = NULL; static struct timer_list apm_timer; -static char driver_version[] = "1.9"; /* no spaces */ +static char driver_version[] = "1.10"; /* no spaces */ -#ifdef APM_DEBUG static char * apm_event_name[] = { "system standby", "system suspend", @@ -338,28 +282,6 @@ }; #define NR_APM_EVENT_NAME \ (sizeof(apm_event_name) / sizeof(apm_event_name[0])) -#endif - -static struct file_operations apm_bios_fops = { - NULL, /* lseek */ - do_read, - NULL, /* write */ - NULL, /* readdir */ - do_poll, - do_ioctl, - NULL, /* mmap */ - do_open, - NULL, /* flush */ - do_release, - NULL, /* fsync */ - NULL /* fasync */ -}; - -static struct miscdevice apm_device = { - APM_MINOR_DEV, - "apm", - &apm_bios_fops -}; typedef struct callback_list_t { int (* callback)(apm_event_t); @@ -502,7 +424,7 @@ return error; } -static int apm_driver_version(u_short *val) +static int __init apm_driver_version(u_short *val) { u32 eax; @@ -543,7 +465,7 @@ return set_power_state(0x0001, state); } -void apm_power_off(void) +void apm_power_off(int force) { /* * smp_hack == 2 means that we would have enabled APM support @@ -553,7 +475,8 @@ * they are doing because they booted with the smp-power-off * kernel option. */ - if (apm_enabled || (smp_hack == 2)) + if ((apm_enabled || (smp_hack == 2)) + && (power_off_enabled || force)) (void) apm_set_power_state(APM_STATE_OFF); } @@ -565,7 +488,7 @@ /* Blank the first display device */ error = set_power_state(0x0100, state); - if (error == APM_BAD_DEVICE) + if (error != APM_SUCCESS) /* try to blank them all instead */ error = set_power_state(0x01ff, state); return error; @@ -733,10 +656,8 @@ if (as->event_head == as->event_tail) { static int notified; - if (notified == 0) { + if (notified++ == 0) printk(KERN_ERR "apm: an event queue overflowed\n"); - notified = 1; - } as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; } as->events[as->event_head] = event; @@ -764,21 +685,19 @@ { unsigned long flags; - if (!got_clock_diff) /* Don't know time zone, can't set clock */ - return; - - save_flags(flags); - cli(); - CURRENT_TIME = get_cmos_time() + clock_cmos_diff; - restore_flags(flags); + if (got_clock_diff) { /* Must know time zone in order to set clock */ + save_flags(flags); + cli(); + CURRENT_TIME = get_cmos_time() + clock_cmos_diff; + restore_flags(flags); + } } -static void suspend(void) +static void get_time_diff(void) { +#ifndef CONFIG_APM_RTC_IS_GMT unsigned long flags; - int err; -#ifndef CONFIG_APM_RTC_IS_GMT /* * Estimate time zone so that set_time can update the clock */ @@ -789,7 +708,14 @@ got_clock_diff = 1; restore_flags(flags); #endif +} + +static void suspend(void) +{ + unsigned long flags; + int err; + get_time_diff(); err = apm_set_power_state(APM_STATE_SUSPEND); if (err) apm_error("suspend", err); @@ -812,9 +738,11 @@ { int err; + get_time_diff(); err = apm_set_power_state(APM_STATE_STANDBY); if (err) apm_error("standby", err); + set_time(); /* should not be necessary ... */ } static apm_event_t get_event(void) @@ -864,14 +792,14 @@ #endif while ((event = get_event()) != 0) { -#ifdef APM_DEBUG - if (event <= NR_APM_EVENT_NAME) - printk(KERN_DEBUG "apm: received %s notify\n", - apm_event_name[event - 1]); - else - printk(KERN_DEBUG "apm: received unknown " - "event 0x%02x\n", event); -#endif + if (debug) { + if (event <= NR_APM_EVENT_NAME) + printk(KERN_DEBUG "apm: received %s notify\n", + apm_event_name[event - 1]); + else + printk(KERN_DEBUG "apm: received unknown " + "event 0x%02x\n", event); + } #ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE if (ignore_bounce && ((jiffies - last_resume) > BOUNCE_INTERVAL)) @@ -1277,6 +1205,8 @@ str += 3; if (strncmp(str, "debug", 5) == 0) debug = !invert; + if (strncmp(str, "power-off", 9) == 0) + power_off_enabled = !invert; if (strncmp(str, "smp-power-off", 13) == 0) smp_hack = !invert; str = strchr(str, ','); @@ -1285,6 +1215,27 @@ } } +static struct file_operations apm_bios_fops = { + NULL, /* lseek */ + do_read, + NULL, /* write */ + NULL, /* readdir */ + do_poll, + do_ioctl, + NULL, /* mmap */ + do_open, + NULL, /* flush */ + do_release, + NULL, /* fsync */ + NULL /* fasync */ +}; + +static struct miscdevice apm_device = { + APM_MINOR_DEV, + "apm", + &apm_bios_fops +}; + void __init apm_bios_init(void) { unsigned short bx; @@ -1378,14 +1329,6 @@ (apm_bios_info.dseg_len - 1) & 0xffff); } #endif -#ifdef CONFIG_SMP - if (smp_num_cpus > 1) { - printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n"); - if (smp_hack) - smp_hack = 2; - return; - } -#endif if (apm_bios_info.version > 0x100) { /* * We only support BIOSs up to version 1.2 @@ -1459,6 +1402,14 @@ if (apm_engage_power_management(0x0001) == APM_SUCCESS) apm_bios_info.flags &= ~APM_BIOS_DISENGAGED; } +#ifdef CONFIG_SMP + if (smp_num_cpus > 1) { + printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n"); + if (smp_hack) + smp_hack = 2; + return; + } +#endif init_timer(&apm_timer); apm_timer.function = do_apm_timer; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/init_task.c linux.ac/arch/i386/kernel/init_task.c --- linux.vanilla/arch/i386/kernel/init_task.c Sun Nov 8 15:08:22 1998 +++ linux.ac/arch/i386/kernel/init_task.c Fri Jun 4 23:52:47 1999 @@ -7,7 +7,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/process.c linux.ac/arch/i386/kernel/process.c --- linux.vanilla/arch/i386/kernel/process.c Thu May 27 22:11:49 1999 +++ linux.ac/arch/i386/kernel/process.c Mon Jun 7 00:10:10 1999 @@ -31,7 +31,7 @@ #include #include #include -#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF) +#if defined(CONFIG_APM) #include #endif @@ -52,11 +52,6 @@ asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); -#ifdef CONFIG_APM -extern int apm_do_idle(void); -extern void apm_do_busy(void); -#endif - static int hlt_counter=0; #define HARD_IDLE_TIMEOUT (HZ / 3) @@ -386,8 +381,8 @@ void machine_power_off(void) { -#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF) - apm_power_off(); +#if defined(CONFIG_APM) + apm_power_off(0); #endif } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/vmlinux.lds linux.ac/arch/i386/vmlinux.lds --- linux.vanilla/arch/i386/vmlinux.lds Mon Dec 28 23:09:40 1998 +++ linux.ac/arch/i386/vmlinux.lds Tue Jun 15 17:43:40 1999 @@ -1,12 +1,12 @@ /* ld script to make i386 Linux kernel - * Written by Martin Mares + * Written by Martin Mares ; */ OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) ENTRY(_start) SECTIONS { - . = 0xC0000000 + 0x100000; + . = 0xC0000000 + 0x100000; _text = .; /* Text and read-only data */ .text : { *(.text) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/vmlinux.lds.S linux.ac/arch/i386/vmlinux.lds.S --- linux.vanilla/arch/i386/vmlinux.lds.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/i386/vmlinux.lds.S Sun Jun 6 02:44:33 1999 @@ -0,0 +1,69 @@ +/* ld script to make i386 Linux kernel + * Written by Martin Mares ; + */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) +SECTIONS +{ + . = PAGE_OFFSET_RAW + 0x100000; + _text = .; /* Text and read-only data */ + .text : { + *(.text) + *(.fixup) + *(.gnu.warning) + } = 0x9090 + .text.lock : { *(.text.lock) } /* out-of-line lock text */ + .rodata : { *(.rodata) } + .kstrtab : { *(.kstrtab) } + + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + __ksymtab : { *(__ksymtab) } + __stop___ksymtab = .; + + _etext = .; /* End of text section */ + + .data : { /* Data */ + *(.data) + CONSTRUCTORS + } + + _edata = .; /* End of data section */ + + . = ALIGN(8192); /* init_task */ + .data.init_task : { *(.data.init_task) } + + . = ALIGN(4096); /* Init code and data */ + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(4096); + __init_end = .; + + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + + . = ALIGN(4096); + .data.page_aligned : { *(.data.idt) } + + + __bss_start = .; /* BSS */ + .bss : { + *(.bss) + } + _end = . ; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/m68k/kernel/process.c linux.ac/arch/m68k/kernel/process.c --- linux.vanilla/arch/m68k/kernel/process.c Thu May 27 22:11:49 1999 +++ linux.ac/arch/m68k/kernel/process.c Mon Jun 7 00:10:10 1999 @@ -40,7 +40,6 @@ */ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; @@ -87,9 +86,6 @@ void machine_power_off(void) { -#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF) - apm_set_power_state(APM_STATE_OFF); -#endif } void show_regs(struct pt_regs * regs) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/jazz/int-handler.S linux.ac/arch/mips/jazz/int-handler.S --- linux.vanilla/arch/mips/jazz/int-handler.S Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/jazz/int-handler.S Fri Jun 4 23:52:50 1999 @@ -144,7 +144,7 @@ /* * Hmm... This is not just a plain PC clone so the question is * which devices on Jazz machines can generate an (E)ISA NMI? - * (Writing to nonexistant memory?) + * (Writing to nonexistent memory?) */ ll_isa_nmi: li s1,~IE_IRQ3 PANIC("Unimplemented isa_nmi handler") @@ -152,7 +152,7 @@ /* * Timer IRQ - remapped to be more similar to an IBM compatible. * - * The timer interrupt is handled specially to insure that the jiffies + * The timer interrupt is handled specially to ensure that the jiffies * variable is updated at all times. Specifically, the timer interrupt is * just like the complete handlers except that it is invoked with interrupts * disabled and should never re-enable them. If other interrupts were diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/Makefile linux.ac/arch/mips/kernel/Makefile --- linux.vanilla/arch/mips/kernel/Makefile Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/Makefile Fri Jun 4 23:52:50 1999 @@ -23,7 +23,7 @@ endif # -# SGI's have very different interrupt/timer hardware. +# SGIs have very different interrupt/timer hardware. # ifndef CONFIG_SGI O_OBJS += irq.o time.o diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/fpe.c linux.ac/arch/mips/kernel/fpe.c --- linux.vanilla/arch/mips/kernel/fpe.c Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/kernel/fpe.c Fri Jun 4 23:52:50 1999 @@ -39,7 +39,7 @@ /* * For easier experimentation we never increment/decrement - * the module useable counter. + * the module usable counter. */ int register_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31)); int unregister_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31)); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/gdb-stub.c linux.ac/arch/mips/kernel/gdb-stub.c --- linux.vanilla/arch/mips/kernel/gdb-stub.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/gdb-stub.c Fri Jun 4 23:52:50 1999 @@ -326,7 +326,7 @@ { 7, SIGBUS }, /* data bus error */ { 9, SIGTRAP }, /* break */ { 10, SIGILL }, /* reserved instruction */ -/* { 11, SIGILL }, */ /* cpu unusable */ +/* { 11, SIGILL }, */ /* CPU unusable */ { 12, SIGFPE }, /* overflow */ { 13, SIGTRAP }, /* trap */ { 14, SIGSEGV }, /* virtual instruction cache coherency */ @@ -379,7 +379,7 @@ } /* - * Convert the MIPS hardware trap type code to a unix signal number. + * Convert the MIPS hardware trap type code to a Unix signal number. */ static int computeSignal(int tt) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/init_task.c linux.ac/arch/mips/kernel/init_task.c --- linux.vanilla/arch/mips/kernel/init_task.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/init_task.c Fri Jun 4 23:52:50 1999 @@ -6,7 +6,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct files * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/irixioctl.c linux.ac/arch/mips/kernel/irixioctl.c --- linux.vanilla/arch/mips/kernel/irixioctl.c Thu May 27 22:11:50 1999 +++ linux.ac/arch/mips/kernel/irixioctl.c Fri Jun 4 23:52:50 1999 @@ -33,15 +33,13 @@ { struct file *filp; - file = fcheck(fd); - if(!file) + if(fd >= current->files->max_fds || !(filp = current->files->fd[fd])) return ((struct tty_struct *) 0); if(filp->private_data) { struct tty_struct *ttyp = (struct tty_struct *) filp->private_data; - if(ttyp->magic == TTY_MAGIC) { + if(ttyp->magic == TTY_MAGIC) return ttyp; - } } return ((struct tty_struct *) 0); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/pci.c linux.ac/arch/mips/kernel/pci.c --- linux.vanilla/arch/mips/kernel/pci.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/pci.c Fri Jun 4 23:52:50 1999 @@ -36,7 +36,7 @@ } /* - * The functions below are machine specific and must be reimplented for + * The functions below are machine specific and must be reimplimented for * each PCI chipset configuration. We just run the hook to the machine * specific implementation. */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/r2300_fpu.S linux.ac/arch/mips/kernel/r2300_fpu.S --- linux.vanilla/arch/mips/kernel/r2300_fpu.S Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/r2300_fpu.S Fri Jun 4 23:52:50 1999 @@ -77,11 +77,11 @@ END(r2300_save_fp_context) /* - * Restore fpu state: + * Restore FPU state: * - fp gp registers * - cp1 status/control register * - * We base the decission which registers to restore from the signal stack + * We base the decision which registers to restore from the signal stack * frame on the current content of c0_status, not on the content of the * stack frame which might have been changed by the user. */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/r2300_misc.S linux.ac/arch/mips/kernel/r2300_misc.S --- linux.vanilla/arch/mips/kernel/r2300_misc.S Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/r2300_misc.S Fri Jun 4 23:52:50 1999 @@ -3,7 +3,7 @@ * * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse * - * Multi-cpu abstraction reworking: + * Multi-CPU abstraction reworking: * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) */ #include @@ -68,7 +68,7 @@ * (No, it's the assembler way to do * k0 = k0 / PAGE_SIZE; * k0 = k0 * sizeof(pte_t) - * Acutally the R4xx0 code will have to change when + * Actually the R4xx0 code will have to change when * switching to 64 bit ... -- Ralf) */ srl k0,12 # get PFN? @@ -131,7 +131,7 @@ * There are two possible causes for an invalid (tlbl) * exception: * 1) pages with present bit set but the valid bit clear - * 2) nonexistant pages + * 2) nonexistent pages * Case one needs fast handling, therefore don't save * registers yet. * @@ -165,7 +165,7 @@ * (No, it's the assembler way to do * k0 = k0 / PAGE_SIZE; * k0 = k0 * sizeof(pte_t) - * Acutally the R4xx0 code will have to change when + * Actually the R4xx0 code will have to change when * switching to 64 bit ... -- Ralf) */ srl k0,12 @@ -252,7 +252,7 @@ * R[23]000? PMA * (The ori/xori combination actually _clears_ bit 2. * This is required for the R4xx0 these CPUs always - * map page pairs; a page pair of 4k pages therfore + * map page pairs; a page pair of 4k pages therefore * has always an address with bit 2 set to zero. -- Ralf) */ ori k0,0x0004 @@ -374,7 +374,7 @@ * R[23]000? PMA * (The ori/xori combination actually _clears_ bit 2. * This is required for the R4xx0 these CPUs always - * map page pairs; a page pair of 4k pages therfore + * map page pairs; a page pair of 4k pages therefore * has always an address with bit 2 set to zero. -- Ralf) */ ori k0,0x0004 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/r4k_fpu.S linux.ac/arch/mips/kernel/r4k_fpu.S --- linux.vanilla/arch/mips/kernel/r4k_fpu.S Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/r4k_fpu.S Fri Jun 4 23:52:50 1999 @@ -79,11 +79,11 @@ END(r4k_save_fp_context) /* - * Restore fpu state: + * Restore FPU state: * - fp gp registers * - cp1 status/control register * - * We base the decission which registers to restore from the signal stack + * We base the decision which registers to restore from the signal stack * frame on the current content of c0_status, not on the content of the * stack frame which might have been changed by the user. */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/r4k_switch.S linux.ac/arch/mips/kernel/r4k_switch.S --- linux.vanilla/arch/mips/kernel/r4k_switch.S Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/kernel/r4k_switch.S Fri Jun 4 23:52:50 1999 @@ -104,8 +104,8 @@ /* * Load the FPU with signalling NANS. This bit pattern we're using has - * the property that no matter wether considered as single or as double - * precission represents signaling NANS. + * the property that no matter whether considered as single or as double + * precision represents signaling NANS. * * We initialize fcr31 to rounding to nearest, no exceptions. */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/r6000_fpu.S linux.ac/arch/mips/kernel/r6000_fpu.S --- linux.vanilla/arch/mips/kernel/r6000_fpu.S Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/r6000_fpu.S Fri Jun 4 23:52:50 1999 @@ -50,11 +50,11 @@ nop END(r6000_save_fp_context) -/* Restore fpu state: +/* Restore FPU state: * - fp gp registers * - cp1 status/control register * - * We base the decission which registers to restore from the signal stack + * We base the decision which registers to restore from the signal stack * frame on the current content of c0_status, not on the content of the * stack frame which might have been changed by the user. */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/setup.c linux.ac/arch/mips/kernel/setup.c --- linux.vanilla/arch/mips/kernel/setup.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/setup.c Fri Jun 4 23:52:50 1999 @@ -95,7 +95,7 @@ /* * Setup information * - * These are intialized so they are in the .data section + * These are initialized so they are in the .data section */ unsigned long mips_memory_upper = KSEG0; /* this is set by kernel_entry() */ unsigned long mips_cputype = CPU_UNKNOWN; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/traps.c linux.ac/arch/mips/kernel/traps.c --- linux.vanilla/arch/mips/kernel/traps.c Wed Jan 6 23:02:18 1999 +++ linux.ac/arch/mips/kernel/traps.c Fri Jun 4 23:52:50 1999 @@ -325,7 +325,7 @@ /* * (A short test says that IRIX 5.3 sends SIGTRAP for all break * insns, even for break codes that indicate arithmetic failures. - * Wiered ...) + * Weird ...) */ force_sig(SIGTRAP, current); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/unaligned.c linux.ac/arch/mips/kernel/unaligned.c --- linux.vanilla/arch/mips/kernel/unaligned.c Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/kernel/unaligned.c Fri Jun 4 23:52:50 1999 @@ -17,7 +17,7 @@ * Putting data to unaligned addresses is a bad practice even on Intel where * only the performance is affected. Much worse is that such code is non- * portable. Due to several programs that die on MIPS due to alignment - * problems I decieded to implement this handler anyway though I originally + * problems I decided to implement this handler anyway though I originally * didn't intend to do this at all for user code. * * For now I enable fixing of address errors by default to make life easier. @@ -140,7 +140,7 @@ goto sigbus; /* - * The remaining opcodes are the ones that are really of interrest. + * The remaining opcodes are the ones that are really of interest. */ case lh_op: check_axs(pc, addr, 2); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/lib/tags.c linux.ac/arch/mips/lib/tags.c --- linux.vanilla/arch/mips/lib/tags.c Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/lib/tags.c Fri Jun 4 23:52:50 1999 @@ -34,7 +34,7 @@ /* * Snarf from the tag list in memory end some tags needed - * before the kernel reachs setup_arch() + * before the kernel reaches setup_arch() * * add yours here if you want to, but *beware*: the kernel var * that will hold the values you want to snarf have to be diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/lib/watch.S linux.ac/arch/mips/lib/watch.S --- linux.vanilla/arch/mips/lib/watch.S Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/lib/watch.S Fri Jun 4 23:52:50 1999 @@ -1,6 +1,6 @@ /* * Kernel debug stuff to use the Watch registers. - * Usefull to find stack overflows, dangeling pointers etc. + * Useful to find stack overflows, dangling pointers etc. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/mm/init.c linux.ac/arch/mips/mm/init.c --- linux.vanilla/arch/mips/mm/init.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/mm/init.c Fri Jun 4 23:52:49 1999 @@ -392,7 +392,7 @@ for (tmp = PAGE_OFFSET; tmp < end_mem; tmp += PAGE_SIZE) { /* * This is only for PC-style DMA. The onboard DMA - * of Jazz and Tyne machines is completly different and + * of Jazz and Tyne machines is completely different and * not handled via a flag in mem_map_t. */ if (tmp >= MAX_DMA_ADDRESS) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/amiga/amiints.c linux.ac/arch/ppc/amiga/amiints.c --- linux.vanilla/arch/ppc/amiga/amiints.c Sat Jan 9 21:50:36 1999 +++ linux.ac/arch/ppc/amiga/amiints.c Fri Jun 4 23:52:51 1999 @@ -108,7 +108,7 @@ custom.intreq = 0x7fff; #ifdef CONFIG_APUS - /* Clear any inter-CPU interupt requests. Circumvents bug in + /* Clear any inter-CPU interrupt requests. Circumvents bug in Blizzard IPL emulation HW (or so it appears). */ APUS_WRITE(APUS_INT_LVL, INTLVL_SETRESET | INTLVL_MASK); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/syscalls.c linux.ac/arch/ppc/kernel/syscalls.c --- linux.vanilla/arch/ppc/kernel/syscalls.c Tue Jun 15 16:49:47 1999 +++ linux.ac/arch/ppc/kernel/syscalls.c Sat Jun 12 20:10:42 1999 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/kernel/init_task.c linux.ac/arch/sparc/kernel/init_task.c --- linux.vanilla/arch/sparc/kernel/init_task.c Sun Nov 8 15:10:06 1998 +++ linux.ac/arch/sparc/kernel/init_task.c Fri Jun 4 23:52:48 1999 @@ -6,7 +6,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/config.in linux.ac/arch/sparc64/config.in --- linux.vanilla/arch/sparc64/config.in Wed Apr 28 19:14:25 1999 +++ linux.ac/arch/sparc64/config.in Mon Jun 14 13:48:03 1999 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.66 1999/03/29 05:08:42 davem Exp $ +# $Id: config.in,v 1.67 1999/05/01 09:17:37 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -235,6 +235,16 @@ 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 +fi +endmenu + +mainmenu_option next_comment +comment 'Video For Linux' +tristate 'Video For Linux' CONFIG_VIDEO_DEV +if [ "$CONFIG_VIDEO_DEV" != "n" ]; then + if [ "$CONFIG_PCI" != "n" ]; then + dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV + fi fi endmenu diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/defconfig linux.ac/arch/sparc64/defconfig --- linux.vanilla/arch/sparc64/defconfig Tue Jun 15 16:49:47 1999 +++ linux.ac/arch/sparc64/defconfig Mon Jun 14 13:48:03 1999 @@ -257,6 +257,12 @@ CONFIG_UNIX98_PTY_COUNT=256 # +# Video For Linux +# +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_BT848=y + +# # Filesystems # # CONFIG_QUOTA is not set diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/binfmt_aout32.c linux.ac/arch/sparc64/kernel/binfmt_aout32.c --- linux.vanilla/arch/sparc64/kernel/binfmt_aout32.c Wed Mar 24 10:55:13 1999 +++ linux.ac/arch/sparc64/kernel/binfmt_aout32.c Fri Jun 4 23:52:52 1999 @@ -57,8 +57,19 @@ * These are the only things you should do on a core-file: use only these * macros to write out all the necessary info. */ -#define DUMP_WRITE(addr,nr) \ -while (file->f_op->write(file,(char *)(addr),(nr),&file->f_pos) != (nr)) goto close_coredump + +static int dump_write(struct file *file, const void *addr, int nr) +{ + int r; + down(&file->f_dentry->d_inode->i_sem); + r = file->f_op->write(file, addr, nr, &file->f_pos) == nr; + up(&file->f_dentry->d_inode->i_sem); + return r; +} + +#define DUMP_WRITE(addr, nr) \ + if (!dump_write(file, (void *)(addr), (nr))) \ + goto close_coredump; #define DUMP_SEEK(offset) \ if (file->f_op->llseek) { \ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/init_task.c linux.ac/arch/sparc64/kernel/init_task.c --- linux.vanilla/arch/sparc64/kernel/init_task.c Sun Nov 8 15:08:40 1998 +++ linux.ac/arch/sparc64/kernel/init_task.c Fri Jun 4 23:52:52 1999 @@ -6,7 +6,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/Config.in linux.ac/drivers/char/Config.in --- linux.vanilla/drivers/char/Config.in Thu May 27 22:11:53 1999 +++ linux.ac/drivers/char/Config.in Fri Jun 4 23:52:40 1999 @@ -174,6 +174,8 @@ tristate 'Double Talk PC internal speech card support' CONFIG_DTLK +tristate 'Mappable DMA driver for 3D graphics cards' CONFIG_DMARAM + mainmenu_option next_comment comment 'Ftape, the floppy tape device driver' tristate 'Ftape (QIC-80/Travan) support' CONFIG_FTAPE diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/Makefile linux.ac/drivers/char/Makefile --- linux.vanilla/drivers/char/Makefile Thu May 27 22:11:53 1999 +++ linux.ac/drivers/char/Makefile Tue Jun 8 00:02:21 1999 @@ -278,6 +278,14 @@ endif endif +ifeq ($(CONFIG_DMARAM),y) +L_OBJS += dmaram.o +else + ifeq ($(CONFIG_DMARAM),m) + M_OBJS += dmaram.o + endif +endif + ifeq ($(CONFIG_RTC),y) L_OBJS += rtc.o endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/bttv.c linux.ac/drivers/char/bttv.c --- linux.vanilla/drivers/char/bttv.c Tue Jun 15 16:49:48 1999 +++ linux.ac/drivers/char/bttv.c Mon Jun 14 13:48:04 1999 @@ -81,8 +81,8 @@ #include "bttv.h" #include "tuner.h" -#define DEBUG(x) /* Debug driver */ -#define IDEBUG(x) /* Debug interrupt handler */ +#define DEBUG(x) /* Debug driver */ +#define IDEBUG(x) /* Debug interrupt handler */ #if LINUX_VERSION_CODE >= 0x020117 MODULE_PARM(vidmem,"i"); @@ -110,7 +110,7 @@ #define CARD_DEFAULT 0 #endif -static unsigned int remap[BTTV_MAX]; /* remap Bt848 */ +static unsigned long remap[BTTV_MAX]; /* remap Bt848 */ static unsigned int radio[BTTV_MAX]; static unsigned int card[BTTV_MAX] = { CARD_DEFAULT, CARD_DEFAULT, CARD_DEFAULT, CARD_DEFAULT }; @@ -129,51 +129,80 @@ #define EEPROM_WRITE_DELAY 20000 #define BURSTOFFSET 76 - - /*******************************/ /* Memory management functions */ /*******************************/ -/* convert virtual user memory address to physical address */ -/* (virt_to_phys only works for kmalloced kernel memory) */ +#define MDEBUG(x) do { } while(0) /* Debug memory management */ + +/* [DaveM] I've recoded most of this so that: + * 1) It's easier to tell what is happening + * 2) It's more portable, especially for translating things + * out of vmalloc mapped areas in the kernel. + * 3) Less unnecessary translations happen. + * + * The code used to assume that the kernel vmalloc mappings + * existed in the page tables of every process, this is simply + * not guarenteed. We now use pgd_offset_k which is the + * defined way to get at the kernel page tables. + */ -static inline unsigned long uvirt_to_phys(unsigned long adr) +/* Given PGD from the address space's page table, return the kernel + * virtual mapping of the physical memory mapped at ADR. + */ +static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) { - pgd_t *pgd; + unsigned long ret = 0UL; pmd_t *pmd; pte_t *ptep, pte; - pgd = pgd_offset(current->mm, adr); - if (pgd_none(*pgd)) - return 0; - pmd = pmd_offset(pgd, adr); - if (pmd_none(*pmd)) - return 0; - ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/); - pte = *ptep; - if(pte_present(pte)) - return - virt_to_phys((void *)(pte_page(pte)|(adr&(PAGE_SIZE-1)))); - return 0; + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, adr); + if (!pmd_none(*pmd)) { + ptep = pte_offset(pmd, adr); + pte = *ptep; + if(pte_present(pte)) + ret = (pte_page(pte)|(adr&(PAGE_SIZE-1))); + } + } + MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret)); + return ret; } static inline unsigned long uvirt_to_bus(unsigned long adr) { - return virt_to_bus(phys_to_virt(uvirt_to_phys(adr))); -} + unsigned long kva, ret; -/* convert virtual kernel memory address to physical address */ -/* (virt_to_phys only works for kmalloced kernel memory) */ + kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); + return ret; +} -static inline unsigned long kvirt_to_phys(unsigned long adr) +static inline unsigned long kvirt_to_bus(unsigned long adr) { - return uvirt_to_phys(VMALLOC_VMADDR(adr)); + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); + return ret; } -static inline unsigned long kvirt_to_bus(unsigned long adr) +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) { - return uvirt_to_bus(VMALLOC_VMADDR(adr)); + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = __pa(kva); + MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); + return ret; } static void * rvmalloc(unsigned long size) @@ -188,8 +217,8 @@ adr=(unsigned long) mem; while (size > 0) { - page = kvirt_to_phys(adr); - mem_map_reserve(MAP_NR(phys_to_virt(page))); + page = kvirt_to_pa(adr); + mem_map_reserve(MAP_NR(__va(page))); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -206,8 +235,8 @@ adr=(unsigned long) mem; while (size > 0) { - page = kvirt_to_phys(adr); - mem_map_unreserve(MAP_NR(phys_to_virt(page))); + page = kvirt_to_pa(adr); + mem_map_unreserve(MAP_NR(__va(page))); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -823,30 +852,30 @@ unsigned int *po=(unsigned int *) btv->vbi_odd; unsigned int *pe=(unsigned int *) btv->vbi_even; - DEBUG(printk(KERN_DEBUG "vbiodd: 0x%08x\n",(int)btv->vbi_odd)); - DEBUG(printk(KERN_DEBUG "vbievn: 0x%08x\n",(int)btv->vbi_even)); - DEBUG(printk(KERN_DEBUG "po: 0x%08x\n",(int)po)); - DEBUG(printk(KERN_DEBUG "pe: 0x%08x\n",(int)pe)); + DEBUG(printk(KERN_DEBUG "vbiodd: 0x%lx\n",(long)btv->vbi_odd)); + DEBUG(printk(KERN_DEBUG "vbievn: 0x%lx\n",(long)btv->vbi_even)); + DEBUG(printk(KERN_DEBUG "po: 0x%lx\n",(long)po)); + DEBUG(printk(KERN_DEBUG "pe: 0x%lx\n",(long)pe)); - *(po++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(po++)=0; + *(po++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(po++)=0; for (i=0; i<16; i++) { - *(po++)=VBI_RISC; - *(po++)=kvirt_to_bus((unsigned long)btv->vbibuf+i*2048); + *(po++)=cpu_to_le32(VBI_RISC); + *(po++)=cpu_to_le32(kvirt_to_bus((unsigned long)btv->vbibuf+i*2048)); } - *(po++)=BT848_RISC_JUMP; - *(po++)=virt_to_bus(btv->risc_jmp+4); + *(po++)=cpu_to_le32(BT848_RISC_JUMP); + *(po++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+4)); - *(pe++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(pe++)=0; + *(pe++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(pe++)=0; for (i=16; i<32; i++) { - *(pe++)=VBI_RISC; - *(pe++)=kvirt_to_bus((unsigned long)btv->vbibuf+i*2048); + *(pe++)=cpu_to_le32(VBI_RISC); + *(pe++)=cpu_to_le32(kvirt_to_bus((unsigned long)btv->vbibuf+i*2048)); } - *(pe++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16); - *(pe++)=virt_to_bus(btv->risc_jmp+10); - DEBUG(printk(KERN_DEBUG "po: 0x%08x\n",(int)po)); - DEBUG(printk(KERN_DEBUG "pe: 0x%08x\n",(int)pe)); + *(pe++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16)); + *(pe++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+10)); + DEBUG(printk(KERN_DEBUG "po: 0x%lx\n",(long)po)); + DEBUG(printk(KERN_DEBUG "pe: 0x%lx\n",(long)pe)); } int fmtbppx2[16] = { @@ -881,8 +910,8 @@ unsigned long bpl=1024; /* bytes per line */ unsigned long vadr=(unsigned long) vbuf; - *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0; - *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0; + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=0; + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=0; /* In PAL 650 blocks of 256 DWORDs are sampled, but only if VDELAY is 2 and without separate VBI grabbing. @@ -890,17 +919,17 @@ for (line=0; line < 640; line++) { - *(ro++)=BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL; - *(ro++)=kvirt_to_bus(vadr); - *(re++)=BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL; - *(re++)=kvirt_to_bus(vadr+BTTV_MAX_FBUF/2); + *(ro++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL); + *(ro++)=cpu_to_le32(kvirt_to_bus(vadr)); + *(re++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL); + *(re++)=cpu_to_le32(kvirt_to_bus(vadr+BTTV_MAX_FBUF/2)); vadr+=bpl; } - *(ro++)=BT848_RISC_JUMP; - *(ro++)=btv->bus_vbi_even; - *(re++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16); - *(re++)=btv->bus_vbi_odd; + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); + *(re++)=cpu_to_le32(btv->bus_vbi_odd); return 0; } @@ -954,8 +983,8 @@ cradr=cbadr+csize; inter = (height>btv->win.cropheight/2) ? 1 : 0; - *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3; *(ro++)=0; - *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3; *(re++)=0; + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); *(ro++)=0; + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); *(re++)=0; for (line=0; line < (height<<(1^inter)); line++) { @@ -991,15 +1020,15 @@ todo-=bl; if(!todo) rcmd|=BT848_RISC_EOL; /* if this is the last EOL */ - *((*rp)++)=rcmd|bl; - *((*rp)++)=blcb|(blcr<<16); - *((*rp)++)=kvirt_to_bus(vadr); + *((*rp)++)=cpu_to_le32(rcmd|bl); + *((*rp)++)=cpu_to_le32(blcb|(blcr<<16)); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); vadr+=bl; if((rcmd&(15<<28))==BT848_RISC_WRITE123) { - *((*rp)++)=kvirt_to_bus(cbadr); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(cbadr)); cbadr+=blcb; - *((*rp)++)=kvirt_to_bus(cradr); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(cradr)); cradr+=blcr; } @@ -1007,10 +1036,10 @@ } } - *(ro++)=BT848_RISC_JUMP; - *(ro++)=btv->bus_vbi_even; - *(re++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16); - *(re++)=btv->bus_vbi_odd; + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); + *(re++)=cpu_to_le32(btv->bus_vbi_odd); return 0; } @@ -1037,8 +1066,8 @@ inter = (height>btv->win.cropheight/2) ? 1 : 0; bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2; - *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0; - *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0; + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=0; + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=0; for (line=0; line < (height<<(1^inter)); line++) { @@ -1050,35 +1079,35 @@ bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr); if (bpl<=bl) { - *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_SOL| - BT848_RISC_EOL|bpl; - *((*rp)++)=kvirt_to_bus(vadr); + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| + BT848_RISC_EOL|bpl); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); vadr+=bpl; } else { todo=bpl; - *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_SOL|bl; - *((*rp)++)=kvirt_to_bus(vadr); + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|bl); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); vadr+=bl; todo-=bl; while (todo>PAGE_SIZE) { - *((*rp)++)=BT848_RISC_WRITE|PAGE_SIZE; - *((*rp)++)=kvirt_to_bus(vadr); + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|PAGE_SIZE); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); vadr+=PAGE_SIZE; todo-=PAGE_SIZE; } - *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_EOL|todo; - *((*rp)++)=kvirt_to_bus(vadr); + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|todo); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); vadr+=todo; } } - *(ro++)=BT848_RISC_JUMP; - *(ro++)=btv->bus_vbi_even; - *(re++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16); - *(re++)=btv->bus_vbi_odd; + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); + *(re++)=cpu_to_le32(btv->bus_vbi_odd); return 0; } @@ -1162,10 +1191,10 @@ adr=btv->win.vidadr+btv->win.x*bpp+btv->win.y*bpl; if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) { /* can't clip, don't generate any risc code */ - *(ro++)=BT848_RISC_JUMP; - *(ro++)=btv->bus_vbi_even; - *(re++)=BT848_RISC_JUMP; - *(re++)=btv->bus_vbi_odd; + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP); + *(re++)=cpu_to_le32(btv->bus_vbi_odd); } if (ncr < 0) { /* bitmap was pased */ memcpy(clipmap, (unsigned char *)cr, VIDEO_CLIPMAP_SIZE); @@ -1187,8 +1216,8 @@ if (btv->win.y<0) clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y)); - *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0; - *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0; + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=0; + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=0; /* translate bitmap to risc code */ for (line=outofmem=0; line < (height<bus_vbi_even; - *(re++)=BT848_RISC_JUMP; - *(re++)=btv->bus_vbi_odd; + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP); + *(re++)=cpu_to_le32(btv->bus_vbi_odd); } /* set geometry for even/odd frames @@ -1297,6 +1326,23 @@ set_pll(btv); btwrite(fmt, BT848_COLOR_FMT); +#ifdef __sparc__ + if(fmt == BT848_COLOR_FMT_RGB32 || + fmt == BT848_COLOR_FMT_RGB24) { + btwrite((BT848_COLOR_CTL_GAMMA | + BT848_COLOR_CTL_WSWAP_ODD | + BT848_COLOR_CTL_WSWAP_EVEN | + BT848_COLOR_CTL_BSWAP_ODD | + BT848_COLOR_CTL_BSWAP_EVEN), + BT848_COLOR_CTL); + } else if(fmt == BT848_COLOR_FMT_RGB16 || + fmt == BT848_COLOR_FMT_RGB15) { + btwrite((BT848_COLOR_CTL_GAMMA | + BT848_COLOR_CTL_BSWAP_ODD | + BT848_COLOR_CTL_BSWAP_EVEN), + BT848_COLOR_CTL); + } +#endif hactive=width; vtc=0; @@ -1474,7 +1520,7 @@ btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI); btor(BT848_VSCALE_COMB, BT848_O_VSCALE_HI); } - btv->risc_jmp[12]=BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ; + btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); } btor(3, BT848_CAP_CTL); btor(3, BT848_GPIO_DMA_CTL); @@ -2268,7 +2314,7 @@ pos=(unsigned long) btv->fbuffer; while (size > 0) { - page = kvirt_to_phys(pos); + page = kvirt_to_pa(pos); if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) return -EAGAIN; start+=PAGE_SIZE; @@ -3110,44 +3156,44 @@ int flags=btv->cap; /* Sync to start of odd field */ - btv->risc_jmp[0]=BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRE; + btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRE); btv->risc_jmp[1]=0; /* Jump to odd vbi sub */ - btv->risc_jmp[2]=BT848_RISC_JUMP|(0x5<<20); + btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0x5<<20)); if (flags&8) - btv->risc_jmp[3]=virt_to_bus(btv->vbi_odd); + btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->vbi_odd)); else - btv->risc_jmp[3]=virt_to_bus(btv->risc_jmp+4); + btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->risc_jmp+4)); /* Jump to odd sub */ - btv->risc_jmp[4]=BT848_RISC_JUMP|(0x6<<20); + btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0x6<<20)); if (flags&2) - btv->risc_jmp[5]=virt_to_bus(btv->risc_odd); + btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_odd)); else - btv->risc_jmp[5]=virt_to_bus(btv->risc_jmp+6); + btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_jmp+6)); /* Sync to start of even field */ - btv->risc_jmp[6]=BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRO; + btv->risc_jmp[6]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRO); btv->risc_jmp[7]=0; /* Jump to even vbi sub */ - btv->risc_jmp[8]=BT848_RISC_JUMP; + btv->risc_jmp[8]=cpu_to_le32(BT848_RISC_JUMP); if (flags&4) - btv->risc_jmp[9]=virt_to_bus(btv->vbi_even); + btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->vbi_even)); else - btv->risc_jmp[9]=virt_to_bus(btv->risc_jmp+10); + btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->risc_jmp+10)); /* Jump to even sub */ - btv->risc_jmp[10]=BT848_RISC_JUMP|(8<<20); + btv->risc_jmp[10]=cpu_to_le32(BT848_RISC_JUMP|(8<<20)); if (flags&1) - btv->risc_jmp[11]=virt_to_bus(btv->risc_even); + btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_even)); else - btv->risc_jmp[11]=virt_to_bus(btv->risc_jmp+12); + btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_jmp+12)); - btv->risc_jmp[12]=BT848_RISC_JUMP; - btv->risc_jmp[13]=virt_to_bus(btv->risc_jmp); + btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP); + btv->risc_jmp[13]=cpu_to_le32(virt_to_bus(btv->risc_jmp)); /* enable capturing */ btaor(flags, ~0x0f, BT848_CAP_CTL); @@ -3165,7 +3211,7 @@ /* reset the bt848 */ btwrite(0, BT848_SRESET); - DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%08x\n",i,(unsigned int) btv->bt848_mem)); + DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%lx\n",i,(unsigned long) btv->bt848_mem)); /* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */ btv->win.norm=0; /* change this to 1 for NTSC, 2 for SECAM */ @@ -3330,8 +3376,7 @@ if (!astat) return; btwrite(astat,BT848_INT_STAT); - IDEBUG(printk ("bttv%d: astat %08x\n", btv->nr, astat)); - IDEBUG(printk ("bttv%d: stat %08x\n", btv->nr, stat)); + IDEBUG(printk ("bttv%d: astat %08x stat %08x\n", btv->nr, astat, stat)); /* get device status bits */ dstat=btread(BT848_DSTATUS); @@ -3387,8 +3432,8 @@ btv->gro = btv->gro_next; btv->gre = btv->gre_next; btv->grf = btv->grf_next; - btv->risc_jmp[5]=btv->gro; - btv->risc_jmp[11]=btv->gre; + btv->risc_jmp[5]=cpu_to_le32(btv->gro); + btv->risc_jmp[11]=cpu_to_le32(btv->gre); bt848_set_geo(btv, btv->gwidth, btv->gheight, btv->gfmt); @@ -3405,9 +3450,9 @@ } if (stat&(8<<28)) { - btv->risc_jmp[5]=btv->gro; - btv->risc_jmp[11]=btv->gre; - btv->risc_jmp[12]=BT848_RISC_JUMP; + btv->risc_jmp[5]=cpu_to_le32(btv->gro); + btv->risc_jmp[11]=cpu_to_le32(btv->gre); + btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP); bt848_set_geo(btv, btv->gwidth, btv->gheight, btv->gfmt); } @@ -3502,14 +3547,16 @@ if (remap[bttv_num]) { + unsigned int dw = btv->bt848_adr; + if (remap[bttv_num] < 0x1000) remap[bttv_num]<<=20; remap[bttv_num]&=PCI_BASE_ADDRESS_MEM_MASK; - printk(KERN_INFO "bttv%d: remapping to : 0x%08x.\n", + printk(KERN_INFO "bttv%d: remapping to : 0x%lx.\n", bttv_num,remap[bttv_num]); remap[bttv_num]|=btv->bt848_adr&(~PCI_BASE_ADDRESS_MEM_MASK); pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, remap[bttv_num]); - pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &btv->bt848_adr); + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &dw); btv->dev->base_address[0] = btv->bt848_adr; } btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK; @@ -3518,7 +3565,7 @@ bttv_num,btv->id, btv->revision); printk("bus: %d, devfn: %d, ",dev->bus->number, dev->devfn); printk("irq: %d, ",btv->irq); - printk("memory: 0x%08x.\n", btv->bt848_adr); + printk("memory: 0x%lx.\n", btv->bt848_adr); btv->pll.pll_crystal = 0; btv->pll.pll_ifreq = 0; @@ -3542,7 +3589,11 @@ } } +#ifdef __sparc__ + btv->bt848_mem=(unsigned char *)btv->bt848_adr; +#else btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000); +#endif /* clear interrupt mask */ btwrite(0, BT848_INT_MASK); @@ -3817,17 +3868,17 @@ if (btv->risc_even) kfree((void *) btv->risc_even); - DEBUG(printk(KERN_DEBUG "free: risc_jmp: 0x%08x.\n", btv->risc_jmp)); + DEBUG(printk(KERN_DEBUG "free: risc_jmp: 0x%p.\n", btv->risc_jmp)); if (btv->risc_jmp) kfree((void *) btv->risc_jmp); - DEBUG(printk(KERN_DEBUG "bt848_vbibuf: 0x%08x.\n", btv->vbibuf)); + DEBUG(printk(KERN_DEBUG "bt848_vbibuf: 0x%p.\n", btv->vbibuf)); if (btv->vbibuf) vfree((void *) btv->vbibuf); free_irq(btv->irq,btv); - DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%08x.\n", btv->bt848_mem)); + DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%p.\n", btv->bt848_mem)); if (btv->bt848_mem) iounmap(btv->bt848_mem); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/bttv.h linux.ac/drivers/char/bttv.h --- linux.vanilla/drivers/char/bttv.h Tue Jun 15 16:49:48 1999 +++ linux.ac/drivers/char/bttv.h Tue Jun 15 17:45:58 1999 @@ -102,9 +102,9 @@ #else struct pci_dev *dev; #endif - unsigned char irq; /* IRQ used by Bt848 card */ + unsigned int irq; /* IRQ used by Bt848 card */ unsigned char revision; - unsigned int bt848_adr; /* bus address of IO mem returned by PCI BIOS */ + unsigned long bt848_adr; /* bus address of IO mem returned by PCI BIOS */ unsigned char *bt848_mem; /* pointer to mapped IO memory */ unsigned long busriscmem; u32 *riscmem; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/dmaram.c linux.ac/drivers/char/dmaram.c --- linux.vanilla/drivers/char/dmaram.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/char/dmaram.c Fri Jun 4 23:52:41 1999 @@ -0,0 +1,236 @@ +/* + * A simple DMA memory driver for the Linux kernel. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define MAX_DMARAM 32 + +#define DMA_MAJOR 125 + + +struct dmaram +{ + int buffsize; + void *raw_buf; + unsigned long raw_buf_phys; +}; + +struct dmaram *dma_dev[MAX_DMARAM]; + +static int dmaram_create(struct dmaram *dp) +{ + char *start_addr, *end_addr; + int size, sz, i; + if(dp->buffsize < PAGE_SIZE) + dp->buffsize = PAGE_SIZE; + dp->raw_buf = NULL; + start_addr = NULL; + + while (start_addr == NULL && dp->buffsize > PAGE_SIZE) { + for (sz = 0, size = PAGE_SIZE; size < dp->buffsize; sz++, size <<= 1); + { + dp->buffsize = PAGE_SIZE * (1 << sz); + start_addr = (char *) __get_free_pages(GFP_KERNEL, sz); + if (start_addr == NULL) + dp->buffsize /= 2; + } + } + if (start_addr == NULL) { + return -ENOMEM; + } else { + /* make some checks */ + end_addr = start_addr + dp->buffsize - 1; + } + dp->raw_buf = start_addr; + dp->raw_buf_phys = virt_to_bus(start_addr); + + for (i = MAP_NR(start_addr); i < MAP_NR(end_addr); i++) + set_bit(PG_reserved, &mem_map[i].flags);; + return 0; +} + +static void dmaram_destroy(struct dmaram *dp) +{ + int sz, size, i; + unsigned long start_addr, end_addr; + + if (dp->raw_buf == NULL) + return; + for (sz = 0, size = PAGE_SIZE; size < dp->buffsize; sz++, size <<= 1); + + start_addr = (unsigned long) dp->raw_buf; + end_addr = start_addr + dp->buffsize; + + for (i = MAP_NR(start_addr); i < MAP_NR(end_addr); i++) + clear_bit(PG_reserved, &mem_map[i].flags);; + + free_pages((unsigned long) dp->raw_buf, sz); + dp->raw_buf = NULL; +} + + +static int dma_open(struct inode *inode, struct file *file) +{ + void *ram; + int minor = MINOR(inode->i_rdev); + if(minor >= MAX_DMARAM) + return -ENXIO; + + /* + * The allocate may sleep - avoid races + */ + + ram = (struct dmaram *)kmalloc(sizeof(struct dmaram), GFP_KERNEL); + if(ram==NULL) + return -ENOMEM; + + if(dma_dev[minor] != NULL) + { + kfree(ram); + return -EBUSY; + } + + dma_dev[minor]=ram; + MOD_INC_USE_COUNT; + memset(dma_dev[minor], 0, sizeof(struct dmaram)); + return 0; +} + + +static int dma_release(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct dmaram *dp = dma_dev[minor]; + if(dp->raw_buf) + dmaram_destroy(dp); + kfree(dma_dev[minor]); + dma_dev[minor]=NULL; + MOD_DEC_USE_COUNT; + return 0; +} + +static long long dma_lseek(struct file *file, long long offset, int origin) +{ + return -ESPIPE; +} + +static int dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct dmaram *dp = dma_dev[MINOR(inode->i_rdev)]; + switch(cmd) + { + case DMAIOCSET: + { + long size; + if(dp->raw_buf) + return -EBUSY; + if(get_user(size, (long *)arg)) + return -EFAULT; + if(size < PAGE_SIZE || size%PAGE_SIZE) + return -EINVAL; + if(size > 32 * PAGE_SIZE) + size = 32 *PAGE_SIZE; + + dp->buffsize = size; + + return dmaram_create(dp); + } + + case DMAIOCGET: + { + struct dma_info dmi; + dmi.size = dp->buffsize; + dmi.phys = dp->raw_buf_phys; + if(copy_to_user((void *)arg, &dmi, sizeof(dmi))) + return -EFAULT; + return 0; + } + } + return -ENOTTY; +} + + +static int dma_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct dmaram *dp = dma_dev[MINOR(file->f_dentry->d_inode->i_rdev)]; + int size; + + if(dp->raw_buf == NULL) + return -EIO; + size = vma->vm_end - vma->vm_start; + if(size != dp->buffsize) + return -EINVAL; + if(remap_page_range(vma->vm_start, dp->raw_buf_phys, + size, vma->vm_page_prot)) + return -EAGAIN; + return 0; +} + +static ssize_t dma_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static ssize_t dma_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static struct file_operations dma_fops= +{ + dma_lseek, + dma_read, + dma_write, + NULL, /* readdir */ + NULL, + dma_ioctl, + dma_mmap, + dma_open, + NULL, /* flush */ + dma_release +}; + +/* + * Initialise DMAram for Linux + */ + +int dmaram_init(void) +{ + printk(KERN_INFO "Linux DMA memory interface v0.02 (c) 1999 Red Hat Software\n"); + if(register_chrdev(DMA_MAJOR,"dmaram", &dma_fops)) + { + printk("dma_dev: unable to get major %d\n", DMA_MAJOR); + return -EIO; + } + return 0; +} + +#ifdef MODULE +int init_module(void) +{ + return dmaram_init(); +} + +void cleanup_module(void) +{ + unregister_chrdev(DMA_MAJOR, "dmaram"); +} + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/esp.c linux.ac/drivers/char/esp.c --- linux.vanilla/drivers/char/esp.c Sun Nov 8 15:10:12 1998 +++ linux.ac/drivers/char/esp.c Fri Jun 4 23:52:41 1999 @@ -2186,7 +2186,7 @@ if (signal_pending(current)) break; - if (timeout && ((orig_jiffies + timeout) < jiffies)) + if (timeout && time_before(orig_jiffies + timeout, jiffies)) break; serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/keyboard.c linux.ac/drivers/char/keyboard.c --- linux.vanilla/drivers/char/keyboard.c Wed Apr 28 19:14:26 1999 +++ linux.ac/drivers/char/keyboard.c Fri Jun 4 23:52:40 1999 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/mem.c linux.ac/drivers/char/mem.c --- linux.vanilla/drivers/char/mem.c Thu May 27 22:11:53 1999 +++ linux.ac/drivers/char/mem.c Sun Jun 6 01:42:54 1999 @@ -250,11 +250,14 @@ count -= read; } - virtr = vread(buf, (char *)p, count); - if (virtr < 0) - return virtr; - *ppos += p + virtr; - return virtr + read; + if(count) { + if((virtr = vread(buf, (char *)p, count)) < 0) + return virtr; + read += virtr; + } + + *ppos += read; + return read; } /* diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/pc_keyb.c linux.ac/drivers/char/pc_keyb.c --- linux.vanilla/drivers/char/pc_keyb.c Wed Apr 28 19:14:26 1999 +++ linux.ac/drivers/char/pc_keyb.c Fri Jun 4 23:52:41 1999 @@ -38,7 +38,6 @@ #include #include #include -#include /* Some configuration switches are present in the include file... */ @@ -427,6 +426,7 @@ static unsigned char handle_kbd_event(void) { unsigned char status = inb(KBD_STATUS_REG); + unsigned int work = 10000; while (status & KBD_STAT_OBF) { unsigned char scancode; @@ -442,6 +442,13 @@ } status = inb(KBD_STATUS_REG); + + if(!work--) + { + printk(KERN_ERR "pc_keyb: controller jammed (0x%02X).\n", + status); + break; + } } return status; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/sysrq.c linux.ac/drivers/char/sysrq.c --- linux.vanilla/drivers/char/sysrq.c Sun Nov 8 15:07:40 1998 +++ linux.ac/drivers/char/sysrq.c Mon Jun 7 00:10:10 1999 @@ -21,13 +21,12 @@ #include #include #include - -#include - #ifdef CONFIG_APM #include #endif +#include + extern void wakeup_bdflush(int); extern void reset_vc(unsigned int); extern int console_loglevel; @@ -85,7 +84,7 @@ #ifdef CONFIG_APM case 'o': /* O -- power off */ printk("Power off\n"); - apm_power_off(); + apm_power_off(1); break; #endif case 's': /* S -- emergency sync */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/wdt.c linux.ac/drivers/char/wdt.c --- linux.vanilla/drivers/char/wdt.c Tue Jun 15 16:49:48 1999 +++ linux.ac/drivers/char/wdt.c Mon Jun 7 22:24:09 1999 @@ -51,27 +51,44 @@ static int wdt_is_open=0; /* - * You must set these - there is no sane way to probe for this board. - * You can use wdt=x,y to set these now. + * There is no sane way to probe for this board. + * You can use wdt=x,y,n to set these values + * or you can use 'insmod wdt io=x irq=y timeout=n' */ static int io=0x240; static int irq=11; +static int timeout=60; /* seconds */ -#define WD_TIMO (100*60) /* 1 minute */ +#ifdef MODULE + +EXPORT_NO_SYMBOLS; +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O port for Watchdog WDT500/501 board"); +MODULE_PARM(irq, "i"); +MODULE_PARM_DESC(irq, "IRQ for Watchdog WDT500/501 board"); +MODULE_PARM(timeout, "i"); +MODULE_PARM_DESC(timeout, + "Timeout value for Watchdog WDT500/501 board (in seconds)"); + +#endif /* * Setup options */ -__initfunc(void wdt_setup(char *str, int *ints)) +void __init wdt_setup(char *str, int *ints) { if(ints[0]>0) { io=ints[1]; if(ints[0]>1) irq=ints[2]; + if(ints[0]>2) + timeout=ints[3]; } + + timeout *= 100; } /* @@ -168,7 +185,7 @@ /* Write a watchdog value */ inb_p(WDT_DC); wdt_ctr_mode(1,2); - wdt_ctr_load(1,WD_TIMO); /* Timeout */ + wdt_ctr_load(1,timeout); /* Timeout */ outb_p(0, WDT_DC); } @@ -260,7 +277,7 @@ wdt_ctr_mode(1,2); wdt_ctr_mode(2,0); wdt_ctr_load(0, 8948); /* count at 100Hz */ - wdt_ctr_load(1,WD_TIMO); /* Timeout 120 seconds */ + wdt_ctr_load(1,timeout); /* Timeout */ wdt_ctr_load(2,65535); outb_p(0, WDT_DC); /* Enable */ return 0; @@ -365,9 +382,9 @@ #endif -__initfunc(int wdt_init(void)) +int __init wdt_init(void) { - printk("WDT500/501-P driver 0.07 at %X (Interrupt %d)\n", io,irq); + printk("WDT500/501-P driver 0.08 at %X (Interrupt %d)\n", io,irq); if(request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", NULL)) { printk("IRQ %d is not free.\n", irq); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/Config.in linux.ac/drivers/net/Config.in --- linux.vanilla/drivers/net/Config.in Tue Jun 15 16:49:49 1999 +++ linux.ac/drivers/net/Config.in Sun Jun 13 20:01:24 1999 @@ -2,6 +2,9 @@ # Network device configuration # +mainmenu_option next_comment +comment 'ARCnet devices' + tristate 'ARCnet support' CONFIG_ARCNET if [ "$CONFIG_ARCNET" != "n" ]; then bool ' Enable arc0e (ARCnet "Ether-Encap" packet format)' CONFIG_ARCNET_ETH @@ -12,6 +15,8 @@ dep_tristate ' ARCnet COM20020 chipset driver' CONFIG_ARCNET_COM20020 $CONFIG_ARCNET fi +endmenu + tristate 'Dummy net driver support' CONFIG_DUMMY tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then @@ -22,6 +27,10 @@ # # Ethernet # + +mainmenu_option next_comment +comment 'Ethernet (10 or 100Mbit)' + bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET if [ "$CONFIG_NET_ETHERNET" = "y" ]; then if [ "$CONFIG_ARM" = "y" ]; then @@ -82,18 +91,15 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139 tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN - tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC fi bool 'Other ISA cards' CONFIG_NET_ISA if [ "$CONFIG_NET_ISA" = "y" ]; then - tristate 'AT1700/1720 support' CONFIG_AT1700 + 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 - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO - fi + 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 @@ -103,7 +109,7 @@ fi tristate 'NE2000/NE1000 support' CONFIG_NE2000 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005 + tristate 'SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005 fi bool 'SK_G16 support' CONFIG_SK_G16 fi @@ -115,6 +121,7 @@ if [ "$CONFIG_NET_EISA" = "y" ]; then tristate 'AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 fi @@ -145,6 +152,8 @@ fi fi +endmenu + bool 'FDDI driver support' CONFIG_FDDI if [ "$CONFIG_FDDI" = "y" ]; then bool 'Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX @@ -153,25 +162,20 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI if [ "$CONFIG_HIPPI" = "y" ]; then - bool 'CERN HIPPI PCI adapter support' CONFIG_CERN_HIPPI - bool 'Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER + 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 -tristate 'Frame relay DLCI support' CONFIG_DLCI -if [ "$CONFIG_DLCI" = "y" -o "$CONFIG_DLCI" = "m" ]; 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 - # # AppleTalk # + 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 @@ -183,6 +187,7 @@ 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 @@ -203,23 +208,38 @@ bool 'Wireless LAN (non-hamradio)' CONFIG_NET_RADIO if [ "$CONFIG_NET_RADIO" = "y" ]; then - tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP + 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' + 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 + 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 @@ -227,8 +247,22 @@ # The COSA/SRP driver has not been tested as non-modular yet. # dep_tristate 'COSA/SRP sync serial boards support' CONFIG_COSA m -tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI # +# There is no way to detect a Sealevel board. Force it modular +# +dep_tristate 'Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m + +tristate 'Frame relay DLCI support' CONFIG_DLCI +if [ "$CONFIG_DLCI" != "n" ]; then + int ' Max open DLCI' CONFIG_DLCI_COUNT 24 + int ' Max DLCI per device' CONFIG_DLCI_MAX 8 + dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI +fi + +# +# Wan router core. +# + if [ "$CONFIG_WAN_ROUTER" != "n" ]; then bool 'WAN drivers' CONFIG_WAN_DRIVERS if [ "$CONFIG_WAN_DRIVERS" = "y" ]; then @@ -238,14 +272,18 @@ bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25 bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP + bool ' WANPIPE Cisco HDLC support' CONFIG_WANPIPE_CHDLC fi fi fi + +endmenu + # # X.25 network drivers # if [ "$CONFIG_X25" != "n" ]; then -if [ "$CONFIG_LAPB" != "n" ]; then +if [ "$CONFIG_LAPB" = "y" -o "$CONFIG_LAPB" = "m" ]; then dep_tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER $CONFIG_LAPB dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB fi diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/Makefile linux.ac/drivers/net/Makefile --- linux.vanilla/drivers/net/Makefile Tue Jun 15 16:49:49 1999 +++ linux.ac/drivers/net/Makefile Sun Jun 13 20:01:30 1999 @@ -67,6 +67,14 @@ 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 @@ -143,14 +151,6 @@ endif endif -ifeq ($(CONFIG_ETHERH),y) -CONFIG_8390_BUILTIN = y -else - ifeq ($(CONFIG_ETHERH),m) - CONFIG_8390_MODULE = y - endif -endif - ifeq ($(CONFIG_WD80x3),y) L_OBJS += wd.o CONFIG_8390_BUILTIN = y @@ -171,14 +171,6 @@ endif endif -ifeq ($(CONFIG_ETHERH),y) -CONFIG_8390_BUILTIN = y -else - ifeq ($(CONFIG_ETHERH),m) - CONFIG_8390_MODULE = y - endif -endif - ifeq ($(CONFIG_NE2K_PCI),y) L_OBJS += ne2k-pci.o CONFIG_8390_BUILTIN = y @@ -438,6 +430,14 @@ endif endif +ifeq ($(CONFIG_SUNBMAC),y) +L_OBJS += sunbmac.o +else + ifeq ($(CONFIG_SUNBMAC),m) + M_OBJS += sunbmac.o + endif +endif + ifeq ($(CONFIG_MYRI_SBUS),y) L_OBJS += myri_sbus.o else @@ -582,6 +582,14 @@ endif endif +ifeq ($(CONFIG_ARLAN),y) +LX_OBJS += arlan.o arlan-proc.o +else + ifeq ($(CONFIG_ARLAN),m) + MX_OBJS += arlan.o arlan-proc.o + endif +endif + ifeq ($(CONFIG_TLAN),y) L_OBJS += tlan.o else @@ -780,6 +788,19 @@ 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 @@ -1039,6 +1060,16 @@ ifeq ($(CONFIG_WANPIPE_PPP),y) L_OBJS += sdla_ppp.o endif + ifeq ($(CONFIG_WANPIPE_CHDLC),y) + L_OBJS += sdla_chdlc.o + endif + ifeq ($(CONFIG_WANPIPE_BSTRM),y) + L_OBJS += sdla_bstrm.o + endif + ifeq ($(CONFIG_WANPIPE_HDLC),y) + L_OBJS += sdla_hdlc.o + endif + endif ifeq ($(CONFIG_VENDOR_SANGOMA),m) @@ -1053,6 +1084,15 @@ endif ifeq ($(CONFIG_WANPIPE_PPP),y) WANPIPE_OBJS += sdla_ppp.o + endif + ifeq ($(CONFIG_WANPIPE_CHDLC),y) + WANPIPE_OBJS += sdla_chdlc.o + endif + ifeq ($(CONFIG_WANPIPE_BSTRM),y) + WANPIPE_OBJS += sdla_bstrm.o + endif + ifeq ($(CONFIG_WANPIPE_HDLC),y) + WANPIPE_OBJS += sdla_hdlc.o endif endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/Space.c linux.ac/drivers/net/Space.c --- linux.vanilla/drivers/net/Space.c Tue Jun 15 16:49:49 1999 +++ linux.ac/drivers/net/Space.c Sun Jun 13 20:01:35 1999 @@ -67,6 +67,7 @@ extern int de4x5_probe(struct device *); extern int el1_probe(struct device *); extern int wavelan_probe(struct device *); +extern int arlan_probe(struct device *); extern int el16_probe(struct device *); extern int elmc_probe(struct device *); extern int skmca_probe(struct device *); @@ -357,6 +358,9 @@ #ifdef CONFIG_WAVELAN /* WaveLAN */ {wavelan_probe, 0}, #endif +#ifdef CONFIG_ARLAN /* Aironet */ + {arlan_probe, 0}, +#endif #ifdef CONFIG_EL16 /* 3c507 */ {el16_probe, 0}, #endif @@ -711,6 +715,7 @@ #ifdef CONFIG_TR /* Token-ring device probe */ extern int ibmtr_probe(struct device *); +extern int olympic_probe(struct device *); static int trif_probe(struct device *dev) @@ -718,6 +723,9 @@ if (1 #ifdef CONFIG_IBMTR && ibmtr_probe(dev) +#endif +#ifdef CONFIG_IBMOL + && olympic_probe(dev) #endif #ifdef CONFIG_SKTR && sktr_probe(dev) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/arlan-proc.c linux.ac/drivers/net/arlan-proc.c --- linux.vanilla/drivers/net/arlan-proc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/arlan-proc.c Fri Jun 4 23:52:39 1999 @@ -0,0 +1,1059 @@ + +#include "arlan.h" + +#ifdef CONFIG_PROC_FS + + +#include +#include + +/* void enableReceive(struct device* dev); +*/ + +static int arlan_command(struct device * dev, int command); + + +#define ARLAN_STR_SIZE 0x2ff0 +#define DEV_ARLAN_INFO 1 +#define DEV_ARLAN 1 +#define SARLG(type,var) {\ + pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n", #var, READSHMB(priva->card->var)); \ + } + +#define SARLBN(type,var,nn) {\ + pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x",#var);\ + for (i=0; i < nn; i++ ) pos += sprintf(arlan_drive_info+pos, "%02x",READSHMB(priva->card->var[i]));\ + pos += sprintf(arlan_drive_info+pos, "\n"); \ + } + +#define SARLBNpln(type,var,nn) {\ + for (i=0; i < nn; i++ ) pos += sprintf(arlan_drive_info+pos, "%02x",READSHMB(priva->card->var[i]));\ + } + +#define SARLSTR(var,nn) {\ + char tmpStr[400];\ + int tmpLn = nn;\ + if (nn > 399 ) tmpLn = 399; \ + memcpy(tmpStr,(char *) priva->conf->var,tmpLn);\ + tmpStr[tmpLn] = 0; \ + pos += sprintf(arlan_drive_info+pos, "%s\t=\t%s \n",#var,priva->conf->var);\ + } + +#define SARLUC(var) SARLG(u_char, var) +#define SARLUCN(var,nn) SARLBN(u_char,var, nn) +#define SARLUS(var) SARLG(u_short, var) +#define SARLUSN(var,nn) SARLBN(u_short,var, nn) +#define SARLUI(var) SARLG(u_int, var) + +#define SARLUSA(var) {\ + u_short tmpVar;\ + memcpy(&tmpVar, (short *) priva->conf->var,2); \ + pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n",#var, tmpVar);\ +} + +#define SARLUIA(var) {\ + u_int tmpVar;\ + memcpy(&tmpVar, (int* )priva->conf->var,4); \ + pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n",#var, tmpVar);\ +} + + +const char *arlan_diagnostic_info_string(struct device *dev) +{ + + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + u_char diagnosticInfo; + + READSHM(diagnosticInfo, arlan->diagnosticInfo, u_char); + + switch (diagnosticInfo) + { + case 0xFF: + return "Diagnostic info is OK"; + case 0xFE: + return "ERROR EPROM Checksum error "; + case 0xFD: + return "ERROR Local Ram Test Failed "; + case 0xFC: + return "ERROR SCC failure "; + case 0xFB: + return "ERROR BackBone failure "; + case 0xFA: + return "ERROR tranceiver not found "; + case 0xF9: + return "ERROR no more address space "; + case 0xF8: + return "ERROR Checksum error "; + case 0xF7: + return "ERROR Missing SS Code"; + case 0xF6: + return "ERROR Invalid config format"; + case 0xF5: + return "ERROR Reserved errorcode F5"; + case 0xF4: + return "ERROR Invalid spreading code/channel number"; + case 0xF3: + return "ERROR Load Code Error"; + case 0xF2: + return "ERROR Reserver errorcode F2 "; + case 0xF1: + return "ERROR Invalid command receivec by LAN card "; + case 0xF0: + return "ERROR Invalid parameter found in command "; + case 0xEF: + return "ERROR On-chip timer failure "; + case 0xEE: + return "ERROR T410 timer failure "; + case 0xED: + return "ERROR Too Many TxEnable commands "; + case 0xEC: + return "ERROR EEPROM error on radio module "; + default: + return "ERROR unknown Diagnostic info reply code "; + } +}; + +static const char *arlan_hardware_type_string(struct device *dev) +{ + u_char hardwareType; + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + + READSHM(hardwareType, arlan->hardwareType, u_char); + switch (hardwareType) + { + case 0x00: + return "type A450"; + case 0x01: + return "type A650 "; + case 0x04: + return "type TMA coproc"; + case 0x0D: + return "type A650E "; + case 0x18: + return "type TMA coproc Australian"; + case 0x19: + return "type A650A "; + case 0x26: + return "type TMA coproc European"; + case 0x2E: + return "type A655 "; + case 0x2F: + return "type A655A "; + case 0x30: + return "type A655E "; + case 0x0B: + return "type A670 "; + case 0x0C: + return "type A670E "; + case 0x2D: + return "type A670A "; + case 0x0F: + return "type A411T"; + case 0x16: + return "type A411TA"; + case 0x1B: + return "type A440T"; + case 0x1C: + return "type A412T"; + case 0x1E: + return "type A412TA"; + case 0x22: + return "type A411TE"; + case 0x24: + return "type A412TE"; + case 0x27: + return "type A671T "; + case 0x29: + return "type A671TA "; + case 0x2B: + return "type A671TE "; + case 0x31: + return "type A415T "; + case 0x33: + return "type A415TA "; + case 0x35: + return "type A415TE "; + case 0x37: + return "type A672"; + case 0x39: + return "type A672A "; + case 0x3B: + return "type A672T"; + case 0x6B: + return "type IC2200"; + default: + return "type A672T"; + } +} + +static void arlan_print_diagnostic_info(struct device *dev) +{ + int i; + u_char diagnosticInfo; + u_short diagnosticOffset; + u_char hardwareType; + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + + // ARLAN_DEBUG_ENTRY("arlan_print_diagnostic_info"); + + if (READSHMB(arlan->configuredStatusFlag) == 0) + printk("Arlan: Card NOT configured\n"); + else + printk("Arlan: Card is configured\n"); + + READSHM(diagnosticInfo, arlan->diagnosticInfo, u_char); + READSHM(diagnosticOffset, arlan->diagnosticOffset, u_short); + + printk(KERN_INFO "%s\n", arlan_diagnostic_info_string(dev)); + + if (diagnosticInfo != 0xff) + printk("%s arlan: Diagnostic Offset %d \n", dev->name, diagnosticOffset); + + printk("arlan: LAN CODE ID = "); + for (i = 0; i < 6; i++) + DEBUGSHM(1, "%03d:", arlan->lanCardNodeId[i], u_char); + printk("\n"); + + printk("arlan: Arlan BroadCast address = "); + for (i = 0; i < 6; i++) + DEBUGSHM(1, "%03d:", arlan->broadcastAddress[i], u_char); + printk("\n"); + + READSHM(hardwareType, arlan->hardwareType, u_char); + printk(KERN_INFO "%s\n", arlan_hardware_type_string(dev)); + + + DEBUGSHM(1, "arlan: channelNumber=%d\n", arlan->channelNumber, u_char); + DEBUGSHM(1, "arlan: channelSet=%d\n", arlan->channelSet, u_char); + DEBUGSHM(1, "arlan: spreadingCode=%d\n", arlan->spreadingCode, u_char); + DEBUGSHM(1, "arlan: radioNodeId=%d\n", arlan->radioNodeId, u_short); + DEBUGSHM(1, "arlan: SID =%d\n", arlan->SID, u_short); + DEBUGSHM(1, "arlan: rxOffset=%d\n", arlan->rxOffset, u_short); + + DEBUGSHM(1, "arlan: registration mode is %d\n", arlan->registrationMode, u_char); + + printk("arlan: name= "); + IFDEBUG(1) + + for (i = 0; i < 16; i++) + { + char c; + READSHM(c, arlan->name[i], char); + if (c) + printk("%c", c); + } + printk("\n"); + +// ARLAN_DEBUG_EXIT("arlan_print_diagnostic_info"); + +} + + +/****************************** TEST MEMORY **************/ + +static int arlan_hw_test_memory(struct device *dev) +{ + u_char *ptr; + int i; + int memlen = sizeof(struct arlan_shmem) - 0xF; /* avoid control register */ + volatile char *arlan_mem = (char *) (dev->mem_start); + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + char pattern; + + ptr = NULL; + + /* hold card in reset state */ + setHardwareReset(dev); + + /* test memory */ + pattern = 0; + for (i = 0; i < memlen; i++) + WRITESHM(arlan_mem[i], ((u_char) pattern++), u_char); + + pattern = 0; + for (i = 0; i < memlen; i++) + { + char res; + READSHM(res, arlan_mem[i], char); + if (res != pattern++) + { + printk(KERN_ERR "Arlan driver memory test 1 failed \n"); + return -1; + } + } + + pattern = 0; + for (i = 0; i < memlen; i++) + WRITESHM(arlan_mem[i], ~(pattern++), char); + + pattern = 0; + for (i = 0; i < memlen; i++) + { + char res; + READSHM(res, arlan_mem[i], char); + if (res != ~(pattern++)) + { + printk(KERN_ERR "Arlan driver memory test 2 failed \n"); + return -1; + } + } + + /* zero memory */ + for (i = 0; i < memlen; i++) + WRITESHM(arlan_mem[i], 0x00, char); + + IFDEBUG(1) printk(KERN_INFO "Arlan: memory tests ok\n"); + + /* set reset flag and then release reset */ + WRITESHM(arlan->resetFlag, 0xff, u_char); + + clearChannelAttention(dev); + clearHardwareReset(dev); + + /* wait for reset flag to become zero, we'll wait for two seconds */ + if (arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW)) + { + printk(KERN_ERR "%s arlan: failed to come back from memory test\n", dev->name); + return -1; + } + return 0; +} + + +static int arlan_setup_card_by_book(struct device *dev) +{ + u_char irqLevel, configuredStatusFlag; + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + +// ARLAN_DEBUG_ENTRY("arlan_setup_card"); + + READSHM(configuredStatusFlag, arlan->configuredStatusFlag, u_char); + + IFDEBUG(10) + if (configuredStatusFlag != 0) + IFDEBUG(10) printk("arlan: CARD IS CONFIGURED\n"); + else + IFDEBUG(10) printk("arlan: card is NOT configured\n"); + + if (testMemory || (READSHMB(arlan->diagnosticInfo) != 0xff)) + if (arlan_hw_test_memory(dev)) + return -1; + + DEBUGSHM(4, "arlan configuredStatus = %d \n", arlan->configuredStatusFlag, u_char); + DEBUGSHM(4, "arlan driver diagnostic: 0x%2x\n", arlan->diagnosticInfo, u_char); + + /* issue nop command - no interupt */ + arlan_command(dev, ARLAN_COMMAND_NOOP); + if (arlan_command(dev, ARLAN_COMMAND_WAIT_NOW) != 0) + return -1; + + IFDEBUG(50) printk("1st Noop successfully executed !!\n"); + + /* try to turn on the arlan interrupts */ + clearClearInterrupt(dev); + setClearInterrupt(dev); + setInterruptEnable(dev); + + /* issue nop command - with interrupt */ + + arlan_command(dev, ARLAN_COMMAND_NOOPINT); + if (arlan_command(dev, ARLAN_COMMAND_WAIT_NOW) != 0) + return -1; + + + IFDEBUG(50) printk("2nd Noop successfully executed !!\n"); + + READSHM(irqLevel, arlan->irqLevel, u_char) + + if (irqLevel != dev->irq) + { + IFDEBUG(1) printk(KERN_WARNING "arlan dip switches set irq to %d\n", irqLevel); + printk(KERN_WARNING "device driver irq set to %d - does not match\n", dev->irq); + dev->irq = irqLevel; + } + else + IFDEBUG(2) printk("irq level is OK\n"); + + + IFDEBUG(3) arlan_print_diagnostic_info(dev); + + arlan_command(dev, ARLAN_COMMAND_CONF); + + READSHM(configuredStatusFlag, arlan->configuredStatusFlag, u_char); + if (configuredStatusFlag == 0) + { + printk(KERN_WARNING "arlan configure failed\n"); + return -1; + } + arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW); + arlan_command(dev, ARLAN_COMMAND_RX); + arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW); + printk(KERN_NOTICE "%s: arlan driver version %s loaded\n", + dev->name, arlan_version); + +// ARLAN_DEBUG_EXIT("arlan_setup_card"); + + return 0; /* no errors */ +} + + +#ifdef ARLAN_PROC_INTERFACE +#ifdef ARLAN_PROC_SHM_DUMP + +static char arlan_drive_info[ARLAN_STR_SIZE] = "A655\n\0"; + +static int arlan_sysctl_info(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int i; + int retv, pos, devnum; + struct arlan_private *priva = NULL; + struct device *dev; + pos = 0; + if (write) + { + printk("wrirte: "); + for (i = 0; i < 100; i++) + printk("adi %x \n", arlan_drive_info[i]); + } + if (ctl->procname == NULL || arlan_drive_info == NULL) + { + printk(KERN_WARNING " procname is NULL in sysctl_table or arlan_drive_info is NULL \n at arlan module\n "); + return -1; + } + devnum = ctl->procname[5] - '0'; + if (devnum < 0 || devnum > MAX_ARLANS - 1) + { + printk(KERN_WARNING "too strange devnum in procfs parse\n "); + return -1; + } + else if (arlan_device[devnum] == NULL) + { + if (ctl->procname) + pos += sprintf(arlan_drive_info + pos, "\t%s\n\n", ctl->procname); + pos += sprintf(arlan_drive_info + pos, "No device found here \n"); + goto final; + } + else + priva = arlan_device[devnum]->priv; + + if (priva == NULL) + { + printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); + return -1; + } + dev = arlan_device[devnum]; + + memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); + + pos = sprintf(arlan_drive_info, "Arlan info \n"); + /* Header Signature */ + SARLSTR(textRegion, 48); + SARLUC(resetFlag); + pos += sprintf(arlan_drive_info + pos, "diagnosticInfo\t=\t%s \n", arlan_diagnostic_info_string(dev)); + SARLUC(diagnosticInfo); + SARLUS(diagnosticOffset); + SARLUCN(_1, 12); + SARLUCN(lanCardNodeId, 6); + SARLUCN(broadcastAddress, 6); + pos += sprintf(arlan_drive_info + pos, "hardwareType =\t %s \n", arlan_hardware_type_string(dev)); + SARLUC(hardwareType); + SARLUC(majorHardwareVersion); + SARLUC(minorHardwareVersion); + SARLUC(radioModule); + SARLUC(defaultChannelSet); + SARLUCN(_2, 47); + + /* Control/Status Block - 0x0080 */ + SARLUC(interruptInProgress); + SARLUC(cntrlRegImage); + + SARLUCN(_3, 14); + SARLUC(commandByte); + SARLUCN(commandParameter, 15); + + /* Receive Status - 0x00a0 */ + SARLUC(rxStatus); + SARLUC(rxFrmType); + SARLUS(rxOffset); + SARLUS(rxLength); + SARLUCN(rxSrc, 6); + SARLUC(rxBroadcastFlag); + SARLUC(rxQuality); + SARLUC(scrambled); + SARLUCN(_4, 1); + + /* Transmit Status - 0x00b0 */ + SARLUC(txStatus); + SARLUC(txAckQuality); + SARLUC(numRetries); + SARLUCN(_5, 14); + SARLUCN(registeredRouter, 6); + SARLUCN(backboneRouter, 6); + SARLUC(registrationStatus); + SARLUC(configuredStatusFlag); + SARLUCN(_6, 1); + SARLUCN(ultimateDestAddress, 6); + SARLUCN(immedDestAddress, 6); + SARLUCN(immedSrcAddress, 6); + SARLUS(rxSequenceNumber); + SARLUC(assignedLocaltalkAddress); + SARLUCN(_7, 27); + + /* System Parameter Block */ + + /* - Driver Parameters (Novell Specific) */ + + SARLUS(txTimeout); + SARLUS(transportTime); + SARLUCN(_8, 4); + + /* - Configuration Parameters */ + SARLUC(irqLevel); + SARLUC(spreadingCode); + SARLUC(channelSet); + SARLUC(channelNumber); + SARLUS(radioNodeId); + SARLUCN(_9, 2); + SARLUC(scramblingDisable); + SARLUC(radioType); + SARLUS(routerId); + SARLUCN(_10, 9); + SARLUC(txAttenuation); + SARLUIA(systemId); + SARLUS(globalChecksum); + SARLUCN(_11, 4); + SARLUS(maxDatagramSize); + SARLUS(maxFrameSize); + SARLUC(maxRetries); + SARLUC(receiveMode); + SARLUC(priority); + SARLUC(rootOrRepeater); + SARLUCN(specifiedRouter, 6); + SARLUS(fastPollPeriod); + SARLUC(pollDecay); + SARLUSA(fastPollDelay); + SARLUC(arlThreshold); + SARLUC(arlDecay); + SARLUCN(_12, 1); + SARLUS(specRouterTimeout); + SARLUCN(_13, 5); + + /* Scrambled Area */ + SARLUIA(SID); + SARLUCN(encryptionKey, 12); + SARLUIA(_14); + SARLUSA(waitTime); + SARLUSA(lParameter); + SARLUCN(_15, 3); + SARLUS(headerSize); + SARLUS(sectionChecksum); + + SARLUC(registrationMode); + SARLUC(registrationFill); + SARLUS(pollPeriod); + SARLUS(refreshPeriod); + SARLSTR(name, 16); + SARLUCN(NID, 6); + SARLUC(localTalkAddress); + SARLUC(codeFormat); + SARLUC(numChannels); + SARLUC(channel1); + SARLUC(channel2); + SARLUC(channel3); + SARLUC(channel4); + SARLUCN(SSCode, 59); + +/* SARLUCN( _16, 0x140); + */ + /* Statistics Block - 0x0300 */ + SARLUC(hostcpuLock); + SARLUC(lancpuLock); + SARLUCN(resetTime, 18); + SARLUIA(numDatagramsTransmitted); + SARLUIA(numReTransmissions); + SARLUIA(numFramesDiscarded); + SARLUIA(numDatagramsReceived); + SARLUIA(numDuplicateReceivedFrames); + SARLUIA(numDatagramsDiscarded); + SARLUS(maxNumReTransmitDatagram); + SARLUS(maxNumReTransmitFrames); + SARLUS(maxNumConsecutiveDuplicateFrames); + /* misaligned here so we have to go to characters */ + SARLUIA(numBytesTransmitted); + SARLUIA(numBytesReceived); + SARLUIA(numCRCErrors); + SARLUIA(numLengthErrors); + SARLUIA(numAbortErrors); + SARLUIA(numTXUnderruns); + SARLUIA(numRXOverruns); + SARLUIA(numHoldOffs); + SARLUIA(numFramesTransmitted); + SARLUIA(numFramesReceived); + SARLUIA(numReceiveFramesLost); + SARLUIA(numRXBufferOverflows); + SARLUIA(numFramesDiscardedAddrMismatch); + SARLUIA(numFramesDiscardedSIDMismatch); + SARLUIA(numPollsTransmistted); + SARLUIA(numPollAcknowledges); + SARLUIA(numStatusTimeouts); + SARLUIA(numNACKReceived); + SARLUS(auxCmd); + SARLUCN(dumpPtr, 4); + SARLUC(dumpVal); + SARLUC(wireTest); + + /* next 4 seems too long for procfs, over single page ? + SARLUCN( _17, 0x86); + SARLUCN( txBuffer, 0x800); + SARLUCN( rxBuffer, 0x800); + SARLUCN( _18, 0x0bff); + */ + + pos += sprintf(arlan_drive_info + pos, "rxRing\t=\t0x"); + for (i = 0; i < 0x50; i++) + pos += sprintf(arlan_drive_info + pos, "%02x", ((char *) priva->conf)[priva->conf->rxOffset + i]); + pos += sprintf(arlan_drive_info + pos, "\n"); + + SARLUC(configStatus); + SARLUC(_22); + SARLUC(progIOCtrl); + SARLUC(shareMBase); + SARLUC(controlRegister); + + pos += sprintf(arlan_drive_info + pos, " total %d chars\n", pos); + if (ctl) + if (ctl->procname) + pos += sprintf(arlan_drive_info + pos, " driver name : %s\n", ctl->procname); +final: + *lenp = pos; + + if (!write) + retv = proc_dostring(ctl, write, filp, buffer, lenp); + else + { + *lenp = 0; + return -1; + } + return retv; +} + + +static int arlan_sysctl_info161719(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int i; + int retv, pos, devnum; + struct arlan_private *priva = NULL; + + pos = 0; + devnum = ctl->procname[5] - '0'; + if (arlan_device[devnum] == NULL) + { + pos += sprintf(arlan_drive_info + pos, "No device found here \n"); + goto final; + } + else + priva = arlan_device[devnum]->priv; + if (priva == NULL) + { + printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); + return -1; + } + memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); + SARLUCN(_16, 0xC0); + SARLUCN(_17, 0x6A); + SARLUCN(_18, 14); + SARLUCN(_19, 0x86); + SARLUCN(_21, 0x3fd); + +final: + *lenp = pos; + retv = proc_dostring(ctl, write, filp, buffer, lenp); + return retv; +} + +static int arlan_sysctl_infotxRing(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int i; + int retv, pos, devnum; + struct arlan_private *priva = NULL; + + pos = 0; + devnum = ctl->procname[5] - '0'; + if (arlan_device[devnum] == NULL) + { + pos += sprintf(arlan_drive_info + pos, "No device found here \n"); + goto final; + } + else + priva = arlan_device[devnum]->priv; + if (priva == NULL) + { + printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); + return -1; + } + memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); + SARLBNpln(u_char, txBuffer, 0x800); +final: + *lenp = pos; + retv = proc_dostring(ctl, write, filp, buffer, lenp); + return retv; +} + +static int arlan_sysctl_inforxRing(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int i; + int retv, pos, devnum; + struct arlan_private *priva = NULL; + + pos = 0; + devnum = ctl->procname[5] - '0'; + if (arlan_device[devnum] == NULL) + { + pos += sprintf(arlan_drive_info + pos, "No device found here \n"); + goto final; + } else + priva = arlan_device[devnum]->priv; + if (priva == NULL) + { + printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); + return -1; + } + memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); + SARLBNpln(u_char, rxBuffer, 0x800); +final: + *lenp = pos; + retv = proc_dostring(ctl, write, filp, buffer, lenp); + return retv; +} + +static int arlan_sysctl_info18(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int i; + int retv, pos, devnum; + struct arlan_private *priva = NULL; + + pos = 0; + devnum = ctl->procname[5] - '0'; + if (arlan_device[devnum] == NULL) + { + pos += sprintf(arlan_drive_info + pos, "No device found here \n"); + goto final; + } + else + priva = arlan_device[devnum]->priv; + if (priva == NULL) + { + printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); + return -1; + } + memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); + SARLBNpln(u_char, _18, 0x800); + +final: + *lenp = pos; + retv = proc_dostring(ctl, write, filp, buffer, lenp); + return retv; +} + + +#endif /* #ifdef ARLAN_PROC_SHM_DUMP */ + + +static char conf_reset_result[200]; + +static int arlan_configure(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int pos = 0; + int devnum = ctl->procname[6] - '0'; + struct arlan_private *priv; + + if (devnum < 0 || devnum > MAX_ARLANS - 1) + { + printk(KERN_WARNING "too strange devnum in procfs parse\n "); + return -1; + } + else if (arlan_device[devnum] != NULL) + { + priv = arlan_device[devnum]->priv; + + arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_CONF); + } + else + return -1; + + *lenp = pos; + return proc_dostring(ctl, write, filp, buffer, lenp); +} + +int arlan_sysctl_reset(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int pos = 0; + int devnum = ctl->procname[5] - '0'; + struct arlan_private *priv; + + if (devnum < 0 || devnum > MAX_ARLANS - 1) + { + printk(KERN_WARNING "too strange devnum in procfs parse\n "); + return -1; + } + else if (arlan_device[devnum] != NULL) + { + priv = arlan_device[devnum]->priv; + arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_RESET); + + } else + return -1; + *lenp = pos + 3; + return proc_dostring(ctl, write, filp, buffer, lenp); +} + + +/* Place files in /proc/sys/dev/arlan */ +#define CTBLN(num,card,nam) \ + {num , #nam, &(arlan_conf[card].nam), \ + sizeof(int), 0600, NULL, &proc_dointvec} + + +#define ARLAN_SYSCTL_TABLE_TOTAL(cardNo)\ + CTBLN(1,cardNo,spreadingCode),\ + CTBLN(2,cardNo, channelNumber),\ + CTBLN(3,cardNo, scramblingDisable),\ + CTBLN(4,cardNo, txAttenuation),\ + CTBLN(5,cardNo, systemId), \ + CTBLN(6,cardNo, maxDatagramSize),\ + CTBLN(7,cardNo, maxFrameSize),\ + CTBLN(8,cardNo, maxRetries),\ + CTBLN(9,cardNo, receiveMode),\ + CTBLN(10,cardNo, priority),\ + CTBLN(11,cardNo, rootOrRepeater),\ + CTBLN(12,cardNo, SID),\ + CTBLN(13,cardNo, registrationMode),\ + CTBLN(14,cardNo, registrationFill),\ + CTBLN(15,cardNo, localTalkAddress),\ + CTBLN(16,cardNo, codeFormat),\ + CTBLN(17,cardNo, numChannels),\ + CTBLN(18,cardNo, channel1),\ + CTBLN(19,cardNo, channel2),\ + CTBLN(20,cardNo, channel3),\ + CTBLN(21,cardNo, channel4),\ + CTBLN(22,cardNo, txClear),\ + CTBLN(23,cardNo, txRetries),\ + CTBLN(24,cardNo, txRouting),\ + CTBLN(25,cardNo, txScrambled),\ + CTBLN(26,cardNo, rxParameter),\ + CTBLN(27,cardNo, txTimeoutMs),\ + CTBLN(28,cardNo, waitCardTimeout),\ + CTBLN(29,cardNo, channelSet), \ + {30, "name", arlan_conf[cardNo].siteName, \ + 16, 0600, NULL, &proc_dostring},\ + CTBLN(31,cardNo,waitTime),\ + CTBLN(32,cardNo,lParameter),\ + CTBLN(33,cardNo,_15),\ + CTBLN(34,cardNo,headerSize),\ + CTBLN(35,cardNo,async),\ + CTBLN(36,cardNo,tx_delay_ms),\ + CTBLN(37,cardNo,retries),\ + CTBLN(38,cardNo,ReTransmitPacketMaxSize),\ + CTBLN(39,cardNo,waitReTransmitPacketMaxSize),\ + CTBLN(40,cardNo,fastReTransCount),\ + CTBLN(41,cardNo,driverRetransmissions),\ + CTBLN(42,cardNo,txAckTimeoutMs),\ + CTBLN(43,cardNo,registrationInterrupts),\ + CTBLN(44,cardNo,hardwareType),\ + CTBLN(45,cardNo,radioType),\ + CTBLN(46,cardNo,writeEEPROM),\ + CTBLN(47,cardNo,writeRadioType),\ + {48, "entry_exit_debug", &arlan_entry_and_exit_debug, \ + sizeof(int), 0600, NULL, &proc_dointvec},\ + {49, "debug", &arlan_debug, \ + sizeof(int), 0600, NULL, &proc_dointvec},\ + CTBLN(50,cardNo,in_speed),\ + CTBLN(51,cardNo,out_speed),\ + CTBLN(52,cardNo,in_speed10),\ + CTBLN(53,cardNo,out_speed10),\ + CTBLN(54,cardNo,in_speed_max),\ + CTBLN(55,cardNo,out_speed_max),\ + CTBLN(56,cardNo,measure_rate),\ + CTBLN(57,cardNo,pre_Command_Wait),\ + CTBLN(58,cardNo,rx_tweak1),\ + CTBLN(59,cardNo,rx_tweak2),\ + CTBLN(60,cardNo,tx_queue_len),\ + + + +static ctl_table arlan_conf_table0[] = +{ + ARLAN_SYSCTL_TABLE_TOTAL(0) + +#ifdef ARLAN_PROC_SHM_DUMP + {150, "arlan0-txRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_infotxRing}, + {151, "arlan0-rxRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_inforxRing}, + {152, "arlan0-18", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info18}, + {153, "arlan0-ring", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info161719}, + {154, "arlan0-shm-cpy", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info}, +#endif + {155, "config0", &conf_reset_result, \ + 100, 0400, NULL, &arlan_configure}, \ + {156, "reset0", &conf_reset_result, \ + 100, 0400, NULL, &arlan_sysctl_reset}, \ + {0} +}; + +static ctl_table arlan_conf_table1[] = +{ + + ARLAN_SYSCTL_TABLE_TOTAL(1) + +#ifdef ARLAN_PROC_SHM_DUMP + {150, "arlan1-txRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_infotxRing}, + {151, "arlan1-rxRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_inforxRing}, + {152, "arlan1-18", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info18}, + {153, "arlan1-ring", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info161719}, + {154, "arlan1-shm-cpy", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info}, +#endif + {155, "config1", &conf_reset_result, + 100, 0400, NULL, &arlan_configure}, + {156, "reset1", &conf_reset_result, + 100, 0400, NULL, &arlan_sysctl_reset}, + {0} +}; + +static ctl_table arlan_conf_table2[] = +{ + + ARLAN_SYSCTL_TABLE_TOTAL(2) + +#ifdef ARLAN_PROC_SHM_DUMP + {150, "arlan2-txRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_infotxRing}, + {151, "arlan2-rxRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_inforxRing}, + {152, "arlan2-18", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info18}, + {153, "arlan2-ring", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info161719}, + {154, "arlan2-shm-cpy", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info}, +#endif + {155, "config2", &conf_reset_result, + 100, 0400, NULL, &arlan_configure}, + {156, "reset2", &conf_reset_result, + 100, 0400, NULL, &arlan_sysctl_reset}, + {0} +}; + +static ctl_table arlan_conf_table3[] = +{ + + ARLAN_SYSCTL_TABLE_TOTAL(3) + +#ifdef ARLAN_PROC_SHM_DUMP + {150, "arlan3-txRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_infotxRing}, + {151, "arlan3-rxRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_inforxRing}, + {152, "arlan3-18", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info18}, + {153, "arlan3-ring", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info161719}, + {154, "arlan3-shm-cpy", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info}, +#endif + {155, "config3", &conf_reset_result, + 100, 0400, NULL, &arlan_configure}, + {156, "reset3", &conf_reset_result, + 100, 0400, NULL, &arlan_sysctl_reset}, + {0} +}; + + + +static ctl_table arlan_table[] = +{ + {0, "arlan0", NULL, 0, 0600, arlan_conf_table0}, + {0, "arlan1", NULL, 0, 0600, arlan_conf_table1}, + {0, "arlan2", NULL, 0, 0600, arlan_conf_table2}, + {0, "arlan3", NULL, 0, 0600, arlan_conf_table3}, + {0} +}; + +#else + +static ctl_table arlan_table[MAX_ARLANS + 1] = +{ + {0} +}; +#endif +#endif + +static int mmtu = 1234; + +static ctl_table arlan_root_table[] = +{ + {254, "arlan", NULL, 0, 0555, arlan_table}, + {0} +}; + +/* Make sure that /proc/sys/dev is there */ +static ctl_table arlan_device_root_table[] = +{ + {CTL_DEV, "dev", NULL, 0, 0555, arlan_root_table}, + {0} +}; + + + +static struct ctl_table_header *arlan_device_sysctl_header = NULL; + +int init_arlan_proc(void) +{ + + int i = 0; + if (arlan_device_sysctl_header) + return 0; + for (i = 0; i < MAX_ARLANS && arlan_device[i]; i++) + arlan_table[i].ctl_name = i + 1; + arlan_device_sysctl_header = register_sysctl_table(arlan_root_table, 0); + if (!arlan_device_sysctl_header) + return -1; + + return 0; + +}; + + + +#ifdef MODULE + +int init_module(void) +{ + + return init_arlan_proc(); +}; + +void cleanup_module(void) +{ + unregister_sysctl_table(arlan_device_sysctl_header); + arlan_device_sysctl_header = NULL; + + return; +}; + +#endif // MODULE diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/arlan.c linux.ac/drivers/net/arlan.c --- linux.vanilla/drivers/net/arlan.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/arlan.c Fri Jun 4 23:52:39 1999 @@ -0,0 +1,2079 @@ +/* + * Copyright (C) 1997 Cullen Jennings + * Copyright (C) 1998 Elmer.Joandi@ut.ee, +37-255-13500 + * Gnu Public License applies + * This module provides support for the Arlan 655 card made by Aironet + */ + + +#include "arlan.h" + +static const char *arlan_version = "C.Jennigs 97 & Elmer.Joandi@ut.ee Oct'98, http://www.ylenurme.ee/~elmer/655/"; + +struct device *arlan_device[MAX_ARLANS]; +int last_arlan = 0; + +static int SID = SIDUNKNOWN; +static int radioNodeId = radioNodeIdUNKNOWN; +static char encryptionKey[12] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}; +static char *siteName = siteNameUNKNOWN; +static int irq = irqUNKNOWN; +static int mem = memUNKNOWN; +static int arlan_debug = debugUNKNOWN; +static int probe = probeUNKNOWN; +static int numDevices = numDevicesUNKNOWN; +static int testMemory = testMemoryUNKNOWN; +static int spreadingCode = spreadingCodeUNKNOWN; +static int channelNumber = channelNumberUNKNOWN; +static int channelSet = channelSetUNKNOWN; +static int systemId = systemIdUNKNOWN; +static int registrationMode = registrationModeUNKNOWN; +static int txScrambled = 1; +static int keyStart = 0; +static int mdebug = 0; +static int tx_delay_ms = 0; +static int retries = 5; +static int async = 1; +static int tx_queue_len = 1; +static int arlan_entry_debug = 0; +static int arlan_exit_debug = 0; +static int arlan_entry_and_exit_debug = 0; +static int arlan_EEPROM_bad = 0; + +#if LINUX_VERSION_CODE > 0x20100 +MODULE_PARM(irq, "i"); +MODULE_PARM(mem, "i"); +MODULE_PARM(probe, "i"); +MODULE_PARM(arlan_debug, "i"); +MODULE_PARM(numDevices, "i"); +MODULE_PARM(testMemory, "i"); +MODULE_PARM(spreadingCode, "i"); +MODULE_PARM(channelNumber, "i"); +MODULE_PARM(channelSet, "i"); +MODULE_PARM(systemId, "i"); +MODULE_PARM(registrationMode, "i"); +MODULE_PARM(radioNodeId, "i"); +MODULE_PARM(SID, "i"); +MODULE_PARM(txScrambled, "i"); +MODULE_PARM(keyStart, "i"); +MODULE_PARM(mdebug, "i"); +MODULE_PARM(tx_delay_ms, "i"); +MODULE_PARM(retries, "i"); +MODULE_PARM(async, "i"); +MODULE_PARM(tx_queue_len, "i"); +MODULE_PARM(arlan_entry_debug, "i"); +MODULE_PARM(arlan_exit_debug, "i"); +MODULE_PARM(arlan_entry_and_exit_debug, "i"); +MODULE_PARM(arlan_EEPROM_bad, "i"); + +EXPORT_SYMBOL(arlan_device); +EXPORT_SYMBOL(last_arlan); + + +// #warning kernel 2.1.110 tested +#define myATOMIC_INIT(a,b) atomic_set(&(a),b) +#define __initfunctio(a) __initfunc(a) + +#else +#define test_and_set_bit set_bit +#define __initfunctio(a) a +#if LINUX_VERSION_CODE != 0x20024 + // #warning kernel 2.0.36 tested +#endif +#define myATOMIC_INIT(a,b) a = b; + +#endif + +struct arlan_conf_stru arlan_conf[MAX_ARLANS]; +int arlans_found = 0; + +static int arlan_probe_here(struct device *dev, int ioaddr); +static int arlan_open(struct device *dev); +static int arlan_tx(struct sk_buff *skb, struct device *dev); +static void arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static int arlan_close(struct device *dev); +static struct enet_statistics * + arlan_statistics (struct device *dev); +static void arlan_set_multicast (struct device *dev); +static int arlan_hw_tx (struct device* dev, char *buf, int length ); +static int arlan_hw_config (struct device * dev); +static void arlan_tx_done_interrupt (struct device * dev, int status); +static void arlan_rx_interrupt (struct device * dev, u_char rxStatus, u_short, u_short); +static void arlan_process_interrupt (struct device * dev); +static int arlan_command(struct device * dev, int command); + +EXPORT_SYMBOL(arlan_command); + +extern inline long long arlan_time(void) +{ + struct timeval timev; + do_gettimeofday(&timev); + return ((long long) timev.tv_sec * 1000000 + timev.tv_usec); +}; + +#ifdef ARLAN_ENTRY_EXIT_DEBUGING +#define ARLAN_DEBUG_ENTRY(name) \ + {\ + struct timeval timev;\ + do_gettimeofday(&timev);\ + if (arlan_entry_debug || arlan_entry_and_exit_debug)\ + printk("--->>>" name " %ld " "\n",((long int) timev.tv_sec * 1000000 + timev.tv_usec));\ + } +#define ARLAN_DEBUG_EXIT(name) \ + {\ + struct timeval timev;\ + do_gettimeofday(&timev);\ + if (arlan_exit_debug || arlan_entry_and_exit_debug)\ + printk("<<<---" name " %ld " "\n",((long int) timev.tv_sec * 1000000 + timev.tv_usec) );\ + } +#else +#define ARLAN_DEBUG_ENTRY(name) +#define ARLAN_DEBUG_EXIT(name) +#endif + + +#define arlan_interrupt_ack(dev)\ + clearClearInterrupt(dev);\ + setClearInterrupt(dev); + + +#define ARLAN_COMMAND_LOCK(dev) \ + if (atomic_dec_and_test(&((struct arlan_private * )dev->priv)->card_users))\ + arlan_wait_command_complete_short(dev,__LINE__); +#define ARLAN_COMMAND_UNLOCK(dev) \ + atomic_inc(&((struct arlan_private * )dev->priv)->card_users); + + +#define ARLAN_COMMAND_INC(dev) \ + {((struct arlan_private *) dev->priv)->under_command++;} +#define ARLAN_COMMAND_ZERO(dev) \ + {((struct arlan_private *) dev->priv)->under_command =0;} +#define ARLAN_UNDER_COMMAND(dev)\ + (((struct arlan_private *) dev->priv)->under_command) + +#define ARLAN_COMMAND_START(dev) ARLAN_COMMAND_INC(dev) +#define ARLAN_COMMAND_END(dev) ARLAN_COMMAND_ZERO(dev) +#define ARLAN_TOGGLE_START(dev)\ + {((struct arlan_private *) dev->priv)->under_toggle++;} +#define ARLAN_TOGGLE_END(dev)\ + {((struct arlan_private *) dev->priv)->under_toggle=0;} +#define ARLAN_UNDER_TOGGLE(dev)\ + (((struct arlan_private *) dev->priv)->under_toggle) + + + +extern inline int arlan_drop_tx(struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + priv->stats.tx_errors++; + if (priv->Conf->tx_delay_ms) + { + priv->tx_done_delayed = jiffies + priv->Conf->tx_delay_ms * HZ / 1000 + 1; + } + else + { + priv->waiting_command_mask &= ~ARLAN_COMMAND_TX; + TXHEAD(dev).offset = 0; + TXTAIL(dev).offset = 0; + priv->txLast = 0; + priv->txOffset = 0; + priv->bad = 0; + if (!priv->under_reset && !priv->under_config) + { + dev->tbusy = 0; + mark_bh(NET_BH); + } + } + return 1; +}; + + +static int arlan_command(struct device *dev, int command_p) +{ + + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf; + struct arlan_private *priv = (struct arlan_private *) dev->priv; + int udelayed = 0; + int i = 0; + long long time_mks = arlan_time(); + + ARLAN_DEBUG_ENTRY("arlan_command"); + + if (priv->card_polling_interval) + priv->card_polling_interval = 1; + + if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) + printk(KERN_DEBUG "arlan_command, %lx lock %x commandByte %x waiting %x incoming %x \n", + jiffies, priv->command_lock, READSHMB(arlan->commandByte), + priv->waiting_command_mask, command_p); + + priv->waiting_command_mask |= command_p; + + if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) + if (jiffies - priv->lastReset < 5 * HZ) + priv->waiting_command_mask &= ~ARLAN_COMMAND_RESET; + + if (priv->waiting_command_mask & ARLAN_COMMAND_INT_ACK) + { + arlan_interrupt_ack(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_ACK; + } + if (priv->waiting_command_mask & ARLAN_COMMAND_INT_ENABLE) + { + setInterruptEnable(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_ENABLE; + } + + /* Card access serializing lock */ + + if (test_and_set_bit(0, (void *) &priv->command_lock)) + { + if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) + printk(KERN_DEBUG "arlan_command: entered when command locked \n"); + goto command_busy_end; + } + /* Check cards status and waiting */ + + if (priv->waiting_command_mask & (ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW)) + { + while (priv->waiting_command_mask & (ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW)) + { + if (READSHMB(arlan->resetFlag) || + READSHMB(arlan->commandByte)) /* || + (readControlRegister(dev) & ARLAN_ACCESS)) + */ + udelay(40); + else + priv->waiting_command_mask &= ~(ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW); + + udelayed++; + + if (priv->waiting_command_mask & ARLAN_COMMAND_LONG_WAIT_NOW) + { + if (udelayed * 40 > 1000000) + { + printk(KERN_ERR "%s long wait too long \n", dev->name); + priv->waiting_command_mask |= ARLAN_COMMAND_RESET; + break; + } + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_WAIT_NOW) + { + if (udelayed * 40 > 1000) + { + printk(KERN_ERR "%s short wait too long \n", dev->name); + goto bad_end; + } + } + } + } + else + { + i = 0; + while ((READSHMB(arlan->resetFlag) || + READSHMB(arlan->commandByte)) && + conf->pre_Command_Wait > (i++) * 10) + udelay(10); + + + if ((READSHMB(arlan->resetFlag) || + READSHMB(arlan->commandByte)) && + !(priv->waiting_command_mask & ARLAN_COMMAND_RESET)) + { + goto card_busy_end; + } + } + if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) + { + priv->under_reset = 1; + dev->start = 0; + } + if (priv->waiting_command_mask & ARLAN_COMMAND_CONF) + { + priv->under_config = 1; + dev->start = 0; + } + + /* Issuing command */ + arlan_lock_card_access(dev); + if (priv->waiting_command_mask & ARLAN_COMMAND_POWERUP) + { + // if (readControlRegister(dev) & (ARLAN_ACCESS && ARLAN_POWER)) + setPowerOn(dev); + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_POWERUP; + priv->waiting_command_mask |= ARLAN_COMMAND_RESET; + priv->card_polling_interval = HZ / 10; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_ACTIVATE) + { + WRITESHMB(arlan->commandByte, ARLAN_COM_ACTIVATE); + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_ACTIVATE; + priv->card_polling_interval = HZ / 10; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_RX_ABORT) + { + if (priv->rx_command_given) + { + WRITESHMB(arlan->commandByte, ARLAN_COM_RX_ABORT); + arlan_interrupt_lancpu(dev); + priv->rx_command_given = 0; + } + priv->waiting_command_mask &= ~ARLAN_COMMAND_RX_ABORT; + priv->card_polling_interval = 1; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_TX_ABORT) + { + if (priv->tx_command_given) + { + WRITESHMB(arlan->commandByte, ARLAN_COM_TX_ABORT); + arlan_interrupt_lancpu(dev); + priv->tx_command_given = 0; + } + priv->waiting_command_mask &= ~ARLAN_COMMAND_TX_ABORT; + priv->card_polling_interval = 1; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) + { + arlan_drop_tx(dev); + if (priv->tx_command_given || priv->rx_command_given) + { + printk(KERN_ERR "%s: Reset under tx or rx command \n", dev->name); + }; + if (arlan_debug & ARLAN_DEBUG_RESET) + printk(KERN_ERR "%s: Doing chip reset\n", dev->name); + priv->lastReset = jiffies; + WRITESHM(arlan->commandByte, 0, u_char); + /* hold card in reset state */ + setHardwareReset(dev); + /* set reset flag and then release reset */ + WRITESHM(arlan->resetFlag, 0xff, u_char); + clearChannelAttention(dev); + clearHardwareReset(dev); + priv->numResets++; + priv->card_polling_interval = HZ / 4; + priv->waiting_command_mask &= ~ARLAN_COMMAND_RESET; + priv->waiting_command_mask |= ARLAN_COMMAND_INT_RACK; +// priv->waiting_command_mask |= ARLAN_COMMAND_INT_RENABLE; +// priv->waiting_command_mask |= ARLAN_COMMAND_RX; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_INT_RACK) + { + clearHardwareReset(dev); + clearClearInterrupt(dev); + setClearInterrupt(dev); + setInterruptEnable(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_RACK; + priv->waiting_command_mask |= ARLAN_COMMAND_CONF; + priv->under_config = 1; + priv->under_reset = 0; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_INT_RENABLE) + { + setInterruptEnable(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_RENABLE; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_CONF) + { + if (priv->tx_command_given || priv->rx_command_given) + { + printk(KERN_ERR "%s: Reset under tx or rx command \n", dev->name); + } + dev->start = 0; + arlan_drop_tx(dev); + setInterruptEnable(dev); + arlan_hw_config(dev); + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_CONF; + priv->card_polling_interval = HZ / 10; +// priv->waiting_command_mask |= ARLAN_COMMAND_INT_RACK; +// priv->waiting_command_mask |= ARLAN_COMMAND_INT_ENABLE; + priv->waiting_command_mask |= ARLAN_COMMAND_CONF_WAIT; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_CONF_WAIT) + { + if (READSHMB(arlan->configuredStatusFlag) != 0 && + READSHMB(arlan->diagnosticInfo) == 0xff) + { + priv->waiting_command_mask &= ~ARLAN_COMMAND_CONF_WAIT; + priv->waiting_command_mask |= ARLAN_COMMAND_RX; + priv->card_polling_interval = HZ / 10; + priv->tx_command_given = 0; + priv->under_config = 0; + if (dev->tbusy || !dev->start) + { + dev->tbusy = 0; + dev->start = 1; + mark_bh(NET_BH); + }; + } + else + { + priv->card_polling_interval = 1; + if (arlan_debug & ARLAN_DEBUG_TIMING) + printk(KERN_ERR "configure delayed \n"); + } + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_RX) + { + if (!registrationBad(dev)) + { + setInterruptEnable(dev); + memset_io((void *) arlan->commandParameter, 0, 0xf); + WRITESHMB(arlan->commandByte, ARLAN_COM_INT | ARLAN_COM_RX_ENABLE); + WRITESHMB(arlan->commandParameter[0], conf->rxParameter); + arlan_interrupt_lancpu(dev); + priv->rx_command_given; + priv->last_rx_time = arlan_time(); + priv->waiting_command_mask &= ~ARLAN_COMMAND_RX; + priv->card_polling_interval = 1; + } + else + priv->card_polling_interval = 2; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_TX) + { + if (!test_and_set_bit(0, (void *) &priv->tx_command_given)) + { + if ((time_mks - priv->last_tx_time > conf->rx_tweak1) || + (time_mks - priv->last_rx_int_ack_time < conf->rx_tweak2)) + { + setInterruptEnable(dev); + memset_io((void *) arlan->commandParameter, 0, 0xf); + WRITESHMB(arlan->commandByte, ARLAN_COM_TX_ENABLE | ARLAN_COM_INT); + memcpy_toio((void *) arlan->commandParameter, &TXLAST(dev), 14); +// for ( i=1 ; i < 15 ; i++) printk("%02x:",READSHMB(arlan->commandParameter[i])); + priv->last_command_was_rx = 0; + priv->tx_last_sent = jiffies; + arlan_interrupt_lancpu(dev); + priv->last_tx_time = arlan_time(); + priv->tx_command_given = 1; + priv->waiting_command_mask &= ~ARLAN_COMMAND_TX; + priv->card_polling_interval = 1; + } + else + { + priv->tx_command_given = 0; + priv->card_polling_interval = 1; + } + } + else if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) + printk(KERN_ERR "tx command when tx chain locked \n"); + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_NOOPINT) + { + { + WRITESHMB(arlan->commandByte, ARLAN_COM_NOP | ARLAN_COM_INT); + } + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_NOOPINT; + priv->card_polling_interval = HZ / 3; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_NOOP) + { + WRITESHMB(arlan->commandByte, ARLAN_COM_NOP); + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_NOOP; + priv->card_polling_interval = HZ / 3; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_SLOW_POLL) + { + WRITESHMB(arlan->commandByte, ARLAN_COM_GOTO_SLOW_POLL); + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_SLOW_POLL; + priv->card_polling_interval = HZ / 3; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_POWERDOWN) + { + setPowerOff(dev); + if (arlan_debug & ARLAN_DEBUG_CARD_STATE) + printk(KERN_WARNING "%s: Arlan Going Standby\n", dev->name); + priv->waiting_command_mask &= ~ARLAN_COMMAND_POWERDOWN; + priv->card_polling_interval = 3 * HZ; + } + arlan_unlock_card_access(dev); + for (i = 0; READSHMB(arlan->commandByte) && i < 20; i++) + udelay(10); + if (READSHMB(arlan->commandByte)) + if (arlan_debug & ARLAN_DEBUG_CARD_STATE) + printk(KERN_ERR "card busy leaving command %x \n", priv->waiting_command_mask); + + priv->command_lock = 0; + ARLAN_DEBUG_EXIT("arlan_command"); + priv->last_command_buff_free_time = jiffies; + return 0; + +card_busy_end: + if (jiffies - priv->last_command_buff_free_time > HZ) + priv->waiting_command_mask |= ARLAN_COMMAND_CLEAN_AND_RESET; + + if (arlan_debug & ARLAN_DEBUG_CARD_STATE) + printk(KERN_ERR "%s arlan_command card busy end \n", dev->name); + priv->command_lock = 0; + ARLAN_DEBUG_EXIT("arlan_command"); + return 1; + +bad_end: + printk(KERN_ERR "%s arlan_command bad end \n", dev->name); + + priv->command_lock = 0; + ARLAN_DEBUG_EXIT("arlan_command"); + + return -1; + +command_busy_end: + if (arlan_debug & ARLAN_DEBUG_CARD_STATE) + printk(KERN_ERR "%s arlan_command command busy end \n", dev->name); + ARLAN_DEBUG_EXIT("arlan_command"); + return 2; + +}; + +extern inline void arlan_command_process(struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + int times = 0; + while (priv->waiting_command_mask && times < 8) + { + if (priv->waiting_command_mask) + { + if (arlan_command(dev, 0)) + break; + times++; + } + /* if long command, we wont repeat trying */ ; + if (priv->card_polling_interval > 1) + break; + times++; + } +} + + +extern inline void arlan_retransmit_now(struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + + ARLAN_DEBUG_ENTRY("arlan_retransmit_now"); + if (TXLAST(dev).offset == 0) + { + if (TXHEAD(dev).offset) + { + priv->txLast = 0; + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_DEBUG "TX buff switch to head \n"); + + } + else if (TXTAIL(dev).offset) + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_DEBUG "TX buff switch to tail \n"); + priv->txLast = 1; + } + else + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_ERR "ReTransmit buff empty"); + priv->txOffset = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + return; + + } + arlan_command(dev, ARLAN_COMMAND_TX); + + priv->nof_tx++; + + priv->Conf->driverRetransmissions++; + priv->retransmissions++; + + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk("Retransmit %d bytes \n", TXLAST(dev).length); + + ARLAN_DEBUG_EXIT("arlan_retransmit_now"); +} + + + +static void arlan_registration_timer(unsigned long data) +{ + struct device *dev = (struct device *) data; + struct arlan_private *priv = (struct arlan_private *) dev->priv; + + int lostTime = ((int) (jiffies - priv->registrationLastSeen)) * 1000 / HZ; + int bh_mark_needed = 0; + int next_tick = 1; + + + priv->timer_chain_active = 1; + + + if (registrationBad(dev)) + { + //debug=100; + priv->registrationLostCount++; + if (lostTime > 7000 && lostTime < 7200) + { + printk(KERN_NOTICE "%s registration Lost \n", dev->name); + } + if (lostTime / priv->reRegisterExp > 2000) + arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_CONF); + if (lostTime / (priv->reRegisterExp) > 3500) + arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET); + if (priv->reRegisterExp < 400) + priv->reRegisterExp += 2; + if (lostTime > 7200) + { + next_tick = HZ; + arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET); + } + } + else + { + if (priv->Conf->registrationMode && lostTime > 10000 && + priv->registrationLostCount) + { + printk(KERN_NOTICE "%s registration is back after %d milliseconds\n", dev->name, + ((int) (jiffies - priv->registrationLastSeen) * 1000) / HZ); + } + priv->registrationLastSeen = jiffies; + priv->registrationLostCount = 0; + priv->reRegisterExp = 1; + if (dev->start == 0) + { + dev->start = 1; + mark_bh(NET_BH); + } + } + + + if (!registrationBad(dev) && priv->ReTransmitRequested) + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk(KERN_ERR "Retranmit from timer \n"); + priv->ReTransmitRequested = 0; + arlan_retransmit_now(dev); + } + if (!registrationBad(dev) && + priv->tx_done_delayed < jiffies && + priv->tx_done_delayed != 0) + { + TXLAST(dev).offset = 0; + if (priv->txLast) + priv->txLast = 0; + else if (TXTAIL(dev).offset) + priv->txLast = 1; + if (TXLAST(dev).offset) + { + arlan_retransmit_now(dev); + dev->trans_start = jiffies; + } + if (!(TXHEAD(dev).offset && TXTAIL(dev).offset)) + { + priv->txOffset = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + } + priv->tx_done_delayed = 0; + bh_mark_needed = 1; + } + if (bh_mark_needed) + { + priv->txOffset = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + } + arlan_process_interrupt(dev); + + if (next_tick < priv->card_polling_interval) + next_tick = priv->card_polling_interval; + + priv->timer_chain_active = 0; + priv->timer.expires = jiffies + next_tick; + + add_timer(&priv->timer); +} + + + + +static void arlan_print_registers(struct device *dev, int line) +{ + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + + u_char hostcpuLock, lancpuLock, controlRegister, cntrlRegImage, + txStatus, rxStatus, interruptInProgress, commandByte; + + + ARLAN_DEBUG_ENTRY("arlan_print_registers"); + READSHM(interruptInProgress, arlan->interruptInProgress, u_char); + READSHM(hostcpuLock, arlan->hostcpuLock, u_char); + READSHM(lancpuLock, arlan->lancpuLock, u_char); + READSHM(controlRegister, arlan->controlRegister, u_char); + READSHM(cntrlRegImage, arlan->cntrlRegImage, u_char); + READSHM(txStatus, arlan->txStatus, u_char); + READSHM(rxStatus, arlan->rxStatus, u_char); + READSHM(commandByte, arlan->commandByte, u_char); + + printk(KERN_WARNING "line %04d IP %02x HL %02x LL %02x CB %02x CR %02x CRI %02x TX %02x RX %02x\n", + line, interruptInProgress, hostcpuLock, lancpuLock, commandByte, + controlRegister, cntrlRegImage, txStatus, rxStatus); + + ARLAN_DEBUG_EXIT("arlan_print_registers"); +} + + +static int arlan_hw_tx(struct device *dev, char *buf, int length) +{ + int i; + + struct arlan_private *priv = (struct arlan_private *) dev->priv; + volatile struct arlan_shmem *arlan = priv->card; + struct arlan_conf_stru *conf = priv->Conf; + + int tailStarts = 0x800; + int headEnds = 0x0; + + + ARLAN_DEBUG_ENTRY("arlan_hw_tx"); + if (TXHEAD(dev).offset) + headEnds = (((TXHEAD(dev).offset + TXHEAD(dev).length - (((int) arlan->txBuffer) - ((int) arlan))) / 64) + 1) * 64; + if (TXTAIL(dev).offset) + tailStarts = 0x800 - (((TXTAIL(dev).offset - (((int) arlan->txBuffer) - ((int) arlan))) / 64) + 2) * 64; + + + if (!TXHEAD(dev).offset && length < tailStarts) + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk(KERN_ERR "TXHEAD insert, tailStart %d\n", tailStarts); + + TXHEAD(dev).offset = + (((int) arlan->txBuffer) - ((int) arlan)); + TXHEAD(dev).length = length - ARLAN_FAKE_HDR_LEN; + for (i = 0; i < 6; i++) + TXHEAD(dev).dest[i] = buf[i]; + TXHEAD(dev).clear = conf->txClear; + TXHEAD(dev).retries = conf->txRetries; /* 0 is use default */ + TXHEAD(dev).routing = conf->txRouting; + TXHEAD(dev).scrambled = conf->txScrambled; + memcpy_toio(((char *) arlan + TXHEAD(dev).offset), buf + ARLAN_FAKE_HDR_LEN, TXHEAD(dev).length); + } + else if (!TXTAIL(dev).offset && length < (0x800 - headEnds)) + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk(KERN_ERR "TXTAIL insert, headEnd %d\n", headEnds); + + TXTAIL(dev).offset = + (((int) arlan->txBuffer) - ((int) arlan)) + 0x800 - (length / 64 + 2) * 64; + TXTAIL(dev).length = length - ARLAN_FAKE_HDR_LEN; + for (i = 0; i < 6; i++) + TXTAIL(dev).dest[i] = buf[i]; + TXTAIL(dev).clear = conf->txClear; + TXTAIL(dev).retries = conf->txRetries; + TXTAIL(dev).routing = conf->txRouting; + TXTAIL(dev).scrambled = conf->txScrambled; + memcpy_toio(((char *) arlan + TXTAIL(dev).offset), buf + ARLAN_FAKE_HDR_LEN, TXTAIL(dev).length); + } + else + { + dev->tbusy = 1; + return -1; + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk(KERN_ERR "TX TAIL & HEAD full, return, tailStart %d headEnd %d\n", tailStarts, headEnds); + } + priv->out_bytes += length; + priv->out_bytes10 += length; + if (conf->measure_rate < 1) + conf->measure_rate = 1; + if (jiffies - priv->out_time > conf->measure_rate * HZ) + { + conf->out_speed = priv->out_bytes / conf->measure_rate; + priv->out_bytes = 0; + priv->out_time = jiffies; + } + if (jiffies - priv->out_time10 > conf->measure_rate * HZ * 10) + { + conf->out_speed10 = priv->out_bytes10 / (10 * conf->measure_rate); + priv->out_bytes10 = 0; + priv->out_time10 = jiffies; + } + if (TXHEAD(dev).offset && TXTAIL(dev).offset) + { + dev->tbusy = 1; + return 0; + } + else + dev->tbusy = 0; + + + IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) + printk(KERN_WARNING "%s Transmit t %2x:%2x:%2x:%2x:%2x:%2x f %2x:%2x:%2x:%2x:%2x:%2x \n", dev->name, + (unsigned char) buf[0], (unsigned char) buf[1], (unsigned char) buf[2], (unsigned char) buf[3], + (unsigned char) buf[4], (unsigned char) buf[5], (unsigned char) buf[6], (unsigned char) buf[7], + (unsigned char) buf[8], (unsigned char) buf[9], (unsigned char) buf[10], (unsigned char) buf[11]); + + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_ERR "TX command prepare for buffer %d\n", priv->txLast); + + arlan_command(dev, ARLAN_COMMAND_TX); + + priv->last_command_was_rx = 0; + priv->tx_last_sent = jiffies; + priv->nof_tx++; + + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk("%s TX Qued %d bytes \n", dev->name, length); + + ARLAN_DEBUG_EXIT("arlan_hw_tx"); + + return 0; +} + + +static int arlan_hw_config(struct device *dev) +{ + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf; + struct arlan_private *priv = (struct arlan_private *) dev->priv; + + ARLAN_DEBUG_ENTRY("arlan_hw_config"); + + printk(KERN_NOTICE "%s arlan configure called \n", dev->name); + if (arlan_EEPROM_bad) + printk(KERN_NOTICE "arlan configure with eeprom bad option \n"); + + + WRITESHM(arlan->spreadingCode, conf->spreadingCode, u_char); + WRITESHM(arlan->channelSet, conf->channelSet, u_char); + + if (arlan_EEPROM_bad) + WRITESHM(arlan->defaultChannelSet, conf->channelSet, u_char); + + WRITESHM(arlan->channelNumber, conf->channelNumber, u_char); + + WRITESHM(arlan->scramblingDisable, conf->scramblingDisable, u_char); + WRITESHM(arlan->txAttenuation, conf->txAttenuation, u_char); + + WRITESHM(arlan->systemId, conf->systemId, u_int); + + WRITESHM(arlan->maxRetries, conf->maxRetries, u_char); + WRITESHM(arlan->receiveMode, conf->receiveMode, u_char); + WRITESHM(arlan->priority, conf->priority, u_char); + WRITESHM(arlan->rootOrRepeater, conf->rootOrRepeater, u_char); + WRITESHM(arlan->SID, conf->SID, u_int); + + WRITESHM(arlan->registrationMode, conf->registrationMode, u_char); + + WRITESHM(arlan->registrationFill, conf->registrationFill, u_char); + WRITESHM(arlan->localTalkAddress, conf->localTalkAddress, u_char); + WRITESHM(arlan->codeFormat, conf->codeFormat, u_char); + WRITESHM(arlan->numChannels, conf->numChannels, u_char); + WRITESHM(arlan->channel1, conf->channel1, u_char); + WRITESHM(arlan->channel2, conf->channel2, u_char); + WRITESHM(arlan->channel3, conf->channel3, u_char); + WRITESHM(arlan->channel4, conf->channel4, u_char); + WRITESHM(arlan->radioNodeId, conf->radioNodeId, u_short); + WRITESHM(arlan->SID, conf->SID, u_int); + WRITESHM(arlan->waitTime, conf->waitTime, u_short); + WRITESHM(arlan->lParameter, conf->lParameter, u_short); + memcpy_toio(&(arlan->_15), &(conf->_15), 3); + WRITESHM(arlan->_15, conf->_15, u_short); + WRITESHM(arlan->headerSize, conf->headerSize, u_short); + if (arlan_EEPROM_bad) + WRITESHM(arlan->hardwareType, conf->hardwareType, u_char); + WRITESHM(arlan->radioType, conf->radioType, u_char); + if (arlan_EEPROM_bad) + WRITESHM(arlan->radioModule, conf->radioType, u_char); + + memcpy_toio(arlan->encryptionKey + keyStart, encryptionKey, 8); + memcpy_toio(arlan->name, conf->siteName, 16); + + WRITESHMB(arlan->commandByte, ARLAN_COM_INT | ARLAN_COM_CONF); /* do configure */ + memset_io(arlan->commandParameter, 0, 0xf); /* 0xf */ + memset_io(arlan->commandParameter + 1, 0, 2); + if (conf->writeEEPROM) + { + memset_io(arlan->commandParameter, conf->writeEEPROM, 1); +// conf->writeEEPROM=0; + } + if (conf->registrationMode && conf->registrationInterrupts) + memset_io(arlan->commandParameter + 3, 1, 1); + else + memset_io(arlan->commandParameter + 3, 0, 1); + + priv->irq_test_done = 0; + + if (conf->tx_queue_len) + dev->tx_queue_len = conf->tx_queue_len; + udelay(100); + + ARLAN_DEBUG_EXIT("arlan_hw_config"); + return 0; +} + + +static int arlan_read_card_configuration(struct device *dev) +{ + u_char tlx415; + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf; + + ARLAN_DEBUG_ENTRY("arlan_read_card_configuration"); + + if (radioNodeId == radioNodeIdUNKNOWN) + { + READSHM(conf->radioNodeId, arlan->radioNodeId, u_short); + } + else + conf->radioNodeId = radioNodeId; + + if (SID == SIDUNKNOWN) + { + READSHM(conf->SID, arlan->SID, u_int); + } + else conf->SID = SID; + + if (spreadingCode == spreadingCodeUNKNOWN) + { + READSHM(conf->spreadingCode, arlan->spreadingCode, u_char); + } + else + conf->spreadingCode = spreadingCode; + + if (channelSet == channelSetUNKNOWN) + { + READSHM(conf->channelSet, arlan->channelSet, u_char); + } + else conf->channelSet = channelSet; + + if (channelNumber == channelNumberUNKNOWN) + { + READSHM(conf->channelNumber, arlan->channelNumber, u_char); + } + else conf->channelNumber = channelNumber; + + READSHM(conf->scramblingDisable, arlan->scramblingDisable, u_char); + READSHM(conf->txAttenuation, arlan->txAttenuation, u_char); + + if (systemId == systemIdUNKNOWN) + { + READSHM(conf->systemId, arlan->systemId, u_int); + } + else conf->systemId = systemId; + + READSHM(conf->maxDatagramSize, arlan->maxDatagramSize, u_short); + READSHM(conf->maxFrameSize, arlan->maxFrameSize, u_short); + READSHM(conf->maxRetries, arlan->maxRetries, u_char); + READSHM(conf->receiveMode, arlan->receiveMode, u_char); + READSHM(conf->priority, arlan->priority, u_char); + READSHM(conf->rootOrRepeater, arlan->rootOrRepeater, u_char); + + if (SID == SIDUNKNOWN) + { + READSHM(conf->SID, arlan->SID, u_int); + } + else conf->SID = SID; + + if (registrationMode == registrationModeUNKNOWN) + { + READSHM(conf->registrationMode, arlan->registrationMode, u_char); + } + else conf->registrationMode = registrationMode; + + READSHM(conf->registrationFill, arlan->registrationFill, u_char); + READSHM(conf->localTalkAddress, arlan->localTalkAddress, u_char); + READSHM(conf->codeFormat, arlan->codeFormat, u_char); + READSHM(conf->numChannels, arlan->numChannels, u_char); + READSHM(conf->channel1, arlan->channel1, u_char); + READSHM(conf->channel2, arlan->channel2, u_char); + READSHM(conf->channel3, arlan->channel3, u_char); + READSHM(conf->channel4, arlan->channel4, u_char); + READSHM(conf->waitTime, arlan->waitTime, u_short); + READSHM(conf->lParameter, arlan->lParameter, u_short); + READSHM(conf->_15, arlan->_15, u_short); + READSHM(conf->headerSize, arlan->headerSize, u_short); + READSHM(conf->hardwareType, arlan->hardwareType, u_char); + READSHM(conf->radioType, arlan->radioModule, u_char); + + if (conf->radioType == 0) + conf->radioType = 0xc; + + WRITESHM(arlan->configStatus, 0xA5, u_char); + READSHM(tlx415, arlan->configStatus, u_char); + + if (tlx415 != 0xA5) + printk(KERN_INFO "%s tlx415 chip \n", dev->name); + + conf->txClear = 0; + conf->txRetries = 1; + conf->txRouting = 1; + conf->txScrambled = 0; + conf->rxParameter = 1; + conf->txTimeoutMs = 4000; + conf->waitCardTimeout = 100000; + conf->receiveMode = ARLAN_RCV_CLEAN; + memcpy_fromio(conf->siteName, arlan->name, 16); + conf->siteName[16] = '\0'; + conf->retries = retries; + conf->tx_delay_ms = tx_delay_ms; + conf->async = async; + conf->ReTransmitPacketMaxSize = 200; + conf->waitReTransmitPacketMaxSize = 200; + conf->txAckTimeoutMs = 900; + conf->fastReTransCount = 3; + + ARLAN_DEBUG_EXIT("arlan_read_card_configuration"); + + return 0; +} + + +static int lastFoundAt = 0xbe000; + + +/* + * This is the real probe routine. Linux has a history of friendly device + * probes on the ISA bus. A good device probes avoids doing writes, and + * verifies that the correct device exists and functions. + */ + +__initfunctio(static int arlan_check_fingerprint(int memaddr)) +{ + static char probeText[] = "TELESYSTEM SLW INC. ARLAN \0"; + char tempBuf[49]; + volatile struct arlan_shmem *arlan = (struct arlan_shmem *) memaddr; + + ARLAN_DEBUG_ENTRY("arlan_check_fingerprint"); + memcpy_fromio(tempBuf, arlan->textRegion, 29); + tempBuf[30] = 0; + + /* check for card at this address */ + if (0 != strncmp(tempBuf, probeText, 29)) + return -ENODEV; + +// printk(KERN_INFO "arlan found at 0x%x \n",memaddr); + ARLAN_DEBUG_EXIT("arlan_check_fingerprint"); + + return 0; + + +} + +__initfunctio(int arlan_probe_everywhere(struct device *dev)) +{ + int m; + int probed = 0; + int found = 0; + + ARLAN_DEBUG_ENTRY("arlan_probe_everywhere"); + if (mem != 0 && numDevices == 1) /* Check a single specified location. */ + { + if (arlan_probe_here(dev, mem) == 0) + return 0; + else + return -ENODEV; + } + for (m = lastFoundAt + 0x2000; m <= 0xDE000; m += 0x2000) + { + if (arlan_probe_here(dev, m) == 0) + { + found++; + lastFoundAt = m; + break; + } + probed++; + } + if (found == 0 && probed != 0) + { + if (lastFoundAt == 0xbe000) + printk(KERN_ERR "arlan: No Arlan devices found \n"); + return ENODEV; + } + else + return 0; + + ARLAN_DEBUG_EXIT("arlan_probe_everywhere"); + + return ENODEV; +} + +__initfunctio(int arlan_find_devices(void)) +{ + int m; + int found = 0; + + ARLAN_DEBUG_ENTRY("arlan_find_devices"); + if (mem != 0 && numDevices == 1) /* Check a single specified location. */ + return 1; + for (m = 0xc000; m <= 0xDE000; m += 0x2000) + { + if (arlan_check_fingerprint(m) == 0) + found++; + } + ARLAN_DEBUG_EXIT("arlan_find_devices"); + + return found; +} + + +static int arlan_change_mtu(struct device *dev, int new_mtu) +{ + struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf; + + ARLAN_DEBUG_ENTRY("arlan_change_mtu"); + if ((new_mtu < 68) || (new_mtu > 2032)) + return -EINVAL; + dev->mtu = new_mtu; + if (new_mtu < 256) + new_mtu = 256; /* cards book suggests 1600 */ + conf->maxDatagramSize = new_mtu; + conf->maxFrameSize = new_mtu + 48; + + arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_CONF); + printk(KERN_NOTICE "%s mtu changed to %d \n", dev->name, new_mtu); + + ARLAN_DEBUG_EXIT("arlan_change_mtu"); + + return 0; +} + +static int arlan_mac_addr(struct device *dev, void *p) +{ + struct sockaddr *addr = p; + + + ARLAN_DEBUG_ENTRY("arlan_mac_addr"); + return -EINVAL; + + if (dev->start) + return -EBUSY; + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + ARLAN_DEBUG_EXIT("arlan_mac_addr"); + return 0; +} + + + + +__initfunctio(static int + arlan_allocate_device(int num, struct device *devs)) +{ + + struct device *dev; + + ARLAN_DEBUG_ENTRY("arlan_allocate_device"); + + if (!devs) + dev = init_etherdev(0, sizeof(struct arlan_private)); + else + { + dev = devs; + dev->priv = kmalloc(sizeof(struct arlan_private), GFP_KERNEL); + }; + + if (dev == NULL || dev->priv == NULL) + { + printk(KERN_CRIT "init_etherdev failed "); + return 0; + } + ((struct arlan_private *) dev->priv)->conf = + kmalloc(sizeof(struct arlan_shmem), GFP_KERNEL); + + if (dev == NULL || dev->priv == NULL || + ((struct arlan_private *) dev->priv)->conf == NULL) + { + return 0; + printk(KERN_CRIT " No memory at arlan_allocate_device \n"); + } + /* Fill in the 'dev' fields. */ + dev->base_addr = 0; + dev->mem_start = 0; + dev->mem_end = 0; + dev->mtu = 1500; + dev->flags = 0; /* IFF_BROADCAST & IFF_MULTICAST & IFF_PROMISC; */ + dev->irq = 0; + dev->dma = 0; + dev->tx_queue_len = tx_queue_len; + ether_setup(dev); + dev->tx_queue_len = tx_queue_len; + dev->open = arlan_open; + dev->stop = arlan_close; + dev->hard_start_xmit = arlan_tx; + dev->get_stats = arlan_statistics; + dev->set_multicast_list = arlan_set_multicast; + dev->change_mtu = arlan_change_mtu; + dev->set_mac_address = arlan_mac_addr; + ((struct arlan_private *) dev->priv)->irq_test_done = 0; + arlan_device[num] = dev; + ((struct arlan_private *) arlan_device[num]->priv)->Conf = &(arlan_conf[num]); + + ((struct arlan_private *) dev->priv)->Conf->pre_Command_Wait = 40; + ((struct arlan_private *) dev->priv)->Conf->rx_tweak1 = 30; + ((struct arlan_private *) dev->priv)->Conf->rx_tweak2 = 0; + + ARLAN_DEBUG_EXIT("arlan_allocate_device"); + return (int) dev; +} + + +__initfunctio(int arlan_probe_here(struct device *dev, int memaddr)) +{ + volatile struct arlan_shmem *arlan; + + ARLAN_DEBUG_ENTRY("arlan_probe_here"); + + if (arlan_check_fingerprint(memaddr)) + return -ENODEV; + + printk(KERN_NOTICE "%s: Arlan found at %#5x, \n ", dev->name, memaddr); + + if (!arlan_allocate_device(arlans_found, dev)) + return -1; + + ((struct arlan_private *) dev->priv)->card = (struct arlan_shmem *) memaddr; + arlan = (void *) memaddr; + + dev->mem_start = memaddr; + dev->mem_end = memaddr + 0x1FFF; + + if (dev->irq < 2) + { + READSHM(dev->irq, arlan->irqLevel, u_char); + } else if (dev->irq == 2) + dev->irq = 9; + + arlan_read_card_configuration(dev); + + ARLAN_DEBUG_EXIT("arlan_probe_here"); + return 0; +} + + + + +static int arlan_open(struct device *dev) +{ + struct arlan_private *priv = (struct arlan_private *) dev->priv; + volatile struct arlan_shmem *arlan = priv->card; + int ret = 0; + + ARLAN_DEBUG_ENTRY("arlan_open"); + + if (dev->mem_start == 0) + ret = arlan_probe_everywhere(dev); + if (ret != 0) + return ret; + + arlan = ((struct arlan_private *) dev->priv)->card; + + if (request_irq(dev->irq, &arlan_interrupt, 0, dev->name, dev)) + { + printk(KERN_ERR "%s: unable to get IRQ %d .\n", + dev->name, dev->irq); + return -EAGAIN; + } + arlan_command(dev, ARLAN_COMMAND_POWERUP | ARLAN_COMMAND_LONG_WAIT_NOW); + + priv->bad = 0; + priv->lastReset = 0; + priv->reset = 0; + priv->open_time = jiffies; + memcpy_fromio(dev->dev_addr, arlan->lanCardNodeId, 6); + memset(dev->broadcast, 0xff, 6); + dev->tbusy = 1; + priv->txOffset = 0; + dev->interrupt = 0; + dev->start = 1; + dev->tx_queue_len = tx_queue_len; + init_timer(&priv->timer); + priv->timer.expires = jiffies + HZ / 10; + priv->timer.data = (unsigned long) dev; + priv->timer.function = &arlan_registration_timer; /* timer handler */ + priv->interrupt_processing_active = 0; + priv->command_lock = 0; + add_timer(&priv->timer); + + priv->card_lock = MUTEX; + myATOMIC_INIT(priv->card_users, 1); /* damn 2.0.33 */ + priv->registrationLostCount = 0; + priv->registrationLastSeen = jiffies; + priv->txLast = 0; + priv->tx_command_given = 0; + + priv->reRegisterExp = 1; + priv->nof_tx = 0; + priv->nof_tx_ack = 0; + priv->last_command_was_rx = 0; + priv->tx_last_sent = jiffies - 1; + priv->tx_last_cleared = jiffies; + priv->Conf->writeEEPROM = 0; + priv->Conf->registrationInterrupts = 1; + + dev->tbusy = 0; + + MOD_INC_USE_COUNT; +#ifdef CONFIG_PROC_FS +#ifndef MODULE + if (arlan_device[0]) + init_arlan_proc(); +#endif +#endif + ARLAN_DEBUG_EXIT("arlan_open"); + return 0; +} + + + + +static int arlan_tx(struct sk_buff *skb, struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf; + + ARLAN_DEBUG_ENTRY("arlan_tx"); + + if (dev->tbusy) + { + /* + * If we get here, some higher level has decided we are broken. + * There should really be a "kick me" function call instead. + */ + int tickssofar = jiffies - dev->trans_start; + + if (((tickssofar * 1000) / HZ) * 2 > conf->txTimeoutMs) + arlan_command(dev, ARLAN_COMMAND_TX_ABORT); + + if (((tickssofar * 1000) / HZ) < conf->txTimeoutMs) + { + // up(&priv->card_lock); + goto bad_end; + } + printk(KERN_ERR "%s: arlan transmit timed out, kernel decided\n", dev->name); + /* Try to restart the adaptor. */ + arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET); + dev->trans_start = jiffies; + goto bad_end; + + } + /* + * 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(KERN_ERR "%s: Transmitter access conflict.\n", + dev->name); + } + else + { + short length; + unsigned char *buf; + + /* + * If some higher layer thinks we've missed an tx-done interrupt + * we are passed NULL. Caution: dev_tint() handles the cli()/sti() + * itself. + */ + + length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + buf = skb->data; + + if (priv->txOffset + length + 0x12 > 0x800) + printk(KERN_ERR "TX RING overflow \n"); + + if (arlan_hw_tx(dev, buf, length) == -1) + goto bad_end; + + dev->trans_start = jiffies; + } + dev_kfree_skb(skb); + + arlan_process_interrupt(dev); + priv->tx_chain_active = 0; + ARLAN_DEBUG_EXIT("arlan_tx"); + return 0; + +bad_end: + arlan_process_interrupt(dev); + priv->tx_chain_active = 0; + ARLAN_DEBUG_EXIT("arlan_tx"); + return 1; +} + + +extern inline int DoNotReTransmitCrap(struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + if (TXLAST(dev).length < priv->Conf->ReTransmitPacketMaxSize) + return 1; + return 0; + +} + +extern inline int DoNotWaitReTransmitCrap(struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + if (TXLAST(dev).length < priv->Conf->waitReTransmitPacketMaxSize) + return 1; + return 0; +} + +extern inline void arlan_queue_retransmit(struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + ARLAN_DEBUG_ENTRY("arlan_queue_retransmit"); + + if (DoNotWaitReTransmitCrap(dev)) + { + arlan_drop_tx(dev); + } else + priv->ReTransmitRequested++; + + ARLAN_DEBUG_EXIT("arlan_queue_retransmit"); +}; + +extern inline void RetryOrFail(struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + ARLAN_DEBUG_ENTRY("RetryOrFail"); + + if (priv->retransmissions > priv->Conf->retries || + DoNotReTransmitCrap(dev)) + { + arlan_drop_tx(dev); + } + else if (priv->bad <= priv->Conf->fastReTransCount) + { + arlan_retransmit_now(dev); + } + else arlan_queue_retransmit(dev); + + ARLAN_DEBUG_EXIT("RetryOrFail"); +} + + +static void arlan_tx_done_interrupt(struct device *dev, int status) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + ARLAN_DEBUG_ENTRY("arlan_tx_done_interrupt"); + + priv->tx_last_cleared = jiffies; + priv->tx_command_given = 0; + priv->nof_tx_ack++; + switch (status) + { + case 1: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit OK\n"); + priv->stats.tx_packets++; + priv->bad = 0; + priv->reset = 0; + priv->retransmissions = 0; + if (priv->Conf->tx_delay_ms) + { + priv->tx_done_delayed = jiffies + (priv->Conf->tx_delay_ms * HZ) / 1000 + 1;; + } + else + { + TXLAST(dev).offset = 0; + if (priv->txLast) + priv->txLast = 0; + else if (TXTAIL(dev).offset) + priv->txLast = 1; + if (TXLAST(dev).offset) + { + arlan_retransmit_now(dev); + dev->trans_start = jiffies; + } + if (!TXHEAD(dev).offset || !TXTAIL(dev).offset) + { + priv->txOffset = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + } + } + } + break; + + case 2: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit timed out\n"); + priv->bad += 1; + //arlan_queue_retransmit(dev); + RetryOrFail(dev); + } + break; + + case 3: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit max retries\n"); + priv->bad += 1; + priv->reset = 0; + //arlan_queue_retransmit(dev); + RetryOrFail(dev); + } + break; + + case 4: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit aborted\n"); + priv->bad += 1; + arlan_queue_retransmit(dev); + //RetryOrFail(dev); + } + break; + + case 5: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit not registered\n"); + priv->bad += 1; + //debug=101; + arlan_queue_retransmit(dev); + } + break; + + case 6: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit destination full\n"); + priv->bad += 1; + priv->reset = 0; + //arlan_drop_tx(dev); + arlan_queue_retransmit(dev); + } + break; + + case 7: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit unknown ack\n"); + priv->bad += 1; + priv->reset = 0; + arlan_queue_retransmit(dev); + } + break; + + case 8: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit dest mail box full\n"); + priv->bad += 1; + priv->reset = 0; + //arlan_drop_tx(dev); + arlan_queue_retransmit(dev); + } + break; + + case 9: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit root dest not reg.\n"); + priv->bad += 1; + priv->reset = 1; + //arlan_drop_tx(dev); + arlan_queue_retransmit(dev); + } + break; + + default: + { + printk(KERN_ERR "arlan intr: transmit status unknown\n"); + priv->bad += 1; + priv->reset = 1; + arlan_drop_tx(dev); + } + } + + ARLAN_DEBUG_EXIT("arlan_tx_done_interrupt"); +} + + +static void arlan_rx_interrupt(struct device *dev, u_char rxStatus, u_short rxOffset, u_short pkt_len) +{ + char *skbtmp; + int i = 0; + + struct arlan_private *priv = (struct arlan_private *) dev->priv; + volatile struct arlan_shmem *arlan = priv->card; + struct arlan_conf_stru *conf = priv->Conf; + + + ARLAN_DEBUG_ENTRY("arlan_rx_interrupt"); + // by spec, not WRITESHMB(arlan->rxStatus,0x00); + // prohibited here arlan_command(dev, ARLAN_COMMAND_RX); + + if (pkt_len < 10 || pkt_len > 2048) + { + printk(KERN_WARNING "%s: got too short or long packet, len %d \n", dev->name, pkt_len); + return; + } + if (rxOffset + pkt_len > 0x2000) + { + printk("%s: got too long packet, len %d offset %x\n", dev->name, pkt_len, rxOffset); + return; + } + priv->in_bytes += pkt_len; + priv->in_bytes10 += pkt_len; + if (conf->measure_rate < 1) + conf->measure_rate = 1; + if (jiffies - priv->in_time > conf->measure_rate * HZ) + { + conf->in_speed = priv->in_bytes / conf->measure_rate; + priv->in_bytes = 0; + priv->in_time = jiffies; + } + if (jiffies - priv->in_time10 > conf->measure_rate * HZ * 10) + { + conf->in_speed10 = priv->in_bytes10 / (10 * conf->measure_rate); + priv->in_bytes10 = 0; + priv->in_time10 = jiffies; + } + DEBUGSHM(1, "arlan rcv pkt rxStatus= %d ", arlan->rxStatus, u_char); + switch (rxStatus) + { + case 1: + case 2: + case 3: + { + /* Malloc up new buffer. */ + struct sk_buff *skb; + + DEBUGSHM(50, "arlan recv pkt offs=%d\n", arlan->rxOffset, u_short); + DEBUGSHM(1, "arlan rxFrmType = %d \n", arlan->rxFrmType, u_char); + DEBUGSHM(1, KERN_INFO "arlan rx scrambled = %d \n", arlan->scrambled, u_char); + + /* here we do multicast filtering to avoid slow 8-bit memcopy */ +#ifdef ARLAN_MULTICAST + if (!(dev->flags & IFF_ALLMULTI) && + !(dev->flags & IFF_PROMISC) && + dev->mc_list) + { + char hw_dst_addr[6]; + struct dev_mc_list *dmi = dev->mc_list; + int i; + + memcpy_fromio(hw_dst_addr, arlan->ultimateDestAddress, 6); + if (hw_dst_addr[0] == 0x01) + { + if (mdebug) + if (hw_dst_addr[1] == 0x00) + printk(KERN_ERR "%s mcast 0x0100 \n", dev->name); + else if (hw_dst_addr[1] == 0x40) + printk(KERN_ERR "%s m/bcast 0x0140 \n", dev->name); + while (dmi) + { if (dmi->dmi_addrlen == 6) + { + if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP) + printk(KERN_ERR "%s mcl %2x:%2x:%2x:%2x:%2x:%2x \n", dev->name, + dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], + dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]); + for (i = 0; i < 6; i++) + if (dmi->dmi_addr[i] != hw_dst_addr[i]) + break; + if (i == 6) + break; + } + else + printk(KERN_ERR "%s: invalid multicast address length given.\n", dev->name); + dmi = dmi->next; + } + /* we reach here if multicast filtering is on and packet + * is multicast and not for receive */ + goto end_of_interupt; + } + } +#endif // ARLAN_MULTICAST + /* multicast filtering ends here */ + pkt_len += ARLAN_FAKE_HDR_LEN; + + skb = dev_alloc_skb(pkt_len + 4); + if (skb == NULL) + { + printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name); + priv->stats.rx_dropped++; + break; + } + skb_reserve(skb, 2); + skb->dev = dev; + skbtmp = skb_put(skb, pkt_len); + + memcpy_fromio(skbtmp + ARLAN_FAKE_HDR_LEN, ((char *) arlan) + rxOffset, pkt_len - ARLAN_FAKE_HDR_LEN); + memcpy_fromio(skbtmp, arlan->ultimateDestAddress, 6); + memcpy_fromio(skbtmp + 6, arlan->rxSrc, 6); + WRITESHMB(arlan->rxStatus, 0x00); + arlan_command(dev, ARLAN_COMMAND_RX); + + IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) + { + char immedDestAddress[6]; + char immedSrcAddress[6]; + memcpy_fromio(immedDestAddress, arlan->immedDestAddress, 6); + memcpy_fromio(immedSrcAddress, arlan->immedSrcAddress, 6); + + printk(KERN_WARNING "%s t %2x:%2x:%2x:%2x:%2x:%2x f %2x:%2x:%2x:%2x:%2x:%2x imd %2x:%2x:%2x:%2x:%2x:%2x ims %2x:%2x:%2x:%2x:%2x:%2x\n", dev->name, + (unsigned char) skbtmp[0], (unsigned char) skbtmp[1], (unsigned char) skbtmp[2], (unsigned char) skbtmp[3], + (unsigned char) skbtmp[4], (unsigned char) skbtmp[5], (unsigned char) skbtmp[6], (unsigned char) skbtmp[7], + (unsigned char) skbtmp[8], (unsigned char) skbtmp[9], (unsigned char) skbtmp[10], (unsigned char) skbtmp[11], + immedDestAddress[0], immedDestAddress[1], immedDestAddress[2], + immedDestAddress[3], immedDestAddress[4], immedDestAddress[5], + immedSrcAddress[0], immedSrcAddress[1], immedSrcAddress[2], + immedSrcAddress[3], immedSrcAddress[4], immedSrcAddress[5]); + } + skb->protocol = eth_type_trans(skb, dev); + IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) + if (skb->protocol != 0x608 && skb->protocol != 0x8) + { + for (i = 0; i <= 22; i++) + printk("%02x:", (u_char) skbtmp[i + 12]); + printk(KERN_ERR "\n"); + printk(KERN_WARNING "arlan kernel pkt type trans %x \n", skb->protocol); + } + netif_rx(skb); + priv->stats.rx_packets++; + } + break; + + default: + printk(KERN_ERR "arlan intr: recieved unknown status\n"); + priv->stats.rx_crc_errors++; + break; + } + ARLAN_DEBUG_EXIT("arlan_rx_interrupt"); +} + +static void arlan_process_interrupt(struct device *dev) +{ + struct arlan_private *priv = (struct arlan_private *) dev->priv; + volatile struct arlan_shmem *arlan = priv->card; + u_char rxStatus = READSHMB(arlan->rxStatus); + u_char txStatus = READSHMB(arlan->txStatus); + u_short rxOffset = READSHMS(arlan->rxOffset); + u_short pkt_len = READSHMS(arlan->rxLength); + int interrupt_count = 0; + + ARLAN_DEBUG_ENTRY("arlan_process_interrupt"); + + if (test_and_set_bit(0, (void *) &priv->interrupt_processing_active)) + { + if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) + printk(KERN_ERR "interrupt chain reentering \n"); + goto end_int_process; + } + while ((rxStatus || txStatus || priv->interrupt_ack_requested) + && (interrupt_count < 5)) + { + if (rxStatus) + priv->last_rx_int_ack_time = arlan_time(); + + arlan_command(dev, ARLAN_COMMAND_INT_ACK); + arlan_command(dev, ARLAN_COMMAND_INT_ENABLE); + + IFDEBUG(ARLAN_DEBUG_INTERRUPT) + printk(KERN_ERR "%s: got IRQ rx %x tx %x comm %x rxOff %x rxLen %x \n", + dev->name, rxStatus, txStatus, READSHMB(arlan->commandByte), + rxOffset, pkt_len); + + if (rxStatus == 0 && txStatus == 0) + { + priv->last_command_was_rx = 0; + if (priv->irq_test_done) + { + if (!registrationBad(dev)) + IFDEBUG(ARLAN_DEBUG_INTERRUPT) printk(KERN_ERR "%s unknown interrupt(nop? regLost ?) reason tx %d rx %d ", + dev->name, txStatus, rxStatus); + } else { + IFDEBUG(ARLAN_DEBUG_INTERRUPT) + printk(KERN_INFO "%s irq $%d test OK \n", dev->name, dev->irq); + + } + priv->interrupt_ack_requested = 0; + goto ends; + } + if (txStatus != 0) + { + WRITESHMB(arlan->txStatus, 0x00); + arlan_tx_done_interrupt(dev, txStatus); + goto ends; + } + if (rxStatus == 1 || rxStatus == 2) + { /* a packet waiting */ + arlan_rx_interrupt(dev, rxStatus, rxOffset, pkt_len); + goto ends; + } + if (rxStatus > 2 && rxStatus < 0xff) + { + priv->last_command_was_rx = 0; + WRITESHMB(arlan->rxStatus, 0x00); + printk(KERN_ERR "%s unknown rxStatus reason tx %d rx %d ", + dev->name, txStatus, rxStatus); + goto ends; + } + if (rxStatus == 0xff) + { + priv->last_command_was_rx = 0; + WRITESHMB(arlan->rxStatus, 0x00); + arlan_command(dev, ARLAN_COMMAND_RX); + if (registrationBad(dev)) + dev->start = 0; + if (!registrationBad(dev)) + { + priv->registrationLastSeen = jiffies; + if (!dev->tbusy && !priv->under_reset && !priv->under_config) + { + mark_bh(NET_BH); + dev->start = 1; + } + } + goto ends; + } +ends: + + arlan_command_process(dev); + + rxStatus = READSHMB(arlan->rxStatus); + txStatus = READSHMB(arlan->txStatus); + rxOffset = READSHMS(arlan->rxOffset); + pkt_len = READSHMS(arlan->rxLength); + + + priv->irq_test_done = 1; + + interrupt_count++; + } + priv->interrupt_processing_active = 0; + +end_int_process: + arlan_command_process(dev); + + ARLAN_DEBUG_EXIT("arlan_process_interrupt"); + return; +} + +static void arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = dev_id; + struct arlan_private *priv = (struct arlan_private *) dev->priv; + volatile struct arlan_shmem *arlan = priv->card; + u_char rxStatus = READSHMB(arlan->rxStatus); + u_char txStatus = READSHMB(arlan->txStatus); + + ARLAN_DEBUG_ENTRY("arlan_interrupt"); + + + if (!rxStatus && !txStatus) + priv->interrupt_ack_requested++; + dev->interrupt++; + + arlan_process_interrupt(dev); + + priv->irq_test_done = 1; + dev->interrupt--; + + ARLAN_DEBUG_EXIT("arlan_interrupt"); + return; + +} + + +static int arlan_close(struct device *dev) +{ + struct arlan_private *priv = (struct arlan_private *) dev->priv; + + if (!dev) + { + printk(KERN_CRIT "arlan: No Device\n"); + return 0; + } + priv = (struct arlan_private *) dev->priv; + if (!priv) + { + printk(KERN_CRIT "arlan: No Device priv \n"); + return 0; + } + ARLAN_DEBUG_ENTRY("arlan_close"); + + IFDEBUG(ARLAN_DEBUG_STARTUP) + printk(KERN_NOTICE "%s: Closing device\n", dev->name); + + priv->open_time = 0; + dev->tbusy = 1; + dev->start = 0; + del_timer(&priv->timer); + free_irq(dev->irq, dev); + + MOD_DEC_USE_COUNT; + + ARLAN_DEBUG_EXIT("arlan_close"); + return 0; +} + + +static long alignLong(volatile u_char * ptr) +{ + long ret; + memcpy_fromio(&ret, (void *) ptr, 4); + return ret; +} + + +/* + * Get the current statistics. + * This may be called with the card open or closed. + */ + +static struct enet_statistics *arlan_statistics(struct device *dev) +{ + struct arlan_private *priv = (struct arlan_private *) dev->priv; + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + + + ARLAN_DEBUG_ENTRY("arlan_statistics"); + + /* Update the statistics from the device registers. */ + + READSHM(priv->stats.collisions, arlan->numReTransmissions, u_int); + READSHM(priv->stats.rx_crc_errors, arlan->numCRCErrors, u_int); + READSHM(priv->stats.rx_dropped, arlan->numFramesDiscarded, u_int); + READSHM(priv->stats.rx_fifo_errors, arlan->numRXBufferOverflows, u_int); + READSHM(priv->stats.rx_frame_errors, arlan->numReceiveFramesLost, u_int); + READSHM(priv->stats.rx_over_errors, arlan->numRXOverruns, u_int); + READSHM(priv->stats.rx_packets, arlan->numDatagramsReceived, u_int); + READSHM(priv->stats.tx_aborted_errors, arlan->numAbortErrors, u_int); + READSHM(priv->stats.tx_carrier_errors, arlan->numStatusTimeouts, u_int); + READSHM(priv->stats.tx_dropped, arlan->numDatagramsDiscarded, u_int); + READSHM(priv->stats.tx_fifo_errors, arlan->numTXUnderruns, u_int); + READSHM(priv->stats.tx_packets, arlan->numDatagramsTransmitted, u_int); + READSHM(priv->stats.tx_window_errors, arlan->numHoldOffs, u_int); + + ARLAN_DEBUG_EXIT("arlan_statistics"); + + return &priv->stats; +} + + +static void arlan_set_multicast(struct device *dev) +{ + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf; + int board_conf_needed = 0; + + + ARLAN_DEBUG_ENTRY("arlan_set_multicast"); + + if (dev->flags & IFF_PROMISC) + { + unsigned char recMode; + READSHM(recMode, arlan->receiveMode, u_char); + conf->receiveMode = (ARLAN_RCV_PROMISC | ARLAN_RCV_CONTROL); + if (conf->receiveMode != recMode) + board_conf_needed = 1; + } + else + { + /* turn off promiscuous mode */ + unsigned char recMode; + READSHM(recMode, arlan->receiveMode, u_char); + conf->receiveMode = ARLAN_RCV_CLEAN | ARLAN_RCV_CONTROL; + if (conf->receiveMode != recMode) + board_conf_needed = 1; + } + if (board_conf_needed) + arlan_command(dev, ARLAN_COMMAND_CONF); + + ARLAN_DEBUG_EXIT("arlan_set_multicast"); +} + + +__initfunctio(int arlan_probe(struct device *dev)) +{ + printk("Arlan driver %s\n", arlan_version); + + if (arlan_probe_everywhere(dev)) + return ENODEV; + + arlans_found++; + + if (arlans_found == 1) + siteName = kmalloc(100, GFP_KERNEL); + return 0; +} + +#ifdef MODULE + +int init_module(void) +{ + int i = 0; + + ARLAN_DEBUG_ENTRY("init_module"); + + if (channelSet != channelSetUNKNOWN || channelNumber != channelNumberUNKNOWN || systemId != systemIdUNKNOWN) + { + printk(KERN_WARNING "arlan: wrong module params for multiple devices\n "); + return -1; + } + numDevices = arlan_find_devices(); + if (numDevices == 0) + { + printk(KERN_ERR "arlan: no devices found \n"); + return -1; + } + + siteName = kmalloc(100, GFP_KERNEL); + if(siteName==NULL) + { + printk(KERN_ERR "arlan: No memory for site name.\n"); + return -1; + } + for (i = 0; i < numDevices && i < MAX_ARLANS; i++) + { + if (!arlan_allocate_device(i, NULL)) + return -1; + if (arlan_device[i] == NULL) + { + printk(KERN_CRIT "arlan: Not Enough memory \n"); + return -1; + } + if (probe) + arlan_probe_everywhere(arlan_device[i]); + } + printk(KERN_INFO "Arlan driver %s\n", arlan_version); + ARLAN_DEBUG_EXIT("init_module"); + return 0; +} + + +void cleanup_module(void) +{ + int i = 0; + + ARLAN_DEBUG_ENTRY("cleanup_module"); + + IFDEBUG(ARLAN_DEBUG_SHUTDOWN) + printk(KERN_INFO "arlan: unloading module\n"); + for (i = 0; i < MAX_ARLANS; i++) + { + if (arlan_device[i]) + { + unregister_netdev(arlan_device[i]); + if (arlan_device[i]->priv) + { + if (((struct arlan_private *) arlan_device[i]->priv)->conf) + kfree(((struct arlan_private *) arlan_device[i]->priv)->conf); + kfree(arlan_device[i]); + } + arlan_device[i] = NULL; + } + } + ARLAN_DEBUG_EXIT("cleanup_module"); +} + + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/arlan.h linux.ac/drivers/net/arlan.h --- linux.vanilla/drivers/net/arlan.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/arlan.h Tue Jun 15 17:47:45 1999 @@ -0,0 +1,574 @@ +/* + * Copyright (C) 1997 Cullen Jennings + * Copyright (C) 1998 Elmer.Joandi@ut.ee, +37-255-13500 + * Gnu Public License applies + */ +#include + +#include +#include +#include +#include +#include +#include /* For the statistics structure. */ +#include /* For ARPHRD_ETHER */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define DEBUG 1 + +#define ARLAN_PROC_INTERFACE +#define MAX_ARLANS 4 /* not more than 4 ! */ +#define ARLAN_PROC_SHM_DUMP /* shows all card registers, makes driver way larger */ + +#define ARLAN_MAX_MULTICAST_ADDRS 16 +#define ARLAN_RCV_CLEAN 0 +#define ARLAN_RCV_PROMISC 1 +#define ARLAN_RCV_CONTROL 2 + + +#ifdef CONFIG_PROC_FS +extern int init_arlan_proc(void); +#endif + +extern struct device *arlan_device[MAX_ARLANS]; +static int arlan_debug; +static char * siteName; +static int arlan_entry_debug; +static int arlan_exit_debug; +static int arlan_entry_and_exit_debug; +static int testMemory; +static const char* arlan_version; + +#define SIDUNKNOWN -1 +#define radioNodeIdUNKNOWN -1 +#define encryptionKeyUNKNOWN '\0'; +#define irqUNKNOWN 0 +#define memUNKNOWN 0 +#define debugUNKNOWN 0 +#define probeUNKNOWN 1 +#define numDevicesUNKNOWN 1 +#define testMemoryUNKNOWN 1 +#define spreadingCodeUNKNOWN 0 +#define channelNumberUNKNOWN 0 +#define channelSetUNKNOWN 0 +#define systemIdUNKNOWN -1 +#define registrationModeUNKNOWN -1 +#define siteNameUNKNOWN "LinuxSite" + + + +#define IFDEBUG( L ) if ( (L) & arlan_debug ) +#define ARLAN_FAKE_HDR_LEN 12 + +#ifdef DEBUG + #define ARLAN_ENTRY_EXIT_DEBUGING 1 + #define ARLAN_DEBUG(a,b) printk(KERN_DEBUG a, b) +#else + #define ARLAN_DEBUG(a,b) +#endif + +struct arlan_shmem +{ + /* Header Signature */ + volatile char textRegion[48]; + volatile u_char resetFlag; + volatile u_char diagnosticInfo; + volatile u_short diagnosticOffset; + volatile u_char _1[12]; + volatile u_char lanCardNodeId[6]; + volatile u_char broadcastAddress[6]; + volatile u_char hardwareType; + volatile u_char majorHardwareVersion; + volatile u_char minorHardwareVersion; + volatile u_char radioModule;// shows EEPROM, can be overridden at 0x111 + volatile u_char defaultChannelSet; // shows EEProm, can be overriiden at 0x10A + volatile u_char _2[47]; + + /* Control/Status Block - 0x0080 */ + volatile u_char interruptInProgress; /* not used by lancpu */ + volatile u_char cntrlRegImage; /* not used by lancpu */ + volatile u_char _3[13]; + volatile u_char dumpByte; + volatile u_char commandByte; /* non-zero = active */ + volatile u_char commandParameter[15]; + + /* Receive Status - 0x00a0 */ + volatile u_char rxStatus; /* 1- data, 2-control, 0xff - registr change */ + volatile u_char rxFrmType; + volatile u_short rxOffset; + volatile u_short rxLength; + volatile u_char rxSrc[6]; + volatile u_char rxBroadcastFlag; + volatile u_char rxQuality; + volatile u_char scrambled; + volatile u_char _4[1]; + + /* Transmit Status - 0x00b0 */ + volatile u_char txStatus; + volatile u_char txAckQuality; + volatile u_char numRetries; + volatile u_char _5[14]; + volatile u_char registeredRouter[6]; + volatile u_char backboneRouter[6]; + volatile u_char registrationStatus; + volatile u_char configuredStatusFlag; + volatile u_char _6[1]; + volatile u_char ultimateDestAddress[6]; + volatile u_char immedDestAddress[6]; + volatile u_char immedSrcAddress[6]; + volatile u_short rxSequenceNumber; + volatile u_char assignedLocaltalkAddress; + volatile u_char _7[27]; + + /* System Parameter Block */ + + /* - Driver Parameters (Novell Specific) */ + + volatile u_short txTimeout; + volatile u_short transportTime; + volatile u_char _8[4]; + + /* - Configuration Parameters */ + volatile u_char irqLevel; + volatile u_char spreadingCode; + volatile u_char channelSet; + volatile u_char channelNumber; + volatile u_short radioNodeId; + volatile u_char _9[2]; + volatile u_char scramblingDisable; + volatile u_char radioType; + volatile u_short routerId; + volatile u_char _10[9]; + volatile u_char txAttenuation; + volatile u_char systemId[4]; + volatile u_short globalChecksum; + volatile u_char _11[4]; + volatile u_short maxDatagramSize; + volatile u_short maxFrameSize; + volatile u_char maxRetries; + volatile u_char receiveMode; + volatile u_char priority; + volatile u_char rootOrRepeater; + volatile u_char specifiedRouter[6]; + volatile u_short fastPollPeriod; + volatile u_char pollDecay; + volatile u_char fastPollDelay[2]; + volatile u_char arlThreshold; + volatile u_char arlDecay; + volatile u_char _12[1]; + volatile u_short specRouterTimeout; + volatile u_char _13[5]; + + /* Scrambled Area */ + volatile u_char SID[4]; + volatile u_char encryptionKey[12]; + volatile u_char _14[2]; + volatile u_char waitTime[2]; + volatile u_char lParameter[2]; + volatile u_char _15[3]; + volatile u_short headerSize; + volatile u_short sectionChecksum; + + volatile u_char registrationMode; + volatile u_char registrationFill; + volatile u_short pollPeriod; + volatile u_short refreshPeriod; + volatile u_char name[16]; + volatile u_char NID[6]; + volatile u_char localTalkAddress; + volatile u_char codeFormat; + volatile u_char numChannels; + volatile u_char channel1; + volatile u_char channel2; + volatile u_char channel3; + volatile u_char channel4; + volatile u_char SSCode[59]; + + volatile u_char _16[0xC0]; + volatile u_short auxCmd; + volatile u_char dumpPtr[4]; + volatile u_char dumpVal; + volatile u_char _17[0x6A]; + volatile u_char wireTest; + volatile u_char _18[14]; + + /* Statistics Block - 0x0300 */ + volatile u_char hostcpuLock; + volatile u_char lancpuLock; + volatile u_char resetTime[18]; + + volatile u_char numDatagramsTransmitted[4]; + volatile u_char numReTransmissions[4]; + volatile u_char numFramesDiscarded[4]; + volatile u_char numDatagramsReceived[4]; + volatile u_char numDuplicateReceivedFrames[4]; + volatile u_char numDatagramsDiscarded[4]; + + volatile u_short maxNumReTransmitDatagram; + volatile u_short maxNumReTransmitFrames; + volatile u_short maxNumConsecutiveDuplicateFrames; + /* misaligned here so we have to go to characters */ + + volatile u_char numBytesTransmitted[4]; + volatile u_char numBytesReceived[4]; + volatile u_char numCRCErrors[4]; + volatile u_char numLengthErrors[4]; + volatile u_char numAbortErrors[4]; + volatile u_char numTXUnderruns[4]; + volatile u_char numRXOverruns[4]; + volatile u_char numHoldOffs[4]; + volatile u_char numFramesTransmitted[4]; + volatile u_char numFramesReceived[4]; + volatile u_char numReceiveFramesLost[4]; + volatile u_char numRXBufferOverflows[4]; + volatile u_char numFramesDiscardedAddrMismatch[4]; + volatile u_char numFramesDiscardedSIDMismatch[4]; + volatile u_char numPollsTransmistted[4]; + volatile u_char numPollAcknowledges[4]; + volatile u_char numStatusTimeouts[4]; + volatile u_char numNACKReceived[4]; + + volatile u_char _19[0x86]; + + volatile u_char txBuffer[0x800]; + volatile u_char rxBuffer[0x800]; + + volatile u_char _20[0x800]; + volatile u_char _21[0x3fb]; + volatile u_char configStatus; + volatile u_char _22; + volatile u_char progIOCtrl; + volatile u_char shareMBase; + volatile u_char controlRegister; +}; + +struct arlan_conf_stru { + int spreadingCode; + int channelSet; + int channelNumber; + int scramblingDisable; + int txAttenuation; + int systemId; + int maxDatagramSize; + int maxFrameSize; + int maxRetries; + int receiveMode; + int priority; + int rootOrRepeater; + int SID; + int radioNodeId; + int registrationMode; + int registrationFill; + int localTalkAddress; + int codeFormat; + int numChannels; + int channel1; + int channel2; + int channel3; + int channel4; + int txClear; + int txRetries; + int txRouting; + int txScrambled; + int rxParameter; + int txTimeoutMs; + int txAckTimeoutMs; + int waitCardTimeout; + int waitTime; + int lParameter; + int _15; + int headerSize; + int async; + int retries; + int tx_delay_ms; + int waitReTransmitPacketMaxSize; + int ReTransmitPacketMaxSize; + int fastReTransCount; + int driverRetransmissions; + int registrationInterrupts; + int hardwareType; + int radioType; + int writeRadioType; + int writeEEPROM; + char siteName[17]; + int measure_rate; + int in_speed; + int out_speed; + int in_speed10; + int out_speed10; + int in_speed_max; + int out_speed_max; + int pre_Command_Wait; + int rx_tweak1; + int rx_tweak2; + int tx_queue_len; +}; + +struct arlan_conf_stru arlan_conf[MAX_ARLANS]; + +struct TxParam +{ + volatile short offset; + volatile short length; + volatile u_char dest[6]; + volatile unsigned char clear; + volatile unsigned char retries; + volatile unsigned char routing; + volatile unsigned char scrambled; +}; + +struct TxRingPoint { + struct TxParam txParam; + + +}; + +#define TX_RING_SIZE 2 +/* Information that need to be kept for each board. */ +struct arlan_private { + struct enet_statistics stats; + long open_time; /* Useless example local info. */ + struct arlan_shmem * card; + struct arlan_shmem * conf; + struct TxParam txParam; + int multicastLength; + char multicastList[ARLAN_MAX_MULTICAST_ADDRS][6]; + int promiscModeEnabled; + struct arlan_conf_stru * Conf; + int bad; + int reset; + long long lastReset; + struct timer_list timer; + struct timer_list tx_delay_timer; + struct timer_list tx_retry_timer; + struct timer_list rx_check_timer; + struct semaphore card_lock; + atomic_t card_users; + atomic_t delay_on; + atomic_t retr_on; + int registrationLostCount; + int reRegisterExp; + int nof_tx; + int nof_tx_ack; + int last_nof_tx; + int last_nof_tx_ack; + int irq_test_done; + int last_command_was_rx; + struct TxParam txRing[TX_RING_SIZE]; + char reTransmitBuff[0x800]; + volatile int txLast; + volatile int txNew; + volatile int txOffset; + volatile char ReTransmitRequested; + volatile long long tx_done_delayed; + volatile long long registrationLastSeen; + volatile char under_command; + volatile char under_toggle; + volatile long long tx_last_sent; + volatile long long tx_last_cleared; + volatile u_char under_tx; + volatile int retransmissions; + volatile int tx_chain_active; + volatile int timer_chain_active; + volatile int interrupt_ack_requested; + volatile int command_lock; + volatile int rx_command_needed; + volatile int tx_command_needed; + volatile int waiting_command_mask; + volatile int card_polling_interval; + volatile int last_command_buff_free_time; + volatile int numResets; + volatile int under_reset; + volatile int under_config; + volatile int rx_command_given; + volatile int tx_command_given; + volatile int interrupt_processing_active; + volatile long long last_tx_time; + volatile long long last_rx_time; + volatile long long last_rx_int_ack_time; + int in_bytes; + int out_bytes; + int in_time; + int out_time; + int in_time10; + int out_time10; + int in_bytes10; + int out_bytes10; +}; + + + +#define ARLAN_CLEAR 0x00 +#define ARLAN_RESET 0x01 +#define ARLAN_CHANNEL_ATTENTION 0x02 +#define ARLAN_INTERRUPT_ENABLE 0x04 +#define ARLAN_CLEAR_INTERRUPT 0x08 +#define ARLAN_POWER 0x40 +#define ARLAN_ACCESS 0x80 + +#define ARLAN_COM_CONF 0x01 +#define ARLAN_COM_RX_ENABLE 0x03 +#define ARLAN_COM_RX_ABORT 0x04 +#define ARLAN_COM_TX_ENABLE 0x05 +#define ARLAN_COM_TX_ABORT 0x06 +#define ARLAN_COM_NOP 0x07 +#define ARLAN_COM_STANDBY 0x08 +#define ARLAN_COM_ACTIVATE 0x09 +#define ARLAN_COM_GOTO_SLOW_POLL 0x0a +#define ARLAN_COM_INT 0x80 + + +#define TXLAST(dev) (((struct arlan_private *)dev->priv)->txRing[((struct arlan_private *)dev->priv)->txLast]) +#define TXHEAD(dev) (((struct arlan_private *)dev->priv)->txRing[0]) +#define TXTAIL(dev) (((struct arlan_private *)dev->priv)->txRing[1]) + +#define TXBuffStart(dev) \ + ((int)(((struct arlan_private *)dev->priv)->card)->txBuffer) - ((int)(((struct arlan_private *)dev->priv)->card) ) +#define TXBuffEnd(dev) \ + ((int)(((struct arlan_private *)dev->priv)->card)->rxBuffer) - ((int)(((struct arlan_private *)dev->priv)->card) + +#define READSHM(to,from,atype) {\ + atype tmp;\ + memcpy_fromio(&(tmp),&(from),sizeof(atype));\ + to = tmp;\ + } + +#define READSHMEM(from,atype)\ + atype from; \ + READSHM(from, arlan->from, atype); + +#define WRITESHM(to,from,atype) \ + { atype tmpSHM = from;\ + memcpy_toio(&(to),&tmpSHM,sizeof(atype));\ + } + +#define DEBUGSHM(levelSHM,stringSHM,stuff,atype) \ + { atype tmpSHM; \ + memcpy_fromio(&tmpSHM,&(stuff),sizeof(atype));\ + IFDEBUG(levelSHM) printk(stringSHM,tmpSHM);\ + } + +#define WRITESHMB(to, val) \ + writeb(val,&(to)) +#define READSHMB(to) \ + readb(&(to)) +#define WRITESHMS(to, val) \ + writew(val,&(to)) +#define READSHMS(to) \ + readw(&(to)) +#define WRITESHMI(to, val) \ + writel(val,&(to)) +#define READSHMI(to) \ + readl(&(to)) + + + + + +#define registrationBad(dev)\ + ( ( READSHMB(((struct arlan_private *)dev->priv)->card->registrationMode) > 0) && \ + ( READSHMB(((struct arlan_private *)dev->priv)->card->registrationStatus) == 0) ) + + +#define readControlRegister(dev)\ + READSHMB(((struct arlan_private *)dev->priv)->card->cntrlRegImage) + +#define writeControlRegister(dev, v){\ + WRITESHMB(((struct arlan_private *)dev->priv)->card->cntrlRegImage ,((v) &0xF) );\ + WRITESHMB(((struct arlan_private *)dev->priv)->card->controlRegister ,(v) );} + + +#define arlan_interrupt_lancpu(dev) {\ + int cr; \ + \ + priv->under_toggle++; \ + cr = readControlRegister(dev);\ + if (cr & ARLAN_CHANNEL_ATTENTION){ \ + writeControlRegister(dev, (cr & ~ARLAN_CHANNEL_ATTENTION));\ + }else \ + writeControlRegister(dev, (cr | ARLAN_CHANNEL_ATTENTION));\ + priv->under_toggle=0; \ +} + +#define clearChannelAttention(dev){ \ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_CHANNEL_ATTENTION);} +#define setHardwareReset(dev) {\ + writeControlRegister(dev,readControlRegister(dev) | ARLAN_RESET);} +#define clearHardwareReset(dev) {\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_RESET);} +#define setInterruptEnable(dev){\ + writeControlRegister(dev,readControlRegister(dev) | ARLAN_INTERRUPT_ENABLE) ;} +#define clearInterruptEnable(dev){\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_INTERRUPT_ENABLE) ;} +#define setClearInterrupt(dev){\ + writeControlRegister(dev,readControlRegister(dev) | ARLAN_CLEAR_INTERRUPT) ;} +#define clearClearInterrupt(dev){\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_CLEAR_INTERRUPT);} +#define setPowerOff(dev){\ + writeControlRegister(dev,readControlRegister(dev) | (ARLAN_POWER && ARLAN_ACCESS));\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_ACCESS);} +#define setPowerOn(dev){\ + writeControlRegister(dev,readControlRegister(dev) & ~(ARLAN_POWER)); } +#define arlan_lock_card_access(dev){\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_ACCESS);} +#define arlan_unlock_card_access(dev){\ + writeControlRegister(dev,readControlRegister(dev) | ARLAN_ACCESS ); } + + + + +#define ARLAN_COMMAND_RX 0x00001 +#define ARLAN_COMMAND_NOOP 0x00002 +#define ARLAN_COMMAND_NOOPINT 0x00004 +#define ARLAN_COMMAND_TX 0x00008 +#define ARLAN_COMMAND_CONF 0x00010 +#define ARLAN_COMMAND_RESET 0x00020 +#define ARLAN_COMMAND_TX_ABORT 0x00040 +#define ARLAN_COMMAND_RX_ABORT 0x00080 +#define ARLAN_COMMAND_POWERDOWN 0x00100 +#define ARLAN_COMMAND_POWERUP 0x00200 +#define ARLAN_COMMAND_SLOW_POLL 0x00400 +#define ARLAN_COMMAND_ACTIVATE 0x00800 +#define ARLAN_COMMAND_INT_ACK 0x01000 +#define ARLAN_COMMAND_INT_ENABLE 0x02000 +#define ARLAN_COMMAND_WAIT_NOW 0x04000 +#define ARLAN_COMMAND_LONG_WAIT_NOW 0x08000 +#define ARLAN_COMMAND_STANDBY 0x10000 +#define ARLAN_COMMAND_INT_RACK 0x20000 +#define ARLAN_COMMAND_INT_RENABLE 0x40000 +#define ARLAN_COMMAND_CONF_WAIT 0x80000 +#define ARLAN_COMMAND_CLEAN_AND_CONF (ARLAN_COMMAND_TX_ABORT\ + | ARLAN_COMMAND_RX_ABORT\ + | ARLAN_COMMAND_CONF) +#define ARLAN_COMMAND_CLEAN_AND_RESET (ARLAN_COMMAND_TX_ABORT\ + | ARLAN_COMMAND_RX_ABORT\ + | ARLAN_COMMAND_RESET) + + + +#define ARLAN_DEBUG_CHAIN_LOCKS 0x00001 +#define ARLAN_DEBUG_RESET 0x00002 +#define ARLAN_DEBUG_TIMING 0x00004 +#define ARLAN_DEBUG_CARD_STATE 0x00008 +#define ARLAN_DEBUG_TX_CHAIN 0x00010 +#define ARLAN_DEBUG_MULTICAST 0x00020 +#define ARLAN_DEBUG_HEADER_DUMP 0x00040 +#define ARLAN_DEBUG_INTERRUPT 0x00080 +#define ARLAN_DEBUG_STARTUP 0x00100 +#define ARLAN_DEBUG_SHUTDOWN 0x00200 + \ No newline at end of file diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/lne390.c linux.ac/drivers/net/lne390.c --- linux.vanilla/drivers/net/lne390.c Tue Dec 22 23:19:46 1998 +++ linux.ac/drivers/net/lne390.c Mon Jun 7 01:13:17 1999 @@ -316,6 +316,15 @@ lne390_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page) { unsigned long hdr_start = dev->mem_start + ((ring_page - LNE390_START_PG)<<8); +#ifdef CONFIG_ALPHA_JENSEN + if (((long)hdr&3)!=0) + { + memcpy_fromio_g32a(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); + hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */ + return; + } +#endif + memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */ } @@ -331,6 +340,25 @@ { unsigned long xfer_start = dev->mem_start + ring_offset - (LNE390_START_PG<<8); +#ifdef CONFIG_ALPHA_JENSEN + if (((long)skb->data&3)!=0) + { + if (xfer_start + count > dev->rmem_end) { + /* Packet wraps over end of ring buffer. */ + int semi_count = dev->rmem_end - xfer_start; + memcpy_fromio_g32a(skb->data, xfer_start, semi_count); + count -= semi_count; + memcpy_fromio_g32a(skb->data + semi_count, dev->rmem_start, count); + } else { + /* Packet is in one chunk. */ + memcpy_fromio_g32a(skb->data, xfer_start, count); + } + return; + } +#endif + + /* printk("%s: lne390_block_input is called with unaligned buffer!\n", dev->name); */ + if (xfer_start + count > dev->rmem_end) { /* Packet wraps over end of ring buffer. */ int semi_count = dev->rmem_end - xfer_start; @@ -349,6 +377,15 @@ unsigned long shmem = dev->mem_start + ((start_page - LNE390_START_PG)<<8); count = (count + 3) & ~3; /* Round up to doubleword */ + /* printk ("%s: lne390_block_output is called!", dev->name); */ + +#ifdef CONFIG_ALPHA_JENSEN + if (((long)buf&3)!=0) { + memcpy_toio_g32a(shmem, buf, count); + return; + } +#endif + memcpy_toio(shmem, buf, count); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/olympic.c linux.ac/drivers/net/olympic.c --- linux.vanilla/drivers/net/olympic.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/olympic.c Wed Jun 9 20:08:19 1999 @@ -0,0 +1,1661 @@ +/* + * 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 + * + * 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.2.0 6/8/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 device *dev); +static int olympic_init(struct device *dev); +static int olympic_open(struct device *dev); +static int olympic_xmit(struct sk_buff *skb, struct device *dev); +static int olympic_close(struct device *dev); +static void olympic_set_rx_mode(struct device *dev); +static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static struct net_device_stats * olympic_get_stats(struct device *dev); +static int olympic_set_mac_address(struct device *dev, void *addr) ; +static void olympic_arb_cmd(struct device *dev); +static int olympic_change_mtu(struct device *dev, int mtu); +static void olympic_srb_bh(struct device *dev) ; +static void olympic_asb_bh(struct device *dev) ; +#if OLYMPIC_NETWORK_MONITOR +#ifdef CONFIG_PROC_FS +static int sprintf_info(char *buffer, struct device *dev) ; +#endif +#endif + +__initfunc(int olympic_probe(struct device *dev)) +{ + int cards_found; + + cards_found=olympic_scan(dev); + return cards_found ? 0 : -ENODEV; +} + +__initfunc(static int olympic_scan(struct 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->base_address[0] & (~3), OLYMPIC_IO_SPACE)) { + card_no++ ; + continue ; + } + + olympic_priv=kmalloc(sizeof (struct olympic_private), GFP_KERNEL); + memset(olympic_priv, 0, sizeof(struct olympic_private)); +#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->base_address[0] & (~3); + dev->init=&olympic_init; + olympic_priv->olympic_mmio=ioremap(pci_device->base_address[1],256); + olympic_priv->olympic_lap=ioremap(pci_device->base_address[2],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 ; +} + + +__initfunc(static int olympic_init(struct 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: IBM PCI tokenring card. I/O at %hx, MMIO at %p, LAP at %p, using irq %d\n",dev->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 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 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 device *dev= (struct 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 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 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 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 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 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 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 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 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 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 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->base_address[0] & (~3)) ) { /* 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 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 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 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 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/olympic.h linux.ac/drivers/net/olympic.h --- linux.vanilla/drivers/net/olympic.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/olympic.h Wed Jun 9 20:08:19 1999 @@ -0,0 +1,303 @@ +/* + * 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; + + volatile int srb_queued; /* True if an SRB is still posted */ + struct wait_queue *srb_wait; + + volatile int asb_queued; /* True if an ASB is posted */ + + volatile int trb_queued; /* True if a TRB is posted */ + struct wait_queue *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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdla_chdlc.c linux.ac/drivers/net/sdla_chdlc.c --- linux.vanilla/drivers/net/sdla_chdlc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/sdla_chdlc.c Fri Jun 4 23:52:39 1999 @@ -0,0 +1,2394 @@ +/***************************************************************************** +* sdla_chdlc.c WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module. +* +* Author: David Fong (Based on Code by 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. +* ============================================================================ +* Oct 30, 1998 Jaspreet Singh Added Support for CHDLC API (HDLC STREAMING). +* Oct 28, 1998 Jaspreet Singh Added Support for Dual Port CHDLC. +* Aug 07, 1998 David Fong 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 +#include /* sockaddr_in */ +#include +#include +#include +#include /* htons(), etc. */ + +#define _GNUC_ +#include /* CHDLC firmware API definitions */ + +/****** Defines & Macros ****************************************************/ + +#ifdef _DEBUG_ +#define STATIC +#else +#define STATIC static +#endif + +#define CHDLC_MIN_DATA_LEN 300 /* minimum mtu */ +#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ +#define CHDLC_MAX_DATA_LEN 15354 /* maximum MTU */ +#define CHDLC_HDR_LEN 1 + +#define IFF_POINTTOPOINT 0x10 + +#define MAX_RETRY 10 + +#define NOT_SET 0x00 +/* For determining whether Set Configuration and Enable Comms has been done. + */ +#define SC 0x01 /* Set global configuration */ +#define EC 0x02 /* Enabled HDLC Communications */ +#define STC 0x04 /* Set Trace configuration */ + +/* For determining whether HDLC_SEND_WAIT command has been issued and requires + * a transmit interrupt. + */ + +#define TX_WAIT 0x01 + +#define NO_READ_CMD 0x00 +#define READ_CMD 0x01 + +#define WANPIPE 0x00 +#define API 0x01 + +/******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 CHDLC specific data + */ + +typedef struct chdlc_private_area +{ + char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ + char usedby; /* interface used by */ + sdla_t *card; + int TracingEnabled; /* For enabling Tracing */ + unsigned char port_number; /* Port number on the board */ + unsigned char ttl; /* Time To Live for UDP security */ + char interface; /* RS-232/V.35, etc. */ + char clocking; /* external/internal */ + unsigned bps; /* data transfer rate */ + unsigned mtu; /* maximum transmit unit size */ + struct enet_statistics if_stats; /* interface statistics */ + + unsigned long curr_trace_addr; /* Used for Tracing */ + unsigned long start_trace_addr; + unsigned long end_trace_addr; + unsigned long base_addr_trace_buffer; + unsigned long end_addr_trace_buffer; + unsigned short number_trace_elements; + unsigned available_buffer_space; + + char status; /* for SK RX Q checks */ + char tx_status; /* for wait tx */ + char read_cmd; /* who is doing read */ + pid_t tx_pid_number; /* pid for send cmd */ + pid_t rx_pid_number; /* pid for read cmd */ + struct sk_buff *saved_skb; /* ptr to new_skb */ + + + unsigned long router_start_time; + unsigned char route_status; + unsigned long tick_counter; /* For 5s timeout counter */ + + unsigned long router_up_time; +} chdlc_private_area_t; + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + + +/* variable for keeping track of enabling/disabling FT1 monitor status */ +static int rCount = 0; + +/* variable for tracking how many interfaces to open for WANPIPE on the + two ports */ +static int num_of_interfaces_for_wanpipe[2]; +static int num_of_interfaces_on_port[2]; + +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 device* dev, + wanif_conf_t* conf); +static int del_if (wan_device_t* wandev, struct device* dev); + +/* Network device interface */ +static int if_init (struct device* dev); +static int if_open (struct device* dev); +static int if_close (struct device* dev); +static int if_header (struct sk_buff* skb, struct 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 device* dev); +static struct enet_statistics* if_stats (struct device* dev); + +/* CHDLC Firmware interface functions */ +static int chdlc_configure (sdla_t* card, void* data, unsigned char ); +static int chdlc_comm_enable (sdla_t* card, unsigned char); +static int chdlc_comm_disable (sdla_t* card, unsigned char); +static int chdlc_read_version (sdla_t* card, char* str); +static int chdlc_set_intr_mode (sdla_t* card, unsigned mode, unsigned char); +static int chdlc_send (sdla_t* card, void* data, unsigned len, unsigned char); + + +/* Miscellaneous CHDLC Functions */ +static int config508 (chdlc_private_area_t* chdlc_priv_area, sdla_t* card); +static void init_chdlc_tx_rx_buff( sdla_t* card, struct device *dev ); +static int chdlc_error (sdla_t *card, int err, TRUE_CHDLC_MAILBOX_STRUCT *mb); +static int process_chdlc_exception(sdla_t *card, unsigned char); +static int process_global_exception(sdla_t *card, unsigned char); +static int chdlc_get_err_stats (sdla_t* card); +static int configure_ip (sdla_t* card, unsigned char); +static int unconfigure_ip (sdla_t* card, unsigned char); +static void process_route(sdla_t *card); +static void port_set_state (sdla_t *card, int, unsigned char); +static int read_chdlc_configuration( sdla_t *, unsigned char ); + + +/* Interrupt handlers */ +static void wpc_isr (sdla_t* card); +static void rx_intr (sdla_t* card, unsigned char); +static void timer_intr(sdla_t *, unsigned char); + +/* Miscellaneous functions */ +static int reply_udp( unsigned char *data, unsigned int mbox_len ); +static int intr_test( sdla_t* card, struct device *dev ); +static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, struct device* dev, + chdlc_private_area_t* chdlc_priv_area ); +static unsigned int dec_to_uint (unsigned char* str, int len); + +static int Intr_test_counter; + +/****** Public Functions ****************************************************/ + +/*============================================================================ + * Cisco HDLC 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 wpc_init (sdla_t* card, wandev_conf_t* conf) + { + union + { + char str[80]; + } u; + + TRUE_CHDLC_MAILBOX_STRUCT* mb; + unsigned long timeout; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_CHDLC) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + + /* Initialize protocol-specific fields */ + /* There is one mailbox common between two ports */ + card->mbox = (void *)(card->hw.dpmbase); + + mb = card->mbox; + + /* The board will place an 'I' in the return code to indicate that it is + ready to accept commands. We expect this to be completed in less + than 1 second. */ + + timeout = jiffies; + while (mb->return_code != 'I') /* Wait 1s for board to initialize */ + if ((jiffies - timeout) > 1*HZ) break; + + if (mb->return_code != 'I') { + printk(KERN_INFO "%s: Initialization not completed by adapter. Please contact Sangoma representative.\n", card->devname); + return -EIO; + } + + /* 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 (chdlc_read_version(card, u.str)) + return -EIO; + printk(KERN_INFO "%s: running Cisco HDLC firmware v%s\n", + card->devname, u.str); + + + card->isr = &wpc_isr; + card->poll = NULL; + card->exec = NULL; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.state = WAN_DUALPORT; + card->wandev.udp_port = conf->udp_port; + + num_of_interfaces_for_wanpipe[0] = 0; + num_of_interfaces_for_wanpipe[1] = 0; + //num_of_interfaces_on_port[0] = 0; + //num_of_interfaces_on_port[1] = 0; + + /* This is for the ports link state */ + card->u.c.state[0] = WAN_DISCONNECTED; + card->u.c.state[1] = WAN_DISCONNECTED; + + /* This is for the API status for returning result code */ + card->u.c.api_status[0] = NOT_SET; + card->u.c.api_status[1] = NOT_SET; + + /* Set the flag pointers for both ports to NULL */ + card->u.c.flags[0] = NULL; + card->u.c.flags[1] = NULL; + + 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; + + chdlc_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 device* dev, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + chdlc_private_area_t* chdlc_priv_area; + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + unsigned char port_num; + int err; + + + 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 */ + chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL); + + if( chdlc_priv_area == NULL ) + return -ENOMEM; + + memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); + + chdlc_priv_area->card = card; + + /* initialize data */ + strcpy(chdlc_priv_area->name, conf->name); + + /* This interface is used for API or WANPIPE */ + if( strcmp(conf->usedby, "WANPIPE") == 0){ + chdlc_priv_area->usedby = WANPIPE; + } else if( strcmp(conf->usedby, "API") == 0){ + printk(KERN_INFO "API mode is not supported by the kernel bundled drivers. Use the drivers.\n"); + printk(KERN_INFO "from Sangoma themselves.\n"); + return -EINVAL; + } + + /* Get the port number information */ + if (is_digit(conf->addr[0])) { + int port_number = dec_to_uint(conf->addr, 0); + + if (port_number == 0 || port_number == 1) { + chdlc_priv_area->port_number = port_number; + } else { + printk(KERN_ERR + "%s: invalid PORT NUMBER %u on interface %s!\n", + wandev->name, port_number, chdlc_priv_area->name); + return -EINVAL; + } + + } else { + + printk(KERN_ERR + "%s: invalid media address on interface %s!\n", + wandev->name, chdlc_priv_area->name); + return -EINVAL; + } + + chdlc_priv_area->saved_skb = NULL; + chdlc_priv_area->status = NO_SK_RX_CHECK; + chdlc_priv_area->read_cmd = NO_READ_CMD; + chdlc_priv_area->tx_pid_number = 0; + chdlc_priv_area->rx_pid_number = 0; + chdlc_priv_area->tx_status = NOT_SET; + + + /* The following is only done when the interface is used for WANPIPE */ + if( chdlc_priv_area->usedby == WANPIPE){ + + if( num_of_interfaces_for_wanpipe[chdlc_priv_area->port_number] > 1 ) + return -EEXIST; + + num_of_interfaces_for_wanpipe[chdlc_priv_area->port_number]++; + chdlc_priv_area->TracingEnabled = 0; + chdlc_priv_area->route_status = NO_ROUTE; + + /* route_status here because we don't want it reset + when cpipemon flushes the statistics */ + + mb->buffer_length = 0; + mb->command = READ_CHDLC_CONFIGURATION; + mb->port_number = chdlc_priv_area->port_number; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + return -EIO; + } + + + chdlc_priv_area->ttl = conf->ttl; + chdlc_priv_area->interface = conf->interface; + chdlc_priv_area->clocking = conf->clocking; + + /* For Port 0 */ + if(chdlc_priv_area->port_number == 0 ){ + chdlc_priv_area->bps = conf->bps ? min(conf->bps, P0_MAX_BAUD_RATE): P0_MAX_BAUD_RATE; + chdlc_priv_area->mtu = ((conf->mtu - CHDLC_MIN_DATA_LEN) >= 0) ? min(conf->mtu, P0_MAX_NO_DATA_BYTES_IN_FRAME) : CHDLC_DFLT_DATA_LEN; + }else if(chdlc_priv_area->port_number == 1){ + /* For Port 1 */ + chdlc_priv_area->bps = conf->bps ? min(conf->bps, P1_MAX_BAUD_RATE): P1_MAX_BAUD_RATE; + chdlc_priv_area->mtu = ((conf->mtu - CHDLC_MIN_DATA_LEN) >= 0) ? min(conf->mtu, P1_MAX_NO_DATA_BYTES_IN_FRAME) : CHDLC_DFLT_DATA_LEN; + } + + + port_num = chdlc_priv_area->port_number; + + card->u.c.flags[port_num] = (void *)( card->hw.dpmbase + + ( ((CHDLC_CONFIGURATION_STRUCT *)mb->data)->ptr_shared_mem_info_struct % SDLA_WINDOWSIZE ) ); /* mod to get offset within window */ + + + card->u.c.protocol_options[port_num] = 0; + if (conf->ignore_dcd == WANOPT_YES) + card->u.c.protocol_options[port_num] |=IGNORE_DCD_FOR_LINK_STAT; + + if (conf->ignore_cts == WANOPT_YES) + card->u.c.protocol_options[port_num] |=IGNORE_CTS_FOR_LINK_STAT; + + if (conf->ignore_keepalive == WANOPT_YES) { + card->u.c.protocol_options[port_num] |= IGNORE_KPALV_FOR_LINK_STAT; + card->u.c.kpalv_tx[port_num] = MIN_Tx_KPALV_TIMER; + card->u.c.kpalv_rx[port_num] = MIN_Rx_KPALV_TIMER; + card->u.c.kpalv_err[port_num] = MIN_KPALV_ERR_TOL; + + } else { /* Do not ignore keepalives */ + + card->u.c.kpalv_tx[port_num] = + (conf->keepalive_tx_tmr - MIN_Tx_KPALV_TIMER) >= 0 ? + min (conf->keepalive_tx_tmr, MAX_Tx_KPALV_TIMER) : + DEFAULT_Tx_KPALV_TIMER; + + card->u.c.kpalv_rx[port_num] = + (conf->keepalive_rx_tmr - MIN_Rx_KPALV_TIMER) >= 0 ? + min (conf->keepalive_rx_tmr, MAX_Rx_KPALV_TIMER) : + DEFAULT_Rx_KPALV_TIMER; + + card->u.c.kpalv_err[port_num] = + (conf->keepalive_err_margin -MIN_KPALV_ERR_TOL) >=0 ? + min (conf->keepalive_err_margin, MAX_KPALV_ERR_TOL) : + DEFAULT_KPALV_ERR_TOL; + } + + card->u.c.slarp_timer[port_num] = + (conf->slarp_timer - MIN_SLARP_REQ_TIMER) >=0 ? + min (conf->slarp_timer, MAX_SLARP_REQ_TIMER) : + DEFAULT_SLARP_REQ_TIMER; + + + } else if( chdlc_priv_area->usedby == API ) { + /* && + (num_of_interfaces_on_port[chdlc_priv_area->port_number] == 0) ){ + */ + num_of_interfaces_on_port[chdlc_priv_area->port_number]++; + if(read_chdlc_configuration(card, chdlc_priv_area->port_number)) + return -EIO; + + } + + + /* prepare network device data space for registration */ + dev->name = chdlc_priv_area->name; + dev->init = &if_init; + dev->priv = chdlc_priv_area; + + return 0; +} + +/*============================================================================ + * Delete logical channel. + */ +static int del_if (wan_device_t* wandev, struct device* dev) +{ + chdlc_private_area_t *chdlc_priv_area = dev->priv; + sdla_t *card = chdlc_priv_area->card; + + if( chdlc_priv_area->usedby == API){ + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev->start = 0; + wanpipe_close(card); + + card->wandev.critical = 0; + + if (dev->priv) { + kfree(dev->priv); + 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 device* dev) + { + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_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->flags |= IFF_POINTTOPOINT; + dev->type = ARPHRD_PPP; /* ARP hw type -- dummy value */ + dev->mtu = chdlc_priv_area->mtu; + dev->hard_header_len = CHDLC_HDR_LEN; + + /* This is done because for an API we do not want to call ifconfig + * which set these calls. + */ + if( chdlc_priv_area->usedby == API){ + dev->flags |= IFF_UP; + /* Set to the Maximum SEND or RECV mailbox */ + dev->mtu = 15384; + } + + /* Initialize hardware parameters */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = wandev->maddr; + dev->mem_end = wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length */ + dev->tx_queue_len = 100; + + /* Initialize socket buffers */ + dev_init_buffers(dev); + + if( chdlc_priv_area->usedby == API ) + if_open( 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 device* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + unsigned char port_num = chdlc_priv_area->port_number; + SHARED_MEMORY_INFO_STRUCT* flags = card->u.c.flags[port_num]; + struct timeval tv; + int err = 0; + + if (dev->start) return -EBUSY; /* only one open is allowed */ + + disable_irq(card->hw.irq); + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + enable_irq(card->hw.irq); + return -EAGAIN; + } + + if( chdlc_priv_area->usedby == WANPIPE ){ + /* + && + !(num_of_interfaces_on_port[port_num] == 1)){ + */ + num_of_interfaces_on_port[port_num]++; + if (config508(chdlc_priv_area, card)) { + err = -EIO; + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return err; + } + + /* Interrupt Testing */ + Intr_test_counter = 0; + err = intr_test( card, dev ); + + if((err) || (Intr_test_counter !=(MAX_INTR_TEST_COUNTER + 1))) { + + printk("%s: Interrupt Test Failed, Counter: %i\n", + chdlc_priv_area->name, Intr_test_counter); + printk("Please choose another interrupt\n"); + err = -EIO; + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return err; + } + printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", + chdlc_priv_area->name, Intr_test_counter); + + /* Initialize Rx/Tx buffer control fields */ + init_chdlc_tx_rx_buff( card, dev); + + /* Set interrupt mode and mask */ + if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_TX_FRAME | + APP_INT_ON_CHDLC_EXCEP_COND, port_num)) { + err = -EIO; + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return err; + } + + flags->interrupt_info_struct.interrupt_permission &= + ~TX_APP_INT_PEND; + /* Enable communications */ + if (chdlc_comm_enable(card, port_num)) { + err = -EIO; + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return err; + } + + port_set_state(card,WAN_CONNECTING, port_num); + do_gettimeofday( &tv ); + chdlc_priv_area->router_start_time = tv.tv_sec; + dev->mtu = min(dev->mtu, chdlc_priv_area->mtu); + } + + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + wanpipe_open(card); + card->wandev.critical = 0; + enable_irq(card->hw.irq); + 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 device* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + unsigned char port_num = chdlc_priv_area->port_number; + + if(chdlc_priv_area && (chdlc_priv_area->usedby == WANPIPE) ){ + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev->start = 0; + wanpipe_close(card); + + port_set_state(card, WAN_DISCONNECTED, port_num); + chdlc_set_intr_mode(card, 0, port_num); + chdlc_comm_disable(card, port_num); + 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 device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len) +{ + skb->protocol = htons(type); + + return CHDLC_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) +{ + 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 device* dev) +{ + chdlc_private_area_t *chdlc_priv_area = dev->priv; + sdla_t *card = chdlc_priv_area->card; + struct in_device *in_dev; + CHDLC_MAILBOX_STRUCT *mbox = card->mbox; + unsigned port_num = chdlc_priv_area->port_number; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags[port_num]; + INTERRUPT_INFORMATION_STRUCT *chdlc_int=&flags->interrupt_info_struct; + CHDLC_MAILBOX_STRUCT *my_mbox= NULL; + pid_t pid_number; + unsigned char *sendpacket; + unsigned long check_braddr, check_mcaddr; + int err, udp_type = 0, retry = 0; + + 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); + + 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. + */ + + ++chdlc_priv_area->if_stats.collisions; + + if ((jiffies - chdlc_priv_area->tick_counter) < (5*HZ)) { + return 1; + } + + printk (KERN_INFO "Port%d: Transmit times out\n",port_num); + + /* unbusy the card (because only one interface per card)*/ + dev->tbusy = 0; + } + sendpacket = skb->data; + + if(ntohs(skb->protocol) != 0x16 ){ + + udp_type = udp_pkt_type( skb, card ); + + in_dev = dev->ip_ptr; + if( in_dev != NULL ) { + struct in_ifaddr *ifa= in_dev->ifa_list; + + if(ifa != NULL) { + /*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 Broadcast address */ + if ((dev->flags & IFF_BROADCAST) && (check_braddr == ifa->ifa_broadcast)) { + + printk(KERN_INFO "%s: Broadcast Src. Addr. silently discarded\n" ,card->devname); + dev_kfree_skb(skb); + ++chdlc_priv_area->if_stats.tx_dropped; + return 0; + } + + /* if the Source Address is a Multicast address */ + if ((check_mcaddr >= 0xE0000001) && (check_mcaddr <= 0xFFFFFFFE)) { + + printk(KERN_INFO "%s: Mutlicast Src. Addr. silently discarded\n" ,card->devname); + dev_kfree_skb(skb); + ++chdlc_priv_area->if_stats.tx_dropped; + return 0; + } + } + } + } + disable_irq(card->hw.irq); + + 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; + printk(KERN_INFO "ENABLE TX\n"); + /* set the counter to see if we get the interrupt in + * 5 seconds. + */ + + chdlc_priv_area->tick_counter = jiffies; + + enable_irq(card->hw.irq); + return 1; + + } + + dev_kfree_skb(skb); + + enable_irq(card->hw.irq); + ++chdlc_priv_area->if_stats.tx_dropped; + return 0; + } + + { + + if (udp_type == UDP_CPIPE_TYPE) { + + err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, chdlc_priv_area); + + } else if (card->u.c.state[port_num] != WAN_CONNECTED) { + ++chdlc_priv_area->if_stats.tx_dropped; + + } else if (!skb->protocol) { + ++chdlc_priv_area->if_stats.tx_errors; + + } else { + if (chdlc_send(card, skb->data, skb->len, port_num)) { + + retry = 1; + dev->tbusy = 1; + chdlc_priv_area->tick_counter = jiffies; + ++chdlc_priv_area->if_stats.tx_errors; + chdlc_int->interrupt_permission |= TX_APP_INT_PEND; + + } else { + ++chdlc_priv_area->if_stats.tx_packets; + } + } + } + + if (!dev->tbusy){ + dev_kfree_skb(skb); + } + + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return dev->tbusy; + +} + +/*============================================================================ + * 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 + 62; + + /* fill in UDP reply */ + data[36] = 0x02; + + /* fill in UDP length */ + udp_length = mbox_len + 42; + + /* 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 */ + + +/*============================================================================ + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +static struct enet_statistics* if_stats (struct device* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + + return &chdlc_priv_area->if_stats; +} + +/****** Cisco HDLC Firmware Interface Functions *******************************/ + +/*============================================================================ + * Read firmware code version. + * Put code version as ASCII string in str. + */ +static int chdlc_read_version (sdla_t* card, char* str) +{ + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + int len; + char err; + mb->buffer_length = 0; + mb->command = READ_CHDLC_CODE_VERSION; + mb->port_number = 0; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + } + else if (str) { /* is not null */ + len = mb->buffer_length; + memcpy(str, mb->data, len); + str[len] = '\0'; + } + return (err); +} + +/*----------------------------------------------------------------------------- + * Configure CHDLC firmware. + */ +static int chdlc_configure (sdla_t* card, void* data, unsigned char port_num) +{ + int err; + TRUE_CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; + int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); + + mailbox->buffer_length = data_length; + memcpy(mailbox->data, data, data_length); + mailbox->command = SET_CHDLC_CONFIGURATION; + mailbox->port_number = port_num; + err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) chdlc_error (card, err, mailbox); + + return err; +} + + +/*============================================================================ + * Set interrupt mode -- HDLC Version. + */ + +static int chdlc_set_intr_mode (sdla_t* card, unsigned mode, unsigned char port_num) +{ + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + CHDLC_INT_TRIGGERS_STRUCT* int_data = + (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; + int err; + + int_data->CHDLC_interrupt_triggers = mode; + int_data->IRQ = card->hw.irq; + int_data->interrupt_timer = 0; + mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); + + mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) chdlc_error (card, err, mb); + + return err; +} + + +/*============================================================================ + * Enable communications. + */ + +static int chdlc_comm_enable (sdla_t* card, unsigned char port_num) +{ + int err; + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + + mb->buffer_length = 0; + mb->command = ENABLE_CHDLC_COMMUNICATIONS; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) chdlc_error(card,err,mb); + + return err; +} + +/*============================================================================ + * Disable communications. + */ +static int chdlc_comm_disable (sdla_t* card, unsigned char port_num) +{ + int err; + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + + mb->buffer_length = 0; + mb->command = DISABLE_CHDLC_COMMUNICATIONS; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) chdlc_error(card,err,mb); + + return err; +} + +/*============================================================================ + * Get communications error statistics. + */ +static int chdlc_get_err_stats (sdla_t* card) +{ + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + int err; + + mb->buffer_length = 0; + mb->command = READ_COMMS_ERROR_STATS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err == COMMAND_OK) { + COMMS_ERROR_STATS_STRUCT* stats = (void*)mb->data; + card->wandev.stats.rx_over_errors = stats->Rx_overrun_err_count; + card->wandev.stats.rx_crc_errors = stats->CRC_err_count; + card->wandev.stats.rx_missed_errors = stats->Rx_abort_count; + + } else { + chdlc_error(card,err,mb); + return err; + } + + mb->buffer_length = 0; + mb->command = READ_CHDLC_OPERATIONAL_STATS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err == COMMAND_OK) { + CHDLC_OPERATIONAL_STATS_STRUCT *stats = (void*)mb->data; + card->wandev.stats.rx_length_errors = + stats->Rx_Data_discard_short_count + + stats->Rx_Data_discard_long_count; + + card->wandev.stats.rx_frame_errors = + stats->Rx_frm_incomp_CHDLC_hdr_count + + stats->Rx_frms_too_long_count + + stats->Rx_invalid_CHDLC_addr_count + + stats->Rx_invalid_CHDLC_ctrl_count + + stats->Rx_invalid_CHDLC_type_count + + stats->Rx_SLARP_invalid_code_count + + stats->Rx_SLARP_Reply_bad_IP_addr + + stats->Rx_SLARP_Reply_bad_netmask; + + } else + chdlc_error(card,err,mb); + + + return err; +} + +/*============================================================================ + * Send packet. + * Return: 0 - o.k. + * 1 - no transmit buffers available + */ +static int chdlc_send (sdla_t* card, void* data, unsigned len, unsigned char port_num) +{ + CHDLC_DATA_TX_STATUS_EL_STRUCT *txbuf = card->u.c.txbuf[port_num]; + + if (txbuf->opp_flag) return 1; + + sdla_poke(&card->hw, txbuf->ptr_data_bfr, data, len); + + txbuf->frame_length = len; + txbuf->opp_flag = 1; /* start transmission */ + + /* Update transmit buffer control fields */ + card->u.c.txbuf[port_num] = ++txbuf; + + if ((void*)txbuf > card->u.c.txbuf_last[port_num]) + card->u.c.txbuf[port_num] = card->u.c.txbuf_base[port_num]; + + 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 chdlc_error (sdla_t *card, int err, TRUE_CHDLC_MAILBOX_STRUCT *mb) +{ + unsigned cmd = mb->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 **************************************************/ + +/*============================================================================ + * Cisco HDLC interrupt service routine. + */ +STATIC void wpc_isr (sdla_t* card) +{ + struct device* dev = card->wandev.dev; + chdlc_private_area_t* chdlc_priv_area; + SHARED_MEMORY_INFO_STRUCT* flags = NULL; + int i, interrupt_serviced = 0; + int port_num; + + card->in_isr = 1; + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + for (i=0; i<2; i++){ + flags = card->u.c.flags[i]; + printk(KERN_INFO "%s: Critical %X while in ISR port%d int type = 0x%02X\n",card->devname, card->wandev.critical,i,flags->interrupt_info_struct.interrupt_type); + } + card->in_isr = 0; + return; + } + card->wandev.critical = 0x61; + /* 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; + + flags = card->u.c.flags[0]; + + /* Check both the ports to see on which port we have the interrupt. */ + //for (port_num=0; port_num<2; port_num++){ + /* check on port 0 first then port 1 */ + port_num = 0; + for( port_num=0; port_num<2; port_num++){ + + if( card->u.c.flags[port_num] != NULL ) { + flags = card->u.c.flags[port_num]; + + switch (flags->interrupt_info_struct.interrupt_type) { + + case RX_APP_INT_PEND: /* 0x01: receive interrupt */ + interrupt_serviced = 1; + +// test_timer = jiffies; +// while (1){ +// if ((jiffies - test_timer) > ((1/4)*HZ)) break; +// } + rx_intr(card, port_num); + break; + + case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ + interrupt_serviced = 1; + flags->interrupt_info_struct. + interrupt_permission &= ~TX_APP_INT_PEND; + + for( dev=card->wandev.dev; dev; dev=dev->slave) { + chdlc_priv_area = dev->priv; + + if(chdlc_priv_area->usedby == WANPIPE && + chdlc_priv_area->port_number == port_num){ + dev->tbusy = 0; + mark_bh(NET_BH); + break; + } + } + break; + + case COMMAND_COMPLETE_APP_INT_PEND: /* 0x04: cmd complete */ + interrupt_serviced = 1; + ++Intr_test_counter; + break; + + case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ + interrupt_serviced = 1; + process_chdlc_exception(card, port_num); + break; + + case GLOBAL_EXCEP_COND_APP_INT_PEND: + interrupt_serviced = 1; + process_global_exception(card, port_num); + break; + case TIMER_APP_INT_PEND: + interrupt_serviced = 1; + timer_intr(card, port_num); + break; + default: + break; + } + if(interrupt_serviced) + break; + } + } + if( !interrupt_serviced) { + + printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", + card->devname, + flags->interrupt_info_struct.interrupt_type); + + printk(KERN_INFO "%s: Code name = ",card->devname); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c",flags->global_info_struct.codename[i]); + printk(KERN_INFO "\n"); + + printk(KERN_INFO "%s: Code version = ",card->devname); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c",flags->global_info_struct.codeversion[i]); + printk(KERN_INFO "\n"); + + } + + + /* 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->interrupt_info_struct. + interrupt_permission |= TX_APP_INT_PEND; + card->wandev.enable_tx_int = 0; + } + + card->in_isr = 0; + flags->interrupt_info_struct.interrupt_type = 0; + card->wandev.critical = 0; + +} + +/*============================================================================ + * Receive interrupt handler. + */ +static void rx_intr (sdla_t* card, unsigned char port_num) +{ + struct device *dev; + chdlc_private_area_t *chdlc_priv_area; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags[port_num]; + INTERRUPT_INFORMATION_STRUCT *chdlc_int=&flags->interrupt_info_struct; + CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb[port_num]; + struct sk_buff *skb, *new_skb; + unsigned len; + void *buf; + int i,udp_type; + + if (rxbuf->opp_flag != 0x01) { + printk(KERN_INFO + "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", + card->devname, (unsigned)rxbuf, rxbuf->opp_flag); + + printk(KERN_INFO "%s: Code name = ",card->devname); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c",flags->global_info_struct.codename[i]); + printk(KERN_INFO "\n"); + + printk(KERN_INFO "%s: Code version = ",card->devname); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c",flags->global_info_struct.codeversion[i]); + printk(KERN_INFO "\n"); + + return; + + } + + for (dev = card->wandev.dev; dev; dev = dev->slave){ + chdlc_priv_area = dev->priv; + if( chdlc_priv_area->usedby == WANPIPE && + chdlc_priv_area->port_number == port_num){ + break; + } else if( chdlc_priv_area->usedby == API && + chdlc_priv_area->read_cmd == READ_CMD && + chdlc_priv_area->port_number == port_num){ + break; + } + } + + if (dev && dev->start) { + + if(chdlc_priv_area->usedby == WANPIPE ) { + + len = rxbuf->frame_length; + + /* Allocate socket buffer */ + skb = dev_alloc_skb(len); + + if (skb != NULL) { + /* Copy data to the socket buffer */ + unsigned addr = rxbuf->ptr_data_bfr; + + if ((addr + len) > card->u.c.rx_top[port_num] + 1) { + unsigned tmp = card->u.c.rx_top[port_num] - addr + 1; + buf = skb_put(skb, tmp); + sdla_peek(&card->hw, addr, buf, tmp); + addr = card->u.c.rx_base[port_num]; + len -= tmp; + } + + buf = skb_put(skb, len); + sdla_peek(&card->hw, addr, buf, len); + + /* Decapsulate packet */ + skb->protocol = htons(ETH_P_IP); + + udp_type = udp_pkt_type( skb, card ); + + if (udp_type == UDP_CPIPE_TYPE){ + process_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, + card, skb, dev, chdlc_priv_area); + dev_kfree_skb(skb); + + } else { + /* Pass it up the protocol stack */ + skb->dev = dev; + skb->mac.raw = skb->data; + netif_rx(skb); + ++chdlc_priv_area->if_stats.rx_packets; + } + + } else { + + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + ++chdlc_priv_area->if_stats.rx_dropped; + } + } + } + + /* Release buffer element and calculate a pointer to the next one */ + rxbuf->opp_flag = 0x00; + card->u.c.rxmb[port_num] = ++rxbuf; + + if ((void*)rxbuf > card->u.c.rxbuf_last[port_num]) + card->u.c.rxmb[port_num] = card->u.c.rxbuf_base[port_num]; +} + + +/*------------------------------------------------------------------------------ + Miscellaneous Functions + - config508 used to set configuration options on the board + static int config508 (chdlc_private_area_t* chdlc_priv_area, sdla_t* card) + +------------------------------------------------------------------------------*/ + +static int config508 (chdlc_private_area_t* chdlc_priv_area, sdla_t* card) +{ + struct device * dev = card->wandev.dev; + struct in_device *in_dev = dev->ip_ptr; + unsigned char port_num = chdlc_priv_area->port_number; + CHDLC_CONFIGURATION_STRUCT cfg; + memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); + + if (chdlc_priv_area->clocking) cfg.baud_rate = chdlc_priv_area->bps; + + cfg.line_config_options = chdlc_priv_area->interface == WANOPT_RS232 ? + INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; + + cfg.modem_config_options = 0; + cfg.modem_status_timer = 100; + + cfg.CHDLC_protocol_options = card->u.c.protocol_options[port_num]; + cfg.percent_data_buffer_for_Tx = 50; + cfg.CHDLC_statistics_options = 0; + cfg.max_CHDLC_data_field_length = chdlc_priv_area->mtu; + cfg.transmit_keepalive_timer = card->u.c.kpalv_tx[port_num]; + cfg.receive_keepalive_timer = card->u.c.kpalv_rx[port_num]; + cfg.keepalive_error_tolerance = card->u.c.kpalv_err[port_num]; + cfg.SLARP_request_timer = card->u.c.slarp_timer[port_num]; + + if (cfg.SLARP_request_timer) { + cfg.IP_address = 0; + cfg.IP_netmask = 0; + } + else { + if(in_dev != NULL) { + struct in_ifaddr *ifa = in_dev->ifa_list; + + if (ifa != NULL ) { + cfg.IP_address = ntohl(ifa->ifa_local); + cfg.IP_netmask = ntohl(ifa->ifa_mask); + } + } + } + + return chdlc_configure(card, &cfg, port_num); +} + + + +/*============================================================================ + * Process global exception condition + */ +static int process_global_exception(sdla_t *card, unsigned char port_num) +{ + CHDLC_MAILBOX_STRUCT* mbox = card->mbox; + struct device *dev; + chdlc_private_area_t *chdlc_priv_area = NULL; + unsigned short length; + struct sk_buff *new_skb; + int err; + + mbox->buffer_length = 0; + mbox->command = READ_GLOBAL_EXCEPTION_CONDITION; + mbox->port_number = port_num; + err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; + + if( err != CMD_TIMEOUT ){ + + switch(mbox->return_code){ + case EXCEP_MODEM_STATUS_CHANGE: + if( (mbox->data[0] & 0x04) ){ + if( (mbox->data[0] & 0x08) ) + printk(KERN_INFO "Port %d: DCD is now high\n", port_num); + else + printk(KERN_INFO "Port %d: DCD is now low\n", port_num); + } + if( (mbox->data[0] & 0x10)){ + if( (mbox->data[0] & 0x20) ) + printk(KERN_INFO "Port %d: CTS is now high\n", port_num); + else + printk(KERN_INFO "Port %d: CTS is now low\n", port_num); + } + break; + case EXCEP_TRC_DISABLED: + printk(KERN_INFO "Port %d: line trace disabled\n", port_num); + break; + default: + printk(KERN_INFO "Port %d: global exception %x\n", port_num, mbox->return_code); + break; + } + + } + return 0; +} + + +/*============================================================================ + * Process chdlc exception condition + */ +static int process_chdlc_exception(sdla_t *card, unsigned char port_num) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + struct device *dev; + chdlc_private_area_t *chdlc_priv_area = NULL; + unsigned short length; + struct sk_buff *new_skb; + int err; + + mb->buffer_length = 0; + mb->command = READ_CHDLC_EXCEPTION_CONDITION; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if( err != CMD_TIMEOUT ) { + switch (err) { + case EXCEP_LINK_ACTIVE: + port_set_state(card, WAN_CONNECTED, port_num); + break; + + case EXCEP_LINK_INACTIVE_MODEM: + port_set_state(card, WAN_DISCONNECTED, port_num); + printk(KERN_INFO "Port%d: CTS and/or DCD down.\n", + port_num); + unconfigure_ip(card, port_num); + break; + + case EXCEP_LINK_INACTIVE_KPALV: + port_set_state(card, WAN_DISCONNECTED, port_num); + printk(KERN_INFO "Port%d: Keepalive timer expired.\n", + port_num); + unconfigure_ip(card, port_num); + break; + + case EXCEP_IP_ADDRESS_DISCOVERED: + if (configure_ip(card, port_num)) return -1; + break; + + case EXCEP_LOOPBACK_CONDITION: + printk(KERN_INFO "Port%d: Loopback Condition Detected.\n", port_num); + break; + + case NO_CHDLC_EXCEP_COND_TO_REPORT: + printk(KERN_INFO "Port%d: No exceptions reported.\n", + port_num); + break; + } + + } + return 0; +} + + +/*============================================================================ + * Configure IP from SLARP negotiation + * This adds dynamic routes when SLARP has provided valid addresses + */ + +static int configure_ip (sdla_t* card, unsigned char port_num) +{ + struct device *dev = card->wandev.dev; + struct in_device *in_dev = dev->ip_ptr; + chdlc_private_area_t *chdlc_priv_area=NULL; + struct ifreq if_info; + struct sockaddr_in *if_data1, *if_data2; + char err; + + for( dev = card->wandev.dev; dev; dev=dev->slave){ + chdlc_priv_area = dev->priv; + if( chdlc_priv_area->port_number == port_num ) + break; + } + + if (card->u.c.slarp_timer[port_num]) { /* set to discover */ + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + CHDLC_CONFIGURATION_STRUCT *cfg; + mm_segment_t fs = get_fs(); + + mb->buffer_length = 0; + mb->command = READ_CHDLC_CONFIGURATION; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + return -1; + } + + /* According to Cisco HDLC, if the point-to-point address is + A.B.C.1, then we are the opposite (A.B.C.2), and vice-versa, + ie 2 and 1 respectively */ + + cfg = (CHDLC_CONFIGURATION_STRUCT *)mb->data; + + if ((cfg->IP_address & ~cfg->IP_netmask) > 2) { + printk(KERN_INFO "%s: Remote address incompatible to SLARP.\n",dev->name); + return -1; + } + + /* Set Local and remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + /* Change the local and remote ip address of the interface. + * This will also add in the destination route. + */ + + if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; + if_data1->sin_addr.s_addr = (ntohl(cfg->IP_address) & ntohl(0xFFFFFF00)) + (~(ntohl(cfg->IP_address)) & ntohl(0x0003)); + if_data1->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFADDR, &if_info ); + if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data2->sin_addr.s_addr = ntohl(cfg->IP_address); + if_data2->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + + set_fs(fs); /* restore old block */ + + + if (err) { + printk (KERN_INFO "%s: Adding of route failed.\n", + card->devname); + } else + printk(KERN_INFO "%s: Dynamic route added.\n", + card->devname); + + } + else { /* not set to discover */ + if (htonl(in_dev->ifa_list->ifa_local & ~(in_dev->ifa_list->ifa_mask)) > 2) { + printk(KERN_INFO "%s: Local address incompatible to SLARP.\n", dev->name); + return -1; + } + + if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data2->sin_addr.s_addr = (in_dev->ifa_list->ifa_local & ntohl(0xFFFFFF00)) + (~(in_dev->ifa_list->ifa_local) & ntohl(0x0003)); + if_data2->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + } + + /* Set flag to add route */ + chdlc_priv_area->route_status = ADD_ROUTE; + + /* The idea here is to add the route in the poll routine. + This way, we aren't in interrupt context when adding routes */ + + card->poll = process_route; + + return 0; +} + + +/*============================================================================ + * Un-Configure IP negotiated by SLARP + * This removes dynamic routes when the link becomes inactive. + */ + +static int unconfigure_ip (sdla_t* card, unsigned char port_num) +{ + struct device *dev = card->wandev.dev; + chdlc_private_area_t *chdlc_priv_area=NULL; + + for( dev = card->wandev.dev; dev; dev=dev->slave){ + chdlc_priv_area = dev->priv; + if( chdlc_priv_area->port_number == port_num ) + break; + } + if (chdlc_priv_area->route_status == ROUTE_ADDED) { + chdlc_priv_area->route_status = REMOVE_ROUTE; + + /* The idea here is to delete the route in the poll routine. + This way, we aren't in interrupt context when adding routes */ + + card->poll = process_route; + } + return 0; +} + +/*============================================================================ + * Routine to add/remove routes + * Called like a polling routine when Routes are flagged to be added/removed. + */ + +static void process_route (sdla_t *card) + { + struct device *dev = card->wandev.dev; + struct ifreq if_info; + struct sockaddr_in *if_data1; + mm_segment_t fs; + int err; + + for(dev=card->wandev.dev; dev; dev=dev->slave){ + + switch (((chdlc_private_area_t *)dev->priv)->route_status) { + + case ADD_ROUTE: + + ((chdlc_private_area_t *)dev->priv)-> + route_status = ROUTE_ADDED; + break; + + case REMOVE_ROUTE: + + fs = get_fs(); + /* Set Local and remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + /* Change the local ip address of the interface to 0. + * This will also delete the destination route. + */ + + if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; + if_data1->sin_addr.s_addr = 0; + if_data1->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFADDR, &if_info ); + set_fs(fs); /* restore old block */ + + if (err) { + printk(KERN_INFO "%s: Remove route failed.\n", + dev->name); + printk(KERN_INFO "Error code: %d\n",err); + } else { + ((chdlc_private_area_t *)dev->priv)-> + route_status = NO_ROUTE; + printk(KERN_INFO "%s: Dynamic route removed.\n", + dev->name); + } + break; + } + } + /* Once we've processed the route, stop polling */ + card->poll = NULL; +} + + +/*============================================================================= + * Process UDP call of type CPIPEAB. + */ + +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, struct device* dev, + chdlc_private_area_t* chdlc_priv_area ) +{ + unsigned char *sendpacket; + unsigned char *data; + unsigned char *buf; + unsigned char buf2[5]; + unsigned int frames, len; + struct sk_buff *new_skb; + unsigned short buffer_length, real_len; + unsigned long data_ptr; + unsigned data_length; + int udp_mgmt_req_valid = 1; + TRUE_CHDLC_MAILBOX_STRUCT *mb = card->mbox; + unsigned char port_num = chdlc_priv_area->port_number; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags[port_num]; + ip_packet_t *ip_packet; + 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 cmd 0x%02X\n" + ,card->devname, ((ip_packet_t *)skb->data)->um_packet.cblock.command); + return 1; + } + + memcpy(data,sendpacket,skb->len); + ip_packet = (ip_packet_t *)data; + + switch(ip_packet->um_packet.cblock.command) { + + case FT1_MONITOR_STATUS_CTRL: + if(card->hw.fwid != SFID_CHDLC508) { + udp_mgmt_req_valid = 0; + break; + } + + case CPIPE_ENABLE_TRACING: + + case CPIPE_DISABLE_TRACING: + + case CPIPE_GET_TRACE_INFO: + + case SET_FT1_MODE: + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + udp_mgmt_req_valid = 0; + } + break; + + default: + break; + } + + if(!udp_mgmt_req_valid) { + + /* set length to 0 */ + ip_packet->um_packet.cblock.buffer_length = 0; + + /* set return code */ + ip_packet->um_packet.cblock.return_code = 0xCD; + + } else { + unsigned long trace_status_cfg_addr = 0; + TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct; + TRACE_STATUS_ELEMENT_STRUCT trace_element_struct; + + switch(ip_packet->um_packet.cblock.command) { + + case CPIPE_ENABLE_TRACING: + if (!chdlc_priv_area->TracingEnabled) { + + /* OPERATE_DATALINE_MONITOR */ + + mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); + mb->command = SET_TRACE_CONFIGURATION; + + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> + trace_config = TRACE_ACTIVE; + /* Trace delay mode is not used because it slows + down transfer and results in a standoff situation + when there is a lot of data */ + + /* Done in 2 steps now because WHAT to be trace will be + configurable in a future release */ + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> trace_config + |= TRACE_SLARP_FRAMES | TRACE_DATA_FRAMES | TRACE_CDP_FRAMES; + + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> + trace_deactivation_timer = 4000; + + mb->port_number = port_num; + + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) { + chdlc_error(card,err,mb); + card->TracingEnabled = 0; + ip_packet->um_packet.cblock.return_code = err; + mb->buffer_length = 0; + break; + } + + /* Get the base address of the trace element list */ + mb->buffer_length = 0; + mb->command = READ_TRACE_CONFIGURATION; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) { + chdlc_error(card,err,mb); + chdlc_priv_area->TracingEnabled = 0; + ip_packet->um_packet.cblock.return_code = err; + mb->buffer_length = 0; + break; + } + + trace_status_cfg_addr =((LINE_TRACE_CONFIG_STRUCT *) + mb->data) -> ptr_trace_stat_el_cfg_struct; + + sdla_peek(&card->hw, trace_status_cfg_addr, + &trace_cfg_struct, sizeof(trace_cfg_struct)); + + chdlc_priv_area->start_trace_addr = trace_cfg_struct. + base_addr_trace_status_elements; + + chdlc_priv_area->number_trace_elements = trace_cfg_struct.number_trace_status_elements; + + chdlc_priv_area->end_trace_addr = (unsigned long) + ((TRACE_STATUS_ELEMENT_STRUCT *) + chdlc_priv_area->start_trace_addr + (chdlc_priv_area->number_trace_elements - 1)); + + chdlc_priv_area->base_addr_trace_buffer = trace_cfg_struct.base_addr_trace_buffer; + + chdlc_priv_area->end_addr_trace_buffer = trace_cfg_struct.end_addr_trace_buffer; + + chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr; + + chdlc_priv_area->available_buffer_space = 2000 - sizeof(ip_packet_t); + } + ip_packet->um_packet.cblock.return_code = COMMAND_OK; + mb->buffer_length = 0; + chdlc_priv_area->TracingEnabled = 1; + break; + + + case CPIPE_DISABLE_TRACING: + if (chdlc_priv_area->TracingEnabled) { + + /* OPERATE_DATALINE_MONITOR */ + mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); + mb->command = SET_TRACE_CONFIGURATION; + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> + trace_config = TRACE_INACTIVE; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + } + + chdlc_priv_area->TracingEnabled = 0; + ip_packet->um_packet.cblock.return_code = COMMAND_OK; + mb->buffer_length = 0; + break; + + + case CPIPE_GET_TRACE_INFO: + + if (!chdlc_priv_area->TracingEnabled) { + ip_packet->um_packet.cblock.return_code = 1; + mb->buffer_length = 0; + break; + } + + buffer_length = 0; /* offset of packet already occupied */ + + for (frames=0; frames < chdlc_priv_area->number_trace_elements; frames++) { + + frame_data_t *frame_data = (frame_data_t *) + &ip_packet->um_packet.data[buffer_length]; + + sdla_peek(&card->hw, chdlc_priv_area->curr_trace_addr, + (unsigned char *)&trace_element_struct, + sizeof(TRACE_STATUS_ELEMENT_STRUCT)); + + if (trace_element_struct.opp_flag == 0x00) { + break; + } + + /* get pointer to real data */ + data_ptr = trace_element_struct.ptr_data_bfr; + + /* See if there is actual data on the trace buffer */ + data_length = data_ptr ? + trace_element_struct.trace_length : 0; + + if( (chdlc_priv_area->available_buffer_space - buffer_length) + < ( sizeof(frame_data_t) + data_length) ) { + + /* indicate there are more frames on board & exit */ + ip_packet->um_packet.ismoredata = 0x01; + break; + } + + frame_data->status = trace_element_struct.trace_type; + + frame_data->time_stamp = + trace_element_struct.trace_time_stamp; + + frame_data->real_length = + trace_element_struct.trace_length; + + + /* see if we can fit the frame into the user buffer */ + real_len = frame_data->real_length; + + if (data_ptr == 0) { + frame_data->data_avail = 0x00; + } else { + unsigned tmp = 0; + + /* get the data from circular buffer + must check for end of buffer */ + frame_data->data_avail = 0x01; + + if ((data_ptr + real_len) > + chdlc_priv_area->end_addr_trace_buffer + 1) { + tmp = chdlc_priv_area->end_addr_trace_buffer - data_ptr + 1; + sdla_peek(&card->hw, data_ptr, + frame_data->data,tmp); + data_ptr = chdlc_priv_area->base_addr_trace_buffer; + } + + sdla_peek(&card->hw, data_ptr, + &frame_data->data[tmp], real_len - tmp); + } + + /* zero the opp flag to show we got the frame */ + buf2[0] = 0x00; + sdla_poke(&card->hw, chdlc_priv_area->curr_trace_addr, &buf2, 1); + + /* now move onto the next frame */ + chdlc_priv_area->curr_trace_addr += sizeof(TRACE_STATUS_ELEMENT_STRUCT); + + /* check if we went over the last address */ + if ( chdlc_priv_area->curr_trace_addr > chdlc_priv_area->end_trace_addr ) { + chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr; + } + + /* update buffer length */ + if ( frame_data->data_avail == 0x01) { + buffer_length += real_len - 1; + } + + /* for the header */ + buffer_length += sizeof(frame_data_t); + + } /* For Loop */ + ip_packet->um_packet.num_frames = frames; + + /* set the data length */ + mb->buffer_length = buffer_length; + ip_packet->um_packet.cblock.buffer_length = buffer_length; + + /* set return code */ + ip_packet->um_packet.cblock.return_code = COMMAND_OK; + + break; + + + case CPIPE_FT1_READ_STATUS: + ((unsigned char *)ip_packet->um_packet.data )[0] = + flags->FT1_info_struct.parallel_port_A_input; + + ((unsigned char *)ip_packet->um_packet.data )[1] = + flags->FT1_info_struct.parallel_port_B_input; + + ip_packet->um_packet.cblock.return_code = COMMAND_OK; + mb->buffer_length = 2; + break; + + case CPIPE_ROUTER_UP_TIME: + do_gettimeofday( &tv ); + chdlc_priv_area->router_up_time = tv.tv_sec - + chdlc_priv_area->router_start_time; + *(unsigned long *)&ip_packet->um_packet.data = + chdlc_priv_area->router_up_time; + mb->buffer_length = sizeof(unsigned long); + break; + + case FT1_MONITOR_STATUS_CTRL: + /* Enable FT1 MONITOR STATUS */ + if( (ip_packet->um_packet.data[0] & ENABLE_READ_FT1_STATUS) || (ip_packet->um_packet.data[0] & ENABLE_READ_FT1_OP_STATS)) { + + if( rCount++ != 0 ) { + ip_packet->um_packet.cblock. + return_code = COMMAND_OK; + mb->buffer_length = 1; + break; + } + } + + /* Disable FT1 MONITOR STATUS */ + if( ip_packet->um_packet.data[0] == 0) { + + if( --rCount != 0) { + ip_packet->um_packet.cblock. + return_code = COMMAND_OK; + mb->buffer_length = 1; + break; + } + } + + default: + /* it's a board command */ + mb->command = ip_packet->um_packet.cblock.command; + mb->buffer_length = ip_packet->um_packet.cblock.buffer_length; + if (mb->buffer_length) { + memcpy(&mb->data, (unsigned char *) ip_packet-> + um_packet.data, mb->buffer_length); + } + mb->port_number = port_num; + /* run the command on the board */ + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) { + + // chdlc_error(card, err, mb); + break; + } + + /* copy the result back to our buffer */ + memcpy(&ip_packet->um_packet.cblock, mb, sizeof(cblock_t)); + + if (mb->buffer_length) { + memcpy(&ip_packet->um_packet.data, &mb->data, mb->buffer_length); + } + + } /* end of switch */ + } /* end of else */ + + /* Fill UDP TTL */ + ip_packet->ip_ttl = chdlc_priv_area->ttl; + + len = reply_udp( data, mb->buffer_length ); + + if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + chdlc_send(card, data, len, port_num); + + } 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); + + /* Decapsulate pkt 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 { + + printk(KERN_INFO "no socket buffers available!\n"); + } + } + kfree(data); + return 0; +} + +/*============================================================================ + * Initialize Receive and Transmit Buffers. + */ + +static void init_chdlc_tx_rx_buff( sdla_t* card, struct device *dev ) +{ + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + chdlc_private_area_t* chdlc_priv_area = dev->priv; + CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config; + CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_config; + unsigned char port_num; + char err; + + port_num = chdlc_priv_area->port_number; + + mb->buffer_length = 0; + mb->command = READ_CHDLC_CONFIGURATION; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + return; + } + + tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + ( ((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> + ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); + + rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + ( ((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> + ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); + + /* Setup Head and Tails for buffers */ + card->u.c.txbuf_base[port_num] = (void *)(card->hw.dpmbase + + (tx_config->base_addr_Tx_status_elements % SDLA_WINDOWSIZE)); + card->u.c.txbuf_last[port_num] = (CHDLC_DATA_TX_STATUS_EL_STRUCT *) + card->u.c.txbuf_base[port_num] + (tx_config->number_Tx_status_elements-1); + + card->u.c.rxbuf_base[port_num] = (void *)(card->hw.dpmbase + + (rx_config->base_addr_Rx_status_elements % SDLA_WINDOWSIZE)); + card->u.c.rxbuf_last[port_num] = (CHDLC_DATA_RX_STATUS_EL_STRUCT *) + card->u.c.rxbuf_base[port_num] + (rx_config->number_Rx_status_elements-1); + + + /* Setup Actual Buffer Start and end addresses */ + card->u.c.rx_base[port_num] = rx_config->base_addr_Rx_buffer; + card->u.c.rx_top[port_num] = rx_config->end_addr_Rx_buffer; + + /* Set up next pointer to be used */ + card->u.c.txbuf[port_num] = (void *)(card->hw.dpmbase + + (tx_config->next_Tx_status_element_to_use % SDLA_WINDOWSIZE)); + card->u.c.rxmb[port_num] = (void *)(card->hw.dpmbase + + (rx_config->next_Rx_status_element_to_use % SDLA_WINDOWSIZE)); +} + +/*============================================================================= + * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR + * _TEST_COUNTER times. + */ +static int intr_test( sdla_t* card, struct device *dev ) +{ + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + chdlc_private_area_t* chdlc_priv_area = dev->priv; + unsigned char port_num = chdlc_priv_area->port_number; + int err,i; + + /* The critical flag is unset because during intialization (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; + enable_irq(card->hw.irq); + err = chdlc_set_intr_mode( card, APP_INT_ON_COMMAND_COMPLETE, port_num); + if ( err == CMD_OK ) { + + for (i=0; ibuffer_length = 0; + mb->command = READ_CHDLC_CODE_VERSION; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err != CMD_OK) + chdlc_error(card, err, mb); + } + } + else { + disable_irq(card->hw.irq); + return err; + } + err = chdlc_set_intr_mode( card, 0, port_num ); + disable_irq(card->hw.irq); + if (err != CMD_OK) return err; + card->wandev.critical = 1; + return 0; +} + +/*============================================================================== + * Determine what type of UDP call it is. CPIPEAB ? + */ +static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ) +{ + ip_packet_t *ip_packet = (ip_packet_t *)skb->data; + + if ( !strncmp(ip_packet->um_packet.signature,UDPMGMT_SIGNATURE,8) && + ip_packet->udp_dst_port == ntohs(card->wandev.udp_port) && + ip_packet->ip_protocol == UDPMGMT_UDP_PROTOCOL && + ip_packet->um_packet.request_reply == UDPMGMT_REQUEST ){ + + return UDP_CPIPE_TYPE; + } + + else return UDP_INVALID_TYPE; +} + +/*============================================================================ + * 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; +} + +/*============================================================================ + * Set PORT state. + */ +static void port_set_state (sdla_t *card, int state, unsigned char port_num) +{ + + if (card->u.c.state[port_num] != state) + { + switch (state) + { + case WAN_CONNECTED: + printk (KERN_INFO "Port%d: link connected!\n", + port_num); + break; + + case WAN_CONNECTING: + printk (KERN_INFO "Port%d: link connecting...\n", + port_num) + ; + break; + + case WAN_DISCONNECTED: + printk (KERN_INFO "Port%d: link disconnected!\n", + port_num) + ; + break; + } + card->u.c.state[port_num] = state; + } +} + +int read_chdlc_configuration( sdla_t *card, unsigned char port_num) +{ + + TRUE_CHDLC_MAILBOX_STRUCT *mbox = card->mbox; + CHDLC_CONFIGURATION_STRUCT *conf_data; + CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_status; + CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_status; + int err, retry = MAX_RETRY; + + do + { + memset(mbox, 0, sizeof(TRUE_CHDLC_MAILBOX_STRUCT)); + mbox->command = READ_CHDLC_CONFIGURATION; + mbox->port_number = port_num; + mbox->buffer_length = 0; + err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; + } while (err && retry--); + + if( !err ){ + conf_data = (CHDLC_CONFIGURATION_STRUCT *)mbox->data; + + card->u.c.flags[port_num] = (void*)(card->hw.dpmbase + + (conf_data->ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); + + tx_status = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + (conf_data->ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); + + card->u.c.tx_status[port_num] = tx_status; + + rx_status = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + (conf_data->ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); + + card->u.c.rx_status[port_num] = rx_status; + + } + return err; +} + + + +void timer_intr( sdla_t *card , unsigned char port_num) +{ +} + + +/****** End ****************************************************************/ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdla_fr.c linux.ac/drivers/net/sdla_fr.c --- linux.vanilla/drivers/net/sdla_fr.c Wed Jan 6 23:02:22 1999 +++ linux.ac/drivers/net/sdla_fr.c Fri Jun 4 23:52:38 1999 @@ -1,8 +1,7 @@ /***************************************************************************** * sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module. * -* Author(s): Gene Kozin -* Jaspreet Singh +* Author(s): Jaspreet Singh * * Copyright: (c) 1995-1997 Sangoma Technologies Inc. * @@ -11,6 +10,14 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Sep 18, 1998 Jaspreet Singh o Updated for 2.2.X kernels. +* Jul 31, 1998 Jaspreet Singh o Removed wpf_poll routine. The channel/DLCI +* status is received through an event interrupt. +* Jul 08, 1998 David Fong o Added inverse ARP support. +* Mar 26, 1997 Jaspreet Singh o Returning return codes for failed UDP cmds. +* Jan 28, 1997 Jaspreet Singh o Improved handling of inactive DLCIs. +* Dec 30, 1997 Jaspreet Singh o Replaced dev_tint() with mark_bh(NET_BH) +* Dec 16, 1997 Jaspreet Singh o Implemented Multiple IPX support. * Nov 26, 1997 Jaspreet Singh o Improved load sharing with multiple boards * o Added Cli() to protect enabling of interrupts * while polling is called. @@ -53,7 +60,7 @@ * 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 +* interrupt occuring 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. @@ -93,72 +100,84 @@ #include /* ARPHRD_* defines */ #include /* htons(), etc. */ #include /* for inb(), outb(), etc. */ -#include /* for do_gettimeofday */ +#include /* for do_gettimeofday */ +#include /* Dynamic Route Creation */ +#include /* sockaddr_in */ +#include /* in_ntoa(), etc... */ +#include +#include +#include #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 */ +#define MAX_CMD_RETRY 10 /* max number of firmware retries */ -/* Q.922 frame types */ +#define FR_HEADER_LEN 8 /* max encapsulation header size */ +#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ -#define Q922_UI 0x03 /* Unnumbered Info frame */ -#define Q922_XID 0xAF /* ??? */ +/* 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 MAX_SEND_FAILS 50 +/* 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 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 */ +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 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 */ + 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 char enable_IPX; /* Enable/Disable the use of IPX */ + unsigned long network_number; /* Internal Network Number for IPX*/ + sdla_t *card; /* -> owner */ + unsigned route_flag; /* Add/Rem dest addr in route tables */ + unsigned inarp; /* Inverse Arp Request status */ + int inarp_interval; /* Time between InArp Requests */ + unsigned long inarp_tick; /* InArp jiffies tick counter */ + + struct net_device_stats ifstats; /* interface statistics */ + + /* This variable is used for discarding packets when consecutive + failures for an interface exceeds a limit */ + + unsigned long consecutive_send_fails; unsigned long if_send_entry; unsigned long if_send_skb_null; unsigned long if_send_broadcast; @@ -174,12 +193,14 @@ 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; @@ -201,32 +222,48 @@ unsigned long router_up_time; } fr_channel_t; -typedef struct dlci_status { - unsigned short dlci PACKED; - unsigned char state PACKED; +/* Route Flag options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + +/* inarp options */ +#define INARP_NONE 0x00 +#define INARP_REQUEST 0x01 +#define INARP_CONFIGURED 0x02 + +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; +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; +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 */ + +/* variable for keeping track of enabling/disabling FT1 monitor status */ static int rCount = 0; + +extern int ip_rt_ioctl(unsigned int, void *); extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); @@ -238,67 +275,72 @@ /****** 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 device *dev, - wanif_conf_t * conf); -static int del_if(wan_device_t * wandev, struct device *dev); +static int update(wan_device_t *wandev); +static int new_if(wan_device_t *wandev, struct device *dev, wanif_conf_t *conf); +static int del_if(wan_device_t *wandev, struct 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 device *dev); static int if_open(struct device *dev); static int if_close(struct device *dev); -static int if_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len); +static int if_header(struct sk_buff *skb, struct 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 device *dev); static struct net_device_stats *if_stats(struct 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); +static void fr508_isr(sdla_t *card); +static void fr508_rx_intr(sdla_t *card); +static void spur_intr(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); +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, unsigned short timeout); +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 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); +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 device *dev); static void set_chan_state(struct device *dev, int state); -static struct device *find_channel(sdla_t * card, unsigned dlci); -static int is_tx_ready(sdla_t * card, fr_channel_t * chan); +static struct 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); +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 ); + +/* Inverse ARP and Dynamic routing functions */ +int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct device *dev); +int is_arp(void *buf); +int send_inarp_request(sdla_t *card, struct device *dev); + /* Udp management functions */ -static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct 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 device *dev, int dlci, fr_channel_t * chan); -static int udp_pkt_type(struct sk_buff *skb, sdla_t * card); +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t *card, struct sk_buff *skb, struct 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 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 ****************************************************/ /*============================================================================ @@ -313,154 +355,183 @@ * Return: 0 o.k. * < 0 failure. */ -int wpf_init(sdla_t * card, wandev_conf_t * conf) +int wpf_init(sdla_t *card, wandev_conf_t *conf) { - union { + union + { char str[80]; fr_conf_t cfg; } u; int i; + /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_FR) - { + if (conf->config_id != WANCONFIG_FR) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); + 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; + switch (card->hw.fwid) { + case SFID_FR508: - card->mbox = (void *) (card->hw.dpmbase + FR508_MBOX_OFFS); - card->flags = (void *) (card->hw.dpmbase + FR508_FLAG_OFFS); + 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); + 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 */ + + /* Initialze the configuration structure sent to the board to zero */ 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; + + /* Configure adapter firmware */ + + 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; + + u.cfg.options = 0x0000; + printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname); + + switch (conf->u.fr.signalling) { + + case WANOPT_FR_Q933: + u.cfg.options |= 0x0200; break; + + case WANOPT_FR_LMI: + u.cfg.options |= 0x0400; break; + + case WANOPT_NO: + u.cfg.options |= 0x0800; break; } - if (conf->station == WANOPT_CPE) - { + + if (conf->station == WANOPT_CPE) { + + u.cfg.station = 0; u.cfg.options |= 0x8000; /* auto config DLCI */ - card->u.f.dlci_num = 0; - } - else - { + 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; + + 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; + 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); + + 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->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.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 = NULL; //&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; + init_global_statistics( card ); + + card->TracingEnabled = 0; + + return 0; } /******* WAN Device Driver Entry Points *************************************/ @@ -468,17 +539,20 @@ /*============================================================================ * Update device status & statistics. */ - -static int update(wan_device_t * wandev) +static int update (wan_device_t* wandev) { - sdla_t *card; + 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)) + + if (test_and_set_bit(0, (void*)&wandev->critical)) return -EAGAIN; + card = wandev->private; fr_get_err_stats(card); fr_get_stats(card); @@ -498,85 +572,111 @@ * Return: 0 o.k. * < 0 failure (channel will not be created) */ - -static int new_if(wan_device_t * wandev, struct device *dev, wanif_conf_t * conf) +static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf) { - sdla_t *card = wandev->private; - fr_channel_t *chan; + sdla_t* card = wandev->private; + fr_channel_t* chan; int err = 0; - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) - { + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + printk(KERN_INFO "%s: invalid interface name!\n", - card->devname); + 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])) - { + if (is_digit(conf->addr[0])) { + int dlci = dec_to_uint(conf->addr, 0); - if (dlci && (dlci <= 4095)) - { + + if (dlci && (dlci <= 4095)) { + chan->dlci = dlci; - } - else - { - printk(KERN_ERR "%s: invalid DLCI %u on interface %s!\n", - wandev->name, dlci, chan->name); + + } 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); + + } else { + printk(KERN_ERR + "%s: invalid media address on interface %s!\n", + wandev->name, chan->name); err = -EINVAL; } - if (err) - { + + 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->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)); + chan->bc = max( 1, min( conf->bc, 512 ) ); if (conf->be) - chan->be = max(0, min(conf->be, 511)); - } - else + 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); + + chan->inarp = conf->inarp ? INARP_REQUEST : INARP_NONE; + chan->inarp_interval = conf->inarp_interval ? conf->inarp_interval : 10; + + chan->dlci_configured = DLCI_NOT_CONFIGURED; + + chan->tx_int_status = DISABLED; + + chan->enable_IPX = conf->enable_IPX; + + if (conf->network_number) + chan->network_number = conf->network_number; + else + chan->network_number = 0xDEADBEEF; + + 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 device *dev) +static int del_if (wan_device_t* wandev, struct device* dev) { - if (dev->priv) - { + if (dev->priv) { + kfree(dev->priv); dev->priv = NULL; } + return 0; } @@ -585,41 +685,46 @@ /*============================================================================ * Execute adapter interface command. */ -static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data) +static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data) { - fr_mbox_t *mbox = card->mbox; + 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; + + if( copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) + return -EFAULT; + /* execute command */ - do + do { memcpy(&mbox->cmd, &cmd, sizeof(cmd)); - if (cmd.length) - { - if(copy_from_user((void *) &mbox->data, u_data, cmd.length)) + + 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 */ + else return -EIO; + + } while (err && retry-- && fr_event(card, err, mbox)); - if(copy_to_user(u_cmd, (void *) &mbox->cmd, sizeof(fr_cmd_t))) + /* 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)) + + if (len && u_data && !copy_to_user(u_data, (void*)&mbox->data, len)) return -EFAULT; return 0; } /****** Network Device Interface ********************************************/ + /*============================================================================ * Initialize Linux network interface. * @@ -627,35 +732,43 @@ * interface registration. Returning anything but zero will fail interface * registration. */ -static int if_init(struct device *dev) +static int if_init (struct device* dev) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - wan_device_t *wandev = &card->wandev; + 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; + 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); + dev->type = ARPHRD_DLCI; /* ARP h/w type */ + dev->flags |= IFF_POINTOPOINT; + 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; + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = wandev->maddr; + dev->mem_end = wandev->maddr + 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; } @@ -667,102 +780,74 @@ * * Return 0 if O.k. or errno. */ - -static int if_open(struct device *dev) +static int if_open (struct device* dev) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - struct device *dev2; + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; int err = 0; - fr508_flags_t *flags = card->flags; + 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 -EBUSY; /* only one open is allowed */ + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; - if (!card->open_cnt) - { + + 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 = intr_test( card ); + + if ((err) || (Intr_test_counter !=(MAX_INTR_TEST_COUNTER +1))) { + + printk( + "%s: Interrupt Test Failed, Counter: %i\n", + card->devname, Intr_test_counter); + printk( "Please choose another interrupt\n"); 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; - } - } + ,card->devname, Intr_test_counter); + + /* - 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); + 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 (fr_set_intr_mode(card, 0xB3, card->wandev.mtu, 100)) { + + err = -EIO; + card->wandev.critical = 0; + return err; } - flags->imask &= ~0x02; + + printk( KERN_INFO "%s: DLCI list Tx Interrupt Mode\n", + card->devname); + + flags->imask &= ~0x22; + 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 @@ -770,23 +855,28 @@ * * 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 + * 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); + 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); + 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); + do_gettimeofday( &tv ); chan->router_start_time = tv.tv_sec; + card->wandev.critical = 0; return err; } @@ -796,19 +886,21 @@ * o if this is the last open, then disable communications and interrupts. * o reset flags. */ - -static int if_close(struct device *dev) +static int if_close (struct device* dev) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) + 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) - { + + if (!card->open_cnt) { + wanpipe_set_state(card, WAN_DISCONNECTED); - fr_set_intr_mode(card, 0, 0); + fr_set_intr_mode(card, 0, 0, 0); fr_comm_disable(card); } card->wandev.critical = 0; @@ -825,15 +917,15 @@ * * Return: media header length. */ - -static int if_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) +static int if_header (struct sk_buff* skb, struct 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) - { + + if (hdr_len < 0) { hdr_len = 0; skb->protocol = 0; } @@ -849,14 +941,14 @@ * Return: 1 physical address resolved. * 0 physical address not resolved */ - -static int if_rebuild_hdr(struct sk_buff *skb) +static int if_rebuild_hdr (struct sk_buff* skb) { - struct device *dev=skb->dev; - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; + struct 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); + card->devname, dev->name); return 1; } @@ -864,6 +956,7 @@ * 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 set critical flag when accessing board. * 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. @@ -878,220 +971,239 @@ * 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 device *dev) +static int if_send (struct sk_buff* skb, struct device* dev) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - int retry = 0, err; - unsigned char *sendpacket; - struct device *dev2; - unsigned long check_braddr, check_mcaddr; - fr508_flags_t *adptr_flags = card->flags; + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + int retry = 0, err; + unsigned char *sendpacket; + struct 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; + fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface; + + ++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. + 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); + ++chan->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. + */ + ++chan->if_send_busy; ++chan->ifstats.collisions; - if ((jiffies - chan->tick_counter) < (5 * HZ)) + + 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) + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) dev2->tbusy = 0; + } + + if (chan->consecutive_send_fails > MAX_SEND_FAILS ) { + chan->consecutive_send_fails = 0; + dev_kfree_skb(skb); + ++chan->ifstats.rx_dropped; + return 0; } + sendpacket = skb->data; - udp_type = udp_pkt_type(skb, card); - if (udp_type == UDP_DRVSTATS_TYPE) - { + + 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) + 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; + + + if (sendpacket[2] == 0x45 ) { + /* 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) - { + disable_irq(card->hw.irq); + + 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); + + /* 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; + enable_irq(card->hw.irq); return 1; } + ++chan->if_send_critical_non_ISR; ++chan->ifstats.tx_dropped; + printk(KERN_INFO "critical %02X\n", card->wandev.critical); 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); + enable_irq(card->hw.irq); 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) - { + + 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) - { + ++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->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + + } else if (!is_tx_ready(card, chan)) { + dlci_interface->gen_interrupt |= 0x02; + dlci_interface->packet_length = skb->len; + dev->tbusy = 1; chan->tick_counter = jiffies; + adptr_flags->imask |= 0x02; - ++chan->if_send_no_bfrs; + ++ chan->if_send_no_bfrs; + ++ chan->ifstats.tx_errors; + ++chan->consecutive_send_fails; retry = 1; - } - else - { + } else { send_data = 1; /* If it's an IPX packet */ - if (sendpacket[1] == 0x00 && + 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! */ + sendpacket[7] == 0x37) { + + if( chan->enable_IPX ) { + switch_net_numbers(sendpacket, + chan->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; + + if (send_data){ + err = + fr508_send(card, chan->dlci, 0, skb->len, skb->data); + + if (err) { + switch(err) { + case FRRES_CIR_OVERFLOW: + case FRRES_BUFFER_OVERFLOW: + dlci_interface->gen_interrupt |= 0x02; + 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; + ++chan->consecutive_send_fails; + break; + default: + ++chan->if_send_dlci_disconnected; + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + break; } - 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; + } else { + chan->consecutive_send_fails = 0; + ++ 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); + 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); + + enable_irq(card->hw.irq); return retry; } @@ -1099,54 +1211,72 @@ * Reply to UDP Management system. * Return nothing. */ - -static int reply_udp(unsigned char *data, unsigned int mbox_len) +static int reply_udp( unsigned char *data, unsigned int mbox_len ) { - unsigned short len, udp_length, temp, i, ip_length; + 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) - { + if ( udp_length & 0x0001 ) { udp_length += 1; len += 1; } - temp = (udp_length << 8) | (udp_length >> 8); - memcpy(&data[26], &temp, 2); + + 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); + 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); + 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; + + for( i = 0; i < udp_length+12; i+=2 ) { + + memcpy(&temp,&data[14+i],2); + sum += (unsigned long)temp; + } - while (sum >> 16) + + while (sum >> 16 ) { sum = (sum & 0xffffUL) + (sum >> 16); + } - temp = (unsigned short) sum; + temp = (unsigned short)sum; temp = ~temp; - if (temp == 0) + + 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); + 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); @@ -1154,600 +1284,499 @@ 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; + + for( i = 0; i < 20; i+=2 ) { + + memcpy(&temp,&data[2+i],2); + sum += (unsigned long)temp; } - while (sum >> 16) + + while (sum >> 16 ) { sum = (sum & 0xffffUL) + (sum >> 16); - temp = (unsigned short) sum; + } + + temp = (unsigned short)sum; temp = ~temp; - if (temp == 0) + + if( temp == 0 ) temp = 0xffff; + memcpy(&data[12], &temp, 2); + return len; -} /* reply_udp */ +} /* 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]); + + 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; + 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); + 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) { + + + 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; + 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); + 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 */ +} /* switch_net_numbers */ /*============================================================================ - * Get Ethernet-style interface statistics. - * Return a pointer to struct net_device_stats. + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. */ - -static struct net_device_stats *if_stats(struct device *dev) +static struct enet_statistics* if_stats (struct device* dev) { - fr_channel_t *chan = dev->priv; - if(chan==NULL) + 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) +static void fr508_isr (sdla_t* card) { - fr508_flags_t *flags = card->flags; - fr_buf_ctl_t *bctl; + fr508_flags_t* flags = card->flags; + fr_buf_ctl_t* bctl; char *ptr = &flags->iflag; - struct device *dev = card->wandev.dev; - struct device *dev2; - int i; - unsigned long host_cpu_flags; - unsigned disable_tx_intr = 1; - fr_channel_t *chan; - fr_dlci_interface_t *dlci_interface; + struct device* dev = card->wandev.dev; + struct device* dev2; + int i,err; + unsigned disable_tx_intr; + fr_channel_t* chan; + fr_dlci_interface_t* dlci_interface; + fr_mbox_t* mbox = card->mbox; + /* This flag prevents nesting of interrupts. See sdla_isr() routine - * in sdlamain.c. + * 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); + + 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) - */ + + /* 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->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); + + 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) - { + + /* Find the structure and make it unbusy */ + dev = find_channel( card, flags->dlci); + dev->tbusy = 0; + chan = dev->priv; + + mark_bh(NET_BH); + + /* check to see if any other interfaces are + * busy. If so then do not disable the tx + * interrupts + */ + if (!card->wandev.enable_tx_int) { + disable_tx_intr = 1; + 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; + } + break; + case 0x08: - Intr_test_counter++; + Intr_test_counter++; ++card->statistics.isr_intr_test; + break; + + case 0x10: /* Event interrupt occured */ + + 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); + break; + + case 0x20: /* Timer interrupt */ + /* Used to send inarp request at given interval */ + + if (card->wandev.state == WAN_CONNECTED) { + int num_remaining = 0; + for (dev=card->wandev.dev;dev;dev=dev->slave) { + fr_channel_t *chan = dev->priv; + + if (chan->inarp == INARP_REQUEST && + chan->state == WAN_CONNECTED) { + num_remaining++; + + if ((jiffies - chan->inarp_tick) > (chan->inarp_interval * HZ)) { + send_inarp_request(card,dev); + chan->inarp_tick = jiffies; + } + } + + } + if (!num_remaining) { /* no more to process */ + flags->imask &= ~0x20; + } + } + 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++) + ++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"); + 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; - } + } + + if (card->wandev.enable_tx_int) { + + 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 |= 0x02; + 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 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 device *dev; - fr_channel_t *chan; - unsigned dlci, len, offs; - void *buf; - unsigned rx_count = 0; - fr508_flags_t *flags = card->flags; + * When a receive interrupt occurs do the following: + * 1- Find the structure for the dlci that the interrupt occured on + * 2- If it doesn't exist then print appropriate msg and goto step 8. + * 3- If it exist then copy data to a skb. + * 4- If skb contains Sangoma UDP data then process them + * 5- If skb contains IPXWAN data then send IPXWAN reply packets + * 6- If skb contains Inverse Arp data then send Inv Arp replies + * 7- If skb contains any other data then decapsulate the packet and + * send it to the stack. + * 8- Release the receive element and update receive pointers on the board + */ +static void fr508_rx_intr (sdla_t* card) +{ + fr_buf_ctl_t* frbuf = card->rxmb; + fr508_flags_t* flags = card->flags; + fr_channel_t* chan; 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++) + struct sk_buff* skb; + struct device* dev; + void* buf; + unsigned dlci, len, offs; + 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); + len = frbuf->length; + dlci = frbuf->dlci; + offs = frbuf->offset; + + /* 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); + ++card->statistics.rx_intr_on_orphaned_DLCI; + + } else { 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; + + 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,chan->name, chan->enable_IPX, chan->network_number)) { + + if (chan->enable_IPX) { + fr508_send(card, dlci, 0, skb->len, skb->data); } - 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); + dev_kfree_skb(skb); + + } else if (is_arp(skb->data)) { + if (process_ARP((arphdr_1490_t *)skb->data, card, dev)) { + printk (KERN_INFO "%s: Error processing ARP Packet.\n", card->devname); } - 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; - } + dev_kfree_skb(skb); + + } else if ( skb->data[0] != 0x03) { + printk(KERN_INFO "%s: Non IETF packet discarded.\n", card->devname); + dev_kfree_skb(skb); + + } 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; } - } - } - /* 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 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); - } + } + } + } + + /* 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; + } + /*============================================================================ * Spurious interrupt handler. * o print a warning * o - * If number of spurious interrupts exceeded some limit, then ??? */ - -static void spur_intr(sdla_t * card) +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! - */ +/*=========================================================================== + * 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 && + + if( sendpacket[1] == 0x00 && sendpacket[2] == 0x80 && sendpacket[6] == 0x81 && - sendpacket[7] == 0x37) - { + sendpacket[7] == 0x37) { + /* It's an IPX packet */ - if (!enable_IPX) { + if(!enable_IPX) { /* Return 1 so we don't pass it up the stack. */ return 1; } - } - else - { + } else { /* It's not IPX so return and pass it up the stack. */ return 0; } - if (sendpacket[24] == 0x90 && - sendpacket[25] == 0x04) + + if( sendpacket[24] == 0x90 && + sendpacket[25] == 0x04) { /* It's IPXWAN */ - if (sendpacket[10] == 0x02 && - sendpacket[42] == 0x00) + + 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) + 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) + if( sendpacket[i + 4] != 0x02) { sendpacket[i + 1] = 0; } } + /* Skip over the extended Node ID option */ - if (sendpacket[i] == 0x04) + if( sendpacket[i] == 0x04 ) + { i += 8; - /* We also want to turn off all header compression opt. */ - for (; sendpacket[i] == 0x80;) + } + + /* 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); + + printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); } - else if (sendpacket[42] == 0x02) + else if( sendpacket[42] == 0x02 ) { /* This is an information request packet */ - printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n", devname); + 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'; @@ -1756,465 +1785,540 @@ 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[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) + for(i = 73; i < 107; i+= 1) + { sendpacket[i] = 0; - printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", devname); + } + + printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); } else { - printk(KERN_INFO "%s: Unknown IPXWAN packet!\n", devname); + 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); + 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); + + /* 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! - */ + * Process Route. + * This routine is called as a polling routine to dynamically add/delete routes + * negotiated by inverse ARP. It is in this "task" because we don't want routes + * to be added while in interrupt context. +*/ + +static void process_route (sdla_t* card) +{ + struct device* dev; + struct in_device *in_dev; + + /* Dynamic Route adding/removing */ + for (dev = card->wandev.dev; dev ; dev = dev->slave) { + if ( ((fr_channel_t*)dev->priv)->route_flag == ADD_ROUTE || + ((fr_channel_t*)dev->priv)->route_flag == REMOVE_ROUTE ) { + struct rtentry route; + int err = 0; + mm_segment_t fs = get_fs(); + + in_dev = dev->ip_ptr; -static void wpf_poll(sdla_t * card) -{ -/* struct 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; + if( in_dev != NULL && in_dev->ifa_list != NULL) { + memset(&route, 0, sizeof(route)); + route.rt_dev = dev->name; + route.rt_flags = 0; + + ((struct sockaddr_in *) &(route.rt_dst)) -> + sin_addr.s_addr=in_dev->ifa_list->ifa_address; + ((struct sockaddr_in *) &(route.rt_dst)) -> + sin_family = AF_INET; + ((struct sockaddr_in *) &(route.rt_genmask)) -> + sin_addr.s_addr = 0xFFFFFFFF; + ((struct sockaddr_in *) &(route.rt_genmask)) -> + sin_family = AF_INET; + + switch(((fr_channel_t*)dev->priv)->route_flag) { + + case ADD_ROUTE: + set_fs(get_ds()); /* get user space block */ + err = ip_rt_ioctl( SIOCADDRT, &route); + set_fs(fs); /* restore old block */ + + if (err) { + printk(KERN_INFO "%s: Adding of route failed. Error: %d\n", card->devname,err); + printk(KERN_INFO "%s: Address: %s\n", + ((fr_channel_t*)dev->priv)->name, + in_ntoa(in_dev->ifa_list->ifa_address) ); + } + else { + ((fr_channel_t*)dev->priv)-> + route_flag = ROUTE_ADDED; + } + break; + + case REMOVE_ROUTE: + set_fs(get_ds()); /* get user space block */ + err = ip_rt_ioctl( SIOCDELRT, &route); + set_fs(fs); /* restore old block */ + + if (err) { + printk(KERN_INFO "%s: Deleting of route failed. Error: %d\n", card->devname,err); + printk(KERN_INFO "%s: Address: %s\n", + dev->name,in_ntoa(in_dev->ifa_list->ifa_address) ); + } else { + printk(KERN_INFO "%s: Removed route.\n", + ((fr_channel_t*)dev->priv)->name); + ((fr_channel_t*)dev->priv)->route_flag = NO_ROUTE; + } + break; + } /* Case Statement */ + } + } /* If ADD/DELETE ROUTE */ + } /* Device 'For' Loop */ + + card->poll = NULL; } + + /****** 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) +static int fr_read_version (sdla_t* card, char* str) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - do + + 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) - { + if (!err && str) { + int len = mbox->cmd.length; + memcpy(str, mbox->data, len); - str[len] = '\0'; + str[len] = '\0'; } return err; } + /*============================================================================ * Set global configuration. */ - -static int fr_configure(sdla_t * card, fr_conf_t * conf) +static int fr_configure (sdla_t* card, fr_conf_t *conf) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int dlci_num = card->u.f.dlci_num; int err, i; - do + + 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]; + + 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); + 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)); + + } 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) +static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci) { - fr_mbox_t *mbox = card->mbox; + 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.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--); + + } while (err && retry--); + return err; } /*============================================================================ * Set interrupt mode. */ -static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu) +static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu, unsigned short timeout) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; + fr508_intr_ctl_t* ictl = (void*)mbox->data; 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); - } + memset(ictl, 0, sizeof(fr508_intr_ctl_t)); + ictl->mode = mode; + ictl->tx_len = mtu; + ictl->irq = card->hw.irq; + + /* indicate timeout on timer */ + if (mode & 0x20) ictl->timeout = timeout; + + 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)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Enable communications. */ -static int fr_comm_enable(sdla_t * card) +static int fr_comm_enable (sdla_t* card) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - do + + 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)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Disable communications. */ -static int fr_comm_disable(sdla_t * card) +static int fr_comm_disable (sdla_t* card) { - fr_mbox_t *mbox = card->mbox; + 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)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Get communications error statistics. */ -static int fr_get_err_stats(sdla_t * card) +static int fr_get_err_stats (sdla_t* card) { - fr_mbox_t *mbox = card->mbox; + 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; + } 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; + + } return err; } + /*============================================================================ * Get statistics. */ -static int fr_get_stats(sdla_t * card) +static int fr_get_stats (sdla_t* card) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - do + + + 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; + } 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; + 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) +static int fr_add_dlci (sdla_t* card, int dlci, int num) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err, i; - do + + do { - unsigned short *dlci_list = (void *) mbox->data; + 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.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)); + + } 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) +static int fr_activate_dlci (sdla_t* card, int dlci, int num) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err, i; + do { - unsigned short *dlci_list = (void *) mbox->data; + 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.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)); + + } 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) +static int fr_issue_isf (sdla_t* card, int isf) { - fr_mbox_t *mbox = card->mbox; + 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.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)); + + } 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) +static int fr508_send (sdla_t* card, int dlci, int attr, int len, void *buf) { - fr_mbox_t *mbox = card->mbox; + 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.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); + } 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. + * Main asyncronous 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) +static int fr_event (sdla_t *card, int event, fr_mbox_t* mbox) { - fr508_flags_t *flags = card->flags; + fr508_flags_t* flags = card->flags; char *ptr = &flags->iflag; int i; - switch (event) - { + + switch (event) { + case FRRES_MODEM_FAILURE: return fr_modem_failure(card, mbox); + case FRRES_CHANNEL_DOWN: + { + struct device *dev; + + /* Remove all routes from associated DLCI's */ + for (dev = card->wandev.dev; dev; dev = dev->slave) { + fr_channel_t *chan = dev->priv; + if (chan->route_flag == ROUTE_ADDED) { + chan->route_flag = REMOVE_ROUTE; + card->poll = &process_route; + } + + if (chan->inarp == INARP_CONFIGURED) { + chan->inarp = INARP_REQUEST; + } + } + wanpipe_set_state(card, WAN_DISCONNECTED); return 1; + } + case FRRES_CHANNEL_UP: + { + struct device *dev; + int num_requests = 0; + + /* Remove all routes from associated DLCI's */ + for (dev = card->wandev.dev; dev; dev = dev->slave) { + fr_channel_t *chan = dev->priv; + if( chan->inarp == INARP_REQUEST ){ + num_requests++; + chan->inarp_tick = jiffies; + } + } + + /* Allow timer interrupts */ + if (num_requests) flags->imask |= 0x20; 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); + 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++) + 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"); + 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; + break; default: printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" - ,card->devname, mbox->cmd.command, event); + , card->devname, mbox->cmd.command, event); } + return 0; } @@ -2223,178 +2327,227 @@ * * Return zero if previous command has to be cancelled. */ -static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox) +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) - { + 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) +static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox) { - dlci_status_t *status = (void *) mbox->data; + 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 device *dev2; - for (; cnt; --cnt, ++status) - { - unsigned short dlci = status->dlci; - struct 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) - { + fr508_flags_t* flags = card->flags; + struct device* dev2; + + + for (; cnt; --cnt, ++status) { + + unsigned short dlci= status->dlci; + struct 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 == 0x00) { printk(KERN_INFO - "%s: DLCI %u has been deleted!\n", - card->devname, dlci); + "%s: DLCI %u is inactive!\n", + card->devname, dlci); + if (dev && dev->start) set_chan_state(dev, WAN_DISCONNECTED); } - else if (status->state & 0x02) - { + + if (status->state & 0x01) { + 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. - */ + "%s: DLCI %u has been deleted!\n", + card->devname, dlci); + + if (dev && dev->start) { + fr_channel_t *chan = dev->priv; + + if (chan->route_flag == ROUTE_ADDED) { + chan->route_flag = REMOVE_ROUTE; + card->poll = &process_route; + } + + if (chan->inarp == INARP_CONFIGURED) { + chan->inarp = INARP_REQUEST; + } + + 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) - { + + for (dev2 =card->wandev.dev; dev2; dev2 = dev2->slave){ + chan = dev2->priv; - if (chan->dlci_configured == DLCI_CONFIG_PENDING) - { + + 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; + + 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); + 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.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); + card->devname, chan->name); + //printk(KERN_INFO + //"%s: CIR Enabled for %s: CIR = %d, BC = %d, + //BE = %d\n",card->devname, chan->name, + //cfg.cir_fwd, cfg.bc_fwd, cfg.be_fwd); + } - if (fr_dlci_configure(card, &cfg, chan->dlci)) - { - printk(KERN_INFO - "%s: DLCI Configure failed for %d\n", - card->devname, chan->dlci); - return 1; + + 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; + + /* Allow timer interrupts */ + if( chan->inarp == INARP_REQUEST && card->wandev.state == WAN_CONNECTED) { + chan->inarp_tick = jiffies; + flags->imask |= 0x20; + } + /* Read the interface byte mapping into the channel structure. */ - if (card->intr_mode == DLCI_LIST_INTR_MODE) - read_DLCI_IB_mapping(card, chan); + read_DLCI_IB_mapping( card, chan ); } + } return 1; } + /******* Miscellaneous ******************************************************/ /*============================================================================ * Update channel state. */ -static int update_chan_state(struct device *dev) +static int update_chan_state (struct device* dev) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - fr_mbox_t *mbox = card->mbox; + 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 + 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)); + + } while (err && retry-- && fr_event(card, err, mbox)); - if (!err) - { - unsigned short *list = (void *) mbox->data; + 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); + + for (; cnt; --cnt, ++list) { + + if (*list == chan->dlci) { + 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 device *dev, int state) +static void set_chan_state (struct device* dev, int state) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; unsigned long flags; - + save_flags(flags); cli(); - - if (chan->state != state) - { - switch (state) - { + + if (chan->state != state) { + + switch (state) { + case WAN_CONNECTED: printk(KERN_INFO "%s: interface %s connected!\n" - ,card->devname, dev->name); + , card->devname, dev->name); break; + case WAN_CONNECTING: - printk(KERN_INFO - "%s: interface %s connecting...\n", - card->devname, dev->name); + 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); + printk (KERN_INFO + "%s: interface %s disconnected!\n", + card->devname, dev->name); break; } + chan->state = state; } + chan->state_tick = jiffies; restore_flags(flags); } @@ -2402,14 +2555,18 @@ /*============================================================================ * Find network device by its channel number. */ -static struct device *find_channel(sdla_t * card, unsigned dlci) +static struct device* find_channel (sdla_t* card, unsigned dlci) { - struct device *dev; + struct device* dev; + for (dev = card->wandev.dev; dev; dev = dev->slave) - if (((fr_channel_t *) dev->priv)->dlci == dlci) + + 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. @@ -2417,22 +2574,13 @@ * Return: 1 - Tx buffer(s) available * 0 - no buffers available */ - -static int is_tx_ready(sdla_t * card, fr_channel_t * chan) +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; - } + unsigned char sb = inb(card->hw.port); + + if (sb & 0x02) + return 1; + return 0; } @@ -2440,13 +2588,16 @@ * 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) +static unsigned int dec_to_uint (unsigned char* str, int len) { unsigned val; - if (!len) + + if (!len) len = strlen(str); + for (val = 0; len && is_digit(*str); ++str, --len) - val = (val * 10) + (*str - (unsigned) '0'); + val = (val * 10) + (*str - (unsigned)'0'); + return val; } @@ -2454,371 +2605,624 @@ * Process UDP call of type FPIPE8ND */ -static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, int dlci, fr_channel_t * chan) +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, struct sk_buff *skb, struct 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 char frames; + unsigned int loops, 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; + 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]); + + + 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; + return 1; } - memcpy(data, sendpacket, skb->len); - switch (data[47]) - { + + memcpy(data,sendpacket,skb->len); + + switch(data[47]) { + /* FPIPE_ENABLE_TRACE */ case 0x41: + /* FPIPE_DISABLE_TRACE */ - case 0x42: + 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; + + 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) - { + if(card->hw.fwid != SFID_FR508) { ++chan->UDP_FPIPE_mgmt_adptr_type_err; udp_mgmt_req_valid = 0; + break; } - break; default: break; - } - if (!udp_mgmt_req_valid) - { + } + + 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) + + } else { + + switch (data[47]) { + + /* FPIPE_ENABLE_TRACE */ + case 0x41: + + if(!card->TracingEnabled) { + do { - /* set return code */ - data[50] = 1; + /* 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) { + + card->TracingEnabled = 0; + /* set the return code */ + data[50] = mbox->cmd.result; 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; + + /* 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 - 30 (IP header + frame + * header (2) ) - 32 (fpipemon CBLOCK) + */ + available_buffer_space = 1938; + /* set return code */ 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; + } else { + /* set return code to line trace already + enabled */ + data[50] = 1; + } + + mbox->cmd.length = 0; + card->TracingEnabled = 1; + break; + + + /* FPIPE_DISABLE_TRACE */ + case 0x42: + + if(card->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; + card->TracingEnabled = 0; + break; + + + /* FPIPE_GET_TRACE_INFO */ + case 0x43: + + /* Line trace cannot be performed on the 502 */ + if(!card->TracingEnabled) { + + /* set return code */ + data[50] = 1; + mbox->cmd.length = 0; + break; + } + + buffer_length = 0; + loops = (num_frames < 20)?num_frames:20; + data[62] = 0x00; + 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 - buffer_length )) { + 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; + } } - } - /* Fill UDP TTL */ - data[10] = card->wandev.ttl; - len = reply_udp(data, mbox->cmd.length); - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) - { + + /* 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 { + memcpy(data,sendpacket,skb->len); + memcpy(&data[47],&mbox->cmd, sizeof(fr_cmd_t)); + ++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) + if (err) ++chan->UDP_FPIPE_mgmt_adptr_send_passed; else ++chan->UDP_FPIPE_mgmt_adptr_send_failed; dev_kfree_skb(skb); - } - else - { + + } else { /* Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) - { + 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)) - { + 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 - { + } else { ++chan->UDP_FPIPE_mgmt_passed_to_stack; netif_rx(new_skb); - } - } - else - { + } + + } else { ++chan->UDP_FPIPE_mgmt_no_socket; - printk(KERN_INFO - "%s: UDP mgmt cmnd, no socket buffers available!\n", - card->devname); - } - } + printk(KERN_INFO + "%s: UDP mgmt cmnd, no socket buffers available!\n", + card->devname); + } + } + kfree(data); return 0; } + +/*============================================================================== + * Send Inverse ARP Request + */ + +int send_inarp_request(sdla_t *card, struct device *dev) +{ + arphdr_1490_t *ArpPacket; + arphdr_fr_t *arphdr; + fr_channel_t *chan = dev->priv; + struct in_device *in_dev; + + in_dev = dev->ip_ptr; + + if(in_dev != NULL ) { + + ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC); + /* SNAP Header indicating ARP */ + ArpPacket->control = 0x03; + ArpPacket->pad = 0x00; + ArpPacket->NLPID = 0x80; + ArpPacket->OUI[0] = 0; + ArpPacket->OUI[1] = 0; + ArpPacket->OUI[2] = 0; + ArpPacket->PID = 0x0608; + + arphdr = (arphdr_fr_t *)(ArpPacket + 1); // Go to ARP Packet + + /* InARP request */ + arphdr->ar_hrd = 0x0F00; /* Frame Relay HW type */ + arphdr->ar_pro = 0x0008; /* IP Protocol */ + arphdr->ar_hln = 2; /* HW addr length */ + arphdr->ar_pln = 4; /* IP addr length */ + arphdr->ar_op = htons(0x08); /* InARP Request */ + arphdr->ar_sha = 0; /* src HW DLCI - Doesn't matter */ + if(in_dev->ifa_list != NULL) + arphdr->ar_sip = in_dev->ifa_list->ifa_local; /* Local Address */else + arphdr->ar_sip = 0; + arphdr->ar_tha = 0; /* dst HW DLCI - Doesn't matter */ + arphdr->ar_tip = 0; /* Remote Address -- what we want */ + + printk(KERN_INFO "%s: Sending InARP request on DLCI %d.\n", card->devname, chan->dlci); + fr508_send(card, chan->dlci, 0, + sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), + (void *)ArpPacket); + kfree(ArpPacket); + } + return 1; +} + + +/*============================================================================== + * Check packet for ARP Type + */ + +int is_arp(void *buf) +{ + arphdr_1490_t *arphdr = (arphdr_1490_t *)buf; + + if (arphdr->pad == 0x00 && + arphdr->NLPID == 0x80 && + arphdr->PID == 0x0608) + return 1; + else return 0; +} + +/*============================================================================== + * Process ARP Packet Type + */ + +int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct device* dev) +{ + arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */ + fr_buf_ctl_t* frbuf = card->rxmb; + struct in_device *in_dev; + + + in_dev = dev->ip_ptr; + if( in_dev != NULL && in_dev->ifa_list != NULL) { + switch (ntohs(arphdr->ar_op)) { + + case 0x08: // Inverse ARP request -- Send Reply, add route. + + /* Check for valid Address */ + printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Req\n", ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip)); + + if ((in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) { + printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", card->devname); + printk(KERN_INFO "mask %X\n", in_dev->ifa_list->ifa_mask); + printk(KERN_INFO "local %X\n", in_dev->ifa_list->ifa_local); + return -1; + } + + if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) { + printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", card->devname); + return -1; + } + + arphdr->ar_op = htons(0x09); /* InARP Reply */ + + /* Set addresses */ + arphdr->ar_tip = arphdr->ar_sip; + arphdr->ar_sip = in_dev->ifa_list->ifa_local; + + fr508_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket); + + /* Modify Point-to-Point Address */ + { + struct ifreq if_info; + struct sockaddr_in *if_data; + mm_segment_t fs = get_fs(); + int err; + + /* Set remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data->sin_addr.s_addr = arphdr->ar_tip; + if_data->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + + set_fs(fs); /* restore old block */ + } + + /* Add Route Flag */ + /* The route will be added in the polling routine so + that it is not interrupt context. */ + + ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE; + card->poll = &process_route; + + break; + + case 0x09: // Inverse ARP reply + + /* Check for valid Address */ + printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Reply\n", ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip)); + + if ((in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) { + printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", card->devname); + return -1; + } + + if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) { + printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", card->devname); + return -1; + } + + /* Modify Point-to-Point Address */ + { + struct ifreq if_info; + struct sockaddr_in *if_data; + mm_segment_t fs = get_fs(); + int err; + + /* Set remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data->sin_addr.s_addr = arphdr->ar_sip; + if_data->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + + set_fs(fs); /* restore old block */ + } + + /* Add Route Flag */ + /* The route will be added in the polling routine so + that it is not interrupt context. */ + + ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE; + ((fr_channel_t *) dev->priv)->inarp = INARP_CONFIGURED; + card->poll = &process_route; + + break; + default: // ARP's and RARP's -- Shouldn't happen. + } + } + + 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) +static int intr_test( sdla_t* card ) { - fr_mbox_t *mb = card->mbox; - int err, i; + 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 */ + + err = fr_set_intr_mode( card, 0x08, card->wandev.mtu, 0 ); + + 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.length = 0; mb->cmd.command = 0x40; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) + + if (err != CMD_OK) fr_event(card, err, mb); } - } - else - { - return err; + + } else { + return err; } - err = fr_set_intr_mode(card, 0, card->wandev.mtu); - if (err != CMD_OK) + + err = fr_set_intr_mode( card, 0, card->wandev.mtu, 0 ); + + 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 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 device* dev, int dlci, fr_channel_t* chan ) { int c_retry = MAX_CMD_RETRY; unsigned char *sendpacket; @@ -2826,151 +3230,222 @@ unsigned char *data; unsigned char *buf; unsigned int len; - fr_mbox_t *mbox = card->mbox; + 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]); + 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]) - { + 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; + *(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[122] = + chan->consecutive_send_fails; + mbox->cmd.length = 64; 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; + *(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; + *(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[146] = 0; + 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) - { + 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; - } - } + 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) - { + + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + err = fr508_send(card, dlci, 0, len, data); - if (err) + + if (err) ++chan->UDP_DRVSTATS_mgmt_adptr_send_failed; else ++chan->UDP_DRVSTATS_mgmt_adptr_send_passed; dev_kfree_skb(skb); - } - else - { + + } else { + /* Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) - { + 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)) - { + + /* 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 - { + } else { ++chan->UDP_DRVSTATS_mgmt_passed_to_stack; netif_rx(new_skb); - } - } - else - { + } + + } else { ++chan->UDP_DRVSTATS_mgmt_no_socket; - printk(KERN_INFO "%s: UDP mgmt cmnd, no socket buffers available!\n", card->devname); - } - } + printk(KERN_INFO + "%s: UDP mgmt cmnd, no socket buffers available!\n", + card->devname); + } + } + kfree(data); return 0; } @@ -2978,52 +3453,57 @@ /*============================================================================== * Determine what type of UDP call it is. DRVSTATS or FPIPE8ND ? */ - -static int udp_pkt_type(struct sk_buff *skb, sdla_t * card) +static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ) { - unsigned char *sendpacket; - unsigned char buf2[5]; + 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) - { + + 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) - { + + } 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 + + } else return UDP_INVALID_TYPE; - } - else + + } else return UDP_INVALID_TYPE; + } + /*============================================================================== * Initializes the Statistics values in the fr_channel structure. */ - -void init_chan_statistics(fr_channel_t * chan) +void init_chan_statistics( fr_channel_t* chan) { + chan->route_flag = NO_ROUTE; chan->if_send_entry = 0; chan->if_send_skb_null = 0; chan->if_send_broadcast = 0; @@ -3039,12 +3519,16 @@ chan->if_send_no_bfrs = 0; chan->if_send_adptr_bfrs_full = 0; chan->if_send_bfrs_passed_to_adptr = 0; + + chan->consecutive_send_fails = 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_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; @@ -3064,64 +3548,66 @@ 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) +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.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; + 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) +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 - { + 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); + } 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; + 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); + 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)); + chan->dlci_int_interface = (void*)(card->hw.dpmbase + + ( chan->IB_addr & 0x00001FFF)); found = 1; - break; - } + break; + } } if (!found) - printk(KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n", - card->devname, chan->dlci); + printk( KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n", + card->devname, chan->dlci); } /****** End *****************************************************************/ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdla_ppp.c linux.ac/drivers/net/sdla_ppp.c --- linux.vanilla/drivers/net/sdla_ppp.c Wed Jan 6 23:02:22 1999 +++ linux.ac/drivers/net/sdla_ppp.c Fri Jun 4 23:52:38 1999 @@ -10,7 +10,15 @@ * 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. +* Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X Kernels. +* Aug 13, 1998 Jaspreet Singh o Improved Line Tracing. +* Jun 22, 1998 David Fong o Added remote IP address assignment +* Mar 15, 1998 Alan Cox o 2.1.8x basic port. +* Apr 16, 1998 Jaspreet Singh o using htons() for the IPX protocol. +* Dec 09, 1997 Jaspreet Singh o Added PAP and CHAP. +* o Implemented new routines like +* ppp_set_inbnd_auth(), ppp_set_outbnd_auth(), +* tokenize() and strstrip(). * 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 @@ -65,10 +73,13 @@ #include /* WANPIPE common user API definitions */ #include /* ARPHRD_* defines */ #include /* htons(), etc. */ -#include /* copyto/from user */ +#include +#include /* sockaddr_in */ +#include /* in_aton(), in_ntoa() prototypes */ +#include +#include #define _GNUC_ -#include /* PPP firmware API definitions */ - +#include /* PPP firmware API definitions */ /****** Defines & Macros ****************************************************/ #ifdef _DEBUG_ @@ -76,27 +87,37 @@ #else #define STATIC static #endif -#define PPP_DFLT_MTU 1500 /* default MTU */ -#define PPP_MAX_MTU 4000 /* maximum MTU */ + +#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 */ + +#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 + +typedef struct ppp_private_area { - sdla_t *card; + 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 */ + unsigned long tick_counter; /*used for 5 second counter*/ + unsigned mc; /*multicast support on or off*/ + unsigned char enable_IPX; + unsigned long network_number; + unsigned char pap; + unsigned char chap; + unsigned char sysname[31]; /* system name for in-bnd auth*/ + unsigned char userid[511]; /* list of user ids */ + unsigned char passwd[511]; /* list of passwords */ /* PPP specific statistics */ unsigned long if_send_entry; unsigned long if_send_skb_null; @@ -113,11 +134,13 @@ 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; @@ -125,7 +148,8 @@ 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_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; @@ -133,74 +157,85 @@ 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; + unsigned long UDP_DRVSTATS_mgmt_no_socket; -/* variable for keeping track of enabling/disabling FT1 monitor status */ + 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 device *dev, - wanif_conf_t * conf); -static int del_if(wan_device_t * wandev, struct device *dev); +static int update(wan_device_t *wandev); +static int new_if(wan_device_t *wandev, struct device *dev, wanif_conf_t *conf); +static int del_if(wan_device_t *wandev, struct device *dev); + /* WANPIPE-specific entry points */ -static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data); +static int wpp_exec (struct sdla *card, void *u_cmd, void *u_data); + /* Network device interface */ static int if_init(struct device *dev); static int if_open(struct device *dev); static int if_close(struct device *dev); -static int if_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len); +static int if_header(struct sk_buff *skb, struct 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 device *dev); static struct enet_statistics *if_stats(struct 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); +static int ppp_read_version(sdla_t *card, char *str); +static int ppp_set_outbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area); +static int ppp_set_inbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area); +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); +STATIC void wpp_isr(sdla_t *card); +static void rx_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); +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 int read_info( sdla_t *card ); +static int remove_route( sdla_t *card ); +static int config508(ppp_private_area_t *ppp_priv_area, 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 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 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 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 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 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 tokenize(char *str, char **tokens); +static char* strstrip(char *str, char *s); + +static int Read_connection_info; 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); - +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_PX, unsigned long network_number, unsigned short proto); /****** Public Functions ****************************************************/ /*============================================================================ @@ -215,30 +250,40 @@ * Return: 0 o.k. * < 0 failure. */ -int wpp_init(sdla_t * card, wandev_conf_t * conf) +int wpp_init(sdla_t *card, wandev_conf_t *conf) { - union { + 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); + 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; + + 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 @@ -246,33 +291,36 @@ */ 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); + + 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; + 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; + card->irq_dis_poll_count = 0; + card->u.p.authenticator = conf->u.ppp.authenticator; + card->u.p.ip_mode = conf->u.ppp.ip_mode ? + conf->u.ppp.ip_mode : WANOPT_PPP_STATIC; + card->TracingEnabled = 0; + Read_connection_info = 1; + /* initialize global statistics */ - init_global_statistics(card); + init_global_statistics( card ); + return 0; } @@ -281,17 +329,22 @@ /*============================================================================ * Update device status & statistics. */ -static int update(wan_device_t * wandev) +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)) + + if (test_and_set_bit(0, (void*)&wandev->critical)) return -EAGAIN; + card = wandev->private; + ppp_get_err_stats(card); wandev->critical = 0; return 0; @@ -309,29 +362,70 @@ * Return: 0 o.k. * < 0 failure (channel will not be created) */ - -static int new_if(wan_device_t * wandev, struct device *dev, wanif_conf_t * conf) +static int new_if(wan_device_t *wandev, struct 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); + 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; + + if( ppp_priv_area == NULL ) + return -ENOMEM; + memset(ppp_priv_area, 0, sizeof(ppp_private_area_t)); - ppp_priv_area->card = card; + + 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); + + init_ppp_priv_struct( ppp_priv_area ); + ppp_priv_area->mc = conf->mc; + ppp_priv_area->pap = conf->pap; + ppp_priv_area->chap = conf->chap; + + /* If no user ids are specified */ + if(!strlen(conf->userid) && (ppp_priv_area->pap || ppp_priv_area->chap)) + return -EINVAL; + + /* If no passwords are specified */ + if(!strlen(conf->passwd) && (ppp_priv_area->pap || ppp_priv_area->chap)) + return -EINVAL; + + if(strlen(conf->sysname) > 31) + return -EINVAL; + + /* If no system name is specified */ + if(!strlen(conf->sysname) && (card->u.p.authenticator)) + return -EINVAL; + + /* copy the data into the ppp private structure */ + memcpy(ppp_priv_area->userid, conf->userid, strlen(conf->userid)); + memcpy(ppp_priv_area->passwd, conf->passwd, strlen(conf->passwd)); + memcpy(ppp_priv_area->sysname, conf->sysname, strlen(conf->sysname)); + + + ppp_priv_area->enable_IPX = conf->enable_IPX; + if (conf->network_number) + ppp_priv_area->network_number = conf->network_number; + else + ppp_priv_area->network_number = 0xDEADBEEF; + /* prepare network device data space for registration */ dev->name = card->u.p.if_name; dev->init = &if_init; @@ -342,13 +436,14 @@ /*============================================================================ * Delete logical channel. */ - -static int del_if(wan_device_t * wandev, struct device *dev) +static int del_if(wan_device_t *wandev, struct device *dev) { if (dev->priv) { - kfree(dev->priv); - dev->priv = NULL; - } + + kfree(dev->priv); + dev->priv = NULL; + } + return 0; } @@ -357,27 +452,35 @@ /*============================================================================ * 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))) + + 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)) + + 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))) + 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)) + + if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)) return -EFAULT; + return 0; } @@ -390,7 +493,6 @@ * interface registration. Returning anything but zero will fail interface * registration. */ - static int if_init(struct device *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; @@ -398,26 +500,33 @@ 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; + 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 */ + dev->type = ARPHRD_PPP; /* ARP h/w type */ + dev->flags |= IFF_POINTOPOINT; + 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; + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = wandev->maddr; + dev->mem_end = wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length */ + dev->tx_queue_len = 100; + /* Initialize socket buffers */ dev_init_buffers(dev); + return 0; } @@ -428,7 +537,6 @@ * * Return 0 if O.k. or errno. */ - static int if_open(struct device *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; @@ -436,48 +544,91 @@ 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 -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)) { + + if (config508(ppp_priv_area, 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 = intr_test( card ); + + if( (err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) { + + printk("%s: Interrupt Test Failed, Counter: %i\n", + card->devname, Intr_test_counter); + printk( "Please choose another interrupt\n"); err = -EIO; card->wandev.critical = 0; return err; + } - printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", - card->devname, Intr_test_counter); + + 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); + 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 you are not the authenticator and any one of the protocol is + * enabled then we call the set_out_bound_authentication. + */ + if ( !card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) { + if ( ppp_set_outbnd_auth(card, ppp_priv_area) ){ + err = -EIO; + card->wandev.critical = 0; + return err; + } + } + + /* If you are the authenticator and any one of the protocol is enabled + * then we call the set_in_bound_authentication. + */ + if ( card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) { + if ( ppp_set_inbnd_auth(card, ppp_priv_area) ){ + err = -EIO; + card->wandev.critical = 0; + return err; + } + } + 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); + do_gettimeofday( &tv ); ppp_priv_area->router_start_time = tv.tv_sec; card->wandev.critical = 0; + return err; } @@ -486,13 +637,14 @@ * o if this is the last open, then disable communications and interrupts. * o reset flags. */ - static int if_close(struct 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)) + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; + dev->start = 0; wanpipe_close(card); wanpipe_set_state(card, WAN_DISCONNECTED); @@ -511,19 +663,21 @@ * * Return: media header length. */ - static int if_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) + unsigned short type, void *daddr, void *saddr, unsigned len) { - switch (type) + switch (type) { case ETH_P_IP: + case ETH_P_IPX: - skb->protocol = type; + skb->protocol = htons(type); break; + default: skb->protocol = 0; } + return PPP_HDR_LEN; } @@ -533,14 +687,14 @@ * Return: 1 physical address resolved. * 0 physical address not resolved */ - -static int if_rebuild_hdr(struct sk_buff *skb) +static int if_rebuild_hdr (struct sk_buff *skb) { - struct device *dev=skb->dev; + struct 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); + card->devname, dev->name); return 1; } @@ -561,133 +715,198 @@ * 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 device *dev) +static int if_send (struct sk_buff *skb, struct device *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; + struct in_device *in_dev; 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); + 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)) { + ++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); + + 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) */ + + /* 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) { + + 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, + 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) + } + 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; + + + in_dev = dev->ip_ptr; + + if( in_dev != NULL ) { + struct in_ifaddr *ifa= in_dev->ifa_list; + + if(ifa != NULL){ + /* 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 Broadcast address */ + if ((dev->flags & IFF_BROADCAST) && (check_braddr == ifa->ifa_broadcast)) { + + printk(KERN_INFO "%s: Broadcast Src. Addr. silently discarded\n" ,card->devname); + dev_kfree_skb(skb); + ++ppp_priv_area->if_send_broadcast; + ++card->wandev.stats.tx_dropped; + return 0; + + } + + /* 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 (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; + 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; + ++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); + 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); + + 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); + 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); + + + + 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) { + ++card->wandev.stats.tx_dropped; + + } else if (!skb->protocol) { ++ppp_priv_area->if_send_protocol_error; - ++card->wandev.stats.tx_errors; + ++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); + + /*If it's IPX change the network numbers to 0 if they're ours.*/ + if( skb->protocol == htons(ETH_P_IPX) ) { + if(ppp_priv_area->enable_IPX) { + switch_net_numbers( skb->data, + ppp_priv_area->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; @@ -695,22 +914,26 @@ 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) { + } + +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); + 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; } @@ -718,52 +941,72 @@ * 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; +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) { + if ( udp_length & 0x0001 ) { udp_length += 1; len += 1; - } - temp = (udp_length << 8) | (udp_length >> 8); - memcpy(&data[24], &temp, 2); + } + + 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); + 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); + 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; + + for ( i = 0; i < udp_length+12; i+=2 ) { + + memcpy(&temp,&data[12+i],2); + sum += (unsigned long)temp; } - while (sum >> 16) { + + while (sum >> 16 ) { + sum = (sum & 0xffffUL) + (sum >> 16); - } - temp = (unsigned short) sum; + + } + + temp = (unsigned short)sum; temp = ~temp; - if (temp == 0) + + 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); + 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); @@ -771,93 +1014,101 @@ 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; + + for( i = 0; i < 20; i+=2 ) { + memcpy(&temp,&data[i],2); + sum += (unsigned long)temp; } - while (sum >> 16) { + + while (sum >> 16 ) { sum = (sum & 0xffffUL) + (sum >> 16); } - temp = (unsigned short) sum; + + temp = (unsigned short)sum; temp = ~temp; - if (temp == 0) + + if( temp == 0 ) temp = 0xffff; + memcpy(&data[10], &temp, 2); + return len; -} /* reply_udp */ + +} /* 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]); + + 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; + //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); + //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; + + + 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); + //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 */ +} /* switch_net_numbers */ /*============================================================================ - * Get Ethernet-style interface statistics. + * Get ethernet-style interface statistics. * Return a pointer to struct enet_statistics. */ - static struct enet_statistics *if_stats(struct device *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card; + sdla_t* card; - /* - * Device is down:No statistics - */ - - if(ppp_priv_area==NULL) + if( ppp_priv_area == NULL ) return NULL; - + card = ppp_priv_area->card; return &card->wandev.stats; } @@ -868,122 +1119,260 @@ * Read firmware code version. * Put code version as ASCII string in str. */ - -static int ppp_read_version(sdla_t * card, char *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) +/*=========================================================================== + * Set Out-Bound Authentication. +*/ +static int ppp_set_outbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area) { 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; + memset(&mb->data, 0, (strlen(ppp_priv_area->userid) + + strlen(ppp_priv_area->passwd) + 2 ) ); + memcpy(mb->data, ppp_priv_area->userid, strlen(ppp_priv_area->userid)); + memcpy((mb->data + strlen(ppp_priv_area->userid) + 1), + ppp_priv_area->passwd, strlen(ppp_priv_area->passwd)); + + mb->cmd.length = strlen(ppp_priv_area->userid) + + strlen(ppp_priv_area->passwd) + 2 ; + + mb->cmd.command = PPP_SET_OUTBOUND_AUTH; + 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) +/*=========================================================================== + * Set In-Bound Authentication. +*/ +static int ppp_set_inbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area) { ppp_mbox_t *mb = card->mbox; - int err; + int err, i; + char* user_tokens[32]; + char* pass_tokens[32]; + int userids, passwds; + int add_ptr; + + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + memset(&mb->data, 0, 1008); + memcpy(mb->data, ppp_priv_area->sysname, + strlen(ppp_priv_area->sysname)); + + /* Parse the userid string and the password string and build a string + to copy it to the data area of the command structure. The string + will look like "SYS_NAMEUSER1PASS1USER2PASS2 + .... " + */ + userids = tokenize( ppp_priv_area->userid, user_tokens); + passwds = tokenize( ppp_priv_area->passwd, pass_tokens); + + if (userids != passwds){ + printk(KERN_INFO "%s: Number of passwords does not equal the number of user ids\n", card->devname); + return 1; + } + + add_ptr = strlen(ppp_priv_area->sysname) + 1; + for (i=0; idata + add_ptr), user_tokens[i], + strlen(user_tokens[i])); + memcpy((mb->data + add_ptr + strlen(user_tokens[i]) + 1), + pass_tokens[i], strlen(pass_tokens[i])); + add_ptr = add_ptr + strlen(user_tokens[i]) + 1 + + strlen(pass_tokens[i]) + 1; + } + + mb->cmd.length = add_ptr + 1; + mb->cmd.command = PPP_SET_INBOUND_AUTH; + + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK) + ppp_error(card, err, mb); + + return err; +} + + +/*============================================================================ + * Tokenize string. + * Parse a string of the following syntax: + * ,,... + * and fill array of tokens with pointers to string elements. + * + */ +static int tokenize (char *str, char **tokens) +{ + int cnt = 0; + + tokens[0] = strtok(str, "/"); + while (tokens[cnt] && (cnt < 32 - 1)) + { + tokens[cnt] = strstrip(tokens[cnt], " \t"); + tokens[++cnt] = strtok(NULL, "/"); + } + return cnt; +} + +/*============================================================================ + * Strip leading and trailing spaces off the string str. + */ +static char* strstrip (char *str, char* s) +{ + char *eos = str + strlen(str); /* -> end of string */ + + while (*str && strchr(s, *str)) + ++str /* strip leading spaces */ + ; + while ((eos > str) && strchr(s, *(eos - 1))) + --eos /* strip trailing spaces */ + ; + *eos = '\0'; + return str; +} +/*============================================================================ + * 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; + + 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) + + if (err != CMD_OK) ppp_error(card, err, mb); + return err; } /*============================================================================ * Enable communications. */ - -static int ppp_comm_enable(sdla_t * card) +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) + + if (err != CMD_OK) ppp_error(card, err, mb); + return err; } /*============================================================================ * Disable communications. */ - -static int ppp_comm_disable(sdla_t * card) +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) + if (err != CMD_OK) ppp_error(card, err, mb); + return err; } /*============================================================================ * Get communications error statistics. */ - -static int ppp_get_err_stats(sdla_t * card) +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; + + 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 + + } else ppp_error(card, err, mb); + return err; } @@ -992,27 +1381,41 @@ * Return: 0 - o.k. * 1 - no transmit buffers available */ - -static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto) +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 - ; + return 1 + ; + if (card->hw.fwid == SFID_PPP502) - addr = (txbuf->buf.o_p[1] << 8) + txbuf->buf.o_p[0]; - else + + 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->length = len; /* frame length */ + + if (proto == htons(ETH_P_IPX)) txbuf->proto = 0x01; /* protocol ID */ - txbuf->flag = 1; /* start transmission */ + else + txbuf->proto = 0x00; /* 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) + + if ((void*)txbuf > card->u.p.txbuf_last) card->u.p.txbuf = card->u.p.txbuf_base; + return 0; } @@ -1025,19 +1428,22 @@ * * Return zero if previous command has to be cancelled. */ - -static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb) +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); + + 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; } @@ -1046,65 +1452,82 @@ /*============================================================================ * PPP interrupt service routine. */ - -STATIC void wpp_isr(sdla_t * card) +STATIC void wpp_isr(sdla_t *card) { ppp_flags_t *flags = card->flags; char *ptr = &flags->iflag; unsigned long host_cpu_flags; struct 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->force_enable_irq = 0; + + 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); + 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"); + + 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) { + 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(); @@ -1112,15 +1535,16 @@ flags->iflag = 0; card->wandev.critical = 0; restore_flags(host_cpu_flags); - if (card->buff_int_mode_unbusy) + + if(card->buff_int_mode_unbusy) mark_bh(NET_BH); + } /*============================================================================ * Receive interrupt handler. */ - -static void rx_intr(sdla_t * card) +static void rx_intr(sdla_t *card) { ppp_buf_ctl_t *rxbuf = card->rxmb; struct device *dev = card->wandev.dev; @@ -1129,159 +1553,198 @@ unsigned len; void *buf; int i, err; - ppp_flags_t *flags = card->flags; - char *ptr = &flags->iflag; + 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 + "%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"); + printk(KERN_INFO "\n"); + ++card->statistics.rx_intr_corrupt_rx_bfr; return; + } + + if (dev && dev->start) { - len = rxbuf->length; + + 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]; + + 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; + + 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; + 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; + + 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) { + 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); + 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 if (handle_IPXWAN(skb->data,card->devname, ppp_priv_area->enable_IPX, ppp_priv_area->network_number, skb->protocol)) { + + if( ppp_priv_area->enable_IPX) { + ppp_send(card, skb->data, skb->len, htons(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; + skb->dev = dev; + skb->mac.raw = skb->data; + netif_rx(skb); + ++card->wandev.stats.rx_packets; + ++ppp_priv_area->rx_intr_bfr_passed_to_stack; } + } else { + printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); + 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) + + 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 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. */ + + 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. */ + //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) { + + 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) { + + //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;) { + + //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 */ + + //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 */ + + 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 */ + + //Set the router name sendpacket[51] = 'P'; sendpacket[52] = 'T'; sendpacket[53] = 'P'; @@ -1290,30 +1753,38 @@ 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[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) + 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); + } + + 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); + + //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); + //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; } } @@ -1329,80 +1800,141 @@ * 1. This routine may be called on interrupt context with all interrupts * enabled. Beware! */ - -static void wpp_poll(sdla_t * card) +static void wpp_poll(sdla_t *card) { struct 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; + + 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)) { + + 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); + 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); + cli(); + if ((!(--card->irq_dis_poll_count)) && + !(card->irq_dis_if_send_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_processed; + + + /* check whether interrupts are turned on on the board and + * someone has done a disable_irq() and the code hasn't recovered + */ + if (adptr_flags->iflag) { + ++card->force_enable_irq; + if(card->force_enable_irq > 2){ + card->wandev.critical = 0; + card->irq_dis_poll_count = 0; + card->irq_dis_if_send_count = 0; + enable_irq(card->hw.irq); + return ; + + } + } + + 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->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); + cli(); + if ( !(--card->irq_dis_poll_count) && !(card->irq_dis_if_send_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + } /*============================================================================ * Monitor active link phase. */ - -static void poll_active(sdla_t * card) +static void poll_active(sdla_t *card) { ppp_flags_t *flags = card->flags; + struct device *dev = card->wandev.dev; + struct in_device *in_dev = dev->ip_ptr; + + if (in_dev != NULL ) { + + if (card->u.p.ip_mode == WANOPT_PPP_PEER && + Read_connection_info && flags->ip_state == 0x9) { + + printk(KERN_INFO "%s: IPCP State Opened.\n", card->devname); + if (read_info( card )) { + printk(KERN_INFO "%s: An error occurred in IP assignment.\n", card->devname); + } else { + struct in_ifaddr *ifa = in_dev->ifa_list; + printk(KERN_INFO "%s: Assigned Lcl. Addr: %s\n", card->devname, in_ntoa(ifa->ifa_local) ); + printk(KERN_INFO "%s: Assigned Rmt. Addr: %s\n", card->devname, in_ntoa(ifa->ifa_address) ); + } + Read_connection_info = 0; + } + } + /* 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)) { + + if (card->u.p.ip_mode == WANOPT_PPP_PEER) { + Read_connection_info = 1; + remove_route (card); + } wanpipe_set_state(card, WAN_DISCONNECTED); show_disc_cause(card, flags->disc_cause); + } } @@ -1410,13 +1942,15 @@ * Monitor link establishment phase. * o if connection timed out, disconnect the link. */ - -static void poll_connecting(sdla_t * card) +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); } @@ -1427,171 +1961,154 @@ * o if interface is up and the hold-down timeout has expired, then retry * connection. */ - -static void poll_disconnected(sdla_t * card) +static void poll_disconnected(sdla_t *card) { struct 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); + + 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) +static int config508(ppp_private_area_t *ppp_priv_area, sdla_t *card) { ppp508_conf_t cfg; + struct device *dev = card->wandev.dev; + struct in_device *in_dev = dev->ip_ptr; + /* 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; - */ + + 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; + + if( !card->u.p.authenticator ) { + printk(KERN_INFO "%s: Device is not configured as an authenticator\n", card->devname); + cfg.auth_options = 0x00; + }else{ + printk(KERN_INFO "%s: Device is configured as an authenticator\n", card->devname); + cfg.auth_options = 0x80; + } + if( ppp_priv_area->pap == WANOPT_YES){ + cfg.auth_options |= 0x01; + printk(KERN_INFO "%s: Pap enabled\n", card->devname); + } + if( ppp_priv_area->chap == WANOPT_YES){ + cfg.auth_options |= 0x02; + printk(KERN_INFO "%s: Chap enabled\n", card->devname); + } + + cfg.ipx_options = 0xA0; + + switch (card->u.p.ip_mode) { + + case WANOPT_PPP_STATIC: + cfg.ip_options = 0x80; + cfg.ip_local = in_dev->ifa_list->ifa_local; + cfg.ip_remote = in_dev->ifa_list->ifa_address; + break; + + case WANOPT_PPP_PEER: + cfg.ip_options = 0x8A; + cfg.ip_local = 0x00; + cfg.ip_remote = 0x00; + break; + + } return ppp_configure(card, &cfg); } /*============================================================================ * Show disconnection cause. */ - -static void show_disc_cause(sdla_t * card, unsigned 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) + 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) + + 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) + "%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) + 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); -} + , card->devname); -/*============================================================================ - * Convert line speed in bps to a number used by S502 code. - */ + else if (cause & 0x0400) -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; + printk(KERN_INFO + "%s: failed to negotiate peer's IPXCP options\n", + card->devname); } /*============================================================================ * Process UDP call of type DRVSTATS. */ -static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct 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 device *dev, ppp_private_area_t *ppp_priv_area ) { unsigned char *sendpacket; unsigned char buf2[5]; @@ -1601,183 +2118,211 @@ 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]); + 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 cmd 0x%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; + 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[120] = + card->irq_dis_if_send_count; + mbox->cmd.length = 62; 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); - } + + 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[128] = + 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) { + /* 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 { + + + } else { + /* Pass it up the stack - Allocate socket buffer */ + 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 + + 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; + 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); + } + } + 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 device *dev, - ppp_private_area_t * ppp_priv_area) +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t *card, struct sk_buff *skb, struct device *dev, ppp_private_area_t *ppp_priv_area ) { unsigned char *sendpacket; unsigned char buf2[5]; @@ -1791,210 +2336,293 @@ 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) { + 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 */ + 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) { + + /* 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; + } + break; + default: - break; - } - if (!udp_mgmt_req_valid) { + break; + } + + if(!udp_mgmt_req_valid) { + /* set length to 0 */ - data[46] = data[47] = 0; - /* set return code */ - data[48] = 0xCD; - } else { + data[46] = data[47] = 0; + + /* set return code */ + data[48] = 0xCD; + + } else { + switch (data[45]) { - /* PPIPE_ENABLE_TRACING */ - case 0x20: - if (!TracingEnabled) { + + /* PPIPE_ENABLE_TRACING */ + case 0x20: + if (!card->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) { + 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; + card->TracingEnabled = 0; + /* set the return code */ - data[48] = mbox->cmd.result; - mbox->cmd.length = 0; - break; - } - if (card->hw.fwid == SFID_PPP502) { + + 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 */ + memcpy(&curr_trace_addr, &buf2, 2); + start_trace_addr = curr_trace_addr; + + /* MAX_SEND_BUFFER_SIZE - 28 (IP header) + - 32 (ppipemon CBLOCK) */ + available_buffer_space = 1940; + } + data[48] = 0; + mbox->cmd.length = 0; + card->TracingEnabled = 1; + break; + + /* PPIPE_DISABLE_TRACING */ case 0x21: - if (TracingEnabled) { + + if(card->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 */ + mbox->cmd.command = 0x33; + 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; + card->TracingEnabled = 0; break; - /* PPIPE_GET_TRACE_INFO */ + + /* PPIPE_GET_TRACE_INFO */ case 0x22: - if (TracingEnabled) { + + if(card->TracingEnabled) { + buffer_length = 0; - /* frames < NUM_TRACE_FRAMES */ - for (frames = 0; frames < 62; frames += 1) { - sdla_peek(&card->hw, curr_trace_addr, - &buf2, 1); + + /* frames < 62, where 62 is the number of trace + information elements. There is in total 496 + bytes of space and each trace information + element is 8 bytes. + */ + 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) { + 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; - } + on board and exit */ + data[60] |= 0x02; + break; + } + /* get frame status */ - sdla_peek(&card->hw, curr_trace_addr + - 0x01, &data[60 + buffer_length], 1); + 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); + 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); + 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); + sdla_peek(&card->hw, curr_trace_addr + + 0x04, &buf2, 2); + data_ptr = 0; - memcpy(&data_ptr, &buf2, 2); + 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; + user buffer */ + memcpy(&real_len, + &data[62+buffer_length], 2); + + /* Initialize the passed length field */ + data[61+buffer_length] = 0x00; + if( data_ptr == 0 ) { + + data[61+buffer_length] = 0x00; + } else { + /* we can take it next time */ - if ((available_buffer_space - - buffer_length) < - (real_len + 8)) { + + if(( available_buffer_space - + buffer_length ) < + ( real_len + 8 )) { + data[60] |= 0x02; - break; - } - /* ok, get the frame */ - data[61 + buffer_length] = 0x01; + 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; - } + 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 + + /* 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 { + 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 */ + 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); + + sdla_peek(&card->hw, 0xA003, &data[60], + mbox->cmd.length); } else { - sdla_peek(&card->hw, 0xF003, &data[60], - mbox->cmd.length); + 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 */ + + /* PPIPE_KILL_BOARD */ case 0x24: break; - /* PPIPE_FT1_READ_STATUS */ + + /* PPIPE_FT1_READ_STATUS */ case 0x25: sdla_peek(&card->hw, 0xF020, &data[60], 2); data[46] = 2; @@ -2002,96 +2630,125 @@ data[48] = 0; mbox->cmd.length = 2; break; + case 0x29: - init_ppp_priv_struct(ppp_priv_area); - init_global_statistics(card); + 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; + + 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: + + /* 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; - } - } + 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); - } + + 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; + + ppp_error(card, err, mbox); + ++ppp_priv_area-> + UDP_PTPIPE_mgmt_adptr_cmnd_timeout; break; } - ++ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK; + + ++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) { + 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 { + + } else { + /* Pass it up the stack - Allocate socket buffer */ + 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 + + 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; + 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); + } + } + kfree(data); return 0; } /*============================================================================= * Initial the ppp_private_area structure. */ - -static void init_ppp_priv_struct(ppp_private_area_t * ppp_priv_area) +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; @@ -2104,12 +2761,15 @@ 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_protocol_error = 0; + ppp_priv_area->if_send_tx_int_enabled = 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; @@ -2118,103 +2778,220 @@ 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) +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.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; + 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) +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); + + 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); + + 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.rx_top = info->rxb_end; } + card->u.p.txbuf = card->u.p.txbuf_base; card->rxmb = card->u.p.rxbuf_base; + +} + +/*============================================================================= + * Read Connection Information (ie for Remote IP address assginment). + * Called when ppp interface connected. + */ +static int read_info( sdla_t *card ) +{ + ppp_mbox_t *mb = card->mbox; + struct device *dev = card->wandev.dev; + int err; + ppp508_connect_info_t *ppp508_connect_info; + struct ifreq if_info; + struct sockaddr_in *if_data1, *if_data2; + + /* Read Connection Information */ + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + mb->cmd.length = 0; + mb->cmd.command = PPP_GET_CONNECTION_INFO; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK) { + ppp_error(card, err, mb); + } + else { + mm_segment_t fs = get_fs(); + ppp508_connect_info = (ppp508_connect_info_t *)mb->data; + + + /* Set Local and remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + /* Change the local and remote ip address of the interface. + * This will also add in the destination route. + */ + if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; + if_data1->sin_addr.s_addr = ppp508_connect_info->ip_local; + if_data1->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFADDR, &if_info ); + if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data2->sin_addr.s_addr = ppp508_connect_info->ip_remote; + if_data2->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + + set_fs(fs); /* restore old block */ + + + if (err) { + printk (KERN_INFO "%s: Adding of route failed.\n", + card->devname); + } + } + return err; +} + +/*============================================================================= + * Remove Dynamic Route. + * Called when ppp interface disconnected. + */ + +static int remove_route( sdla_t *card ) +{ + mm_segment_t fs = get_fs(); + struct ifreq if_info; + struct sockaddr_in *if_data1; + struct device *dev = card->wandev.dev; + int err; + + + /* Set Local and remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + /* Change the local ip address of the interface to 0. + * This will also delete the destination route. + */ + if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; + if_data1->sin_addr.s_addr = 0; + if_data1->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFADDR, &if_info ); + + set_fs(fs); /* restore old block */ + + if (err) { + printk (KERN_INFO "%s: Deleting dynamic route failed %d!\n", + card->devname, err); + return err; + } + + 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) +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) + int err,i; + + /* The critical flag is unset because during intialization (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++) { + + err = ppp_set_intr_mode( card, 0x08 ); + + if ( err == CMD_OK ) { + + for (i=0; icmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.length = 0; + mb->cmd.length = 0; mb->cmd.command = 0x10; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) + + if (err != CMD_OK) ppp_error(card, err, mb); } - } else - return err; - err = ppp_set_intr_mode(card, 0); - if (err != CMD_OK) + } + else return err; + + err = ppp_set_intr_mode( card, 0 ); + if (err != CMD_OK) return err; + card->wandev.critical = 1; return 0; } @@ -2222,40 +2999,49 @@ /*============================================================================== * Determine what type of UDP call it is. DRVSTATS or PTPIPEAB ? */ - -static int udp_pkt_type(struct sk_buff *skb, sdla_t * card) +static int udp_pkt_type( struct sk_buff *skb, sdla_t *card ) { unsigned char *sendpacket; - unsigned char buf2[5]; + 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) { + + 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) { + + } 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdla_x25.c linux.ac/drivers/net/sdla_x25.c --- linux.vanilla/drivers/net/sdla_x25.c Wed Jan 6 23:02:22 1999 +++ linux.ac/drivers/net/sdla_x25.c Fri Jun 4 23:52:38 1999 @@ -1,16 +1,18 @@ /***************************************************************************** * sdla_x25.c WANPIPE(tm) Multiprotocol WAN Link Driver. X.25 module. * -* Author: Gene Kozin +* Author: Jaspreet Singh * -* Copyright: (c) 1995-1997 Sangoma Technologies Inc. +* Copyright: (c) 1995-1999 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 +* Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X kernel +* Mar 15, 1998 Alan Cox o 2.1.x porting +* Dec 19, 1997 Jaspreet Singh o Added multi-channel IPX support * 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 @@ -38,7 +40,6 @@ * Jan 07, 1997 Gene Kozin Initial version. *****************************************************************************/ - #include /* printk(), and other useful stuff */ #include /* offsetof(), etc. */ #include /* return codes */ @@ -48,11 +49,14 @@ #include /* WANPIPE common user API definitions */ #include /* htons(), etc. */ #include - +#include +#include #define _GNUC_ #include /* X.25 firmware API definitions */ -/****** Defines & Macros ****************************************************/ +/* + * Defines & Macros + */ #define CMD_OK 0 /* normal firmware return code */ #define CMD_TIMEOUT 0xFF /* firmware command timed out */ @@ -65,10 +69,14 @@ #define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ #define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ -/* For IPXWAN */ +/* + * 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 *****************************************************/ +/* + * Data Structures + */ /* This is an extention of the 'struct device' we create for each network * interface to keep the rest of X.25 channel-specific data. @@ -93,7 +101,9 @@ struct sk_buff* tx_skb; /* transmit socket buffer */ sdla_t* card; /* -> owner */ int ch_idx; - struct net_device_stats ifstats; /* interface statistics */ + unsigned char enable_IPX; + unsigned long network_number; + struct enet_statistics ifstats; /* interface statistics */ } x25_channel_t; typedef struct x25_call_info @@ -110,18 +120,28 @@ } facil[64]; /* facilities */ } x25_call_info_t; -/****** Function Prototypes *************************************************/ +/* + * Function Prototypes + */ -/* WAN link driver entry points. These are called by the WAN router module. */ +/* + * 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 device* dev, wanif_conf_t* conf); static int del_if (wan_device_t* wandev, struct device* dev); -/* WANPIPE-specific entry points */ +/* + * WANPIPE-specific entry points + */ + static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data); -/* Network device interface */ +/* + * Network device interface + */ + static int if_init (struct device* dev); static int if_open (struct device* dev); static int if_close (struct device* dev); @@ -129,9 +149,12 @@ 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 device* dev); -static struct net_device_stats * if_stats (struct device* dev); +static struct net_device_stats *if_stats (struct device* dev); + +/* + * Interrupt handlers + */ -/* Interrupt handlers */ static void wpx_isr (sdla_t* card); static void rx_intr (sdla_t* card); static void tx_intr (sdla_t* card); @@ -139,13 +162,19 @@ static void event_intr (sdla_t* card); static void spur_intr (sdla_t* card); -/* Background polling routines */ +/* + * 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 */ +/* + * 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); @@ -163,14 +192,20 @@ 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 */ +/* + * 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 */ +/* + * Miscellaneous functions + */ + static int connect (sdla_t* card); static int disconnect (sdla_t* card); static struct device* get_dev_by_lcn(wan_device_t* wandev, unsigned lcn); @@ -183,29 +218,30 @@ 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 */ +/* + * 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 */ -/****** Public Functions ****************************************************/ - -/*============================================================================ - * X.25 Protocol Initialization routine. +/* + * 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. + * 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. + * Return: 0 o.k. * < 0 failure. */ int wpx_init (sdla_t* card, wandev_conf_t* conf) @@ -349,20 +385,17 @@ 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 *************************************/ +/* + * WAN Device Driver Entry Points + */ -/*============================================================================ - * Update device status & statistics. +/* + * Update device status & statistics. */ + static int update (wan_device_t* wandev) { sdla_t* card; @@ -382,18 +415,19 @@ 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. +/* + * 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. + * Return: 0 o.k. * < 0 failure (channel will not be created) */ + static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf) { sdla_t* card = wandev->private; @@ -441,8 +475,7 @@ { printk(KERN_ERR "%s: PVC %u is out of range on interface %s!\n", - wandev->name, lcn, chan->name) - ; + wandev->name, lcn, chan->name); err = -EINVAL; } } @@ -450,8 +483,7 @@ { printk(KERN_ERR "%s: invalid media address on interface %s!\n", - wandev->name, chan->name) - ; + wandev->name, chan->name); err = -EINVAL; } if (err) @@ -459,6 +491,14 @@ kfree(chan); return err; } + + chan->enable_IPX = conf->enable_IPX; + if (chan->enable_IPX) + chan->protocol = ETH_P_IPX; + if (conf->network_number) + chan->network_number = conf->network_number; + else + chan->network_number = 0xDEADBEEF; /* prepare network device data space for registration */ dev->name = chan->name; @@ -467,8 +507,8 @@ return 0; } -/*============================================================================ - * Delete logical channel. +/* + * Delete logical channel. */ static int del_if (wan_device_t* wandev, struct device* dev) { @@ -480,10 +520,12 @@ return 0; } -/****** WANPIPE-specific entry points ***************************************/ +/* + * WANPIPE-specific entry points + */ -/*============================================================================ - * Execute adapter interface command. +/* + * Execute adapter interface command. */ static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data) @@ -495,20 +537,19 @@ if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) return -EFAULT; - - /* execute command */ + /* execute command */ + do { memcpy(&mbox->cmd, &cmd, sizeof(cmd)); - if (cmd.length) - { + if (cmd.length) { if(copy_from_user((void*)&mbox->data, u_data, cmd.length)) - return-EFAULT; + return -EFAULT; } if (sdla_exec(mbox)) - err = mbox->cmd.result - ; + err = mbox->cmd.result; + else return -EIO; } while (err && retry-- && x25_error(card, err, cmd.command, cmd.lcn)); @@ -517,20 +558,24 @@ 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)) + if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len) ) return -EFAULT; + return 0; } -/****** Network Device Interface ********************************************/ +/* + * Network Device Interface + */ -/*============================================================================ - * Initialize Linux network 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. + * 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 device* dev) { x25_channel_t* chan = dev->priv; @@ -546,7 +591,8 @@ dev->get_stats = &if_stats; /* Initialize media-specific parameters */ - dev->type = 30; /* ARP h/w type */ + dev->type = ARPHRD_X25; /* ARP h/w type */ + dev->flags |= IFF_POINTOPOINT; dev->mtu = X25_CHAN_MTU; dev->hard_header_len = X25_HRDHDR_SZ; /* media header length */ dev->addr_len = 2; /* hardware address length */ @@ -558,25 +604,26 @@ 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; + dev->mem_end = wandev->maddr + wandev->msize - 1; /* Set transmit buffer queue length */ dev->tx_queue_len = 10; /* Initialize socket buffers */ - - dev_init_buffers(dev); + 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 +/* + * 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. + * Return 0 if O.k. or errno. */ + static int if_open (struct device* dev) { x25_channel_t* chan = dev->priv; @@ -600,11 +647,12 @@ return 0; } -/*============================================================================ - * Close network interface. - * o reset flags. - * o if there's no more open channels then disconnect physical link. +/* + * Close network interface. + * o reset flags. + * o if there's no more open channels then disconnect physical link. */ + static int if_close (struct device* dev) { x25_channel_t* chan = dev->priv; @@ -612,37 +660,38 @@ 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. +/* + * 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. + * 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. + * Return: media header length. */ + static int if_header (struct sk_buff* skb, struct 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) { @@ -656,16 +705,16 @@ return hdr_len; } -/*============================================================================ - * Re-build media header. +/* + * Re-build media header. * - * Return: 1 physical address resolved. - * 0 physical address not resolved + * Return: 1 physical address resolved. + * 0 physical address not resolved */ - + static int if_rebuild_hdr (struct sk_buff* skb) { - struct device *dev=skb->dev; + struct device *dev = skb->dev; x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; @@ -674,22 +723,22 @@ 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 +/* + * 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) + * 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. + * 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 device* dev) @@ -700,6 +749,7 @@ TX25Status* status = card->flags; unsigned long host_cpu_flags; + if (dev->tbusy) { ++chan->ifstats.rx_dropped; @@ -749,94 +799,95 @@ 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))) + + else if ( 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->name, skb->protocol, dev->name) + ; + + printk(KERN_INFO "PROTO %Xn", chan->protocol); ++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_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; + case WAN_CONNECTED: + if( skb->protocol == ETH_P_IPX ) { + if(chan->enable_IPX) { + switch_net_numbers( skb->data, + chan->network_number, 0); + } else { + ++card->wandev.stats.tx_dropped; + ++chan->ifstats.tx_dropped; + goto tx_done; } - break; + } + 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; + 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 +/* + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. */ - -static struct net_device_stats* if_stats (struct device* dev) +static struct net_device_stats *if_stats (struct device* dev) { - x25_channel_t* chan = dev->priv; - if(chan==NULL) + x25_channel_t *chan = dev->priv; + + if(chan == NULL) return NULL; + return &chan->ifstats; } -/****** Interrupt Handlers **************************************************/ +/* + * Interrupt Handlers + */ -/*============================================================================ +/* * X.25 Interrupt Service Routine. */ - + static void wpx_isr (sdla_t* card) { TX25Status* status = card->flags; @@ -846,8 +897,7 @@ card->in_isr = 1; card->buff_int_mode_unbusy = 0; - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - { + 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; @@ -862,27 +912,28 @@ 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 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; - case 0x04: /* modem status interrupt */ - status_intr(card); - break; - - case 0x10: /* network event interrupt */ - event_intr(card); - break; - - default: /* unwanted interrupt */ - spur_intr(card); + default: /* unwanted interrupt */ + spur_intr(card); } + card->wandev.critical = CRITICAL_INTR_HANDLED; if( card->wandev.enable_tx_int) { @@ -909,21 +960,21 @@ } } -/*============================================================================ - * 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. +/* + * 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. + * 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) @@ -991,7 +1042,7 @@ bufptr = skb_put(skb, len); memcpy(bufptr, rxmb->data, len); - if (qdm & 0x01) + if (qdm & 0x01) return; /* more data is comming */ dev->last_rx = jiffies; /* timestamp */ @@ -1006,9 +1057,9 @@ } else { - if( handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) + if( handle_IPXWAN(skb->data, chan->name, chan->enable_IPX, chan->network_number, skb->protocol)) { - if( card->wandev.enable_IPX ) + if( chan->enable_IPX ) { if(chan_send(dev, skb)) { @@ -1021,29 +1072,30 @@ } else { - /* FIXME: increment IPX packet dropped statistic */ + /* increment IPX packet dropped statistic */ + ++chan->ifstats.rx_dropped; } } else { + skb->mac.raw = skb->data; netif_rx(skb); ++chan->ifstats.rx_packets; - chan->ifstats.rx_bytes += skb->len; } } } -/*============================================================================ - * Transmit interrupt handler. - * o Release socket buffer - * o Clear 'tbusy' flag +/* + * Transmit interrupt handler. + * o Release socket buffer + * o Clear 'tbusy' flag */ static void tx_intr (sdla_t* card) { struct device *dev; - /* unbusy all devices and then dev_tint(); */ + /* unbusy all devices and then dev_tint() */ for(dev = card->wandev.dev; dev; dev = dev->slave) { ((x25_channel_t*)dev->priv)->devtint = dev->tbusy; @@ -1052,41 +1104,43 @@ } -/*============================================================================ - * Modem status interrupt handler. +/* + * Modem status interrupt handler. */ static void status_intr (sdla_t* card) { } -/*============================================================================ - * Network event interrupt handler. +/* + * 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 ??? +/* + * Spurious interrupt handler. + * o print a warning + * o */ + static void spur_intr (sdla_t* card) { printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); } -/****** Background Polling Routines ****************************************/ +/* + * Background Polling Routines + */ -/*============================================================================ - * Main polling routine. - * This routine is repeatedly called by the WANPIPE 'thread' to allow for - * time-dependent housekeeping work. +/* + * Main polling routine. + * This routine is repeatedly called by the WANPIPE 'thead' to allow for + * time-dependent housekeeping work. * - * Notes: - * 1. This routine may be called on interrupt context with all interrupts - * enabled. Beware! + * Notes: + * 1. This routine may be called on interrupt context with all interrupts + * enabled. Beware! */ static void wpx_poll (sdla_t* card) @@ -1096,15 +1150,17 @@ 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); + 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; } @@ -1121,18 +1177,22 @@ 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. +/* + * Handle physical link establishment phase. + * o if connection timed out, disconnect the link. */ + static void poll_connecting (sdla_t* card) { TX25Status* status = card->flags; @@ -1147,22 +1207,24 @@ disconnect(card); } -/*============================================================================ - * Handle physical link disconnected phase. - * o if hold-down timeout has expired and there are open interfaces, connect - * link. +/* + * 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. +/* + * 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 device* dev; @@ -1202,20 +1264,22 @@ } } -/****** 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. +/* + * 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 delt 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. +/* + * 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; @@ -1233,14 +1297,15 @@ if (!err && str) { int len = mbox->cmd.length; + memcpy(str, mbox->data, len); str[len] = '\0'; } return err; } -/*============================================================================ - * Configure adapter. +/* + * Configure adapter. */ static int x25_configure (sdla_t* card, TX25Config* conf) @@ -1275,7 +1340,7 @@ 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; @@ -1288,9 +1353,10 @@ return err; } -/*============================================================================ - * Get protocol statistics. +/* + * Get protocol statistics. */ + static int x25_get_stats (sdla_t* card) { TX25Mbox* mbox = card->mbox; @@ -1302,7 +1368,7 @@ 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)); + } while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0)) ; if (!err) { @@ -1314,9 +1380,10 @@ return err; } -/*============================================================================ - * Close HDLC link. +/* + * Close HDLC link. */ + static int x25_close_hdlc (sdla_t* card) { TX25Mbox* mbox = card->mbox; @@ -1329,13 +1396,14 @@ 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. +/* + * Open HDLC link. */ + static int x25_open_hdlc (sdla_t* card) { TX25Mbox* mbox = card->mbox; @@ -1348,7 +1416,7 @@ 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; } @@ -1371,9 +1439,10 @@ return err; } -/*============================================================================ - * Set (raise/drop) DTR. +/* + * Set (raise/drop) DTR. */ + static int x25_set_dtr (sdla_t* card, int dtr) { TX25Mbox* mbox = card->mbox; @@ -1390,13 +1459,14 @@ 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. +/* + * Set interrupt mode. */ + static int x25_set_intr_mode (sdla_t* card, int mode) { TX25Mbox* mbox = card->mbox; @@ -1415,13 +1485,15 @@ 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)) ; + } while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)); + return err; } -/*============================================================================ - * Read X.25 channel configuration. +/* + * Read X.25 channel configuration. */ + static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan) { TX25Mbox* mbox = card->mbox; @@ -1450,11 +1522,11 @@ switch (mbox->data[0] && 0x1F) { - case 0x01: + case 0x01: offset = status->pvc_map; break; - case 0x03: + case 0x03: offset = status->icc_map; break; - case 0x07: + case 0x07: offset = status->twc_map; break; case 0x0B: offset = status->ogc_map; break; @@ -1467,26 +1539,26 @@ /* get actual transmit packet size on this channel */ switch(mbox->data[1] & 0x38) { - case 0x00: - chan->tx_pkt_size = 16; + case 0x00: + chan->tx_pkt_size = 16; break; - case 0x08: - chan->tx_pkt_size = 32; + case 0x08: + chan->tx_pkt_size = 32; break; - case 0x10: - chan->tx_pkt_size = 64; + case 0x10: + chan->tx_pkt_size = 64; break; - case 0x18: - chan->tx_pkt_size = 128; + case 0x18: + chan->tx_pkt_size = 128; break; - case 0x20: - chan->tx_pkt_size = 256; + case 0x20: + chan->tx_pkt_size = 256; break; - case 0x28: - chan->tx_pkt_size = 512; + case 0x28: + chan->tx_pkt_size = 512; break; - case 0x30: - chan->tx_pkt_size = 1024; + case 0x30: + chan->tx_pkt_size = 1024; break; } printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n", @@ -1495,8 +1567,8 @@ return err; } -/*============================================================================ - * Place X.25 call. +/* + * Place X.25 call. */ static int x25_place_call (sdla_t* card, x25_channel_t* chan) @@ -1506,7 +1578,11 @@ int err; char str[64]; - sprintf(str, "-d%s -uCC", chan->addr); + + if (chan->protocol == ETH_P_IP) + sprintf(str, "-d%s -uCC", chan->addr); + if (chan->protocol == ETH_P_IPX) + sprintf(str, "-d%s -u800000008137", chan->addr); do { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); @@ -1519,13 +1595,12 @@ if (!err) { chan->lcn = mbox->cmd.lcn; - chan->protocol = ETH_P_IP; } return err; } -/*============================================================================ - * Accept X.25 call. +/* + * Accept X.25 call. */ static int x25_accept_call (sdla_t* card, int lcn, int qdm) @@ -1542,13 +1617,14 @@ 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. +/* + * Clear X.25 call. */ + static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn) { TX25Mbox* mbox = card->mbox; @@ -1564,13 +1640,14 @@ 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. +/* + * Send X.25 data packet. */ + static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf) { TX25Mbox* mbox = card->mbox; @@ -1590,9 +1667,10 @@ return err; } -/*============================================================================ - * Fetch X.25 asynchronous events. +/* + * Fetch X.25 asynchronous events. */ + static int x25_fetch_events (sdla_t* card) { TX25Status* status = card->flags; @@ -1604,25 +1682,26 @@ 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); + 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. +/* + * 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. + * 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; @@ -1639,106 +1718,116 @@ 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); - } + 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 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); + case 0x31: /* connected */ + retry = call_accepted(card, cmd, lcn, mb); break; - case 0x42: /* X.25 timeout */ - retry = timeout_event(card, cmd, lcn, mb); + case 0x02: /* call clear request */ + retry = call_cleared(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); + 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: /* modem failure */ - printk(KERN_INFO "%s: modem failure!\n", card->devname); + case 0x08: /* restart request */ + retry = restart_event(card, cmd, lcn, mb); break; - case 0x09: /* N2 retry limit */ - printk(KERN_INFO "%s: exceeded HDLC retry limit!\n", - card->devname); - 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 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 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 CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd); - retry = 0; /* abort command */ - break; + case 0x42: /* X.25 timeout */ + retry = timeout_event(card, cmd, lcn, mb); + break; - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", - card->devname, cmd, err); - retry = 0; /* abort command */ + 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. +/* + * 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. +/* + * 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 occured), 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) @@ -1749,13 +1838,14 @@ 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; } @@ -1766,6 +1856,7 @@ 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; } @@ -1780,7 +1871,9 @@ 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); @@ -1790,18 +1883,31 @@ chan = dev->priv; if (!chan->svc || (chan->state != WAN_DISCONNECTED)) + continue + ; + if (info->user[0] == NLPID_IP && chan->protocol != ETH_P_IP){ + printk(KERN_INFO "IP packet but configured for IPX : %x, %x\n", chan->protocol, info->user[0]); + continue; + } + + if (info->user[0] == NLPID_SNAP && chan->protocol != ETH_P_IPX){ + printk(KERN_INFO "IPX packet but configured for IP: %x\n", chan->protocol); continue; + } if (strcmp(info->src, chan->addr) == 0) - break; + break + ; /* If just an '@' is specified, accept all incoming calls */ if (strcmp(chan->addr, "") == 0) - break; + break + ; } if (dev == NULL) { printk(KERN_INFO "%s: no channels available!\n", - card->devname); + card->devname) + ; x25_clear_call(card, new_lcn, 0, 0); } @@ -1810,7 +1916,8 @@ { printk(KERN_INFO "%s: no user data in incoming call on LCN %d!\n", - card->devname, new_lcn); + card->devname, new_lcn) + ; x25_clear_call(card, new_lcn, 0, 0); } else switch (info->user[0]) @@ -1821,35 +1928,34 @@ 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 + else x25_clear_call(card, new_lcn, 0, 0); } kfree(info); return 1; } -/*============================================================================ - * Handle accepted call. +/* + * Handle accepted call. */ static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) @@ -1880,8 +1986,8 @@ return 1; } -/*============================================================================ - * Handle cleared call. +/* + * Handle cleared call. */ static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) @@ -1892,16 +1998,19 @@ 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) + + 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. +/* + * Handle X.25 restart event. */ - + static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) { wan_device_t* wandev = &card->wandev; @@ -1914,12 +2023,14 @@ /* 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; @@ -1930,7 +2041,8 @@ printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n", card->devname, new_lcn); - if (dev) + + if (dev) set_chan_state(dev, WAN_DISCONNECTED); } else printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n", @@ -1938,32 +2050,37 @@ return 1; } -/******* Miscellaneous ******************************************************/ +/* + * Miscellaneous + */ -/*============================================================================ - * Establish physical connection. - * o open HDLC and raise DTR +/* + * Establish physical connection. + * o open HDLC and raise DTR * - * Return: 0 connection established - * 1 connection is in progress - * <0 error + * 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 +/* + * Tear down physical connection. + * o close HDLC link + * o drop DTR * - * Return: 0 - * <0 error + * Return: 0 + * <0 error */ + static int disconnect (sdla_t* card) { wanpipe_set_state(card, WAN_DISCONNECTED); @@ -1973,28 +2090,30 @@ return 0; } -/*============================================================================ +/* * Find network device by its channel number. */ + static struct device* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn) { struct device* dev; for (dev = wandev->dev; dev; dev = dev->slave) - if (((x25_channel_t*)dev->priv)->lcn == lcn) + 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 +/* + * 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 + * Return: 0 connected + * >0 connection in progress + * <0 failure */ + static int chan_connect (struct device* dev) { x25_channel_t* chan = dev->priv; @@ -2004,10 +2123,13 @@ { 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; } @@ -2015,28 +2137,31 @@ { 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 +/* + * Disconnect logical channel. + * o if SVC then clear X.25 call */ + static int chan_disc (struct device* dev) { x25_channel_t* chan = dev->priv; - if (chan->svc) + if (chan->svc) x25_clear_call(chan->card, chan->lcn, 0, 0); set_chan_state(dev, WAN_DISCONNECTED); return 0; } -/*============================================================================ - * Set logical channel state. +/* + * Set logical channel state. */ + static void set_chan_state (struct device* dev, int state) { x25_channel_t* chan = dev->priv; @@ -2050,22 +2175,18 @@ switch (state) { case WAN_CONNECTED: - printk (KERN_INFO "%s: interface %s connected!\n", - card->devname, dev->name); + 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); + 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) - { + printk (KERN_INFO "%s: interface %s disconnected!\n", card->devname, dev->name); + if (chan->svc) { *(unsigned short*)dev->dev_addr = 0; chan->lcn = 0; } @@ -2077,21 +2198,22 @@ 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. +/* + * 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 + * 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. + * 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 device* dev, struct sk_buff* skb) { x25_channel_t* chan = dev->priv; @@ -2123,7 +2245,6 @@ return 1; } ++chan->ifstats.tx_packets; - chan->ifstats.tx_bytes += skb->len; break; case 0x33: /* Tx busy */ @@ -2131,13 +2252,12 @@ default: /* failure */ ++chan->ifstats.tx_errors; -/* return 1; */ } return 0; } -/*============================================================================ - * Parse X.25 call request data and fill x25_call_info_t structure. +/* + * 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) @@ -2154,18 +2274,16 @@ for (i = 0; i < 16; ++i) { ch = str[2+i]; - if (!is_digit(ch)) - break; + 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; + if (!is_digit(ch)) break; info->src[i] = ch; } break; @@ -2185,15 +2303,13 @@ for (i = 0; i < 64; ++i) { ch = str[2+4*i]; - if (!is_hex_digit(ch)) + if (!is_hex_digit(ch)) break; - info->facil[i].code = - hex_to_uint(&str[2+4*i], 2); + info->facil[i].code = hex_to_uint(&str[2+4*i], 2); ch = str[4+4*i]; - if (!is_hex_digit(ch)) + if (!is_hex_digit(ch)) break; - info->facil[i].parm = - hex_to_uint(&str[4+4*i], 2); + info->facil[i].parm = hex_to_uint(&str[4+4*i], 2); } info->nfacil = i; break; @@ -2201,14 +2317,15 @@ } } -/*============================================================================ - * Convert line speed in bps to a number used by S502 code. +/* + * 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 ; + if (bps <= 1200) number = 0x01; else if (bps <= 2400) number = 0x02; else if (bps <= 4800) number = 0x03; else if (bps <= 9600) number = 0x04; @@ -2225,29 +2342,36 @@ return number; } -/*============================================================================ - * Convert decimal string to unsigned integer. - * If len != 0 then only 'len' characters of the string are converted. +/* + * 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); + 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. +/* + * 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); + if (!len) + len = strlen(str); + for (val = 0; len; ++str, --len) { ch = *str; @@ -2255,8 +2379,7 @@ val = (val << 4) + (ch - (unsigned)'0'); else if (is_hex_digit(ch)) val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10); - else - break; + else break; } return val; } @@ -2273,14 +2396,14 @@ return 1; } } else { - /* It's not IPX so pass it up the stack. */ + /* It's not IPX so pass it up the stack.*/ return 0; } if( sendpacket[16] == 0x90 && sendpacket[17] == 0x04) { - /* It's IPXWAN */ + /* It's IPXWAN */ if( sendpacket[2] == 0x02 && sendpacket[34] == 0x00) @@ -2289,19 +2412,24 @@ 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 */ + * 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. */ + /* We also want to turn off all header compression opt. */ for(; sendpacket[i] == 0x80 ;) { sendpacket[i + 1] = 0; @@ -2338,7 +2466,9 @@ 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); } @@ -2356,18 +2486,18 @@ return 1; } else { - /* If we get here its an IPX-data packet, so it'll get passed up the stack. - switch the network numbers */ + /*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 - -*/ + * 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) { @@ -2376,21 +2506,17 @@ 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) - { + 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 - { + } else { /* If the incoming network is 0, make it ours */ - if( pnetwork_number == 0) - { + if( pnetwork_number == 0) { sendpacket[6] = (unsigned char)(network_number >> 24); sendpacket[7] = (unsigned char)((network_number & 0x00FF0000) >> 16); @@ -2405,21 +2531,17 @@ pnetwork_number = (unsigned long)((sendpacket[18] << 24) + (sendpacket[19] << 16) + (sendpacket[20] << 8) + sendpacket[21]); - - if( !incoming ) - { + + + if( !incoming ) { /* If the source network is ours, make it 0 */ - if( pnetwork_number == network_number) - { + if( pnetwork_number == network_number) { sendpacket[18] = sendpacket[19] = sendpacket[20] = sendpacket[21] = 0x00; } - } - else - { + } else { /* If the source network is 0, make it ours */ - if( pnetwork_number == 0 ) - { + if( pnetwork_number == 0 ) { sendpacket[18] = (unsigned char)(network_number >> 24); sendpacket[19] = (unsigned char)((network_number & 0x00FF0000) >> 16); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdladrv.c linux.ac/drivers/net/sdladrv.c --- linux.vanilla/drivers/net/sdladrv.c Sat Jan 9 21:50:42 1999 +++ linux.ac/drivers/net/sdladrv.c Fri Jun 4 23:52:38 1999 @@ -13,6 +13,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Sep 17, 1998 Jaspreet Singh Updates for linux 2.2.X kernels * 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. @@ -179,7 +180,7 @@ /* private data */ static char modname[] = "sdladrv"; static char fullname[] = "SDLA Support Module"; -static char copyright[] = "(c) 1995-1996 Sangoma Technologies Inc."; +static char copyright[] = "(c) 1995-1999 Sangoma Technologies Inc."; static unsigned exec_idle; /* Hardware configuration options. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdlamain.c linux.ac/drivers/net/sdlamain.c --- linux.vanilla/drivers/net/sdlamain.c Mon Dec 28 23:09:43 1998 +++ linux.ac/drivers/net/sdlamain.c Fri Jun 4 23:52:38 1999 @@ -11,6 +11,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Sep 17, 1998 Jaspreet Singh Updated for 2.1.121+ kernel * 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 @@ -52,8 +53,8 @@ #define STATIC static #endif -#define DRV_VERSION 4 /* version number */ -#define DRV_RELEASE 1 /* release (minor version) number */ +#define DRV_VERSION 5 /* version number */ +#define DRV_RELEASE 0 /* release (minor version) number */ #define MAX_CARDS 8 /* max number of adapters */ #ifndef CONFIG_WANPIPE_CARDS /* configurable option */ @@ -90,7 +91,7 @@ /* private data */ static char drvname[] = "wanpipe"; static char fullname[] = "WANPIPE(tm) Multiprotocol Driver"; -static char copyright[] = "(c) 1995-1996 Sangoma Technologies Inc."; +static char copyright[] = "(c) 1995-1999 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 */ @@ -322,6 +323,24 @@ break; #endif +#ifdef CONFIG_WANPIPE_CHDLC + case SFID_CHDLC508: + err = wpc_init(card, conf); + break; +#endif + +#ifdef CONFIG_WANPIPE_BSTRM + case SFID_BSC502: + err = bsc_init(card, conf); + break; +#endif + +#ifdef CONFIG_WANPIPE_HDLC + case SFID_HDLC508: + err = hdlc_init(card, conf); + break; +#endif + default: printk(KERN_ERR "%s: this firmware is not supported!\n", wandev->name) @@ -335,9 +354,7 @@ 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); @@ -374,17 +391,10 @@ 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; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sealevel.c linux.ac/drivers/net/sealevel.c --- linux.vanilla/drivers/net/sealevel.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/sealevel.c Fri Jun 4 23:52:39 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 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 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 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 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 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 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 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 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/seeq8005.c linux.ac/drivers/net/seeq8005.c --- linux.vanilla/drivers/net/seeq8005.c Thu Dec 31 18:10:43 1998 +++ linux.ac/drivers/net/seeq8005.c Sat Jun 12 14:00:10 1999 @@ -736,6 +736,54 @@ outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD); } +#ifdef MODULE + +static char devicename[9] = { 0, }; + +static struct device dev_seeq = +{ + devicename, /* device name is inserted by linux/drivers/net/net_init.c */ + 0, 0, 0, 0, + 0x300, 5, + 0, 0, 0, NULL, seeq8005_probe +}; + +static int io=0x320; +static int irq=10; +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); + +int init_module(void) +{ + dev_seeq.irq=irq; + dev_seeq.base_addr=io; + if (register_netdev(&dev_seeq) != 0) + return -EIO; + return 0; +} + +void cleanup_module(void) +{ + /* + * No need to check MOD_IN_USE, as sys_delete_module() checks. + */ + + unregister_netdev(&dev_seeq); + + /* + * Free up the private structure, or leak memory :-) + */ + + kfree(dev_seeq.priv); + dev_seeq.priv = NULL; /* gets re-allocated by el1_probe1 */ + + /* + * If we don't do this, we can't re-insmod it later. + */ + release_region(dev_seeq.base_addr, EL1_IO_EXTENT); +} + +#endif /* MODULE */ /* * Local variables: diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/pci/oldproc.c linux.ac/drivers/pci/oldproc.c --- linux.vanilla/drivers/pci/oldproc.c Tue Jun 15 16:49:50 1999 +++ linux.ac/drivers/pci/oldproc.c Sun Jun 13 20:08:33 1999 @@ -303,6 +303,7 @@ DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_128V, "MagicGraph 128V"), DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_128ZV, "MagicGraph 128ZV"), DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_NM2160, "MagicGraph NM2160"), + DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_128ZVPLUS, "MagicGraph 128ZV+"), DEVICE( ASP, ASP_ABP940, "ABP940"), DEVICE( ASP, ASP_ABP940U, "ABP940U"), DEVICE( ASP, ASP_ABP940UW, "ABP940UW"), @@ -460,6 +461,7 @@ DEVICE( SATSAGEM, SATSAGEM_PCR2101,"PCR2101 DVB receiver"), DEVICE( SATSAGEM, SATSAGEM_TELSATTURBO,"Telsat Turbo DVB"), DEVICE( HUGHES, HUGHES_DIRECPC, "DirecPC"), + DEVICE( ENSONIQ, ENSONIQ_ES1371, "ES1371"), DEVICE( ENSONIQ, ENSONIQ_AUDIOPCI,"AudioPCI"), DEVICE( ALTEON, ALTEON_ACENIC, "AceNIC"), DEVICE( PICTUREL, PICTUREL_PCIVST,"PCIVST"), diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sbus/sbus.c linux.ac/drivers/sbus/sbus.c --- linux.vanilla/drivers/sbus/sbus.c Tue Jun 15 16:49:50 1999 +++ linux.ac/drivers/sbus/sbus.c Mon Jun 7 22:24:51 1999 @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/53c7,8xx.c linux.ac/drivers/scsi/53c7,8xx.c --- linux.vanilla/drivers/scsi/53c7,8xx.c Sun Nov 8 15:07:50 1998 +++ linux.ac/drivers/scsi/53c7,8xx.c Fri Jun 4 23:52:42 1999 @@ -1901,7 +1901,8 @@ */ timeout = jiffies + 5 * HZ / 10; - while ((hostdata->test_completed == -1) && jiffies < timeout) + while ((hostdata->test_completed == -1) && + time_before(jiffies,timeout)) barrier(); failed = 1; @@ -1986,7 +1987,8 @@ restore_flags(flags); timeout = jiffies + 5 * HZ; /* arbitrary */ - while ((hostdata->test_completed == -1) && jiffies < timeout) + while ((hostdata->test_completed == -1) && + time_before(jiffies, timeout)) barrier(); NCR53c7x0_write32 (DSA_REG, 0); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/53c7xx.c linux.ac/drivers/scsi/53c7xx.c --- linux.vanilla/drivers/scsi/53c7xx.c Sun Nov 8 15:07:55 1998 +++ linux.ac/drivers/scsi/53c7xx.c Fri Jun 4 23:52:42 1999 @@ -298,6 +298,10 @@ */ #undef inb #undef outb +#undef inw +#undef outw +#undef inl +#undef outl #define inb(x) 1 #define inw(x) 1 #define inl(x) 1 @@ -1612,7 +1616,8 @@ */ timeout = jiffies + 5 * HZ / 10; - while ((hostdata->test_completed == -1) && jiffies < timeout) + while ((hostdata->test_completed == -1) && + time_before(jiffies, timeout)) barrier(); failed = 1; @@ -1698,7 +1703,8 @@ restore_flags(flags); timeout = jiffies + 5 * HZ; /* arbitrary */ - while ((hostdata->test_completed == -1) && jiffies < timeout) + while ((hostdata->test_completed == -1) && + time_before(jiffies, timeout)) barrier(); NCR53c7x0_write32 (DSA_REG, 0); @@ -1899,7 +1905,7 @@ if (left < 0) printk("scsi%d: loop detected in ncr reconncect list\n", host->host_no); - else if (ncr_search) + else if (ncr_search) { if (found) printk("scsi%d: scsi %ld in ncr issue array and reconnect lists\n", host->host_no, c->pid); @@ -1910,6 +1916,7 @@ /* If we're at the tail end of the issue queue, update that pointer too. */ found = 1; } + } /* * Traverse the host running list until we find this command or discover @@ -2960,14 +2967,14 @@ NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM); else NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl); -#if 0 - /* Following disables snooping - run with caches disabled at first */ + /* Following disables snooping - snooping is not required, as non- + * cached pages are used for shared data, and appropriate use is + * made of cache_push/cache_clear. Indeed, for 68060 + * enabling snooping causes disk corruption of ext2fs free block + * bitmaps and the like. If you have a 68060 with snooping hardwared + * on, then you need to enable CONFIG_060_WRITETHROUGH. + */ NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD); -#else - /* Setup CTEST7 for SC1=0, SC0=1 - sink/source data without invalidating - * cache lines. */ - NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD|CTEST7_10_SC0); -#endif /* Actually burst of eight, according to my 53c710 databook */ NCR53c7x0_write8(hostdata->dmode, DMODE_10_BL_8 | DMODE_10_FC2); NCR53c7x0_write8(SCID_REG, 1 << host->this_id); @@ -5947,11 +5954,12 @@ } } } - if (!(istat & (ISTAT_SIP|ISTAT_DIP))) + if (!(istat & (ISTAT_SIP|ISTAT_DIP))) { if (stage == 0) ++stage; else if (stage == 3) break; + } } hostdata->state = STATE_HALTED; restore_flags(flags); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/amiga7xx.c linux.ac/drivers/scsi/amiga7xx.c --- linux.vanilla/drivers/scsi/amiga7xx.c Sun Nov 8 15:07:55 1998 +++ linux.ac/drivers/scsi/amiga7xx.c Fri Jun 4 23:52:42 1999 @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -33,9 +34,9 @@ S_IFDIR | S_IRUGO | S_IXUGO, 2 }; -extern ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip, - u32 base, int io_port, int irq, int dma, - long long options, int clock); +extern int ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip, + u32 base, int io_port, int irq, int dma, + long long options, int clock); int amiga7xx_detect(Scsi_Host_Template *tpnt) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/atari_NCR5380.c linux.ac/drivers/scsi/atari_NCR5380.c --- linux.vanilla/drivers/scsi/atari_NCR5380.c Sun Nov 8 15:07:54 1998 +++ linux.ac/drivers/scsi/atari_NCR5380.c Fri Jun 4 23:52:42 1999 @@ -1459,9 +1459,9 @@ unsigned long timeout = jiffies + 2*NCR_TIMEOUT; while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) - && jiffies < timeout && !hostdata->connected) + && time_before(jiffies, timeout) && !hostdata->connected) ; - if (jiffies >= timeout) + if (time_after_eq(jiffies, timeout)) { printk("scsi : arbitration timeout at %d\n", __LINE__); NCR5380_write(MODE_REG, MR_BASE); @@ -1616,7 +1616,7 @@ * only wait for BSY... (Famous german words: Der Klügere gibt nach :-) */ - while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) & + while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO))); if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == @@ -1629,7 +1629,7 @@ return -1; } #else - while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY)); + while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY)); #endif /* diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/atari_scsi.c linux.ac/drivers/scsi/atari_scsi.c --- linux.vanilla/drivers/scsi/atari_scsi.c Sun Nov 8 15:07:50 1998 +++ linux.ac/drivers/scsi/atari_scsi.c Fri Jun 4 23:52:42 1999 @@ -132,51 +132,51 @@ } while(0) #define SCSI_DMA_READ_P(elt) \ - (((unsigned long)tt_scsi_dma.elt##_hi << 24) | \ - ((unsigned long)tt_scsi_dma.elt##_hmd << 16) | \ - ((unsigned long)tt_scsi_dma.elt##_lmd << 8) | \ - (unsigned long)tt_scsi_dma.elt##_lo) - - -#define SCSI_DMA_SETADR(adr) \ - do { \ - unsigned long __adr = (adr); \ - st_dma.dma_lo = (unsigned char)__adr; \ - MFPDELAY(); \ - __adr >>= 8; \ - st_dma.dma_md = (unsigned char)__adr; \ - MFPDELAY(); \ - __adr >>= 8; \ - st_dma.dma_hi = (unsigned char)__adr; \ - MFPDELAY(); \ - } while(0) - -#define SCSI_DMA_GETADR() ({ \ - unsigned long __adr; \ - __adr = st_dma.dma_lo; \ - MFPDELAY(); \ - __adr |= (st_dma.dma_md & 0xff) << 8; \ - MFPDELAY(); \ - __adr |= (st_dma.dma_hi & 0xff) << 16; \ - MFPDELAY(); \ - __adr; \ -}) - -#define ENABLE_IRQ() \ - do { \ - if (IS_A_TT()) \ - atari_enable_irq( IRQ_TT_MFP_SCSI ); \ - else \ - atari_enable_irq( IRQ_MFP_FSCSI ); \ - } while(0) - -#define DISABLE_IRQ() \ - do { \ - if (IS_A_TT()) \ - atari_disable_irq( IRQ_TT_MFP_SCSI ); \ - else \ - atari_disable_irq( IRQ_MFP_FSCSI ); \ - } while(0) + (((((((unsigned long)tt_scsi_dma.elt##_hi << 8) | \ + (unsigned long)tt_scsi_dma.elt##_hmd) << 8) | \ + (unsigned long)tt_scsi_dma.elt##_lmd) << 8) | \ + (unsigned long)tt_scsi_dma.elt##_lo) + + +static inline void SCSI_DMA_SETADR(unsigned long adr) +{ + st_dma.dma_lo = (unsigned char)adr; + MFPDELAY(); + adr >>= 8; + st_dma.dma_md = (unsigned char)adr; + MFPDELAY(); + adr >>= 8; + st_dma.dma_hi = (unsigned char)adr; + MFPDELAY(); +} + +static inline unsigned long SCSI_DMA_GETADR(void) +{ + unsigned long adr; + adr = st_dma.dma_lo; + MFPDELAY(); + adr |= (st_dma.dma_md & 0xff) << 8; + MFPDELAY(); + adr |= (st_dma.dma_hi & 0xff) << 16; + MFPDELAY(); + return adr; +} + +static inline void ENABLE_IRQ(void) +{ + if (IS_A_TT()) + atari_enable_irq(IRQ_TT_MFP_SCSI); + else + atari_enable_irq(IRQ_MFP_FSCSI); +} + +static inline void DISABLE_IRQ(void) +{ + if (IS_A_TT()) + atari_disable_irq(IRQ_TT_MFP_SCSI); + else + atari_disable_irq(IRQ_MFP_FSCSI); +} #define HOSTDATA_DMALEN (((struct NCR5380_hostdata *) \ @@ -480,16 +480,17 @@ /* fetch rest bytes in the DMA register */ dst = (char *)SCSI_DMA_READ_P( dma_addr ); - if ((nr = ((long)dst & 3))) { + nr = ((long)dst & 3); + if (nr) { /* there are 'nr' bytes left for the last long address before the DMA pointer */ - dst = (char *)( (unsigned long)dst & ~3 ); + dst = (char *)((unsigned long)dst ^ nr); DMA_PRINTK("SCSI DMA: there are %d rest bytes for phys addr 0x%08lx", nr, (long)dst); dst = (char *)PTOV(dst); /* The content of the DMA pointer * is a physical address! */ DMA_PRINTK(" = virt addr 0x%08lx\n", (long)dst); - for( src = (char *)&tt_scsi_dma.dma_restdata; nr > 0; --nr ) + for (src = (char *)&tt_scsi_dma.dma_restdata; nr != 0; --nr) *dst++ = *src++; } } @@ -764,7 +765,7 @@ } #endif -__initfunc(void atari_scsi_setup( char *str, int *ints )) +void __init atari_scsi_setup(char *str, int *ints) { /* Format of atascsi parameter is: * atascsi=,,,, @@ -772,23 +773,6 @@ * Negative values mean don't change. */ - /* Grmbl... the standard parameter parsing can't handle negative numbers - * :-( So let's do it ourselves! - */ - - int i = ints[0]+1, fact; - - while( str && (isdigit(*str) || *str == '-') && i <= 10) { - if (*str == '-') - fact = -1, ++str; - else - fact = 1; - ints[i++] = simple_strtoul( str, NULL, 0 ) * fact; - if ((str = strchr( str, ',' )) != NULL) - ++str; - } - ints[0] = i-1; - if (ints[0] < 1) { printk( "atari_scsi_setup: no arguments!\n" ); return; @@ -869,7 +853,7 @@ #ifdef CONFIG_ATARI_SCSI_RESET_BOOT -__initfunc(static void atari_scsi_reset_boot( void )) +static void __init atari_scsi_reset_boot(void) { unsigned long end; @@ -892,7 +876,7 @@ NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); NCR5380_read( RESET_PARITY_INTERRUPT_REG ); - for( end = jiffies + AFTER_RESET_DELAY; jiffies < end; ) + for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies,end); ) barrier(); printk( " done\n" ); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/constants.c linux.ac/drivers/scsi/constants.c --- linux.vanilla/drivers/scsi/constants.c Sun Nov 8 15:07:49 1998 +++ linux.ac/drivers/scsi/constants.c Fri Jun 4 23:52:42 1999 @@ -1,6 +1,8 @@ /* * ASCII values for a number of symbolic constants, printing functions, * etc. + * Additions for SCSI 2 and Linux 2.2.x by D. Gilbert (990422) + * */ #define __NO_VERSION__ @@ -37,7 +39,7 @@ /* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reasssign Blocks", /* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown, /* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry", -/* 13-16 */ unknown, "Recover Buffered Data", "Mode Select", "Reserve", +/* 13-16 */ "Verify", "Recover Buffered Data", "Mode Select", "Reserve", /* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit", /* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", /* 1e-1f */ "Prevent/Allow Medium Removal", unknown, @@ -46,37 +48,57 @@ static const char *group_1_commands[] = { /* 20-22 */ unknown, unknown, unknown, -/* 23-28 */ unknown, unknown, "Read Capacity", unknown, unknown, "Read (10)", -/* 29-2d */ unknown, "Write (10)", "Seek (10)", unknown, unknown, +/* 23-28 */ unknown, "Define window parameters", "Read Capacity", + unknown, unknown, "Read (10)", +/* 29-2d */ "Read Generation", "Write (10)", "Seek (10)", "Erase", + "Read updated block", /* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal", /* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", /* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data", -/* 38-3c */ "Medium Scan", "Compare","Copy Verify", "Write Buffer", "Read Buffer", +/* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer", + "Read Buffer", /* 3d-3f */ "Update Block", "Read Long", "Write Long", }; static const char *group_2_commands[] = { /* 40-41 */ "Change Definition", "Write Same", -/* 42-48 */ unknown, "Read TOC", unknown, unknown, unknown, unknown, unknown, -/* 49-4f */ unknown, unknown, unknown, "Log Select", "Log Sense", unknown, unknown, +/* 42-48 */ "Read sub-channel", "Read TOC", "Read header", + "Play audio (10)", unknown, "Play audio msf", + "Play audio track/index", +/* 49-4f */ "Play track relative (10)", unknown, "Pause/resume", + "Log Select", "Log Sense", unknown, unknown, /* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)", /* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown, /* 5c-5f */ unknown, unknown, unknown, }; +/* The following are 12 byte commands in group 5 */ +static const char *group_5_commands[] = { +/* a0-a5 */ unknown, unknown, unknown, unknown, unknown, + "Move medium/play audio(12)", +/* a6-a9 */ "Exchange medium", unknown, "Read(12)", "Play track relative(12)", +/* aa-ae */ "Write(12)", unknown, "Erase(12)", unknown, + "Write and verify(12)", +/* af-b1 */ "Verify(12)", "Search data high(12)", "Search data equal(12)", +/* b2-b4 */ "Search data low(12)", "Set limits(12)", unknown, +/* b5-b6 */ "Request volume element address", "Send volume tag", +/* b7-b9 */ "Read defect data(12)", "Read element status", unknown, +/* ba-bf */ unknown, unknown, unknown, unknown, unknown, unknown, +}; + + #define group(opcode) (((opcode) >> 5) & 7) #define RESERVED_GROUP 0 #define VENDOR_GROUP 1 -#define NOTEXT_GROUP 2 static const char **commands[] = { group_0_commands, group_1_commands, group_2_commands, (const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, - (const char **) NOTEXT_GROUP, (const char **) VENDOR_GROUP, + group_5_commands, (const char **) VENDOR_GROUP, (const char **) VENDOR_GROUP }; @@ -89,9 +111,6 @@ case RESERVED_GROUP: printk("%s(0x%02x) ", reserved, opcode); break; - case NOTEXT_GROUP: - printk("%s(0x%02x) ", unknown, opcode); - break; case VENDOR_GROUP: printk("%s(0x%02x) ", vendor, opcode); break; @@ -119,15 +138,18 @@ #if (CONSTANTS & CONST_STATUS) static const char * statuses[] = { -/* 0-4 */ "Good", "Check Condition", "Condition Good", unknown, "Busy", -/* 5-9 */ unknown, unknown, unknown, "Intermediate Good", unknown, -/* a-d */ "Intermediate Good", unknown, "Reservation Conflict", unknown, -/* e-f */ unknown, unknown, +/* 0-4 */ "Good", "Check Condition", "Condition Met", unknown, "Busy", +/* 5-9 */ unknown, unknown, unknown, "Intermediate", unknown, +/* a-c */ "Intermediate-Condition Met", unknown, "Reservation Conflict", +/* d-10 */ unknown, unknown, unknown, unknown, +/* 11-14 */ "Command Terminated", unknown, unknown, "Queue Full", +/* 15-1a */ unknown, unknown, unknown, unknown, unknown, unknown, +/* 1b-1f */ unknown, unknown, unknown, unknown, unknown, }; #endif void print_status (int status) { - status = (status >> 1) & 0xf; + status = (status >> 1) & 0x1f; #if (CONSTANTS & CONST_STATUS) printk("%s ",statuses[status]); #else @@ -405,8 +427,10 @@ s = sizeof(SCpnt->sense_buffer); if (!valid) - printk("extra data not valid "); - + printk("[valid=0] "); + printk("Info fld=0x%x, ", (int)((sense_buffer[3] << 24) | + (sense_buffer[4] << 16) | (sense_buffer[5] << 8) | + sense_buffer[6])); if (sense_buffer[2] & 0x80) printk( "FMK "); /* current command has read a filemark */ if (sense_buffer[2] & 0x40) @@ -427,7 +451,7 @@ error = "Invalid"; } - printk("%s error ", error); + printk("%s ", error); #if (CONSTANTS & CONST_SENSE) printk( "%s%s: sense key %s\n", devclass, @@ -603,7 +627,8 @@ #if (CONSTANTS & CONST_HOST) static const char * hostbyte_table[]={ "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", -"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",NULL}; +"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", +"DID_PASSTHROUGH", "DID_SOFT_ERROR", NULL}; void print_hostbyte(int scsiresult) { static int maxcode=0; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/gdth_proc.c linux.ac/drivers/scsi/gdth_proc.c --- linux.vanilla/drivers/scsi/gdth_proc.c Fri Apr 16 22:10:54 1999 +++ linux.ac/drivers/scsi/gdth_proc.c Fri Jun 4 23:52:42 1999 @@ -3,6 +3,7 @@ */ #include "gdth_ioctl.h" +#include int gdth_proc_info(char *buffer,char **start,off_t offset,int length, int hostno,int inout) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/ide-scsi.c linux.ac/drivers/scsi/ide-scsi.c --- linux.vanilla/drivers/scsi/ide-scsi.c Wed Apr 28 19:14:28 1999 +++ linux.ac/drivers/scsi/ide-scsi.c Fri Jun 4 23:52:42 1999 @@ -606,6 +606,8 @@ host = scsi_register(host_template, 0); for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++); host->max_id = id; + host->max_lun = 1; /* We should query the drive for multilun + support ? */ host->can_queue = host->cmd_per_lun * id; return 1; } @@ -729,6 +731,9 @@ if (!drive) { printk (KERN_ERR "ide-scsi: drive id %d not present\n", cmd->target); + goto abort; + } + if (cmd->lun != 0) { /* Only respond to LUN 0. Drop others */ goto abort; } scsi = drive->driver_data; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/ncr53c8xx.c linux.ac/drivers/scsi/ncr53c8xx.c --- linux.vanilla/drivers/scsi/ncr53c8xx.c Fri Apr 16 22:10:54 1999 +++ linux.ac/drivers/scsi/ncr53c8xx.c Fri Jun 4 23:52:42 1999 @@ -5003,7 +5003,7 @@ ** Force ordered tag if necessary to avoid timeouts ** and to preserve interactivity. */ - if (lp && lp->tags_stime + (3*HZ) <= jiffies) { + if (lp && time_before_eq(lp->tags_stime + 3*HZ, jiffies)) { if (lp->tags_smap) { order = M_ORDERED_TAG; if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>2){ @@ -9850,7 +9850,8 @@ /* PCI_CACHE_LINE_SIZE value is in 32-bit words. */ cache_line_size = 64 / sizeof(u_int32); if (initverbose >= 2) - printk("ncr53c8xx: setting PCI_CACHE_LINE_SIZE to %d (fixup)\n", cache_line_size); + printk("ncr53c8xx: setting PCI_CACHE_LINE_SIZE to %d (fixup)\n", + cache_line_size); pcibios_write_config_byte(bus, device_fn, PCI_CACHE_LINE_SIZE, cache_line_size); pcibios_read_config_byte(bus, device_fn, diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/qlogicfas.c linux.ac/drivers/scsi/qlogicfas.c --- linux.vanilla/drivers/scsi/qlogicfas.c Tue Feb 23 14:21:33 1999 +++ linux.ac/drivers/scsi/qlogicfas.c Fri Jun 4 23:52:42 1999 @@ -276,9 +276,9 @@ int i,k; k = 0; i = jiffies + WATCHDOG; - while ( i > jiffies && !qabort && !((k = inb(qbase + 4)) & 0xe0)) + while ( time_after(i, jiffies) && !qabort && !((k = inb(qbase + 4)) & 0xe0)) barrier(); - if (i <= jiffies) + if (time_before_eq(i, jiffies)) return (DID_TIME_OUT); if (qabort) return (qabort == 1 ? DID_ABORT : DID_RESET); @@ -408,8 +408,8 @@ } /*** Enter Status (and Message In) Phase ***/ k = jiffies + WATCHDOG; - while ( k > jiffies && !qabort && !(inb(qbase + 4) & 6)); /* wait for status phase */ - if ( k <= jiffies ) { + while ( time_after(k, jiffies) && !qabort && !(inb(qbase + 4) & 6)); /* wait for status phase */ + if ( time_before_eq(k, jiffies) ) { ql_zap(); return (DID_TIME_OUT << 16); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/scsi.c linux.ac/drivers/scsi/scsi.c --- linux.vanilla/drivers/scsi/scsi.c Tue Jun 15 16:49:51 1999 +++ linux.ac/drivers/scsi/scsi.c Mon Jun 14 13:54:11 1999 @@ -32,6 +32,8 @@ * Converted cli() code to spinlocks, Ingo Molnar * * Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli + * + * out_of_space + add-single-device work, D. Gilbert (dpg) 990612 */ #include @@ -180,6 +182,7 @@ int * sparse_lun, Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt, struct Scsi_Host *shpnt, char * scsi_result); void scsi_build_commandblocks(Scsi_Device * SDpnt); +static int scsi_unregister_device(struct Scsi_Device_Template * tpnt); /* * These are the interface to the old error handling code. It should go away @@ -451,16 +454,18 @@ Scsi_Device * SDtail; int sparse_lun; - SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), GFP_ATOMIC | GFP_DMA); - memset (SCpnt, 0, sizeof (Scsi_Cmnd)); - - SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC); - memset (SDpnt, 0, sizeof (Scsi_Device)); - - - /* Make sure we have something that is valid for DMA purposes */ - scsi_result = ( ( !shpnt->unchecked_isa_dma ) - ? &scsi_result0[0] : scsi_init_malloc (512, GFP_DMA)); + scsi_result = NULL; + SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), + GFP_ATOMIC | GFP_DMA); + if (SCpnt) { + SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), + GFP_ATOMIC); + if (SDpnt) { + /* Make sure we have something that is valid for DMA purposes */ + scsi_result = ( ( !shpnt->unchecked_isa_dma ) + ? &scsi_result0[0] : scsi_init_malloc (512, GFP_DMA)); + } + } if (scsi_result == NULL) { @@ -512,18 +517,32 @@ if(lun >= shpnt->max_lun) goto leave; scan_scsis_single (channel, dev, lun, &max_dev_lun, &sparse_lun, &SDpnt, SCpnt, shpnt, scsi_result); + + /* See warning by (DB) in scsi_proc_info() towards end of + 'add-single-device' section. (dpg) */ + if (shpnt->select_queue_depths != NULL) + (shpnt->select_queue_depths)(shpnt, shpnt->host_queue); + if(SDpnt!=oldSDpnt) { /* it could happen the blockdevice hasn't yet been inited */ - for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)(); + for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) + if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)(); - oldSDpnt->scsi_request_fn = NULL; - for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if(sdtpnt->attach) { - (*sdtpnt->attach)(oldSDpnt); - if(oldSDpnt->attached) scsi_build_commandblocks(oldSDpnt);} - resize_dma_pool(); + oldSDpnt->scsi_request_fn = NULL; + for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { + if(sdtpnt->attach) { + (*sdtpnt->attach)(oldSDpnt); + if(oldSDpnt->attached) { + scsi_build_commandblocks(oldSDpnt); + if (0 == oldSDpnt->has_cmdblocks) { + printk("scan_scsis: DANGER, no command blocks\n"); + /* What to do now ?? */ + } + } + } + } + resize_dma_pool(); for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { if(sdtpnt->finish && sdtpnt->nr_dev) @@ -884,8 +903,6 @@ return 0; } - memset (SDpnt, 0, sizeof (Scsi_Device)); - /* * And hook up our command block to the new device we will be testing * for. @@ -1899,9 +1916,9 @@ for (order = 0, a_size = PAGE_SIZE; a_size < size; order++, a_size <<= 1) ; - retval = (void *) __get_free_pages(gfp_mask | GFP_DMA, order); + retval = (void *) __get_free_pages(gfp_mask | GFP_DMA, order); } else - retval = kmalloc(size, gfp_mask); + retval = kmalloc(size, gfp_mask); if (retval) memset(retval, 0, size); @@ -1970,9 +1987,10 @@ printk("scsi_build_commandblocks: want=%d, space for=%d blocks\n", SDpnt->queue_depth, j); SDpnt->queue_depth = j; - /* Still problem if 0==j , continue anyway ... */ + SDpnt->has_cmdblocks = (0 != j); } - SDpnt->has_cmdblocks = 1; + else + SDpnt->has_cmdblocks = 1; } #ifndef MODULE /* { */ @@ -2036,7 +2054,13 @@ /* SDpnt->scsi_request_fn = NULL; */ for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt); - if(SDpnt->attached) scsi_build_commandblocks(SDpnt); + if(SDpnt->attached) { + scsi_build_commandblocks(SDpnt); + if (0 == SDpnt->has_cmdblocks) { + printk("scsi_dev_init: DANGER, no command blocks\n"); + /* What to do now ?? */ + } + } } } @@ -2332,8 +2356,9 @@ /* FIXME (DB) This assumes that the queue_depth routines can be used in this context as well, while they were all designed to be called only once after the detect routine. (DB) */ - if (HBA_ptr->select_queue_depths != NULL) - (HBA_ptr->select_queue_depths)(HBA_ptr, HBA_ptr->host_queue); + /* ... but scan_scsis(,1,,,) needs the correct queue_length. So + select_queue_depths() has been moved inside scan_scsis() and + is only used in this context (ie scan_scsis(,1,,,) ). (dpg) */ return(length); @@ -2429,7 +2454,7 @@ */ static void resize_dma_pool(void) { - int i; + int i, k; unsigned long size; struct Scsi_Host * shpnt; struct Scsi_Host * host = NULL; @@ -2438,6 +2463,7 @@ unsigned int new_dma_sectors = 0; unsigned int new_need_isa_buffer = 0; unsigned char ** new_dma_malloc_pages = NULL; + int out_of_space = 0; if( !scsi_hostlist ) { @@ -2529,27 +2555,67 @@ * race conditions that I would rather not even think * about right now. */ - if( new_dma_sectors < dma_sectors ) +#if 0 /* Why do this? No gain and risks out_of_space */ + if( new_dma_sectors < dma_sectors ) new_dma_sectors = dma_sectors; +#endif + if( new_dma_sectors <= dma_sectors ) + return; /* best to quit while we are in front */ - if (new_dma_sectors) - { - size = (new_dma_sectors / SECTORS_PER_PAGE)*sizeof(FreeSectorBitmap); - new_dma_malloc_freelist = (FreeSectorBitmap *) scsi_init_malloc(size, GFP_ATOMIC); - memset(new_dma_malloc_freelist, 0, size); - - size = (new_dma_sectors / SECTORS_PER_PAGE)*sizeof(*new_dma_malloc_pages); - new_dma_malloc_pages = (unsigned char **) scsi_init_malloc(size, GFP_ATOMIC); - memset(new_dma_malloc_pages, 0, size); - } + for (k = 0; k < 20; ++k) { /* just in case */ + out_of_space = 0; + size = (new_dma_sectors / SECTORS_PER_PAGE) * + sizeof(FreeSectorBitmap); + new_dma_malloc_freelist = (FreeSectorBitmap *) + scsi_init_malloc(size, GFP_ATOMIC); + if (new_dma_malloc_freelist) { + size = (new_dma_sectors / SECTORS_PER_PAGE) * + sizeof(*new_dma_malloc_pages); + new_dma_malloc_pages = (unsigned char **) + scsi_init_malloc(size, GFP_ATOMIC); + if (! new_dma_malloc_pages) { + size = (new_dma_sectors / SECTORS_PER_PAGE) * + sizeof(FreeSectorBitmap); + scsi_init_free((char *)new_dma_malloc_freelist, size); + out_of_space = 1; + } + } + else + out_of_space = 1; + + if ((! out_of_space) && (new_dma_sectors > dma_sectors)) { + for(i = dma_sectors / SECTORS_PER_PAGE; + i < new_dma_sectors / SECTORS_PER_PAGE; i++) { + new_dma_malloc_pages[i] = (unsigned char *) + scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); + if (! new_dma_malloc_pages[i]) + break; + } + if (i != new_dma_sectors / SECTORS_PER_PAGE) { /* clean up */ + int k = i; - /* - * If we need more buffers, expand the list. - */ - if( new_dma_sectors > dma_sectors ) { - for(i=dma_sectors / SECTORS_PER_PAGE; i< new_dma_sectors / SECTORS_PER_PAGE; i++) - new_dma_malloc_pages[i] = (unsigned char *) - scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); + out_of_space = 1; + for (i = 0; i < k; ++i) + scsi_init_free(new_dma_malloc_pages[i], PAGE_SIZE); + } + } + if (out_of_space) { /* try scaling down new_dma_sectors request (dpg) */ + printk("scsi::resize_dma_pool: WARNING, dma_sectors=%u, " + "wanted=%u, scaling\n", dma_sectors, new_dma_sectors); + if (new_dma_sectors < (8 * SECTORS_PER_PAGE)) + break; /* pretty well hopeless ... */ + new_dma_sectors = (new_dma_sectors * 3) / 4; + new_dma_sectors = (new_dma_sectors + 15) & 0xfff0; + if (new_dma_sectors <= dma_sectors) + break; /* stick with what we have got */ + } + else + break; /* found space ... */ + } /* end of for loop */ + if (out_of_space) { + scsi_need_isa_buffer = new_need_isa_buffer; /* some useful info */ + printk(" WARNING, not enough memory, pool not expanded\n"); + return; } /* When we dick with the actual DMA list, we need to @@ -2596,6 +2662,7 @@ struct Scsi_Device_Template * sdtpnt; const char * name; unsigned long flags; + int out_of_space = 0; if (tpnt->next || !tpnt->detect) return 1;/* Must be already loaded, or * no detect routine available @@ -2695,11 +2762,11 @@ { if(shpnt->hostt == tpnt) { - scan_scsis(shpnt,0,0,0,0); - if (shpnt->select_queue_depths != NULL) - { - (shpnt->select_queue_depths)(shpnt, shpnt->host_queue); - } + scan_scsis(shpnt,0,0,0,0); + if (shpnt->select_queue_depths != NULL) + { + (shpnt->select_queue_depths)(shpnt, shpnt->host_queue); + } } } @@ -2718,14 +2785,19 @@ { for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt); - if(SDpnt->attached) scsi_build_commandblocks(SDpnt); + if(SDpnt->attached) { + scsi_build_commandblocks(SDpnt); + if (0 == SDpnt->has_cmdblocks) + out_of_space = 1; + } } } /* * Now that we have all of the devices, resize the DMA pool, * as required. */ - resize_dma_pool(); + if (! out_of_space) + resize_dma_pool(); /* This does any final handling that is required. */ @@ -2746,7 +2818,13 @@ #endif MOD_INC_USE_COUNT; - return 0; + + if (out_of_space) { + scsi_unregister_host(tpnt); /* easiest way to clean up?? */ + return 1; + } + else + return 0; } /* @@ -3007,6 +3085,7 @@ { Scsi_Device * SDpnt; struct Scsi_Host * shpnt; + int out_of_space = 0; if (tpnt->next) return 1; @@ -3048,6 +3127,8 @@ { SDpnt->online = TRUE; scsi_build_commandblocks(SDpnt); + if (0 == SDpnt->has_cmdblocks) + out_of_space = 1; } } } @@ -3056,9 +3137,16 @@ * This does any final handling that is required. */ if(tpnt->finish && tpnt->nr_dev) (*tpnt->finish)(); - resize_dma_pool(); + if (! out_of_space) + resize_dma_pool(); MOD_INC_USE_COUNT; - return 0; + + if (out_of_space) { + scsi_unregister_device(tpnt); /* easiest way to clean up?? */ + return 1; + } + else + return 0; } static int scsi_unregister_device(struct Scsi_Device_Template * tpnt) @@ -3229,7 +3317,7 @@ printk("(%3d) %2d:%1d:%2d:%2d (%6s %4ld %4ld %4ld %4x %1d) (%1d %1d 0x%2x) (%4d %4d %4d) 0x%2.2x 0x%2.2x 0x%8.8x\n", i++, - SCpnt->host->host_no, + SCpnt->host ? SCpnt->host->host_no : -1, SCpnt->channel, SCpnt->target, SCpnt->lun, @@ -3294,6 +3382,7 @@ int init_module(void) { unsigned long size; + int has_space = 0; /* * This makes /proc/scsi visible. @@ -3309,7 +3398,6 @@ proc_scsi_register(0, &proc_scsi_scsi); #endif - dma_sectors = PAGE_SIZE / SECTOR_SIZE; scsi_dma_free_sectors= dma_sectors; /* @@ -3318,15 +3406,31 @@ */ /* One bit per sector to indicate free/busy */ - size = (dma_sectors / SECTORS_PER_PAGE)*sizeof(FreeSectorBitmap); - dma_malloc_freelist = (FreeSectorBitmap *) scsi_init_malloc(size, GFP_ATOMIC); - memset(dma_malloc_freelist, 0, size); - - /* One pointer per page for the page list */ - dma_malloc_pages = (unsigned char **) - scsi_init_malloc((dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_pages), GFP_ATOMIC); - dma_malloc_pages[0] = (unsigned char *) - scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); + size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(FreeSectorBitmap); + dma_malloc_freelist = (FreeSectorBitmap *) + scsi_init_malloc(size, GFP_ATOMIC); + if (dma_malloc_freelist) { + /* One pointer per page for the page list */ + dma_malloc_pages = (unsigned char **)scsi_init_malloc( + (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages), + GFP_ATOMIC); + if (dma_malloc_pages) { + dma_malloc_pages[0] = (unsigned char *) + scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); + if (dma_malloc_pages[0]) + has_space = 1; + } + } + if (! has_space) { + if (dma_malloc_freelist) { + scsi_init_free((char *)dma_malloc_freelist, size); + if (dma_malloc_pages) + scsi_init_free((char *)dma_malloc_pages, + (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages)); + } + printk("scsi::init_module: failed, out of memory\n"); + return 1; + } /* * This is where the processing takes place for most everything diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/scsi.h linux.ac/drivers/scsi/scsi.h --- linux.vanilla/drivers/scsi/scsi.h Tue Jun 15 16:49:51 1999 +++ linux.ac/drivers/scsi/scsi.h Tue Jun 15 17:39:14 1999 @@ -377,6 +377,9 @@ extern int scsi_decide_disposition (Scsi_Cmnd * SCpnt); extern int scsi_block_when_processing_errors(Scsi_Device *); extern void scsi_sleep(int); +extern int scsi_partsize(struct buffer_head *bh, unsigned long capacity, + unsigned int *cyls, unsigned int *hds, + unsigned int *secs); /* * scsi_abort aborts the current command that is executing on host host. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/scsi_error.c linux.ac/drivers/scsi/scsi_error.c --- linux.vanilla/drivers/scsi/scsi_error.c Wed Mar 10 21:13:06 1999 +++ linux.ac/drivers/scsi/scsi_error.c Sat Jun 12 18:09:05 1999 @@ -1926,6 +1926,7 @@ int rtn; struct semaphore sem = MUTEX_LOCKED; unsigned long flags; + struct fs_struct *fs; lock_kernel(); @@ -1936,16 +1937,18 @@ */ exit_mm(current); - current->session = 1; current->pgrp = 1; - /* - * FIXME(eric) this is still a child process of the one that did the insmod. - * This needs to be attached to task[0] instead. - */ + + /* Become as one with the init task */ + + exit_fs(current); /* current->fs->count--; */ + fs = init_task.fs; + current->fs = fs; + atomic_inc(&fs->count); siginitsetinv(¤t->blocked, SHUTDOWN_SIGS); - current->fs->umask = 0; + /* * Set the name of this process. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sd.c linux.ac/drivers/scsi/sd.c --- linux.vanilla/drivers/scsi/sd.c Tue Jun 15 16:49:51 1999 +++ linux.ac/drivers/scsi/sd.c Mon Jun 7 16:25:49 1999 @@ -1139,8 +1139,8 @@ unsigned char cmd[10]; char nbuff[6]; unsigned char *buffer; - unsigned long spintime; - int the_result, retries; + unsigned long spintime_value = 0; + int the_result, retries, spintime; Scsi_Cmnd * SCpnt; /* @@ -1235,16 +1235,18 @@ SCpnt->request.sem = NULL; } - spintime = jiffies; + spintime = 1; + spintime_value = jiffies; } time1 = jiffies + HZ; spin_unlock_irq(&io_request_lock); - while(jiffies < time1); /* Wait 1 second for next try */ + while(time_before(jiffies, time1)); /* Wait 1 second for next try */ printk( "." ); spin_lock_irq(&io_request_lock); } - } while(the_result && spintime && spintime+100*HZ > jiffies); + } while(the_result && spintime && + time_after(spintime_value+100*HZ, jiffies)); if (spintime) { if (the_result) printk( "not responding...\n" ); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/Config.in linux.ac/drivers/sound/Config.in --- linux.vanilla/drivers/sound/Config.in Wed Mar 10 21:13:06 1999 +++ linux.ac/drivers/sound/Config.in Fri Jun 4 23:52:43 1999 @@ -97,6 +97,9 @@ comment 'Enter -1 to the following question if you have something else such as SB16/32.' int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' CONFIG_SB_MPU_IRQ -1 fi + + dep_tristate 'PCI Legacy soundblaster enabler' CONFIG_SOUND_PCISB $CONFIG_SOUND_OSS + dep_tristate 'ESS-Tech Maestro support' CONFIG_SOUND_ESSMAESTRO $CONFIG_SOUND_OSS dep_tristate 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_SOUND_ADLIB $CONFIG_SOUND_OSS @@ -272,16 +275,18 @@ hex 'I/O base for UART 6850 MIDI port (Unknown)' CONFIG_U6850_BASE 0 int 'UART6850 IRQ (Unknown)' CONFIG_U6850_IRQ -1 fi + + dep_tristate 'USB audio support' CONFIG_SOUND_USBAUDIO $CONFIG_SOUND_OSS if [ "$CONFIG_ARM" = "y" ]; then dep_tristate 'VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS - dep_tristate 'Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS - if [ "$CONFIG_SOUND_WAVEARTIST" != "n" ]; then - hex ' WaveArtist I/O base' CONFIG_WAVEARTIST_BASE 250 - int ' WaveArtist IRQ' CONFIG_WAVEARTIST_IRQ 28 - int ' WaveArtist DMA' CONFIG_WAVEARTIST_DMA 3 - int ' WaveArtist second DMA' CONFIG_WAVEARTIST_DMA2 7 - fi + fi + dep_tristate 'Rockwell WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS + if [ "$CONFIG_SOUND_WAVEARTIST" = "y" ]; then + hex ' WaveArtist I/O base' CONFIG_WAVEARTIST_BASE 250 + int ' WaveArtist IRQ' CONFIG_WAVEARTIST_IRQ 28 + int ' WaveArtist DMA' CONFIG_WAVEARTIST_DMA 3 + int ' WaveArtist second DMA' CONFIG_WAVEARTIST_DMA2 7 fi diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/Makefile linux.ac/drivers/sound/Makefile --- linux.vanilla/drivers/sound/Makefile Tue Jan 19 02:57:32 1999 +++ linux.ac/drivers/sound/Makefile Sat Jun 12 20:00:29 1999 @@ -53,6 +53,8 @@ obj-$(CONFIG_SOUND_CS4232) += uart401.o obj-$(CONFIG_SOUND_GUS) += gus.o ad1848.o obj-$(CONFIG_SOUND_MAD16) += mad16.o ad1848.o sb.o uart401.o +obj-$(CONFIG_SOUND_ESSMAESTRO) += maestro.o +obj-$(CONFIG_SOUND_PCISB) += pci_legacy.o sb.o uart401.o obj-$(CONFIG_SOUND_MAUI) += maui.o mpu401.o obj-$(CONFIG_SOUND_MPU401) += mpu401.o obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o @@ -64,11 +66,12 @@ obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_SB) += sb.o uart401.o obj-$(CONFIG_SOUND_SOFTOSS) += softoss2.o -obj-$(CONFIG_SOUND_SGALAXY) += sgalaxy.o +obj-$(CONFIG_SOUND_SGALAXY) += sgalaxy.o ad1848.o obj-$(CONFIG_SOUND_AD1816) += ad1816.o obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb.o uart401.o obj-$(CONFIG_SOUND_UART6850) += uart6850.o +obj-$(CONFIG_SOUND_USBAUDIO) += usb_audio.o obj-$(CONFIG_SOUND_VMIDI) += v_midi.o obj-$(CONFIG_SOUND_YM3812) += adlib_card.o opl3.o obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/dev_table.h linux.ac/drivers/sound/dev_table.h --- linux.vanilla/drivers/sound/dev_table.h Fri Apr 16 22:10:56 1999 +++ linux.ac/drivers/sound/dev_table.h Sat Jun 12 20:06:07 1999 @@ -25,30 +25,18 @@ #define SNDCARD_DESKPROXL 27 /* Compaq Deskpro XL */ #define SNDCARD_VIDC 28 /* ARMs VIDC */ #define SNDCARD_SBPNP 29 -#define SNDCARD_OPL3SA1 38 -#define SNDCARD_OPL3SA1_SB 39 -#define SNDCARD_OPL3SA1_MPU 40 #define SNDCARD_SOFTOSS 36 #define SNDCARD_VMIDI 37 +#define SNDCARD_OPL3SA1 38 /* Note: clash in msnd.h */ +#define SNDCARD_OPL3SA1_SB 39 +#define SNDCARD_OPL3SA1_MPU 40 #define SNDCARD_WAVEFRONT 41 #define SNDCARD_OPL3SA2 42 #define SNDCARD_OPL3SA2_MPU 43 #define SNDCARD_WAVEARTIST 44 +#define SNDCARD_OPL3SA2_MSS 45 /* Originally missed */ #define SNDCARD_AD1816 88 -void attach_opl3sa_wss (struct address_info *hw_config); -int probe_opl3sa_wss (struct address_info *hw_config); -void attach_opl3sa_sb (struct address_info *hw_config); -int probe_opl3sa_sb (struct address_info *hw_config); -void attach_opl3sa_mpu (struct address_info *hw_config); -int probe_opl3sa_mpu (struct address_info *hw_config); -void unload_opl3sa_wss(struct address_info *hw_info); -void unload_opl3sa_sb(struct address_info *hw_info); -void unload_opl3sa_mpu(struct address_info *hw_info); -void attach_softsyn_card (struct address_info *hw_config); -int probe_softsyn (struct address_info *hw_config); -void unload_softsyn (struct address_info *hw_config); - /* * NOTE! NOTE! NOTE! NOTE! * @@ -424,6 +412,7 @@ #ifdef CONFIG_SOUND_OPL3SA2 {"OPL3SA2", 0, SNDCARD_OPL3SA2, "OPL3SA2", attach_opl3sa2, probe_opl3sa2, unload_opl3sa2}, + {"OPL3SA2MSS", 1, SNDCARD_OPL3SA2_MSS, "OPL3SA2 MSS", attach_opl3sa2_mss, probe_opl3sa2_mss, unload_opl3sa2_mss}, {"OPL3SA2MPU", 0, SNDCARD_OPL3SA2_MPU, "OPL3SA2 MIDI", attach_opl3sa2_mpu, probe_opl3sa2_mpu, unload_opl3sa2_mpu}, #endif @@ -587,10 +576,11 @@ #ifndef CONFIG_OPL3SA2_DMA2 #define CONFIG_OPL3SA2_DMA2 CONFIG_OPL3SA2_DMA #endif + {SNDCARD_OPL3SA2, {CONFIG_OPL3SA2_CTRL_BASE, CONFIG_OPL3SA2_IRQ, CONFIG_OPL3SA2_DMA, CONFIG_OPL3SA2_DMA2}, SND_DEFAULT_ENABLE}, + {SNDCARD_OPL3SA2_MSS, {CONFIG_OPL3SA2_BASE, CONFIG_OPL3SA2_IRQ, CONFIG_OPL3SA2_DMA, CONFIG_OPL3SA2_DMA2}, SND_DEFAULT_ENABLE}, #ifdef CONFIG_OPL3SA2_MPU_BASE - {SNDCARD_OPL3SA2_MPU, {CONFIG_OPL3SA2_MPU_BASE, CONFIG_OPL3SA2_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, + {SNDCARD_OPL3SA2_MPU, {CONFIG_OPL3SA2_MPU_BASE, CONFIG_OPL3SA2_MPU_IRQ, CONFIG_OPL3SA2_DMA, -1}, SND_DEFAULT_ENABLE}, #endif - {SNDCARD_OPL3SA2, {CONFIG_OPL3SA2_BASE, CONFIG_OPL3SA2_IRQ, CONFIG_OPL3SA2_DMA, CONFIG_OPL3SA2_DMA2}, SND_DEFAULT_ENABLE}, #endif #ifdef CONFIG_SGALAXY diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/ess_pci.c linux.ac/drivers/sound/ess_pci.c --- linux.vanilla/drivers/sound/ess_pci.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/ess_pci.c Fri Jun 4 23:52:44 1999 @@ -0,0 +1,962 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include "maestro.h" +#include "maestro_tables.h" + +#include "sound_config.h" +#include "soundmodule.h" +#include "sb_mixer.h" +#include "sb.h" + + +#ifndef PCI_VENDOR_ESS +#define PCI_VENDOR_ESS 0x125D +#define PCI_DEVICE_ID_ESS_ESS1969 0x1969 +#define PCI_DEVICE_ID_ESS_ESS1948 0x1948 /* Solo ?? */ +#define PCI_DEVICE_ID_ESS_ESS1968 0x1968 /* Maestro 2 */ +#define PCI_DEVICE_ID_ESS_ESS1978 0x1978 /* Maestro 2E */ +#endif + +#define ESS_SBBASE 0x220 + +struct address_info maestro_cfg; + + +/* + * ESS Maestro AC97 codec programming interface. + */ + +static void maestro_ac97_set(int io, u8 cmd, u16 val) +{ + int i; + /* + * Wait for the codec bus to be free + */ + + for(i=0;i<10000;i++) + { + if(!(inb(io+ESS_AC97_INDEX)&1)) + break; + } + /* + * Write the bus + */ + outw(val, io+ESS_AC97_DATA); + udelay(1); + outb(cmd, io+ESS_AC97_INDEX); + udelay(1); +} + +static u16 maestro_ac97_get(int io, u8 cmd) +{ + int sanity=100000; + u16 data; + int i; + + /* + * Wait for the codec bus to be free + */ + + for(i=0;i<10000;i++) + { + if(!(inb(io+ESS_AC97_INDEX)&1)) + break; + } + + outb(cmd|0x80, io+ESS_AC97_INDEX); + udelay(1); + + while(inb(io+ESS_AC97_INDEX)&1) + { + sanity--; + if(!sanity) + { + printk(KERN_ERR "ess_pci: ac97 codec timeout.\n"); + return 0; + } + } + data=inw(io+ESS_AC97_DATA); + udelay(1); + return data; +} + +/* + * The Maestro can be wired to a standard AC97 compliant codec + * (see www.intel.com for the pdf's on this), or to a PT101 codec + * which appears to be the ES1918 (data sheet on the esstech.com.tw site) + * + * The PT101 setup is untested. + */ + +static u16 maestro_ac97_init(int iobase) +{ + maestro_ac97_set(iobase, 0x02, 0x0000); + maestro_ac97_set(iobase, 0x04, 0x0000); + maestro_ac97_set(iobase, 0x06, 0x0000); + maestro_ac97_set(iobase, 0x08, 0x9F1F); + maestro_ac97_set(iobase, 0x0A, 0x9F1F); + maestro_ac97_set(iobase, 0x0C, 0x9F1F); + maestro_ac97_set(iobase, 0x0E, 0x9F1F); + maestro_ac97_set(iobase, 0x10, 0x9F1F); + maestro_ac97_set(iobase, 0x12, 0x9F1F); + maestro_ac97_set(iobase, 0x14, 0x9F1F); + maestro_ac97_set(iobase, 0x16, 0x9F1F); + maestro_ac97_set(iobase, 0x18, 0x0808); + maestro_ac97_set(iobase, 0x1A, 0x0000); + maestro_ac97_set(iobase, 0x1C, 0x0404); + maestro_ac97_set(iobase, 0x1E, 0x0404); + maestro_ac97_set(iobase, 0x20, 0x0000); + maestro_ac97_set(iobase, 0x26, 0x000F); + return 0; +} + +static u16 maestro_pt101_init(int iobase) +{ + maestro_ac97_set(iobase, 0x2A, 0x0001); + maestro_ac97_set(iobase, 0x2C, 0x0000); + maestro_ac97_set(iobase, 0x2C, 0xFFFF); + maestro_ac97_set(iobase, 0x10, 0x9F1F); + maestro_ac97_set(iobase, 0x12, 0x0808); + maestro_ac97_set(iobase, 0x14, 0x9F1F); + maestro_ac97_set(iobase, 0x16, 0x9F1F); + maestro_ac97_set(iobase, 0x18, 0x0404); + maestro_ac97_set(iobase, 0x1A, 0x0000); + maestro_ac97_set(iobase, 0x1C, 0x0000); + maestro_ac97_set(iobase, 0x02, 0x0404); + maestro_ac97_set(iobase, 0x04, 0x0808); + maestro_ac97_set(iobase, 0x0C, 0x801F); + maestro_ac97_set(iobase, 0x0E, 0x801F); + return 0; +} + +static void maestro_ac97_reset(int ioaddr) +{ + outw(0x2000, ioaddr+0x36); + udelay(100); + outw(0x0000, ioaddr+0x36); + udelay(100); +} + + +/* + * Indirect register access. Not all registers are readable so we + * need to keep register state ourselves + */ + +static u16 maestro_map[32]; +#define WRITEABLE_MAP 0xEFFFFF +#define READABLE_MAP 0x64003F + +/* + * The ESS engineers were a little indirection happy. These indirected + * registers themselves include indirect registers at another layer + */ + +static void maestro_write(int ioaddr, u16 reg, u16 data) +{ + unsigned long flags; + save_flags(flags); + cli(); + outw(reg, ioaddr+0x02); + outw(data, ioaddr+0x00); + maestro_map[reg]=data; + restore_flags(flags); +} + +static u16 maestro_read(int ioaddr, u16 reg) +{ + if(READABLE_MAP & (1<>=1; + + for(channel=low_apu; channel <= high_apu; channel++) + { + int i; + + pa = virt_to_bus(buffer); + wave_set_register(io, 0x01FC+channel, 0x0000); + wave_set_register(io,0x0000, pa&0xFFFF); + pa>>=1; + if(mode&1) /* Enable stereo */ + pa|=0x00800000; + pa|=0x00400000; /* System RAM */ + + /* Begin loading the APU */ + + for(i=0;i<15;i++) + apu_set_register(io, channel, i, 0x0000); + + /* Load the frequency, turn on 6dB, turn off the effects */ + apu_set_register(io, channel, 2, (rate&0xFF)<<8|0x10); + apu_set_register(io, channel, 3, rate>>8); + + /* Load the buffer into the wave engine */ + apu_set_register(io, channel, 4, ((pa>>16)&0xFF)<<8); + apu_set_register(io, channel, 5, pa&0xFFFF); + apu_set_register(io, channel, 6, (pa+size)&0xFFFF); + apu_set_register(io, channel, 7, size); + + apu_set_register(io, channel, 8, 0x0000); + apu_set_register(io, channel, 9, 0xD000); + + if(mode&1) + { + /* Set left or right */ + if(channel == low_apu) + apu_set_register(io, channel, 10, 0x8F00); + else + apu_set_register(io, channel, 10, 0x8F10); + } + else + apu_set_register(io, channel, 10, 0x8F08); + apu_set_register(io, channel, 11, 0x0000); + apu_set_register(io, channel, 0, 0x400F); + } + +// outw(1, io+0x04) +// outw(inw(io+0x18)|4, io+0x18); + + for(channel=low_apu; channel<=high_apu; channel++) + { + /* Turn on the DMA */ + if(mode&2) /* 16 bit */ + apu_set_register(io, channel, 0, + (apu_get_register(io, channel, 0)&0xFF0F)|0x20); + else + apu_set_register(io, channel, 0, + (apu_get_register(io, channel, 0)&0xFF0F)|0x40); + } +} + +static void ess_play_finish(int io, int channel, int mode) +{ + apu_set_register(io, channel, 0, + apu_get_register(io, channel, 0)&0xFF0F); + if(mode&1) + { + channel++; + apu_set_register(io, channel, 0, + apu_get_register(io, channel, 0)&0xFF0F); + } +} + +static void ess_play_test(int io) +{ + u8 *buf=kmalloc(8192, GFP_KERNEL|GFP_DMA); + int ct; + long time=jiffies; + for(ct=0; ct<8192;ct++) + { + buf[ct]=ct^39; + } + ess_play_setup(io, 10, 0, 0x39CD, buf, 8192); + + while((jiffies-time)<5*HZ) + { + schedule(); + } + printk("\n"); + ess_play_finish(io, 10, 0); + kfree(buf); +} + + +/* + * Configure up legacy mode on the ESS-Tech Maestro and Maestro-2 + * + * This is also pretty much the same set up to configure the native + * mode which is what we will finally use. This is the "2.2 at least + * you get sound" stopgap for the moment. + */ + +static int maestro_install(struct pci_dev *pcidev, char *name) +{ + u16 w; + u32 n; + int iobase; + int i; + + iobase = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + + /* + * Ok card ready. Begin setup proper + */ + + printk(KERN_INFO "ess_pci: Configuring %s at 0x%04X\n", name, iobase); + + if(check_region(ESS_SBBASE, 16)) + { + printk(KERN_WARNING "ess_pci: skipping - I/O 0x%03X is not free.\n", + ESS_SBBASE); + return 0; + } + + /* + * Disable ACPI + */ + + pci_write_config_dword(pcidev, 0x54, 0x00000000); + + /* + * Use TDMA for now. TDMA works on all boards, so while its + * not the most efficient its the simplest. + */ + + pci_read_config_word(pcidev, 0x50, &w); + + /* Clear DMA bits */ + w&=~(1<<10|1<<9|1<<8); + + /* TDMA on */ + w|=(1<<8); + + /* + * MPU at 330 + */ + + w&=~((1<<4)|(1<<3)); + + /* + * SB at 0x220 + */ + + w&=~(1<<2); + + /* + * Reserved write as 0 + */ + + w&=~(1<<1); + + /* + * Some of these are undocumented bits + */ + + w&=~(1<<13)|(1<<14); /* PIC Snoop mode bits */ + w&=~(1<<11); /* Safeguard off */ + w|= (1<<7); /* Posted write */ + w|= (1<<6); /* ISA timing on */ + w&=~(1<<1); /* Subtractive decode off */ + w&=~(1<<5); /* Don't swap left/right */ + + pci_write_config_word(pcidev, 0x50, w); + + pci_read_config_word(pcidev, 0x52, &w); + w&=~(1<<15); /* Turn off internal clock multiplier */ + w&=~(1<<14); /* External clock */ + + w&=~(1<<7); /* HWV off */ + w&=~(1<<6); /* Debounce off */ + w&=~(1<<5); /* GPIO 4:5 */ + w&=~(1<<4); /* Disconnect from the CHI */ + w&=~(1<<3); /* IDMA off (undocumented) */ + w&=~(1<<2); /* MIDI fix off (undoc) */ + w&=~(1<<0); /* IRQ to ISA off (undoc) */ + pci_write_config_word(pcidev, 0x52, w); + + /* + * DDMA off + */ + + pci_read_config_word(pcidev, 0x60, &w); + w&=~(1<<0); + pci_write_config_word(pcidev, 0x60, w); + + /* + * Legacy mode + */ + + pci_read_config_word(pcidev, 0x40, &w); + w&=~(1<<15); /* legacy decode on */ + w&=~(1<<14); /* Disable SIRQ */ + w&=~(1<<13|1<<12|1<<11); + + /* + * We don't use the emulation IRQ's + */ + + w|=(1<<11); /* MPU IRQ 7 */ + w&=~(1<<10|1<<9|1<<8); /* SB IRQ 5 */ + w|=(1<<3)|(1<<1)|(1<<0); /* SB on , FM on, MPU on */ + w&=~(1<<7|1<<6); + w|=(1<<6); /* DMA 1 */ + + /* + * Default to DMA 1 + */ + + pci_write_config_word(pcidev, 0x40, w); + + sound_reset(iobase); + + + /* + * Reset the CODEC + */ + + maestro_ac97_reset(iobase); + + /* + * Ring Bus Setup + */ + + n=inl(iobase+0x34); + n&=~0xF000; + n|=12<<12; /* Direct Sound, Stereo */ + + n=inl(iobase+0x34); + n&=~0x0F00; /* Modem off */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x00F0; + n|=9<<4; /* DAC, Stereo */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x000F; /* ASSP off */ + outl(n, iobase+0x34); + + + n=inl(iobase+0x34); + n|=(1<<29); /* Enable ring bus */ + outl(n, iobase+0x34); + + + n=inl(iobase+0x34); + n|=(1<<28); /* Enable serial bus */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x00F00000; /* MIC off */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x000F0000; /* I2S off */ + outl(n, iobase+0x34); + + w=inw(iobase+0x18); + w&=~(1<<7); /* ClkRun off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<6); /* Harpo off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<4); /* ASSP irq off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<3); /* ISDN irq off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w|=(1<<2); /* Direct Sound IRQ on */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<1); /* MPU401 IRQ off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w|=(1<<0); /* SB IRQ on */ + outw(w, iobase+0x18); + + + outb(0, iobase+0xA4); + outb(3, iobase+0xA2); + outb(0, iobase+0xA6); + + for(i=0;i<16;i++) + { + /* Write 0 into the buffer area 0x1E0->1EF */ + outw(0x01E0+i, 0x10+iobase); + outw(0x0000, 0x12+iobase); + } + + wave_set_register(iobase, IDR7_WAVE_ROMRAM, + (wave_get_register(iobase, IDR7_WAVE_ROMRAM)&0xFF00)); + wave_set_register(iobase, IDR7_WAVE_ROMRAM, + wave_get_register(iobase, IDR7_WAVE_ROMRAM)|0x100); + wave_set_register(iobase, IDR7_WAVE_ROMRAM, + wave_get_register(iobase, IDR7_WAVE_ROMRAM)&~0x200); + wave_set_register(iobase, IDR7_WAVE_ROMRAM, + wave_get_register(iobase, IDR7_WAVE_ROMRAM)|~0x400); + + maestro_write(iobase, IDR2_CRAM_DATA, 0x0000); + maestro_write(iobase, 0x08, 0xB004); + /* Now back to the DirectSound stuff */ + maestro_write(iobase, 0x09, 0x001B); + maestro_write(iobase, 0x0A, 0x8000); + maestro_write(iobase, 0x0B, 0x3F37); + maestro_write(iobase, 0x0C, 0x0098); + + maestro_write(iobase, 0x0C, + (maestro_read(iobase, 0x0C)&~0xF000)|0x8000); + maestro_write(iobase, 0x0C, + (maestro_read(iobase, 0x0C)&~0x0F00)|0x0500); + + maestro_write(iobase, 0x0D, 0x7632); + + /* Wave cache control on - test off, sg off, + enable, enable extra chans 1Mb */ + + outw(inw(0x14+iobase)|(1<<8),0x14+iobase); + outw(inw(0x14+iobase)&0xFE03,0x14+iobase); + outw((inw(0x14+iobase)&0xFFFC), 0x14+iobase); + outw(inw(0x14+iobase)|(1<<7),0x14+iobase); + + outw(0xA1A0, 0x14+iobase); + + if(maestro_ac97_get(iobase, 0x00)==0x0080) + { + printk(KERN_INFO "ess_pci: PT101 Codec detected\n"); + maestro_pt101_init(iobase); + } + else + { + printk(KERN_INFO "ess_pci: AC97 Codec detected\n"); + maestro_ac97_init(iobase); + } + + /* Now clear the channel data */ + + for(i=0;i<64;i++) + { + for(w=0;w<0x0E;w++) + apu_set_register(iobase, i, w, 0); + } + + /* Now we program up the APU's */ + + /* + * APU 6 is the mixer + */ + + apu_set_register(iobase, 6, 0, + apu_get_register(iobase, 6, 0)&~(1<<14)); + apu_set_register(iobase, 6, 0, + apu_get_register(iobase, 6, 0)&~(1<<13)); + apu_set_register(iobase, 6, 0, + apu_get_register(iobase, 6, 0)&~(1<<12)); + apu_set_register(iobase, 6, 0, + apu_get_register(iobase, 6, 0)&0xFCFF); + apu_set_register(iobase, 6, 0, + apu_get_register(iobase, 6, 0)&0xF3FF); + apu_set_register(iobase, 6, 0, + (apu_get_register(iobase, 6, 0)&0xFFF0)|0x0F); + apu_set_register(iobase, 6, 2, + apu_get_register(iobase, 6, 2)&0x00FF); + apu_set_register(iobase, 6, 3, 0x0000); + apu_set_register(iobase, 6, 2, + apu_get_register(iobase, 6, 2)&0xFF3F); + apu_set_register(iobase, 6, 2, + apu_get_register(iobase, 6, 2)|(1<<5)); + apu_set_register(iobase, 6, 2, + apu_get_register(iobase, 6, 2)&~(1<<4)); + apu_set_register(iobase, 6, 2, + apu_get_register(iobase, 6, 2)&0xFFF0); + apu_set_register(iobase, 6, 4, 0x4B5F); + apu_set_register(iobase, 6, 5, 0xFDD5); + apu_set_register(iobase, 6, 6, 0xFE00); + apu_set_register(iobase, 6, 7, 0x0100); + apu_set_register(iobase, 6, 8, 0x78FF); + apu_set_register(iobase, 6, 9, 0xFFFF); + apu_set_register(iobase, 6, 0xA,0x8A10); + apu_set_register(iobase, 6, 0xB,0x8009); + + /* + * APU 62 - Right channel DSP + */ + + apu_set_register(iobase, 62, 0, + apu_get_register(iobase, 62, 0)&~(1<<14)); + apu_set_register(iobase, 62, 0, + apu_get_register(iobase, 62, 0)&~(1<<13)); + apu_set_register(iobase, 62, 0, + apu_get_register(iobase, 62, 0)&~(1<<12)); + apu_set_register(iobase, 62, 0, + apu_get_register(iobase, 62, 0)&0xFCFF); + apu_set_register(iobase, 62, 0, + apu_get_register(iobase, 62, 0)&0xF3FF); + apu_set_register(iobase, 62, 0, + (apu_get_register(iobase, 62, 0)&0xFFF0)|0x0F); + apu_set_register(iobase, 62, 2, + apu_get_register(iobase, 62, 2)&0x00FF); + apu_set_register(iobase, 62, 3, 0x1000); + apu_set_register(iobase, 62, 2, + apu_get_register(iobase, 62, 2)&0xFF3F); + apu_set_register(iobase, 62, 2, + apu_get_register(iobase, 62, 2)&~(1<<5)); + apu_set_register(iobase, 62, 2, + apu_get_register(iobase, 62, 2)&~(1<<4)); + apu_set_register(iobase, 62, 2, + apu_get_register(iobase, 62, 2)&0xFFF0); + apu_set_register(iobase, 62, 4, 0x7F00); + apu_set_register(iobase, 62, 5, 0x8000); + apu_set_register(iobase, 62, 6, 0x8080); + apu_set_register(iobase, 62, 7, 0x0080); + apu_set_register(iobase, 62, 8, 0x7F00); + apu_set_register(iobase, 62, 9, 0xFFFF); + apu_set_register(iobase, 62, 0xA,0x7F00); + apu_set_register(iobase, 62, 0xB,0x00F0); + + /* + * APU 63 - Left channel DSP + */ + + apu_set_register(iobase, 63, 0, + apu_get_register(iobase, 63, 0)&~(1<<14)); + apu_set_register(iobase, 63, 0, + apu_get_register(iobase, 63, 0)&~(1<<13)); + apu_set_register(iobase, 63, 0, + apu_get_register(iobase, 63, 0)&~(1<<12)); + apu_set_register(iobase, 63, 0, + apu_get_register(iobase, 63, 0)&0xFCFF); + apu_set_register(iobase, 63, 0, + apu_get_register(iobase, 63, 0)&0xF3FF); + apu_set_register(iobase, 63, 0, + (apu_get_register(iobase, 63, 0)&0xFFF0)|0x0F); + apu_set_register(iobase, 63, 2, + apu_get_register(iobase, 63, 2)&0x00FF); + apu_set_register(iobase, 63, 3, 0x1000); + apu_set_register(iobase, 63, 2, + apu_get_register(iobase, 63, 2)&0xFF3F); + apu_set_register(iobase, 63, 2, + apu_get_register(iobase, 63, 2)&~(1<<5)); + apu_set_register(iobase, 63, 2, + apu_get_register(iobase, 63, 2)&~(1<<4)); + apu_set_register(iobase, 63, 2, + apu_get_register(iobase, 63, 2)&0xFFF0); + apu_set_register(iobase, 63, 4, 0x7F00); + apu_set_register(iobase, 63, 5, 0x0000); + apu_set_register(iobase, 63, 6, 0x0080); + apu_set_register(iobase, 63, 7, 0x0080); + apu_set_register(iobase, 63, 8, 0x7F00); + apu_set_register(iobase, 63, 9, 0xFFFF); + apu_set_register(iobase, 63, 0xA,0x7F10); + apu_set_register(iobase, 63, 0xB,0x00F0); + + apu_set_register(iobase, 6, 0, + (apu_get_register(iobase,6, 0)&0xFF0F)|(9<<4)); + + udelay(30); + + apu_set_register(iobase, 62, 0, + (apu_get_register(iobase,6, 0)&0xFF0F)|(1<<4)); + apu_set_register(iobase, 63, 0, + (apu_get_register(iobase,6, 0)&0xFF0F)|(1<<4)); + + load_tables(iobase); + + outb(0x41, ESS_SETUP_A4+iobase); + udelay(1); + + printk(KERN_INFO "ess_pci: Programmed %s at 0x%X to legacy mode.\n", + name, iobase); + + ess_play_test(iobase); + maestro_cfg.dma = 1; + maestro_cfg.irq = pcidev->irq; + maestro_cfg.io_base = ESS_SBBASE; + maestro_cfg.dma2 = -1; + if(sb_dsp_detect(&maestro_cfg, SB_PCI_ESSMAESTRO, iobase)==-1) + { + printk(KERN_WARNING "esspci: Sound blaster emulation not responding.\n"); + return 0; + } + attach_sb_card(&maestro_cfg); + return 1; +} + + + +/* + * For now this does one card only. It is written this way as it will change + */ + +int init_ess19xx(void) +{ + struct pci_dev *pcidev=NULL; + int count=0; + + if(!pci_present()) + return -ENODEV; + + pcidev = NULL; + + /* + * Find the ESS Maestro 2. + */ + + while((pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1968, pcidev))!=NULL) + { + count+=maestro_install(pcidev, "ESS Maestro 2"); + if(count) + return 0; + } + + /* + * Find the ESS Maestro 2E + */ + + while((pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1978, pcidev))!=NULL) + { +// count+=maestro_install(pcidev, "ESS Maestro 2E"); + printk(KERN_INFO "ESS Maestro 2E not yet supported.\n"); + if(count) + return 0; + } + + /* + * ESS Maestro 1 + */ + + while((pcidev = pci_find_device(0x1285, 0x100, pcidev))!=NULL) + { + count+=maestro_install(pcidev, "ESS Maestro"); + if(count) + return 0; + } + if(count==0) + return -ENODEV; + return 0; +} + + +int init_module(void) +{ + if(init_ess19xx()<0) + { + printk(KERN_ERR "No ESS Maestro cards found.\n"); + return -ENODEV; + } + return 0; +} + +void cleanup_module(void) +{ + if(maestro_cfg.slots[0] != -1) + unload_sb(&maestro_cfg); +} + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/maestro.c linux.ac/drivers/sound/maestro.c --- linux.vanilla/drivers/sound/maestro.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/maestro.c Fri Jun 4 23:52:44 1999 @@ -0,0 +1,2796 @@ +/*****************************************************************************/ + +/* + * ESS Maestro/Maestro-2 driver for Linux 2.2.x + * + * + * 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. + * + * + * Based heavily on SonicVibes.c: + * Copyright (C) 1998-1999 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * + * Supported devices: + * /dev/dsp0-7 standard /dev/dsp device, (mostly) OSS compatible + * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible + * + * Revision history + * + */ + +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "maestro.h" +#include "maestro_tables.h" + + + + +/* --------------------------------------------------------------------- */ + +#undef OSS_DOCUMENTED_MIXER_SEMANTICS + +/* --------------------------------------------------------------------- */ + +#ifndef PCI_VENDOR_ESS +#define PCI_VENDOR_ESS 0x125D +#define PCI_DEVICE_ID_ESS_ESS1969 0x1969 +#define PCI_DEVICE_ID_ESS_ESS1948 0x1948 /* Solo ?? */ +#define PCI_DEVICE_ID_ESS_ESS1968 0x1968 /* Maestro 2 */ +#define PCI_DEVICE_ID_ESS_ESS1978 0x1978 /* Maestro 2E */ +#endif + +#define ESS_CHAN_HARD 0x100 + +#define ESS_CFMT_STEREO 0x01 +#define ESS_CFMT_16BIT 0x02 +#define ESS_CFMT_MASK 0x03 +#define ESS_CFMT_ASHIFT 0 +#define ESS_CFMT_CSHIFT 4 + +#define ESS_ENABLE_PE 1 +#define ESS_ENABLE_RE 2 + +#define ESS_MAGIC 0x125D1968 + +#define DAC_RUNNING 1 +#define ADC_RUNNING 2 + +static const unsigned sample_size[] = { 1, 2, 2, 4 }; +static const unsigned sample_shift[] = { 0, 1, 1, 2 }; + +#define SND_DEV_DSP16 5 + +/* --------------------------------------------------------------------- */ + +struct ess_state { + unsigned int magic; + /* FIXME: we probably want submixers in here, but only one record pair */ + u8 apu[4]; /* Left, Right, Left In, Right In */ + u8 apu_mode[4]; /* Running mode for this APU */ + u8 apu_pan[4]; /* Panning setup for this APU */ + struct ess_card *card; /* Card info */ + /* wave stuff */ + unsigned int rateadc, ratedac; + unsigned char fmt, enable; + + spinlock_t lock; + struct semaphore open_sem; + mode_t open_mode; + struct wait_queue *open_wait; + + /* soundcore stuff */ + int dev_audio; + int dev_mixer; + + struct dmabuf { + void *rawbuf; + unsigned buforder; + unsigned numfrag; + unsigned fragshift; + unsigned hwptr, swptr; + unsigned total_bytes; + int count; + unsigned error; /* over/underrun */ + struct wait_queue *wait; + /* redundant, but makes calculations easier */ + unsigned fragsize; + unsigned dmasize; + unsigned fragsamples; + /* OSS stuff */ + unsigned mapped:1; + unsigned ready:1; + unsigned endcleared:1; + unsigned ossfragshift; + int ossmaxfrags; + unsigned subdivision; + u16 base; /* Offset for ptr */ + } dma_dac, dma_adc; +}; + +struct ess_card { + unsigned int magic; + + /* We keep maestro cards in a linked list */ + struct ess_card *next; + + struct ess_state channels[8]; + u16 maestro_map[32]; /* Register map */ + + /* hardware resources */ + u32 iobase; + u32 irq; + + /* mixer stuff */ + struct { + unsigned int modcnt; +#ifndef OSS_DOCUMENTED_MIXER_SEMANTICS + unsigned short vol[13]; +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + } mix; +}; + +extern __inline__ unsigned ld2(unsigned int x) +{ + unsigned r = 0; + + if (x >= 0x10000) { + x >>= 16; + r += 16; + } + if (x >= 0x100) { + x >>= 8; + r += 8; + } + if (x >= 0x10) { + x >>= 4; + r += 4; + } + if (x >= 4) { + x >>= 2; + r += 2; + } + if (x >= 2) + r++; + return r; +} + + +/* --------------------------------------------------------------------- */ + +static struct ess_card *devs = NULL; + +/* --------------------------------------------------------------------- */ + + +/* + * ESS Maestro AC97 codec programming interface. + */ + +static void maestro_ac97_set(int io, u8 cmd, u16 val) +{ + int i; + /* + * Wait for the codec bus to be free + */ + + for(i=0;i<10000;i++) + { + if(!(inb(io+ESS_AC97_INDEX)&1)) + break; + } + /* + * Write the bus + */ + outw(val, io+ESS_AC97_DATA); + udelay(1); + outb(cmd, io+ESS_AC97_INDEX); + udelay(1); +} + +static u16 maestro_ac97_get(int io, u8 cmd) +{ + int sanity=100000; + u16 data; + int i; + + /* + * Wait for the codec bus to be free + */ + + for(i=0;i<10000;i++) + { + if(!(inb(io+ESS_AC97_INDEX)&1)) + break; + } + + outb(cmd|0x80, io+ESS_AC97_INDEX); + udelay(1); + + while(inb(io+ESS_AC97_INDEX)&1) + { + sanity--; + if(!sanity) + { + printk(KERN_ERR "ess_pci: ac97 codec timeout.\n"); + return 0; + } + } + data=inw(io+ESS_AC97_DATA); + udelay(1); + return data; +} + +/* + * The Maestro can be wired to a standard AC97 compliant codec + * (see www.intel.com for the pdf's on this), or to a PT101 codec + * which appears to be the ES1918 (data sheet on the esstech.com.tw site) + * + * The PT101 setup is untested. + */ + +static u16 maestro_ac97_init(int iobase) +{ + maestro_ac97_set(iobase, 0x02, 0x0000); + maestro_ac97_set(iobase, 0x04, 0x0000); + maestro_ac97_set(iobase, 0x06, 0x0000); + maestro_ac97_set(iobase, 0x08, 0x9F1F); + maestro_ac97_set(iobase, 0x0A, 0x9F1F); + maestro_ac97_set(iobase, 0x0C, 0x9F1F); + maestro_ac97_set(iobase, 0x0E, 0x9F1F); + maestro_ac97_set(iobase, 0x10, 0x9F1F); + maestro_ac97_set(iobase, 0x12, 0x9F1F); + maestro_ac97_set(iobase, 0x14, 0x9F1F); + maestro_ac97_set(iobase, 0x16, 0x9F1F); + maestro_ac97_set(iobase, 0x18, 0x0808); + maestro_ac97_set(iobase, 0x1A, 0x0000); + maestro_ac97_set(iobase, 0x1C, 0x0404); + maestro_ac97_set(iobase, 0x1E, 0x0404); + maestro_ac97_set(iobase, 0x20, 0x0000); + maestro_ac97_set(iobase, 0x26, 0x000F); + return 0; +} + +static u16 maestro_pt101_init(int iobase) +{ + maestro_ac97_set(iobase, 0x2A, 0x0001); + maestro_ac97_set(iobase, 0x2C, 0x0000); + maestro_ac97_set(iobase, 0x2C, 0xFFFF); + maestro_ac97_set(iobase, 0x10, 0x9F1F); + maestro_ac97_set(iobase, 0x12, 0x0808); + maestro_ac97_set(iobase, 0x14, 0x9F1F); + maestro_ac97_set(iobase, 0x16, 0x9F1F); + maestro_ac97_set(iobase, 0x18, 0x0404); + maestro_ac97_set(iobase, 0x1A, 0x0000); + maestro_ac97_set(iobase, 0x1C, 0x0000); + maestro_ac97_set(iobase, 0x02, 0x0404); + maestro_ac97_set(iobase, 0x04, 0x0808); + maestro_ac97_set(iobase, 0x0C, 0x801F); + maestro_ac97_set(iobase, 0x0E, 0x801F); + return 0; +} + +static void maestro_ac97_reset(int ioaddr) +{ + outw(0x2000, ioaddr+0x36); + udelay(20); + outw(0x0000, ioaddr+0x36); + udelay(200); +} + + + +/* + * Indirect register access. Not all registers are readable so we + * need to keep register state ourselves + */ + +#define WRITEABLE_MAP 0xEFFFFF +#define READABLE_MAP 0x64003F + +/* + * The ESS engineers were a little indirection happy. These indirected + * registers themselves include indirect registers at another layer + */ + +static void maestro_write(struct ess_state *ess, u16 reg, u16 data) +{ + long ioaddr = ess->card->iobase; + unsigned long flags; + save_flags(flags); + cli(); + outw(reg, ioaddr+0x02); + outw(data, ioaddr+0x00); + ess->card->maestro_map[reg]=data; + restore_flags(flags); +} + +static u16 maestro_read(struct ess_state *ess, u16 reg) +{ + long ioaddr = ess->card->iobase; + if(READABLE_MAP & (1<card->maestro_map[reg]=inw(ioaddr+0x00); + restore_flags(flags); + } + return ess->card->maestro_map[reg]; +} + +/* + * These routines handle accessing the second level indirections to the + * wave ram. + */ + +/* + * The register names are the ones ESS uses (see 104T31.ZIP) + */ + +#define IDR0_DATA_PORT 0x00 +#define IDR1_CRAM_POINTER 0x01 +#define IDR2_CRAM_DATA 0x02 +#define IDR3_WAVE_DATA 0x03 +#define IDR4_WAVE_PTR_LOW 0x04 +#define IDR5_WAVE_PTR_HI 0x05 +#define IDR6_TIMER_CTRL 0x06 +#define IDR7_WAVE_ROMRAM 0x07 + +static void apu_index_set(struct ess_state *ess, u16 index) +{ + int i; + maestro_write(ess, IDR1_CRAM_POINTER, index); + for(i=0;i<1000;i++) + if(maestro_read(ess, IDR1_CRAM_POINTER)==index) + return; + printk(KERN_WARNING "ess_pci: APU register select failed.\n"); +} + +static void apu_data_set(struct ess_state *ess, u16 data) +{ + int i; + for(i=0;i<1000;i++) + { + if(maestro_read(ess, IDR0_DATA_PORT)==data) + return; + maestro_write(ess, IDR0_DATA_PORT, data); + } +} + +/* + * This is the public interface for APU manipulation. It handles the + * interlock to avoid two APU writes in parallel etc. Don't diddle + * directly with the stuff above. + */ + +static void apu_set_register(struct ess_state *ess, u16 channel, u8 reg, u16 data) +{ + unsigned long flags; + + if(channel&ESS_CHAN_HARD) + channel&=~ESS_CHAN_HARD; + else + { + if(channel>3) + printk("BAD CHANNEL %d.\n",channel); + else + channel = ess->apu[channel]; + } + + reg|=(channel<<4); + + save_flags(flags); + cli(); + apu_index_set(ess, reg); + apu_data_set(ess, data); + restore_flags(flags); +} + +static u16 apu_get_register(struct ess_state *ess, u16 channel, u8 reg) +{ + unsigned long flags; + u16 v; + + if(channel&ESS_CHAN_HARD) + channel&=~ESS_CHAN_HARD; + else + channel = ess->apu[channel]; + + reg|=(channel<<4); + + save_flags(flags); + cli(); + apu_index_set(ess, reg); + v=maestro_read(ess, IDR0_DATA_PORT); + restore_flags(flags); + return v; +} + + +/* + * The ASSP is fortunately not double indexed + */ + +static void assp_set_register(int ioaddr, u32 reg, u32 value) +{ + unsigned long flags; + + save_flags(flags); + cli(); + outl(reg, ioaddr+0x80); + outl(value, ioaddr+0x84); + restore_flags(flags); +} + +static u32 assp_get_register(int ioaddr, u32 reg) +{ + unsigned long flags; + u32 value; + + save_flags(flags); + cli(); + outl(reg, ioaddr+0x80); + value=inl(ioaddr+0x84); + restore_flags(flags); + + return value; +} + +/* + * The wavecache is also sane + */ + +static void wave_set_register(struct ess_state *ess, u16 reg, u16 value) +{ + long ioaddr = ess->card->iobase; + unsigned long flags; + + save_flags(flags); + cli(); + outw(reg, ioaddr+0x10); + outw(value, ioaddr+0x12); + restore_flags(flags); +} + +static u16 wave_get_register(struct ess_state *ess, u16 reg) +{ + long ioaddr = ess->card->iobase; + unsigned long flags; + u16 value; + + save_flags(flags); + cli(); + outw(reg, ioaddr+0x10); + value=inw(ioaddr+0x12); + restore_flags(flags); + + return value; +} + +/* + * Additional Reset Functions + */ + +static void maestro_reset(int ioaddr) +{ + outw(0x8000, 0x18+ioaddr); + udelay(10); + outw(0x0000, 0x18+ioaddr); + udelay(10); +} + +static void sound_reset(int ioaddr) +{ + outw(0x2000, 0x18+ioaddr); + udelay(10); + outw(0x0000, 0x18+ioaddr); + udelay(10); +} + +static void asp_load(int ioaddr, u16 l, u16 h, u16 *data, int len) +{ + int i; + outw(l, ioaddr+0x80); + outw(h, ioaddr+0x82); + for(i=0;i>=1; + + + for(channel=0; channel <= high_apu; channel++) + { + int i; + + /* + * To understand this it helps to know how the + * wave cache works. There are 4 DSP wavecache + * blocks which are 0x1FC->0x1FF. They are selected + * by setting bits 22,21,20 of the address to + * 1 X Y where X Y select the block. + * + * In addition stereo pairing is supported. This is + * set in the wave cache control for the channel as is + * 8bit unsigned. + * + * Note that this causes a problem. With our limit of + * about 12 full duplex pairs (48 channels active) we + * will need to do a lot of juggling to get all the + * memory we want sufficiently close together. + * + * Even with 64K blocks that means + * 24 channel pairs + * 6 pairs/block + * + * 10K per channel pair = 5000 samples. + */ + + pa = virt_to_bus(buffer); + + wave_set_register(ess, 0x01FC, (pa&0xFFE00000)>>12); + + /* Flush the wave cache entry */ + if(!(mode&1)) + wave_set_register(ess, ess->apu[channel]<<3, (pa&0xFFFF)-0x10); + else + wave_set_register(ess, ess->apu[channel]<<3, ((pa&0xFFFF)-0x10)|2); + + pa&=0x1FFFFF; /* Low 21 bits */ + pa>>=1; + + ess->dma_dac.base = pa&0xFFFF; + + if(mode&1) /* Enable stereo */ + pa|=0x00800000; + pa|=0x00400000; /* System RAM */ + + /* Begin loading the APU */ + + for(i=0;i<15;i++) + apu_set_register(ess, channel, i, 0x0000); + + /* Load the frequency, turn on 6dB, turn off the effects */ + apu_set_register(ess, channel, 2, (rate&0xFF)<<8|0x10); + apu_set_register(ess, channel, 3, rate>>8); + + /* Load the buffer into the wave engine */ + apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8); + apu_set_register(ess, channel, 5, pa&0xFFFF); + apu_set_register(ess, channel, 6, (pa+size)&0xFFFF); + apu_set_register(ess, channel, 7, size); + + apu_set_register(ess, channel, 8, 0x0000); + apu_set_register(ess, channel, 9, 0xD000); + + if(mode&1) + { + /* Set left or right */ + if(channel == 0) + apu_set_register(ess, channel, 10, 0x8F00); + else + apu_set_register(ess, channel, 10, 0x8F10); + } + else + apu_set_register(ess, channel, 10, 0x8F08); + apu_set_register(ess, channel, 11, 0x0000); + apu_set_register(ess, channel, 0, 0x400F); + } + + outw(1, ess->card->iobase+0x04); + outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18); + + for(channel=0; channel<=high_apu; channel++) + { + /* Turn on the DMA */ + if(mode&2) + { /* 16 bit */ + apu_set_register(ess, channel, 0, + (apu_get_register(ess, channel, 0)&0xFF0F)|0x20); + ess->apu_mode[channel]=0x20; + } + else + { + apu_set_register(ess, channel, 0, + (apu_get_register(ess, channel, 0)&0xFF0F)|0x40); + ess->apu_mode[channel]=0x40; + } + } +} + +static void ess_play_finish(struct ess_state *ess, int mode) +{ + apu_set_register(ess, 0, 0, + apu_get_register(ess, 0, 0)&0xFF0F); + if(mode&1) + { + apu_set_register(ess, 1, 0, + apu_get_register(ess, 1, 0)&0xFF0F); + } +} + +static void ess_play_test(struct ess_state *ess) +{ + u8 *buf=kmalloc(16384, GFP_KERNEL|GFP_DMA); + int ct; + long time=jiffies; + if(buf!=NULL) + { + for(ct=0; ct<16384;ct++) + { + buf[ct]=ct^39; + } + } + ess_play_setup(ess, 0, 0x39CD, buf, 16384); + + while((jiffies-time)<5*HZ) + { + schedule(); + } + printk("\n"); + ess_play_finish(ess, 0); + if(buf) + kfree(buf); +} + + + + +/* --------------------------------------------------------------------- */ + +static void set_dmaa(struct ess_state *s, unsigned int addr, unsigned int count) +{ +} + +static void set_dmac(struct ess_state *s, unsigned int addr, unsigned int count) +{ +} + +/* Playback pointer */ + +extern __inline__ unsigned get_dmaa(struct ess_state *s) +{ + long ioport = s->card->iobase; + int offset; + + outw(1, ioport+2); + outw(s->apu[0]<<4|5, ioport); + outw(0, ioport+2); + offset=inw(ioport); + + offset-=s->dma_dac.base; + +// printk("Offset = %d\n", (offset&0x0FFFE)<<1); + return (offset&0xFFFE)/*<<1*/; +} + +/* Record pointer */ +extern __inline__ unsigned get_dmac(struct ess_state *s) +{ + long ioport = s->card->iobase; + int offset; + + outw(1, ioport+2); + outw(s->apu[2]<<4|5, ioport); + outw(0, ioport+2); + offset=inw(ioport); + + /* The offset is an address not a position relative to base */ + + + return (offset&0xFFFE)<<1; +} + +static void set_apu_fmt(struct ess_state *s, int apu, int mode) +{ + if(mode&ESS_CFMT_16BIT) + { + s->apu_mode[apu] = 2; + s->apu_mode[apu+1] = 2; + } + else + { + s->apu_mode[apu] = 4; + s->apu_mode[apu+1] = 4; + } +} + +static void set_fmt(struct ess_state *s, unsigned char mask, unsigned char data) +{ + s->fmt = (s->fmt & mask) | data; + set_apu_fmt(s, 0, s->fmt & ESS_CFMT_MASK); + set_apu_fmt(s, 2, (s->fmt >> ESS_CFMT_CSHIFT) & ESS_CFMT_MASK); +} + +static u16 compute_rate(u32 freq) +{ + if(freq==48000) + return 0xFFFF; + freq<<=16; + freq/=48000; + return freq; +} + +static void set_dac_rate(struct ess_state *s, unsigned rate) +{ + u32 freq; + + if (rate > 48000) + rate = 48000; + if (rate < 4000) + rate = 4000; + freq = compute_rate(rate); + + /* Load the frequency, turn on 6dB, turn off the effects */ + apu_set_register(s, 0, 2, (freq&0xFF)<<8|0x10); + apu_set_register(s, 0, 3, freq>>8); + apu_set_register(s, 1, 2, (freq&0xFF)<<8|0x10); + apu_set_register(s, 1, 3, freq>>8); + s->ratedac = rate; +} + +static void set_adc_rate(struct ess_state *s, unsigned rate) +{ + u32 freq; + + if (rate > 48000) + rate = 48000; + if (rate < 4000) + rate = 4000; + freq = compute_rate(rate); + + /* Load the frequency, turn on 6dB, turn off the effects */ + apu_set_register(s, 2, 2, (freq&0xFF)<<8|0x10); + apu_set_register(s, 2, 3, freq>>8); + apu_set_register(s, 3, 2, (freq&0xFF)<<8|0x10); + apu_set_register(s, 3, 3, freq>>8); + s->rateadc = rate; +} + +/* + * Meet Bob, the timer... + */ + + +static struct timer_list tmp_timer; + +static int bob_stopped; + +static int ess_interrupt_fake(unsigned long v) +{ + extern int ess_interrupt(int, void *, struct pt_regs *); + ess_interrupt(5, (void *)v, NULL); + del_timer(&tmp_timer); + if(!bob_stopped) + { + tmp_timer.expires=jiffies+1; + add_timer(&tmp_timer); + } + else + printk("Stopping bob\n"); + return 0; +} + +static void stop_bob(struct ess_state *s) +{ + bob_stopped=1; +// /* Mask IDR 11,17 */ +// maestro_write(s, 0x11, maestro_read(s, 11)&~1); +// maestro_write(s, 0x17, maestro_read(s, 11)&~1); +} + +static void kill_bob(struct ess_state *s) +{ + del_timer(&tmp_timer); + printk("Killing bob\n"); +// /* Mask IDR 11,17 */ +// maestro_write(s, 0x11, maestro_read(s, 11)&~1); +// maestro_write(s, 0x17, maestro_read(s, 11)&~1); +} + +static void start_bob(struct ess_state *s) +{ +// stop_bob(s); +// maestro_write(s, 6, 0x8000 |(1<<12) | (5<<5) | 11); +// /* Now set IDR 11/17 */ +// maestro_write(s, 0x11, maestro_read(s, 11)|1); +// maestro_write(s, 0x17, maestro_read(s, 11)|1); + static int init=1; + if(init) + { + init=0; + init_timer(&tmp_timer); + tmp_timer.function = ess_interrupt_fake; + } + bob_stopped = 0; + if(!timer_pending(&tmp_timer)) + { + del_timer(&tmp_timer); + tmp_timer.expires = jiffies+1; + tmp_timer.data = (unsigned long)s->card; + add_timer(&tmp_timer); + printk("Starting bob\n"); + } +} + +/* --------------------------------------------------------------------- */ + +static int adc_active = 0; + +extern inline void stop_adc(struct ess_state *s) +{ + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + /* Stop left and right recording APU */ + s->enable &= ~ADC_RUNNING; + apu_set_register(s, 2, 0, apu_get_register(s, 2, 0)&0xFF0F); + apu_set_register(s, 3, 0, apu_get_register(s, 3, 0)&0xFF0F); + adc_active&=~1; +// if(!adc_active) +// stop_bob(s); + spin_unlock_irqrestore(&s->lock, flags); +} + +extern inline void stop_dac(struct ess_state *s) +{ + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + s->enable &= ~DAC_RUNNING; + apu_set_register(s, 0, 0, apu_get_register(s, 0, 0)&0xFF0F); + apu_set_register(s, 1, 0, apu_get_register(s, 1, 0)&0xFF0F); + adc_active&=~2; +// if(!adc_active) +// stop_bob(s); + spin_unlock_irqrestore(&s->lock, flags); +} + +static void start_dac(struct ess_state *s) +{ + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) { + s->enable |= DAC_RUNNING; + apu_set_register(s, 0, 0, + (apu_get_register(s, 0, 0)&0xFF0F)|s->apu_mode[0]); + apu_set_register(s, 1, 0, + (apu_get_register(s, 1, 0)&0xFF0F)|s->apu_mode[1]); + } +// if(!adc_active) +// start_bob(s); + adc_active|=2; + spin_unlock_irqrestore(&s->lock, flags); +} + +static void start_adc(struct ess_state *s) +{ + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) + && s->dma_adc.ready) { + s->enable |= ADC_RUNNING; + apu_set_register(s, 2, 0, + (apu_get_register(s, 2, 0)&0xFF0F)|s->apu_mode[2]); + apu_set_register(s, 3, 0, + (apu_get_register(s, 3, 0)&0xFF0F)|s->apu_mode[3]); + } +// if(!adc_active) +// start_bob(s); + adc_active|=1; + spin_unlock_irqrestore(&s->lock, flags); +} + +/* --------------------------------------------------------------------- */ + +#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT) +#define DMABUF_MINORDER 1 + +static void dealloc_dmabuf(struct dmabuf *db) +{ + unsigned long map, mapend; + + if (db->rawbuf) { + /* undo marking the pages as reserved */ + mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); + for (map = MAP_NR(db->rawbuf); map <= mapend; map++) + clear_bit(PG_reserved, &mem_map[map].flags); + free_pages((unsigned long)db->rawbuf, db->buforder); + } + db->rawbuf = NULL; + db->mapped = db->ready = 0; +} + + +static int prog_dmabuf(struct ess_state *s, unsigned rec) +{ + struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac; + unsigned rate = rec ? s->rateadc : s->ratedac; + int order; + unsigned bytepersec; + unsigned bufs; + unsigned long map, mapend; + unsigned char fmt; + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + fmt = s->fmt; + if (rec) { + s->enable &= ~ESS_ENABLE_RE; + fmt >>= ESS_CFMT_CSHIFT; + } else { + s->enable &= ~ESS_ENABLE_PE; + fmt >>= ESS_CFMT_ASHIFT; + } + spin_unlock_irqrestore(&s->lock, flags); + + db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; + if (!db->rawbuf) { + db->ready = db->mapped = 0; + for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER && !db->rawbuf; order--) + db->rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order); + if (!db->rawbuf) + return -ENOMEM; + db->buforder = order; + if ((virt_to_bus(db->rawbuf) ^ (virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1)) & ~0xffff) + printk(KERN_DEBUG "maestro: DMA buffer crosses 64k boundary: busaddr 0x%lx size %ld\n", + virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder); + if ((virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1) & ~0xffffff) + printk(KERN_DEBUG "maestro: DMA buffer beyond 16MB: busaddr 0x%lx size %ld\n", + virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder); + /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */ + mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); + for (map = MAP_NR(db->rawbuf); map <= mapend; map++) + set_bit(PG_reserved, &mem_map[map].flags); + } + bytepersec = rate << sample_shift[fmt]; + bufs = PAGE_SIZE << db->buforder; + if (db->ossfragshift) { + if ((1000 << db->ossfragshift) < bytepersec) + db->fragshift = ld2(bytepersec/1000); + else + db->fragshift = db->ossfragshift; + } else { + db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1)); + if (db->fragshift < 3) + db->fragshift = 3; + } + db->numfrag = bufs >> db->fragshift; + while (db->numfrag < 4 && db->fragshift > 3) { + db->fragshift--; + db->numfrag = bufs >> db->fragshift; + } + db->fragsize = 1 << db->fragshift; + if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) + db->numfrag = db->ossmaxfrags; + db->fragsamples = db->fragsize >> sample_shift[fmt]; + db->dmasize = db->numfrag << db->fragshift; + memset(db->rawbuf, (fmt & ESS_CFMT_16BIT) ? 0 : 0x80, db->dmasize); + spin_lock_irqsave(&s->lock, flags); + if (rec) { + set_dmac(s, virt_to_bus(db->rawbuf), db->numfrag << db->fragshift); + /* program enhanced mode registers */ + /* FILL */ + } else { + //set_dmaa(s, virt_to_bus(db->rawbuf), db->numfrag << db->fragshift); + /* program enhanced mode registers */ + /* FILL */ + set_dac_rate(s, s->ratedac); + ess_play_setup(s, fmt, compute_rate(s->ratedac), + db->rawbuf, db->numfrag << db->fragshift); + + } + spin_unlock_irqrestore(&s->lock, flags); + db->ready = 1; + return 0; +} + +extern __inline__ void clear_advance(struct ess_state *s) +{ + unsigned char c = (s->fmt & (ESS_CFMT_16BIT << ESS_CFMT_ASHIFT)) ? 0 : 0x80; + unsigned char *buf = s->dma_dac.rawbuf; + unsigned bsize = s->dma_dac.dmasize; + unsigned bptr = s->dma_dac.swptr; + unsigned len = s->dma_dac.fragsize; + + if (bptr + len > bsize) { + unsigned x = bsize - bptr; + memset(buf + bptr, c, x); + bptr = 0; + len -= x; + } + memset(buf + bptr, c, len); +} + +/* call with spinlock held! */ +static void ess_update_ptr(struct ess_state *s) +{ + unsigned hwptr; + int diff; + + /* update ADC pointer */ + if (s->dma_adc.ready) { + hwptr = (/*s->dma_adc.dmasize - */get_dmac(s)) % s->dma_adc.dmasize; + diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize; + s->dma_adc.hwptr = hwptr; + s->dma_adc.total_bytes += diff; + s->dma_adc.count += diff; + if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) + wake_up(&s->dma_adc.wait); + if (!s->dma_adc.mapped) { + if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) { + s->enable &= ~ESS_ENABLE_RE; + /* FILL ME */ +// wrindir(s, SV_CIENABLE, s->enable); + stop_adc(s); + s->dma_adc.error++; + } + } + } + /* update DAC pointer */ + if (s->dma_dac.ready) { + hwptr = (s->dma_dac.dmasize - get_dmaa(s)) % s->dma_dac.dmasize; + diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize; + s->dma_dac.hwptr = hwptr; + s->dma_dac.total_bytes += diff; + if (s->dma_dac.mapped) { + s->dma_dac.count += diff; + if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) + wake_up(&s->dma_dac.wait); + } else { + s->dma_dac.count -= diff; + if (s->dma_dac.count <= 0) { + s->enable &= ~ESS_ENABLE_PE; +/* FILL ME */ +// wrindir(s, SV_CIENABLE, s->enable); + + stop_dac(s); + s->dma_dac.error++; + } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) { + clear_advance(s); + s->dma_dac.endcleared = 1; + } + if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) + wake_up(&s->dma_dac.wait); + } + } +} + +static void ess_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct ess_state *s; + struct ess_card *c = (struct ess_card *)dev_id; + int i; + u32 event; +/* + * 0x1A is a byte on maestro2E + * Turning this to byte cause the ess_play_test to play something + * but I don't know if it is what is intended to play .... seems a single + * note, in the medium range. + */ + event = inb(c->iobase+0x1A); + + outw(inw(c->iobase+4)&1, c->iobase+4); + + if(event&(1<<6)) + { + event = inw(c->iobase+0x18); + outb(0xFF, c->iobase+0x1A); + } + else + { + outb(0xFF, c->iobase+0x1A); + } + + /* + * Update the pointers for all 32 APU's we are running. + */ + for(i=0;i<8;i++) + { + s=&c->channels[i]; + if(s->dev_audio == -1) + break; + spin_lock(&s->lock); + ess_update_ptr(s); + spin_unlock(&s->lock); + } +} + + +/* --------------------------------------------------------------------- */ + +static const char invalid_magic[] = KERN_CRIT "maestro: invalid magic value\n"; + +#define VALIDATE_STATE(s) \ +({ \ + if (!(s) || (s)->magic != ESS_MAGIC) { \ + printk(invalid_magic); \ + return -ENXIO; \ + } \ +}) + +/* --------------------------------------------------------------------- */ +#if 0 + +#define MT_4 1 +#define MT_5MUTE 2 +#define MT_4MUTEMONO 3 +#define MT_6MUTE 4 + +static const struct { + unsigned left:5; + unsigned right:5; + unsigned type:3; + unsigned rec:3; +} mixtable[SOUND_MIXER_NRDEVICES] = { + [SOUND_MIXER_RECLEV] = { SV_CIMIX_ADCINL, SV_CIMIX_ADCINR, MT_4, 0 }, + [SOUND_MIXER_LINE1] = { SV_CIMIX_AUX1INL, SV_CIMIX_AUX1INR, MT_5MUTE, 5 }, + [SOUND_MIXER_CD] = { SV_CIMIX_CDINL, SV_CIMIX_CDINR, MT_5MUTE, 1 }, + [SOUND_MIXER_LINE] = { SV_CIMIX_LINEINL, SV_CIMIX_LINEINR, MT_5MUTE, 4 }, + [SOUND_MIXER_MIC] = { SV_CIMIX_MICIN, SV_CIMIX_ADCINL, MT_4MUTEMONO, 6 }, + [SOUND_MIXER_SYNTH] = { SV_CIMIX_SYNTHINL, SV_CIMIX_SYNTHINR, MT_5MUTE, 2 }, + [SOUND_MIXER_LINE2] = { SV_CIMIX_AUX2INL, SV_CIMIX_AUX2INR, MT_5MUTE, 3 }, + [SOUND_MIXER_VOLUME] = { SV_CIMIX_ANALOGINL, SV_CIMIX_ANALOGINR, MT_5MUTE, 7 }, + [SOUND_MIXER_PCM] = { SV_CIMIX_PCMINL, SV_CIMIX_PCMINR, MT_6MUTE, 0 } +}; + +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + +static int return_mixval(struct ess_state *s, unsigned i, int *arg) +{ + unsigned long flags; + unsigned char l, r, rl, rr; + + spin_lock_irqsave(&s->lock, flags); +// l = rdindir(s, mixtable[i].left); +// r = rdindir(s, mixtable[i].right); + /* FILL ME */ + spin_unlock_irqrestore(&s->lock, flags); + switch (mixtable[i].type) { + case MT_4: + r &= 0xf; + l &= 0xf; + rl = 10 + 6 * (l & 15); + rr = 10 + 6 * (r & 15); + break; + + case MT_4MUTEMONO: + rl = 55 - 3 * (l & 15); + if (r & 0x10) + rl += 45; + rr = rl; + r = l; + break; + + case MT_5MUTE: + default: + rl = 100 - 3 * (l & 31); + rr = 100 - 3 * (r & 31); + break; + + case MT_6MUTE: + rl = 100 - 3 * (l & 63) / 2; + rr = 100 - 3 * (r & 63) / 2; + break; + } + if (l & 0x80) + rl = 0; + if (r & 0x80) + rr = 0; + return put_user((rr << 8) | rl, arg); +} + +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + +static const unsigned char volidx[SOUND_MIXER_NRDEVICES] = +{ + [SOUND_MIXER_RECLEV] = 1, + [SOUND_MIXER_LINE1] = 2, + [SOUND_MIXER_CD] = 3, + [SOUND_MIXER_LINE] = 4, + [SOUND_MIXER_MIC] = 5, + [SOUND_MIXER_SYNTH] = 6, + [SOUND_MIXER_LINE2] = 7, + [SOUND_MIXER_VOLUME] = 8, + [SOUND_MIXER_PCM] = 9 +}; + +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + +static unsigned mixer_recmask(struct ess_state *s) +{ + unsigned long flags; + int i, j; + + spin_lock_irqsave(&s->lock, flags); +// j = rdindir(s, SV_CIMIX_ADCINL) >> 5; + /* FILL ME */ + spin_unlock_irqrestore(&s->lock, flags); + j &= 7; + for (i = 0; i < SOUND_MIXER_NRDEVICES && mixtable[i].rec != j; i++); + return 1 << i; +} + +static int mixer_ioctl(struct ess_state *s, unsigned int cmd, unsigned long arg) +{ + unsigned long flags; + int i, val; + unsigned char l, r, rl, rr; + + VALIDATE_STATE(s); + if (cmd == SOUND_MIXER_INFO) { + mixer_info info; + strncpy(info.id, "SonicVibes", sizeof(info.id)); + strncpy(info.name, "S3 SonicVibes", sizeof(info.name)); + info.modify_counter = s->mix.modcnt; + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + if (cmd == SOUND_OLD_MIXER_INFO) { + _old_mixer_info info; + strncpy(info.id, "SonicVibes", sizeof(info.id)); + strncpy(info.name, "S3 SonicVibes", sizeof(info.name)); + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + if (cmd == OSS_GETVERSION) + return put_user(SOUND_VERSION, (int *)arg); + if (cmd == SOUND_MIXER_PRIVATE1) { /* SRS settings */ + get_user_ret(val, (int *)arg, -EFAULT); + spin_lock_irqsave(&s->lock, flags); + if (val & 1) { + if (val & 2) { + l = 4 - ((val >> 2) & 7); + if (l & ~3) + l = 4; + r = 4 - ((val >> 5) & 7); + if (r & ~3) + r = 4; + wrindir(s, SV_CISRSSPACE, l); + wrindir(s, SV_CISRSCENTER, r); + } else + wrindir(s, SV_CISRSSPACE, 0x80); + } + l = rdindir(s, SV_CISRSSPACE); + r = rdindir(s, SV_CISRSCENTER); + spin_unlock_irqrestore(&s->lock, flags); + if (l & 0x80) + return put_user(0, (int *)arg); + return put_user(((4 - (l & 7)) << 2) | ((4 - (r & 7)) << 5) | 2, (int *)arg); + } + if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int)) + return -EINVAL; + if (_IOC_DIR(cmd) == _IOC_READ) { + switch (_IOC_NR(cmd)) { + case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ + return put_user(mixer_recmask(s), (int *)arg); + + case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ + for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) + if (mixtable[i].type) + val |= 1 << i; + return put_user(val, (int *)arg); + + case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ + for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) + if (mixtable[i].rec) + val |= 1 << i; + return put_user(val, (int *)arg); + + case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ + for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) + if (mixtable[i].type && mixtable[i].type != MT_4MUTEMONO) + val |= 1 << i; + return put_user(val, (int *)arg); + + case SOUND_MIXER_CAPS: + return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg); + + default: + i = _IOC_NR(cmd); + if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type) + return -EINVAL; +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + return return_mixval(s, i, (int *)arg); +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + if (!volidx[i]) + return -EINVAL; + return put_user(s->mix.vol[volidx[i]-1], (int *)arg); +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + } + } + if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE)) + return -EINVAL; + s->mix.modcnt++; + switch (_IOC_NR(cmd)) { + case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ + get_user_ret(val, (int *)arg, -EFAULT); + i = hweight32(val); + if (i == 0) + return 0; /*val = mixer_recmask(s);*/ + else if (i > 1) + val &= ~mixer_recmask(s); + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if (!(val & (1 << i))) + continue; + if (mixtable[i].rec) + break; + } + if (!mixtable[i].rec) + return 0; + spin_lock_irqsave(&s->lock, flags); + frobindir(s, SV_CIMIX_ADCINL, 0x1f, mixtable[i].rec << 5); + frobindir(s, SV_CIMIX_ADCINR, 0x1f, mixtable[i].rec << 5); + spin_unlock_irqrestore(&s->lock, flags); + return 0; + + default: + i = _IOC_NR(cmd); + if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type) + return -EINVAL; + get_user_ret(val, (int *)arg, -EFAULT); + l = val & 0xff; + r = (val >> 8) & 0xff; + if (mixtable[i].type == MT_4MUTEMONO) + l = (r + l) / 2; + if (l > 100) + l = 100; + if (r > 100) + r = 100; + spin_lock_irqsave(&s->lock, flags); + switch (mixtable[i].type) { + case MT_4: + if (l >= 10) + l -= 10; + if (r >= 10) + r -= 10; + frobindir(s, mixtable[i].left, 0xf0, l / 6); + frobindir(s, mixtable[i].right, 0xf0, l / 6); + break; + + case MT_4MUTEMONO: + rr = 0; + if (l < 10) + rl = 0x80; + else { + if (l >= 55) { + rr = 0x10; + l -= 45; + } + rl = (55 - l) / 3; + } + wrindir(s, mixtable[i].left, rl); + frobindir(s, mixtable[i].right, ~0x10, rr); + break; + + case MT_5MUTE: + if (l < 7) + rl = 0x80; + else + rl = (100 - l) / 3; + if (r < 7) + rr = 0x80; + else + rr = (100 - r) / 3; + wrindir(s, mixtable[i].left, rl); + wrindir(s, mixtable[i].right, rr); + break; + + case MT_6MUTE: + if (l < 6) + rl = 0x80; + else + rl = (100 - l) * 2 / 3; + if (r < 6) + rr = 0x80; + else + rr = (100 - r) * 2 / 3; + wrindir(s, mixtable[i].left, rl); + wrindir(s, mixtable[i].right, rr); + break; + } + spin_unlock_irqrestore(&s->lock, flags); +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + return return_mixval(s, i, (int *)arg); +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + if (!volidx[i]) + return -EINVAL; + s->mix.vol[volidx[i]-1] = val; + return put_user(s->mix.vol[volidx[i]-1], (int *)arg); +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + } +} + +#endif + +/* --------------------------------------------------------------------- */ + +static loff_t ess_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +/* --------------------------------------------------------------------- */ + +#if 0 +static int ess_open_mixdev(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct ess_state *s = devs; + + while (s && s->dev_mixer != minor) + s = s->next; + if (!s) + return -ENODEV; + VALIDATE_STATE(s); + file->private_data = s; + MOD_INC_USE_COUNT; + return 0; +} + +static int ess_release_mixdev(struct inode *inode, struct file *file) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + + VALIDATE_STATE(s); + MOD_DEC_USE_COUNT; + return 0; +} + +static int ess_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + return mixer_ioctl((struct ess_state *)file->private_data, cmd, arg); +} + +static /*const*/ struct file_operations ess_mixer_fops = { + &ess_llseek, + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + &ess_ioctl_mixdev, + NULL, /* mmap */ + &ess_open_mixdev, + NULL, /* flush */ + &ess_release_mixdev, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL, /* lock */ +}; + +#endif + +/* --------------------------------------------------------------------- */ + +static int drain_dac(struct ess_state *s, int nonblock) +{ + struct wait_queue wait = { current, NULL }; + unsigned long flags; + int count, tmo; + + if (s->dma_dac.mapped || !s->dma_dac.ready) + return 0; + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&s->dma_dac.wait, &wait); + for (;;) { + spin_lock_irqsave(&s->lock, flags); + count = s->dma_dac.count; + spin_unlock_irqrestore(&s->lock, flags); + if (count <= 0) + break; + if (signal_pending(current)) + break; + if (nonblock) { + remove_wait_queue(&s->dma_dac.wait, &wait); + current->state = TASK_RUNNING; + return -EBUSY; + } + tmo = (count * HZ) / s->ratedac; + tmo >>= sample_shift[(s->fmt >> ESS_CFMT_ASHIFT) & ESS_CFMT_MASK]; + if (!schedule_timeout(tmo ? : 1) && tmo) + printk(KERN_DEBUG "maestro: dma timed out??\n"); + } + remove_wait_queue(&s->dma_dac.wait, &wait); + current->state = TASK_RUNNING; + if (signal_pending(current)) + return -ERESTARTSYS; + return 0; +} + +/* --------------------------------------------------------------------- */ + +static ssize_t ess_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + ssize_t ret; + unsigned long flags; + unsigned swptr; + int cnt; + + VALIDATE_STATE(s); + if (ppos != &file->f_pos) + return -ESPIPE; + if (s->dma_adc.mapped) + return -ENXIO; + if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) + return ret; + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; + ret = 0; +#if 0 + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + spin_unlock_irqrestore(&s->lock, flags); +#endif + while (count > 0) { + spin_lock_irqsave(&s->lock, flags); + swptr = s->dma_adc.swptr; + cnt = s->dma_adc.dmasize-swptr; + if (s->dma_adc.count < cnt) + cnt = s->dma_adc.count; + spin_unlock_irqrestore(&s->lock, flags); + if (cnt > count) + cnt = count; + if (cnt <= 0) { + start_adc(s); + if (file->f_flags & O_NONBLOCK) + return ret ? ret : -EAGAIN; + if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) { + printk(KERN_DEBUG "maestro: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, + s->dma_adc.hwptr, s->dma_adc.swptr); + stop_adc(s); + spin_lock_irqsave(&s->lock, flags); + set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift); + /* program enhanced mode registers */ + /* FILL ME */ +// wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8); +// wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1); + s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0; + spin_unlock_irqrestore(&s->lock, flags); + } + if (signal_pending(current)) + return ret ? ret : -ERESTARTSYS; + continue; + } + if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) + return ret ? ret : -EFAULT; + swptr = (swptr + cnt) % s->dma_adc.dmasize; + spin_lock_irqsave(&s->lock, flags); + s->dma_adc.swptr = swptr; + s->dma_adc.count -= cnt; + spin_unlock_irqrestore(&s->lock, flags); + count -= cnt; + buffer += cnt; + ret += cnt; + start_adc(s); + } + return ret; +} + +static ssize_t ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + ssize_t ret; + unsigned long flags; + unsigned swptr; + int cnt; + + VALIDATE_STATE(s); + if (ppos != &file->f_pos) + return -ESPIPE; + if (s->dma_dac.mapped) + return -ENXIO; + if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) + return ret; + if (!access_ok(VERIFY_READ, buffer, count)) + return -EFAULT; + ret = 0; +#if 0 + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + spin_unlock_irqrestore(&s->lock, flags); +#endif + while (count > 0) { + spin_lock_irqsave(&s->lock, flags); + if (s->dma_dac.count < 0) { + s->dma_dac.count = 0; + s->dma_dac.swptr = s->dma_dac.hwptr; + } + swptr = s->dma_dac.swptr; + cnt = s->dma_dac.dmasize-swptr; + if (s->dma_dac.count + cnt > s->dma_dac.dmasize) + cnt = s->dma_dac.dmasize - s->dma_dac.count; + spin_unlock_irqrestore(&s->lock, flags); + if (cnt > count) + cnt = count; + if (cnt <= 0) { + start_dac(s); + if (file->f_flags & O_NONBLOCK) + return ret ? ret : -EAGAIN; + if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) { + printk(KERN_DEBUG "maestro: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, + s->dma_dac.hwptr, s->dma_dac.swptr); + stop_dac(s); + spin_lock_irqsave(&s->lock, flags); + set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift); + /* program enhanced mode registers */ +// wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8); +// wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1); + /* FILL ME */ + s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0; + spin_unlock_irqrestore(&s->lock, flags); + } + if (signal_pending(current)) + return ret ? ret : -ERESTARTSYS; + continue; + } + if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) + return ret ? ret : -EFAULT; + swptr = (swptr + cnt) % s->dma_dac.dmasize; + spin_lock_irqsave(&s->lock, flags); + s->dma_dac.swptr = swptr; + s->dma_dac.count += cnt; + s->dma_dac.endcleared = 0; + spin_unlock_irqrestore(&s->lock, flags); + count -= cnt; + buffer += cnt; + ret += cnt; + start_dac(s); + } + return ret; +} + +static unsigned int ess_poll(struct file *file, struct poll_table_struct *wait) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + unsigned long flags; + unsigned int mask = 0; + + VALIDATE_STATE(s); + if (file->f_mode & FMODE_WRITE) + poll_wait(file, &s->dma_dac.wait, wait); + if (file->f_mode & FMODE_READ) + poll_wait(file, &s->dma_adc.wait, wait); + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + if (file->f_mode & FMODE_READ) { + if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) + mask |= POLLIN | POLLRDNORM; + } + if (file->f_mode & FMODE_WRITE) { + if (s->dma_dac.mapped) { + if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) + mask |= POLLOUT | POLLWRNORM; + } else { + if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize) + mask |= POLLOUT | POLLWRNORM; + } + } + spin_unlock_irqrestore(&s->lock, flags); + return mask; +} + +static int ess_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + struct dmabuf *db; + int ret; + unsigned long size; + + VALIDATE_STATE(s); + if (vma->vm_flags & VM_WRITE) { + if ((ret = prog_dmabuf(s, 1)) != 0) + return ret; + db = &s->dma_dac; + } else if (vma->vm_flags & VM_READ) { + if ((ret = prog_dmabuf(s, 0)) != 0) + return ret; + db = &s->dma_adc; + } else + return -EINVAL; + if (vma->vm_offset != 0) + return -EINVAL; + size = vma->vm_end - vma->vm_start; + if (size > (PAGE_SIZE << db->buforder)) + return -EINVAL; + if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) + return -EAGAIN; + db->mapped = 1; + return 0; +} + +static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + unsigned long flags; + audio_buf_info abinfo; + count_info cinfo; + int val, mapped, ret; + unsigned char fmtm, fmtd; + + VALIDATE_STATE(s); + mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || + ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); + switch (cmd) { + case OSS_GETVERSION: + return put_user(SOUND_VERSION, (int *)arg); + + case SNDCTL_DSP_SYNC: + if (file->f_mode & FMODE_WRITE) + return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/); + return 0; + + case SNDCTL_DSP_SETDUPLEX: + return 0; + + case SNDCTL_DSP_GETCAPS: + return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg); + + case SNDCTL_DSP_RESET: + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + synchronize_irq(); + s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0; + } + if (file->f_mode & FMODE_READ) { + stop_adc(s); + synchronize_irq(); + s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; + } + return 0; + + case SNDCTL_DSP_SPEED: + get_user_ret(val, (int *)arg, -EFAULT); + if (val >= 0) { + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + set_adc_rate(s, val); + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + set_dac_rate(s, val); + } + } + return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); + + case SNDCTL_DSP_STEREO: + get_user_ret(val, (int *)arg, -EFAULT); + fmtd = 0; + fmtm = ~0; + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + if (val) + fmtd |= ESS_CFMT_STEREO << ESS_CFMT_CSHIFT; + else + fmtm &= ~(ESS_CFMT_STEREO << ESS_CFMT_CSHIFT); + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + if (val) + fmtd |= ESS_CFMT_STEREO << ESS_CFMT_ASHIFT; + else + fmtm &= ~(ESS_CFMT_STEREO << ESS_CFMT_ASHIFT); + } + set_fmt(s, fmtm, fmtd); + return 0; + + case SNDCTL_DSP_CHANNELS: + get_user_ret(val, (int *)arg, -EFAULT); + if (val != 0) { + fmtd = 0; + fmtm = ~0; + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + if (val >= 2) + fmtd |= ESS_CFMT_STEREO << ESS_CFMT_CSHIFT; + else + fmtm &= ~(ESS_CFMT_STEREO << ESS_CFMT_CSHIFT); + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + if (val >= 2) + fmtd |= ESS_CFMT_STEREO << ESS_CFMT_ASHIFT; + else + fmtm &= ~(ESS_CFMT_STEREO << ESS_CFMT_ASHIFT); + } + set_fmt(s, fmtm, fmtd); + } + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_CFMT_STEREO << ESS_CFMT_CSHIFT) + : (ESS_CFMT_STEREO << ESS_CFMT_ASHIFT))) ? 2 : 1, (int *)arg); + + case SNDCTL_DSP_GETFMTS: /* Returns a mask */ + return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg); + + case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ + get_user_ret(val, (int *)arg, -EFAULT); + if (val != AFMT_QUERY) { + fmtd = 0; + fmtm = ~0; + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + if (val == AFMT_S16_LE) + fmtd |= ESS_CFMT_16BIT << ESS_CFMT_CSHIFT; + else + fmtm &= ~(ESS_CFMT_16BIT << ESS_CFMT_CSHIFT); + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + if (val == AFMT_S16_LE) + fmtd |= ESS_CFMT_16BIT << ESS_CFMT_ASHIFT; + else + fmtm &= ~(ESS_CFMT_16BIT << ESS_CFMT_ASHIFT); + } + set_fmt(s, fmtm, fmtd); + } + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_CFMT_16BIT << ESS_CFMT_CSHIFT) + : (ESS_CFMT_16BIT << ESS_CFMT_ASHIFT))) ? AFMT_S16_LE : AFMT_U8, (int *)arg); + + case SNDCTL_DSP_POST: + return 0; + + case SNDCTL_DSP_GETTRIGGER: + val = 0; + if (file->f_mode & FMODE_READ && s->enable & ESS_ENABLE_RE) + val |= PCM_ENABLE_INPUT; + if (file->f_mode & FMODE_WRITE && s->enable & ESS_ENABLE_PE) + val |= PCM_ENABLE_OUTPUT; + return put_user(val, (int *)arg); + + case SNDCTL_DSP_SETTRIGGER: + get_user_ret(val, (int *)arg, -EFAULT); + if (file->f_mode & FMODE_READ) { + if (val & PCM_ENABLE_INPUT) { + if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) + return ret; + start_adc(s); + } else + stop_adc(s); + } + if (file->f_mode & FMODE_WRITE) { + if (val & PCM_ENABLE_OUTPUT) { + if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) + return ret; + start_dac(s); + } else + stop_dac(s); + } + return 0; + + case SNDCTL_DSP_GETOSPACE: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + if (!(s->enable & ESS_ENABLE_PE) && (val = prog_dmabuf(s, 0)) != 0) + return val; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + abinfo.fragsize = s->dma_dac.fragsize; + abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count; + abinfo.fragstotal = s->dma_dac.numfrag; + abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_GETISPACE: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + if (!(s->enable & ESS_ENABLE_RE) && (val = prog_dmabuf(s, 1)) != 0) + return val; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + abinfo.fragsize = s->dma_adc.fragsize; + abinfo.bytes = s->dma_adc.count; + abinfo.fragstotal = s->dma_adc.numfrag; + abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_NONBLOCK: + file->f_flags |= O_NONBLOCK; + return 0; + + case SNDCTL_DSP_GETODELAY: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + val = s->dma_dac.count; + spin_unlock_irqrestore(&s->lock, flags); + return put_user(val, (int *)arg); + + case SNDCTL_DSP_GETIPTR: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + cinfo.bytes = s->dma_adc.total_bytes; + cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; + cinfo.ptr = s->dma_adc.hwptr; + if (s->dma_adc.mapped) + s->dma_adc.count &= s->dma_adc.fragsize-1; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETOPTR: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + cinfo.bytes = s->dma_dac.total_bytes; + cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift; + cinfo.ptr = s->dma_dac.hwptr; + if (s->dma_dac.mapped) + s->dma_dac.count &= s->dma_dac.fragsize-1; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETBLKSIZE: + if (file->f_mode & FMODE_WRITE) { + if ((val = prog_dmabuf(s, 0))) + return val; + return put_user(s->dma_dac.fragsize, (int *)arg); + } + if ((val = prog_dmabuf(s, 1))) + return val; + return put_user(s->dma_adc.fragsize, (int *)arg); + + case SNDCTL_DSP_SETFRAGMENT: + get_user_ret(val, (int *)arg, -EFAULT); + if (file->f_mode & FMODE_READ) { + s->dma_adc.ossfragshift = val & 0xffff; + s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; + if (s->dma_adc.ossfragshift < 4) + s->dma_adc.ossfragshift = 4; + if (s->dma_adc.ossfragshift > 15) + s->dma_adc.ossfragshift = 15; + if (s->dma_adc.ossmaxfrags < 4) + s->dma_adc.ossmaxfrags = 4; + } + if (file->f_mode & FMODE_WRITE) { + s->dma_dac.ossfragshift = val & 0xffff; + s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; + if (s->dma_dac.ossfragshift < 4) + s->dma_dac.ossfragshift = 4; + if (s->dma_dac.ossfragshift > 15) + s->dma_dac.ossfragshift = 15; + if (s->dma_dac.ossmaxfrags < 4) + s->dma_dac.ossmaxfrags = 4; + } + return 0; + + case SNDCTL_DSP_SUBDIVIDE: + if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || + (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) + return -EINVAL; + get_user_ret(val, (int *)arg, -EFAULT); + if (val != 1 && val != 2 && val != 4) + return -EINVAL; + if (file->f_mode & FMODE_READ) + s->dma_adc.subdivision = val; + if (file->f_mode & FMODE_WRITE) + s->dma_dac.subdivision = val; + return 0; + + case SOUND_PCM_READ_RATE: + return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); + + case SOUND_PCM_READ_CHANNELS: + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_CFMT_STEREO << ESS_CFMT_CSHIFT) + : (ESS_CFMT_STEREO << ESS_CFMT_ASHIFT))) ? 2 : 1, (int *)arg); + + case SOUND_PCM_READ_BITS: + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_CFMT_16BIT << ESS_CFMT_CSHIFT) + : (ESS_CFMT_16BIT << ESS_CFMT_ASHIFT))) ? 16 : 8, (int *)arg); + + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_SETSYNCRO: + case SOUND_PCM_READ_FILTER: + return -EINVAL; + + } +// return mixer_ioctl(s, cmd, arg); + return -EINVAL; +} + +static int ess_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct ess_card *c = devs; + struct ess_state *s = NULL, *sp; + int i; + unsigned char fmtm = ~0, fmts = 0; + + /* + * Scan the cards and find the channel. We only + * do this at open time so it is ok + */ + + while (c!=NULL) + { + for(i=0;i<8;i++) + { + sp=&c->channels[i]; + if(sp->dev_audio < 0) + continue; + if((sp->dev_audio ^ minor) & ~0xf) + continue; + s=sp; + } + c=c->next; + } + + if (!s) + return -ENODEV; + + VALIDATE_STATE(s); + file->private_data = s; + /* wait for device to become free */ + down(&s->open_sem); + while (s->open_mode & file->f_mode) { + if (file->f_flags & O_NONBLOCK) { + up(&s->open_sem); + return -EWOULDBLOCK; + } + up(&s->open_sem); + interruptible_sleep_on(&s->open_wait); + if (signal_pending(current)) + return -ERESTARTSYS; + down(&s->open_sem); + } + if (file->f_mode & FMODE_READ) { + fmtm &= ~((ESS_CFMT_STEREO | ESS_CFMT_16BIT) << ESS_CFMT_CSHIFT); + if ((minor & 0xf) == SND_DEV_DSP16) + fmts |= ESS_CFMT_16BIT << ESS_CFMT_CSHIFT; + s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; + set_adc_rate(s, 8000); + } + if (file->f_mode & FMODE_WRITE) { + fmtm &= ~((ESS_CFMT_STEREO | ESS_CFMT_16BIT) << ESS_CFMT_ASHIFT); + if ((minor & 0xf) == SND_DEV_DSP16) + fmts |= ESS_CFMT_16BIT << ESS_CFMT_ASHIFT; + s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0; + set_dac_rate(s, 8000); + } + set_fmt(s, fmtm, fmts); + s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); + start_bob(s); + up(&s->open_sem); + MOD_INC_USE_COUNT; + return 0; +} + +static int ess_release(struct inode *inode, struct file *file) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + + VALIDATE_STATE(s); + if (file->f_mode & FMODE_WRITE) + drain_dac(s, file->f_flags & O_NONBLOCK); + down(&s->open_sem); + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + dealloc_dmabuf(&s->dma_dac); + } + if (file->f_mode & FMODE_READ) { + stop_adc(s); + dealloc_dmabuf(&s->dma_adc); + } + s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); + stop_bob(s); + up(&s->open_sem); + wake_up(&s->open_wait); + MOD_DEC_USE_COUNT; + return 0; +} + +static /*const*/ struct file_operations ess_audio_fops = { + &ess_llseek, + &ess_read, + &ess_write, + NULL, /* readdir */ + &ess_poll, + &ess_ioctl, + &ess_mmap, + &ess_open, + NULL, /* flush */ + &ess_release, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL, /* lock */ +}; + + +/* --------------------------------------------------------------------- */ + +/* maximum number of devices */ +#define NR_DEVICE 4 + +/* --------------------------------------------------------------------- */ + +#if 0 +static struct initvol { + int mixch; + int vol; +} initvol[] __initdata = { + { SOUND_MIXER_WRITE_RECLEV, 0x4040 }, + { SOUND_MIXER_WRITE_LINE1, 0x4040 }, + { SOUND_MIXER_WRITE_CD, 0x4040 }, + { SOUND_MIXER_WRITE_LINE, 0x4040 }, + { SOUND_MIXER_WRITE_MIC, 0x4040 }, + { SOUND_MIXER_WRITE_SYNTH, 0x4040 }, + { SOUND_MIXER_WRITE_LINE2, 0x4040 }, + { SOUND_MIXER_WRITE_VOLUME, 0x4040 }, + { SOUND_MIXER_WRITE_PCM, 0x4040 } +}; + +#endif + +static int maestro_install(struct pci_dev *pcidev, char *name, int index) +{ + u16 w; + u32 n; + int iobase; + int i; + struct ess_card *card; + struct ess_state *ess; + int apu; + int num = 0; + + iobase = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + + card = kmalloc(sizeof(struct ess_card), GFP_KERNEL); + if(card == NULL) + { + printk(KERN_WARNING "maestro: out of memory\n"); + return 0; + } + + memset(card, 0, sizeof(*card)); + + card->iobase = iobase; + card->irq = pcidev->irq; + card->next = devs; + devs = card; + + for(i=0;i<8;i++) + { + struct ess_state *s=&card->channels[i]; + + s->card = card; + init_waitqueue(&s->dma_adc.wait); + init_waitqueue(&s->dma_dac.wait); + init_waitqueue(&s->open_wait); + s->open_sem = MUTEX; + s->magic = ESS_MAGIC; + + s->apu[0] = 4*i; + s->apu[1] = (4*i)+1; + s->apu[2] = (4*i)+2; + s->apu[3] = (4*i)+3; + + if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf) + printk("BOTCH!\n"); + /* register devices */ + if ((s->dev_audio = register_sound_dsp(&ess_audio_fops, -1)) < 0) + break; +// if ((s->dev_mixer = register_sound_mixer(&ess_mixer_fops, -1)) < 0) +// break; + } + + num = i; + + for(;i<8;i++) + { + struct ess_state *s=&card->channels[i]; + s->dev_audio = -1; + } + + ess = &card->channels[0]; + + /* + * Ok card ready. Begin setup proper + */ + + printk(KERN_INFO "ess_pci: Configuring %s at 0x%04X\n", name, iobase); + + /* + * Disable ACPI + */ + + pci_write_config_dword(pcidev, 0x54, 0x00000000); + + /* + * Use TDMA for now. TDMA works on all boards, so while its + * not the most efficient its the simplest. + */ + + pci_read_config_word(pcidev, 0x50, &w); + + /* Clear DMA bits */ + w&=~(1<<10|1<<9|1<<8); + + /* TDMA on */ + w|=(1<<8); + + /* + * MPU at 330 + */ + + w&=~((1<<4)|(1<<3)); + + /* + * SB at 0x220 + */ + + w&=~(1<<2); + + /* + * Reserved write as 0 + */ + + w&=~(1<<1); + + /* + * Some of these are undocumented bits + */ + + w&=~(1<<13)|(1<<14); /* PIC Snoop mode bits */ + w&=~(1<<11); /* Safeguard off */ + w|= (1<<7); /* Posted write */ + w|= (1<<6); /* ISA timing on */ + w&=~(1<<1); /* Subtractive decode off */ + w&=~(1<<5); /* Don't swap left/right */ + + pci_write_config_word(pcidev, 0x50, w); + + pci_read_config_word(pcidev, 0x52, &w); + w&=~(1<<15); /* Turn off internal clock multiplier */ + w&=~(1<<14); /* External clock */ + + w&=~(1<<7); /* HWV off */ + w&=~(1<<6); /* Debounce off */ + w&=~(1<<5); /* GPIO 4:5 */ + w&=~(1<<4); /* Disconnect from the CHI */ + w&=~(1<<3); /* IDMA off (undocumented) */ + w&=~(1<<2); /* MIDI fix off (undoc) */ + w&=~(1<<0); /* IRQ to ISA off (undoc) */ + pci_write_config_word(pcidev, 0x52, w); + + /* + * DDMA off + */ + + pci_read_config_word(pcidev, 0x60, &w); + w&=~(1<<0); + pci_write_config_word(pcidev, 0x60, w); + + /* + * Legacy mode + */ + + pci_read_config_word(pcidev, 0x40, &w); + w&=~(1<<15); /* legacy decode on */ + w&=~(1<<14); /* Disable SIRQ */ + w&=~(1<<13|1<<12|1<<11); + + /* + * We don't use the emulation IRQ's + */ + + w|=(1<<11); /* MPU IRQ 7 */ + w&=~(1<<10|1<<9|1<<8); /* SB IRQ 5 */ + w|=(1<<3)|(1<<1)|(1<<0); /* SB on , FM on, MPU on */ + w&=~(1<<7|1<<6); + w|=(1<<6); /* DMA 1 */ + + /* + * Default to DMA 1 + */ + + pci_write_config_word(pcidev, 0x40, w); + + sound_reset(iobase); + + + /* + * Reset the CODEC + */ + + maestro_ac97_reset(iobase); + + /* + * Ring Bus Setup + */ + + n=inl(iobase+0x34); + n&=~0xF000; + n|=12<<12; /* Direct Sound, Stereo */ + + n=inl(iobase+0x34); + n&=~0x0F00; /* Modem off */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x00F0; + n|=9<<4; /* DAC, Stereo */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x000F; /* ASSP off */ + outl(n, iobase+0x34); + + + n=inl(iobase+0x34); + n|=(1<<29); /* Enable ring bus */ + outl(n, iobase+0x34); + + + n=inl(iobase+0x34); + n|=(1<<28); /* Enable serial bus */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x00F00000; /* MIC off */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x000F0000; /* I2S off */ + outl(n, iobase+0x34); + + w=inw(iobase+0x18); + w&=~(1<<7); /* ClkRun off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<6); /* Harpo off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<4); /* ASSP irq off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<3); /* ISDN irq off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w|=(1<<2); /* Direct Sound IRQ on */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<1); /* MPU401 IRQ off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w|=(1<<0); /* SB IRQ on */ + outw(w, iobase+0x18); + + + outb(0, iobase+0xA4); + outb(3, iobase+0xA2); + outb(0, iobase+0xA6); + + for(apu=0;apu<16;apu++) + { + /* Write 0 into the buffer area 0x1E0->1EF */ + outw(0x01E0+apu, 0x10+iobase); + outw(0x0000, 0x12+iobase); + + /* + * The 1.10 test program seem to write 0 into the buffer area + * 0x1D0-0x1DF too. + */ + outw(0x01D0+apu, 0x10+iobase); + outw(0x0000, 0x12+iobase); + } + +#if 1 + wave_set_register(ess, IDR7_WAVE_ROMRAM, + (wave_get_register(ess, IDR7_WAVE_ROMRAM)&0xFF00)); + wave_set_register(ess, IDR7_WAVE_ROMRAM, + wave_get_register(ess, IDR7_WAVE_ROMRAM)|0x100); + wave_set_register(ess, IDR7_WAVE_ROMRAM, + wave_get_register(ess, IDR7_WAVE_ROMRAM)&~0x200); + wave_set_register(ess, IDR7_WAVE_ROMRAM, + wave_get_register(ess, IDR7_WAVE_ROMRAM)|~0x400); +#else + maestro_write(ess, IDR7_WAVE_ROMRAM, + (maestro_read(ess, IDR7_WAVE_ROMRAM)&0xFF00)); + maestro_write(ess, IDR7_WAVE_ROMRAM, + maestro_read(ess, IDR7_WAVE_ROMRAM)|0x100); + maestro_write(ess, IDR7_WAVE_ROMRAM, + maestro_read(ess, IDR7_WAVE_ROMRAM)&~0x200); + maestro_write(ess, IDR7_WAVE_ROMRAM, + maestro_read(ess, IDR7_WAVE_ROMRAM)|0x400); +#endif + + maestro_write(ess, IDR2_CRAM_DATA, 0x0000); + maestro_write(ess, 0x08, 0xB004); + /* Now back to the DirectSound stuff */ + maestro_write(ess, 0x09, 0x001B); + maestro_write(ess, 0x0A, 0x8000); + maestro_write(ess, 0x0B, 0x3F37); + maestro_write(ess, 0x0C, 0x0098); + + maestro_write(ess, 0x0C, + (maestro_read(ess, 0x0C)&~0xF000)|0x8000); + maestro_write(ess, 0x0C, + (maestro_read(ess, 0x0C)&~0x0F00)|0x0500); + + maestro_write(ess, 0x0D, 0x7632); + + /* Wave cache control on - test off, sg off, + enable, enable extra chans 1Mb */ + + outw(inw(0x14+iobase)|(1<<8),0x14+iobase); + outw(inw(0x14+iobase)&0xFE03,0x14+iobase); + outw((inw(0x14+iobase)&0xFFFC), 0x14+iobase); + outw(inw(0x14+iobase)|(1<<7),0x14+iobase); + + outw(0xA1A0, 0x14+iobase); /* 0300 ? */ + + if(maestro_ac97_get(iobase, 0x00)==0x0080) + { + printk(KERN_INFO "ess_pci: PT101 Codec detected\n"); + maestro_pt101_init(iobase); + } + else + { + printk(KERN_INFO "ess_pci: AC97 Codec detected\n"); + maestro_ac97_init(iobase); + } + + /* Now clear the channel data */ + for(apu=0;apu<64;apu++) + { + for(w=0;w<0x0E;w++) + apu_set_register(ess, apu|ESS_CHAN_HARD, w, 0); + } + + + /* Now we program up the APU's */ + + /* + * APU 6 is the mixer + */ + + apu_set_register(ess, 6|ESS_CHAN_HARD, 0, + apu_get_register(ess, 6|ESS_CHAN_HARD, 0)&~(1<<14)); + apu_set_register(ess, 6|ESS_CHAN_HARD, 0, + apu_get_register(ess, 6|ESS_CHAN_HARD, 0)&~(1<<13)); + apu_set_register(ess, 6|ESS_CHAN_HARD, 0, + apu_get_register(ess, 6|ESS_CHAN_HARD, 0)&~(1<<12)); + apu_set_register(ess, 6|ESS_CHAN_HARD, 0, + apu_get_register(ess, 6|ESS_CHAN_HARD, 0)&0xFCFF); + apu_set_register(ess, 6|ESS_CHAN_HARD, 0, + apu_get_register(ess, 6|ESS_CHAN_HARD, 0)&0xF3FF); + apu_set_register(ess, 6|ESS_CHAN_HARD, 0, + (apu_get_register(ess, 6|ESS_CHAN_HARD, 0)&0xFFF0)|0x0F); + apu_set_register(ess, 6|ESS_CHAN_HARD, 2, + apu_get_register(ess, 6|ESS_CHAN_HARD, 2)&0x00FF); + apu_set_register(ess, 6|ESS_CHAN_HARD, 3, 0x0000); + apu_set_register(ess, 6|ESS_CHAN_HARD, 2, + apu_get_register(ess, 6|ESS_CHAN_HARD, 2)&0xFF3F); + apu_set_register(ess, 6|ESS_CHAN_HARD, 2, + apu_get_register(ess, 6|ESS_CHAN_HARD, 2)|(1<<5)); + apu_set_register(ess, 6|ESS_CHAN_HARD, 2, + apu_get_register(ess, 6|ESS_CHAN_HARD, 2)&~(1<<4)); + apu_set_register(ess, 6|ESS_CHAN_HARD, 2, + apu_get_register(ess, 6|ESS_CHAN_HARD, 2)&0xFFF0); + apu_set_register(ess, 6|ESS_CHAN_HARD, 4, 0x4B5F); + apu_set_register(ess, 6|ESS_CHAN_HARD, 5, 0xFDD5); + apu_set_register(ess, 6|ESS_CHAN_HARD, 6, 0xFE00); + apu_set_register(ess, 6|ESS_CHAN_HARD, 7, 0x0100); + apu_set_register(ess, 6|ESS_CHAN_HARD, 8, 0x78FF); + apu_set_register(ess, 6|ESS_CHAN_HARD, 9, 0xFFFF); + apu_set_register(ess, 6|ESS_CHAN_HARD, 0xA,0x8A10); + apu_set_register(ess, 6|ESS_CHAN_HARD, 0xB,0x8009); + + /* + * APU 62 - Right channel DSP + */ + + apu_set_register(ess, 62|ESS_CHAN_HARD, 0, + apu_get_register(ess, 62|ESS_CHAN_HARD, 0)&~(1<<14)); + apu_set_register(ess, 62|ESS_CHAN_HARD, 0, + apu_get_register(ess, 62|ESS_CHAN_HARD, 0)&~(1<<13)); + apu_set_register(ess, 62|ESS_CHAN_HARD, 0, + apu_get_register(ess, 62|ESS_CHAN_HARD, 0)&~(1<<12)); + apu_set_register(ess, 62|ESS_CHAN_HARD, 0, + apu_get_register(ess, 62|ESS_CHAN_HARD, 0)&0xFCFF); + apu_set_register(ess, 62|ESS_CHAN_HARD, 0, + apu_get_register(ess, 62|ESS_CHAN_HARD, 0)&0xF3FF); + apu_set_register(ess, 62|ESS_CHAN_HARD, 0, + (apu_get_register(ess, 62|ESS_CHAN_HARD, 0)&0xFFF0)|0x0F); + apu_set_register(ess, 62|ESS_CHAN_HARD, 2, + apu_get_register(ess, 62|ESS_CHAN_HARD, 2)&0x00FF); + apu_set_register(ess, 62|ESS_CHAN_HARD, 3, 0x1000); + apu_set_register(ess, 62|ESS_CHAN_HARD, 2, + apu_get_register(ess, 62|ESS_CHAN_HARD, 2)&0xFF3F); + apu_set_register(ess, 62|ESS_CHAN_HARD, 2, + apu_get_register(ess, 62|ESS_CHAN_HARD, 2)&~(1<<5)); + apu_set_register(ess, 62|ESS_CHAN_HARD, 2, + apu_get_register(ess, 62|ESS_CHAN_HARD, 2)&~(1<<4)); + apu_set_register(ess, 62|ESS_CHAN_HARD, 2, + apu_get_register(ess, 62|ESS_CHAN_HARD, 2)&0xFFF0); + apu_set_register(ess, 62|ESS_CHAN_HARD, 4, 0x7F00); + apu_set_register(ess, 62|ESS_CHAN_HARD, 5, 0x8000); + apu_set_register(ess, 62|ESS_CHAN_HARD, 6, 0x8080); + apu_set_register(ess, 62|ESS_CHAN_HARD, 7, 0x0080); + apu_set_register(ess, 62|ESS_CHAN_HARD, 8, 0x7F00); + apu_set_register(ess, 62|ESS_CHAN_HARD, 9, 0xFFFF); + apu_set_register(ess, 62|ESS_CHAN_HARD, 0xA,0x7F00); + apu_set_register(ess, 62|ESS_CHAN_HARD, 0xB,0x00F0); + + /* + * APU 63 - Left channel DSP + */ + + apu_set_register(ess, 63|ESS_CHAN_HARD, 0, + apu_get_register(ess, 63|ESS_CHAN_HARD, 0)&~(1<<14)); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0, + apu_get_register(ess, 63|ESS_CHAN_HARD, 0)&~(1<<13)); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0, + apu_get_register(ess, 63|ESS_CHAN_HARD, 0)&~(1<<12)); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0, + apu_get_register(ess, 63|ESS_CHAN_HARD, 0)&0xFCFF); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0, + apu_get_register(ess, 63|ESS_CHAN_HARD, 0)&0xF3FF); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0, + (apu_get_register(ess, 63|ESS_CHAN_HARD, 0)&0xFFF0)|0x0F); + apu_set_register(ess, 63|ESS_CHAN_HARD, 2, + apu_get_register(ess, 63|ESS_CHAN_HARD, 2)&0x00FF); + apu_set_register(ess, 63|ESS_CHAN_HARD, 3, 0x1000); + apu_set_register(ess, 63|ESS_CHAN_HARD, 2, + apu_get_register(ess, 63|ESS_CHAN_HARD, 2)&0xFF3F); + apu_set_register(ess, 63|ESS_CHAN_HARD, 2, + apu_get_register(ess, 63|ESS_CHAN_HARD, 2)&~(1<<5)); + apu_set_register(ess, 63|ESS_CHAN_HARD, 2, + apu_get_register(ess, 63|ESS_CHAN_HARD, 2)&~(1<<4)); + apu_set_register(ess, 63|ESS_CHAN_HARD, 2, + apu_get_register(ess, 63|ESS_CHAN_HARD, 2)&0xFFF0); + apu_set_register(ess, 63|ESS_CHAN_HARD, 4, 0x7F00); + apu_set_register(ess, 63|ESS_CHAN_HARD, 5, 0x0000); + apu_set_register(ess, 63|ESS_CHAN_HARD, 6, 0x0080); + apu_set_register(ess, 63|ESS_CHAN_HARD, 7, 0x0080); + apu_set_register(ess, 63|ESS_CHAN_HARD, 8, 0x7F00); + apu_set_register(ess, 63|ESS_CHAN_HARD, 9, 0xFFFF); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0xA,0x7F10); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0xB,0x00F0); + + apu_set_register(ess, 6|ESS_CHAN_HARD, 0, + (apu_get_register(ess, 6|ESS_CHAN_HARD, 0)&0xFF0F)|(9<<4)); + + udelay(30); + + apu_set_register(ess, 62|ESS_CHAN_HARD, 0, + (apu_get_register(ess,6|ESS_CHAN_HARD, 0)&0xFF0F)|(1<<4)); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0, + (apu_get_register(ess,6|ESS_CHAN_HARD, 0)&0xFF0F)|(1<<4)); + + + load_tables(iobase); + + udelay(1); + + + if(request_irq(card->irq, ess_interrupt, SA_SHIRQ, name, card)) + { + printk(KERN_ERR "ess_maestro: unable to allocate irq %d,\n", card->irq); + return 0; + } + + ess_play_test(ess); + printk("ess_maestro: %d channels configured.\n", num); + return 1; +} + +#ifdef MODULE + +__initfunc(int init_module(void)) +#else +__initfunc(int init_maestro(void)) +#endif +{ + struct pci_dev *pcidev = NULL; + int index = 0; + + if (!pci_present()) /* No PCI bus in this machine! */ + return -ENODEV; + printk(KERN_INFO "maestro: version v0.01 time " __TIME__ " " __DATE__ "\n"); + + pcidev = NULL; + + /* + * Find the ESS Maestro 2. + */ + + while((pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1968, pcidev))!=NULL) + { + index+=maestro_install(pcidev, "ESS Maestro 2", index); + if(index == NR_DEVICE) + return index; + } + + /* + * Find the ESS Maestro 2E + */ + + while((pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1978, pcidev))!=NULL) + { + index+=maestro_install(pcidev, "ESS Maestro 2E", index); +// printk(KERN_INFO "ESS Maestro 2E not yet supported.\n"); + if(index == NR_DEVICE) + return index; + } + + /* + * ESS Maestro 1 + */ + + while((pcidev = pci_find_device(0x1285, 0x100, pcidev))!=NULL) + { + index+=maestro_install(pcidev, "ESS Maestro", index); + if(index == NR_DEVICE) + return index; + } + if(index==0) + return -ENODEV; + return 0;; +} + +/* --------------------------------------------------------------------- */ + +#ifdef MODULE + +MODULE_AUTHOR("Alan Cox "); +MODULE_DESCRIPTION("ESS Maestro Driver"); + +void cleanup_module(void) +{ + struct ess_card *s; + + while ((s = devs)) { + int i; + devs = devs->next; +// ess_play_test(&s->channels[0]); + kill_bob(&s->channels[0]); +// outb(~0, s->ioenh + SV_CODEC_INTMASK); /* disable ints */ +// synchronize_irq(); +// inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */ +// wrindir(s, SV_CIENABLE, 0); /* disable DMAA and DMAC */ + //outb(0, s->iodmaa + SV_DMA_RESET); + //outb(0, s->iodmac + SV_DMA_RESET); + free_irq(s->irq, s); +// unregister_sound_mixer(s->dev_mixer); + for(i=0;i<8;i++) + { + struct ess_state *ess = &s->channels[i]; + if(ess->dev_audio != -1) + unregister_sound_dsp(ess->dev_audio); + } + kfree(s); + } + printk(KERN_INFO "maestro: unloading\n"); +} + +#endif /* MODULE */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/maestro.h linux.ac/drivers/sound/maestro.h --- linux.vanilla/drivers/sound/maestro.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/maestro.h Fri Jun 4 23:52:44 1999 @@ -0,0 +1,60 @@ +/* + * Registers for the ESS PCI cards + */ + +/* + * Memory access + */ + +#define ESS_MEM_DATA 0x00 +#define ESS_MEM_INDEX 0x02 + +/* + * AC-97 Codec port. Delay 1uS after each write. This is used to + * talk AC-97 (see intel.com). Write data then register. + */ + +#define ESS_AC97_INDEX 0x30 /* byte wide */ +#define ESS_AC97_DATA 0x32 + +/* + * Reading is a bit different. You write register|0x80 to ubdex + * delay 1uS poll the low bit of index, when it clears read the + * data value. + */ + +/* + * Control port. Not yet fully understood + * The value 0xC090 gets loaded to it then 0x0000 and 0x2800 + * to the data port. Then after 4uS the value 0x300 is written + */ + +#define RING_BUS_CTRL_L 0x34 +#define RING_BUS_CTRL_H 0x36 + +/* + * This is also used during setup. The value 0x17 is written to it + */ + +#define ESS_SETUP_18 0x18 + +/* + * And this one gets 0x000b + */ + +#define ESS_SETUP_A2 0xA2 + +/* + * And this 0x0000 + */ + +#define ESS_SETUP_A4 0xA4 +#define ESS_SETUP_A6 0xA6 + +/* + * Stuff to do with Harpo - the wave stuff + */ + +#define ESS_WAVETABLE_SIZE 0x14 +#define ESS_WAVETABLE_2M 0xA180 + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/maestro_tables.h linux.ac/drivers/sound/maestro_tables.h --- linux.vanilla/drivers/sound/maestro_tables.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/maestro_tables.h Fri Jun 4 23:52:44 1999 @@ -0,0 +1,333 @@ +/* + * Set up data block for the ESS soundblaster emulation. This is like + * the example code from ftp.esstech.com.tw (104T31.ZIP) + */ + +u16 asp_block_0[]= { + 0x7980, 0x003a, 0x7980, 0x007d, 0xbe3a, 0x8b00, 0xbe3a, 0x8b00, + 0xbe3a, 0x8b00, 0xbe3a, 0x8b00, 0xbe3a, 0x8b00, 0xbe3a, 0x8b00, + 0x7980, 0x0be6, 0x7980, 0x0069, 0xbe3a, 0x8b00, 0x8048, 0x6945, + 0xb801, 0x9045, 0x6941, 0xe388, 0x0031, 0x6944, 0xba50, 0xe38c, + 0x0031, 0x8b88, 0x6942, 0x304a, 0xe308, 0x0028, 0x6949, 0x9042, + 0x0042, 0xafa0, 0x8000, 0xafa0, 0x8000, 0x8042, 0x6944, 0xb801, + 0x9044, 0x0048, 0xbe3a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xbe41, 0xbf80, 0x0101, 0x8806, 0x8804, 0xb912, + 0x8807, 0xbc26, 0xbe40, 0xb92f, 0x9001, 0x9002, 0x003b, 0x0122, + 0x7a88, 0x0055, 0x003a, 0x013c, 0x7a88, 0x0055, 0x4902, 0xe100, + 0x0800, 0x0c02, 0xa000, 0x7980, 0x004e, 0xb908, 0x8809, 0xbec6, + 0x0067, 0x4a80, 0xe200, 0x0065, 0x4880, 0xe200, 0x0063, 0xb97f, + 0x6e80, 0x7980, 0x0066, 0x1089, 0x9088, 0xb900, 0x90a9, 0x8ba8, + 0xef00, 0x803d, 0x0003, 0x1007, 0x881f, 0x8b88, 0xbb0f, 0xada0, + 0x0810, 0x9003, 0x4903, 0xe200, 0x007b, 0x9002, 0x6a05, 0x6d04, + 0x9803, 0x9804, 0x9005, 0x003d, 0xbe3a, 0xaf06, 0x0000, 0x803d, + 0x8b88, 0x6906, 0x8810, 0xaf06, 0x0001, 0xbfb0, 0x00ff, 0xbaf5, + 0xe3cc, 0x009a, 0x5e06, 0x003f, 0xbf80, 0x0080, 0x4a06, 0xe200, + 0x0095, 0x6e80, 0x6d06, 0x7980, 0x009b, 0x9080, 0x0810, 0xba46, + 0x8810, 0x8b00, 0x1006, 0x9080, 0x003d, 0xbe3a, 0x1024, 0x2009, + 0x8810, 0x8b88, 0x8b00, 0x1089, 0xbfb0, 0x000e, 0xbe0a, 0x880d, + 0x903e, 0x1038, 0x2008, 0x8810, 0x1037, 0x2008, 0x8811, 0x5f3e, + 0x0000, 0x8b00, 0xf500, 0x5e80, 0xfffe, 0x1039, 0x2008, 0x8815, + 0x8b8d, 0x0231, 0x0333, 0x108a, 0x90ad, 0x1025, 0x200a, 0x8815, + 0x0605, 0xb91f, 0x8809, 0x4f16, 0x1080, 0xf600, 0xbfb0, + 0x0003, 0xbfb0, 0x0007, 0x9089, 0xbe47, 0xbe43, 0xbec6, + 0x00f6, 0x4f8b, 0x14a8, 0xe500, 0x6380, 0x8b89, 0x4e8a, + 0xbfe3, 0xe500, 0x2480, 0xbe46, 0x8b9d, 0xbfe7, 0xbfb0, + 0x00ff, 0x288c, 0x2026, 0x8814, 0xbe47, 0x8b00, 0x738f, + 0x54aa, 0xbe03, 0xbe0a, 0x2fa8, 0x988a, 0x8da9, 0xbe03, + 0x4d8e, 0xbfe1, 0xf500, 0x6180, 0x9880, 0x8ba9, 0xbe03, + 0x4c8e, 0xbfe1, 0xf500, 0x6180, 0x9880, 0x8ba9, 0xbe42, + 0x1039, 0x2008, 0x8815, 0x8b8d, 0x8b00, 0x8d8a, 0x7980, + 0x0bcf}; + +u16 asp_block_1[]={ + 0x0005, 0xb900, 0x9008, 0x9009, 0x900a, 0xbb3f, 0x90a0, + 0x001a, 0x011b, 0x021c, 0x0323, 0x1089, 0x9015, 0x108a, + 0x9016, 0x108b, 0x9017, 0x1088, 0x9018, 0x0137, 0x0524, + 0x8b8d, 0x4f16, 0xe200, 0x0827, 0x4f15, 0xe200, 0x0827, + 0x7a80, 0x08e6, 0x102c, 0xb802, 0x8813, 0x8b8b, 0xb900, + 0x90a0, 0x908d, 0x7980, 0x0833, 0x7a80, 0x0913, 0x7803, + 0x7a80, 0x0913, 0x102c, 0xb802, 0x8813, 0x8b8b, 0xb903, + 0x90a0, 0x908d, 0x7c02, 0x4f16, 0xe200, 0x0845, 0x4e15, + 0xe200, 0x0845, 0x7a80, 0x08e6, 0x102c, 0xb806, 0x8813, + 0x8b8b, 0xb901, 0x90a0, 0x908d, 0x7980, 0x0851, 0x7a80, + 0x0913, 0x7803, 0x7a80, 0x0913, 0x102c, 0xb806, 0x8813, + 0x8b8b, 0xb904, 0x90a0, 0x908d, 0x7c02, 0x4f16, 0xe200, + 0x0863, 0x4d15, 0xe200, 0x0863, 0x7a80, 0x08e6, 0x102c, + 0xb80a, 0x8813, 0x8b8b, 0xb902, 0x90a0, 0x908d, 0x7980, + 0x086f, 0x7a80, 0x0913, 0x7803, 0x7a80, 0x0913, 0x102c, + 0xb80a, 0x8813, 0x8b8b, 0xb905, 0x90a0, 0x908d, 0x7801, + 0x7a80, 0x0913, 0x7801, 0x7a80, 0x0913, 0x7801, 0x7a80, + 0x0913, 0x1024, 0xbf90, 0x0100, 0x8815, 0x4f16, 0xe200, + 0x088e, 0x4c15, 0xe200, 0x088e, 0x7a80, 0x08e6, 0x102c, + 0xb814, 0x8813, 0x8b8b, 0xbf80, 0x0100, 0x90a0, 0x908d, + 0x7980, 0x089b, 0x7a80, 0x0913, 0x7803, 0x7a80, 0x0913, + 0x102c, 0xb814, 0x8813, 0x8b8b, 0xbf80, 0x0103, 0x90a0, + 0x908d, 0x7c02, 0x4f16, 0xe200, 0x08ae, 0x4b15, 0xe200, + 0x08ae, 0x7a80, 0x08e6, 0x102c, 0xb818, 0x8813, 0x8b8b, + 0xbf80, 0x0101, 0x90a0, 0x908d, 0x7980, 0x08bb, 0x7a80, + 0x0913, 0x7803, 0x7a80, 0x0913, 0x102c, 0xb818, 0x8813, + 0x8b8b, 0xbf80, 0x0104, 0x90a0, 0x908d, 0x7c02, 0x4f16, + 0xe200, 0x08ce, 0x4a15, 0xe200, 0x08ce, 0x7a80, 0x08e6, + 0x102c, 0xb81c, 0x8813, 0x8b8b, 0xbf80, 0x0102, 0x90a0, + 0x908d, 0x7980, 0x08db, 0x7a80, 0x0913, 0x7803, 0x7a80, + 0x0913, 0x102c, 0xb81c, 0x8813, 0x8b8b, 0xbf80, 0x0105, + 0x90a0, 0x908d, 0x7801, 0x7a80, 0x0913, 0x7801, 0x7a80, + 0x0913, 0x7801, 0x7a80, 0x0913, 0x7980, 0x0920, 0x4f80, + 0x7803, 0xe100, 0x08fe, 0x4f89, 0xe100, 0x08f5, 0xb901, + 0x90a0, 0xb902, 0x90a0, 0x90a0, 0xb906, 0x90ad, 0xef00, + 0xb901, 0x90a0, 0xb906, 0x90a0, 0xb900, 0x90a0, 0xb906, + 0x90ad, 0xef00, 0x4f89, 0xe100, 0x090a, 0xb905, 0x90a0, + 0xb900, 0x90a0, 0xb902, 0x90a0, 0xb906, 0x90ad, 0xef00, + 0xb905, 0x90a0, 0xb900, 0x90a0, 0xb906, 0x90a0, 0xb904, + 0x90ad, 0xef00, 0x4f89, 0xe100, 0x091b, 0xb901, 0x90a0, + 0xb906, 0x90ad, 0xef00, 0xb905, 0x90a0, 0xb904, 0x90ad, + 0xef00, 0xb91f, 0x8809, 0x0034, 0x8b88, 0xbec6, 0x0932, + 0x1313, 0xbe1e, 0x1014, 0xbe1a, 0xbe01, 0xbfe8, 0xbe17, + 0x6a13, 0x6214, 0xbe14, 0x9813, 0x9014, 0x98a0, 0xbe47, + 0x5f0f, 0x002e, 0xe200, 0x093d, 0xbf80, 0xffd2, 0x900f, + 0x7980, 0x0940, 0x100f, 0xb801, 0x900f, 0x400f, 0x8b00, + 0xe500, 0xbe01, 0xbe09, 0x9010, 0xbe46, 0x5f11, 0x003f, + 0xe200, 0x094f, 0xb900, 0x9011, 0x7980, 0x0952, 0x1011, + 0xb801, 0x9011, 0x1001, 0xe388, 0x0bcf, 0x1021, 0x2009, + 0x8813, 0x8b8b, 0x8b00, 0x1080, 0xbfe6, 0x7810, 0x8b00, + 0x8b00, 0x2180, 0xbfb0, 0x0007, 0x4c11, 0x8b00, 0xe100, + 0x096c, 0x4b11, 0x8b00, 0xe600, 0xb900, 0x7980, 0x096d, + 0xbe0a, 0x4a11, 0x8b00, 0xe500, 0xbe01, 0x9012, 0x1037, + 0x2008, 0x8811, 0x102e, 0x2008, 0x8812, 0x4a89, 0xb901, + 0xe500, 0x9019, 0xe100, 0x09c9, 0xb900, 0x9019, 0x4a18, + 0xe200, 0x09c9, 0x5f0a, 0x0010, 0xe200, 0x098d, 0x4b18, + 0xb901, 0xe500, 0x9019, 0x7980, 0x09c9, 0x5f0a, 0x0013, + 0xe200, 0x0997, 0x4b18, 0xb901, 0xe500, 0x9019, 0x7980, + 0x09c9, 0x5f0a, 0x0011, 0xe200, 0x09a4, 0x4f18, 0xb905, + 0xe500, 0x9080, 0xb901, 0xe500, 0x9019, 0x7980, 0x09c9, + 0x5f0a, 0x0014, 0xe200, 0x09b1, 0x4c18, 0xb904, 0xe500, + 0x9080, 0xb901, 0xe500, 0x9019, 0x7980, 0x09c9, 0x5f0a, + 0x0012, 0xe200, 0x09be, 0x4d18, 0xb905, 0xe500, 0x9080, + 0xb901, 0xe500, 0x9019, 0x7980, 0x09c9, 0x5f0a, 0x0015, + 0xe200, 0x09c9, 0x4e18, 0xb904, 0xe500, 0x9080, 0xb901, + 0xe500, 0x9019, 0x8b8a, 0x4f19, 0xe200, 0x09d4, 0x4b80, + 0xe200, 0x09d6, 0x5d80, 0x0020, 0x7980, 0x09d9, 0x5d80, + 0x0010, 0x4a80, 0xe200, 0x0bca, 0x1001, 0xba01, 0x9001, + 0x1024, 0x2009, 0x8815, 0x8b89, 0x4d8d, 0xe200, 0x09f8, + 0x4f16, 0xe100, 0x09ed, 0x8b89, 0x1080, 0xbfc0, 0x000c, + 0x908c, 0x7980, 0x09f8, 0x4b89, 0x108d, 0xf600, 0xbfb0, + 0x0003, 0x4a89, 0x8b00, 0xf500, 0xbfc0, 0x0008, 0x908c, + 0x1022, 0x2009, 0x8811, 0x102e, 0x2008, 0x8812, 0x102f, + 0x2008, 0x8813, 0x1020, 0x200a, 0x8814, 0x101d, 0x200a, + 0x8815, 0x8b8a, 0x4f19, 0xe100, 0x0a11, 0x5e80, 0x0020, + 0x5d80, 0x0018, 0x7980, 0x0a3e, 0x4f80, 0xe200, 0x0a1e, + 0x8b8b, 0x108a, 0xbfa0, 0x7fc0, 0x8b00, 0xf704, 0x5c80, + 0x0003, 0x7980, 0x0a3e, 0x4e80, 0xe200, 0x0a36, 0x8b8c, + 0x178b, 0xbe01, 0xbfb7, 0x00f0, 0x308a, 0xe344, 0x0a3e, + 0x8b8d, 0x4a8a, 0x8b00, 0xe200, 0x0a32, 0x5c80, 0x0006, + 0x7980, 0x0a3e, 0x5c80, 0x000a, 0x7980, 0x0a3e, 0x4c80, + 0xe200, 0x0a3e, 0x4b80, 0x8b00, 0xf500, 0x5c80, 0x0019, + 0x4f80, 0xe200, 0x0a4d, 0x101f, 0x200a, 0x8816, 0x8b00, + 0x8b00, 0x8b8e, 0x1780, 0xbfb7, 0x00f0, 0x900b, 0x7980, + 0x0a64, 0x4e80, 0xe200, 0x0a5c, 0x101f, 0x200a, 0x8816, + 0x8b00, 0x8b00, 0x8b8e, 0x1b80, 0xbfbb, 0x000f, 0x900b, + 0x7980, 0x0a64, 0x4c80, 0xe200, 0x0a64, 0x8b8c, 0x1b80, + 0xbfbb, 0x000f, 0x900b, 0x8b89, 0x1880, 0xbfb8, 0x001c, + 0x4917, 0xe100, 0x0a6e, 0x4f80, 0x7980, 0x0a70, 0x4e80, + 0x8b00, 0xf500, 0xbf98, 0x0002, 0x8b8d, 0x4b89, 0x8b00, + 0xe600, 0xbfe1, 0x903e, 0xbe43, 0x6a0b, 0x613e, 0xbfe8, + 0x980c, 0xbe42, 0x7c10, 0x1080, 0xbfe5, 0xbe1e, 0x7810, + 0x1280, 0xbfb2, 0x001f, 0xbe11, 0x2027, 0x8811, 0x101e, + 0x200a, 0x8816, 0x8b00, 0x128e, 0x4980, 0xe100, 0x0a9b, + 0x4880, 0xe100, 0x0a98, 0xb900, 0x7980, 0x0a9f, 0xbe0a, + 0x7980, 0x0a9f, 0x4880, 0xe200, 0x0a9f, 0xbe09, 0xbe1e, + 0x158d, 0xbfb5, 0x003f, 0xbe11, 0x4889, 0xe200, 0x0aae, + 0xbe1e, 0x1010, 0x4818, 0x8b00, 0xe600, 0xbfe1, 0xbe11, + 0xbfe1, 0x8811, 0xbe1e, 0xb9ff, 0x8819, 0x8b00, 0x8b00, + 0xbf46, 0x8b00, 0xe600, 0xbe1f, 0xbe01, 0xbfb0, 0x00ff, + 0x202a, 0x8811, 0x8b00, 0x8b00, 0x108a, 0x900d, 0xb91f, + 0x8809, 0x0732, 0x730d, 0x4f80, 0xe200, 0x0ad8, 0x1028, + 0x200c, 0x8815, 0xbe43, 0x8b8b, 0x6a8d, 0xbec6, 0x0ad4, + 0x618b, 0x9880, 0x548f, 0x8dad, 0xbe42, 0x7980, 0x0b24, + 0x4e80, 0xe200, 0x0af9, 0x8b8c, 0x178b, 0xbe01, 0xbfb7, + 0x00f0, 0x903e, 0x1029, 0x200c, 0x8815, 0x108d, 0xbec6, + 0x0af6, 0x308b, 0xbe1e, 0x303e, 0x903f, 0x403f, 0xbe1f, + 0xe500, 0x103e, 0x9080, 0xbfe6, 0x202a, 0x8811, 0x8b00, + 0x1089, 0x548f, 0x8dad, 0x7980, 0x0b24, 0x4c8b, 0xe200, + 0x0b1b, 0x1029, 0x200c, 0x8815, 0xbf80, 0x007f, 0x903e, + 0x108d, 0xbec6, 0x0b14, 0x308b, 0xbe1e, 0x303e, 0x903f, + 0x403f, 0xbe1f, 0xe500, 0xb900, 0x9080, 0xbfe6, 0x202a, + 0x8811, 0x8b00, 0x1089, 0x548f, 0x8dad, 0x8b8a, 0xf500, + 0x5e80, 0xffdf, 0x7980, 0x0b24, 0x1089, 0xbfe6, 0x202a, + 0x8811, 0x8b00, 0x8b00, 0x548f, 0xbb1f, 0x8da0, 0x8b8f, + 0x0732, 0x1021, 0x2009, 0x8811, 0x8b89, 0x101d, 0x200a, + 0x8812, 0x1080, 0x7810, 0x8b00, 0xbe47, 0x288a, 0xbfb0, + 0x03ff, 0x4989, 0xe200, 0x0b3e, 0xbe1e, 0x1012, 0x4918, + 0x8b00, 0xe600, 0xbe0a, 0xbe11, 0x900e, 0xbe46, 0x108a, + 0xbfb0, 0x001c, 0xbfe1, 0x880d, 0x8b00, 0x6b0e, 0xbe0a, + 0x880c, 0x108c, 0xbfb0, 0x000f, 0x202d, 0x8814, 0x8b00, + 0x8b00, 0x5589, 0xbf03, 0x8c0e, 0xbf00, 0x1030, 0x2008, + 0x8811, 0xb91f, 0x8809, 0x108b, 0x0333, 0xbec6, 0x0b5f, + 0x200e, 0x90a0, 0x8b00, 0x8b89, 0x9080, 0x4a18, 0xe200, + 0x0b7a, 0x5f0a, 0x0011, 0xe200, 0x0b6c, 0x4f18, 0xe900, + 0x0b7c, 0x5f0a, 0x0014, 0xe200, 0x0b73, 0x4c18, 0xe900, + 0x0b9b, 0x5f0a, 0x0015, 0xe200, 0x0b7a, 0x4e18, 0xe900, + 0x0bb2, 0x7980, 0x009e, 0x0034, 0xb91f, 0x8809, 0x0333, + 0x8b8b, 0xbec6, 0x0b99, 0x1280, 0x6c80, 0xbfea, 0xbe1e, + 0x1580, 0x6c88, 0xbfec, 0xbe13, 0x903e, 0x6cab, 0x903f, + 0x4f3e, 0xb900, 0xf500, 0xbf80, 0x8000, 0x4f3f, 0xbf90, + 0x0d00, 0xf500, 0xbf90, 0x2700, 0x90a0, 0xef00, 0x0034, + 0xb91f, 0x8809, 0x0333, 0x8b88, 0xbec6, 0x0bb0, 0x1eab, + 0x6c80, 0xbfed, 0x903e, 0x4180, 0xb900, 0xf500, 0xbf80, + 0x8000, 0x4f3e, 0x8b00, 0xf500, 0xbf90, 0x4000, 0x90a8, + 0xef00, 0x0034, 0xb91f, 0x8809, 0x0333, 0x8b8b, 0xbec6, + 0x0bc8, 0x1280, 0x6c8b, 0xbfea, 0xbe1e, 0x1580, 0x6c80, + 0xbfec, 0xbe13, 0x903e, 0x4f3e, 0xbf80, 0x4000, 0xf500, + 0xbf90, 0x8000, 0x90a0, 0xef00, 0x0231, 0x8b8a, 0xb900, + 0xbb20, 0x90a0, 0x5f08, 0x0023, 0xe100, 0x0043, 0x1008, + 0xb801, 0x9008, 0x102b, 0x2008, 0x8812, 0x8b00, 0x8b00, + 0x1080, 0x900a, 0x102c, 0x2008, 0x8812, 0x8b00, 0x8b00, + 0x1080, 0x9009, 0x7980, 0x0952, 0x8148, 0x6946, 0xb801, + 0x9046, 0xb901, 0x9041, 0x6944, 0xba08, 0xe344, 0x0bfe, + 0x9044, 0x8b89, 0x0143, 0x694b, 0x881f, 0xbb0f, 0xada0, + 0x8143, 0x0811, 0x304a, 0xe308, 0x0bfe, 0x6949, 0x9043, + 0x0148, 0xbe3a +}; + +u16 asp_block_2[]={ + 0x0000, 0x0000, 0x0003, 0x0003, 0x0001, 0x0001, + 0x0004, 0x0004, 0x0002, 0x0002, 0x0005, 0x0005, + 0x0006, 0x0006, 0x0007, 0x0007, 0x0008, 0x0008, + 0x0100, 0x0100, 0x0103, 0x0103, 0x0101, 0x0101, + 0x0104, 0x0104, 0x0102, 0x0102, 0x0105, 0x0105, + 0x0106, 0x0106, 0x0107, 0x0107, 0x0108, 0x0108 +}; + +u16 asp_block_3[]={ + 0x0000, 0x0000, 0x0000, 0x1200, 0x1200, 0x1280, 0x0000, 0x05d0, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x1104, 0x1105, 0x1008, 0x1020, 0x1040, 0x1060, + 0x1080, 0x10a0, 0x10b0, 0x100d, 0x1010, 0x10e0, 0x2000, 0x2980, + 0x2b00, 0x2b40, 0x2a00, 0x2b90, 0x13dc, 0x2b80, 0x11bc, 0x134c, + 0x1370, 0x12e0, 0x1240, 0x1260, 0x12c0, 0x009e, 0x0045, 0x10bc, + 0x1394, 0x13b8, 0x11f6, 0x10f6, 0x11b0, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0815, 0x0956, 0x09df, 0x0be5, 0x0a19, 0x0a48, 0x0b37, + 0x0b5d, 0x0a8b, 0x0aae, 0x0ad2 }; + + +u16 asp_block_4[] = { + 0x0192, 0x04b6, 0x07d9, 0x0afb, 0x0e1c, 0x113a, 0x1455, 0x176e, + 0x1a83, 0x1d93, 0x209f, 0x23a7, 0x26a8, 0x29a4, 0x2c99, 0x2f87, + 0x326e, 0x354e, 0x3825, 0x3af3, 0x3db8, 0x4074, 0x4326, 0x45cd, + 0x486a, 0x4afb, 0x4d81, 0x4ffb, 0x5269, 0x54ca, 0x571e, 0x5964, + 0x5b9d, 0x5dc8, 0x5fe4, 0x61f1, 0x63ef, 0x65de, 0x67bd, 0x698c, + 0x6b4b, 0x6cf9, 0x6e97, 0x7023, 0x719e, 0x7308, 0x7460, 0x75a6, + 0x76d9, 0x77fb, 0x790a, 0x7a06, 0x7aef, 0x7bc6, 0x7c89, 0x7d3a, + 0x7dd6, 0x7e60, 0x7ed6, 0x7f38, 0x7f87, 0x7fc2, 0x7fea, 0x7ffe, + 0x7ffe, 0x7fea, 0x7fc2, 0x7f87, 0x7f38, 0x7ed6, 0x7e60, 0x7dd6, + 0x7d3a, 0x7c89, 0x7bc6, 0x7aef, 0x7a06, 0x790a, 0x77fb, 0x76d9, + 0x75a6, 0x7460, 0x7308, 0x719e, 0x7023, 0x6e97, 0x6cf9, 0x6b4b, + 0x698c, 0x67bd, 0x65de, 0x63ef, 0x61f1, 0x5fe4, 0x5dc8, 0x5b9d, + 0x5964, 0x571e, 0x54ca, 0x5269, 0x4ffb, 0x4d81, 0x4afb, 0x486a, + 0x45cd, 0x4326, 0x4074, 0x3db8, 0x3af3, 0x3825, 0x354e, 0x326e, + 0x2f87, 0x2c99, 0x29a4, 0x26a8, 0x23a7, 0x209f, 0x1d93, 0x1a83, + 0x176e, 0x1455, 0x113a, 0x0e1c, 0x0afb, 0x07d9, 0x04b6, 0x0192, + 0xfe6f, 0xfb4b, 0xf828, 0xf506, 0xf1e5, 0xeec7, 0xebac, 0xe893, + 0xe57e, 0xe26e, 0xdf62, 0xdc5a, 0xd959, 0xd65d, 0xd368, 0xd07a, + 0xcd93, 0xcab3, 0xc7dc, 0xc50e, 0xc249, 0xbf8d, 0xbcdb, 0xba34, + 0xb797, 0xb506, 0xb280, 0xb006, 0xad98, 0xab37, 0xa8e3, 0xa69d, + 0xa464, 0xa239, 0xa01d, 0x9e10, 0x9c12, 0x9a23, 0x9844, 0x9675, + 0x94b6, 0x9308, 0x916a, 0x8fde, 0x8e63, 0x8cf9, 0x8ba1, 0x8a5b, + 0x8928, 0x8806, 0x86f7, 0x85fb, 0x8512, 0x843b, 0x8378, 0x82c7, + 0x822b, 0x81a1, 0x812b, 0x80c9, 0x807a, 0x803f, 0x8017, 0x8003, + 0x8003, 0x8017, 0x803f, 0x807a, 0x80c9, 0x812b, 0x81a1, 0x822b, + 0x82c7, 0x8378, 0x843b, 0x8512, 0x85fb, 0x86f7, 0x8806, 0x8928, + 0x8a5b, 0x8ba1, 0x8cf9, 0x8e63, 0x8fde, 0x916a, 0x9308, 0x94b6, + 0x9675, 0x9844, 0x9a23, 0x9c12, 0x9e10, 0xa01d, 0xa239, 0xa464, + 0xa69d, 0xa8e3, 0xab37, 0xad98, 0xb006, 0xb280, 0xb506, 0xb797, + 0xba34, 0xbcdb, 0xbf8d, 0xc249, 0xc50e, 0xc7dc, 0xcab3, 0xcd93, + 0xd07a, 0xd368, 0xd65d, 0xd959, 0xdc5a, 0xdf62, 0xe26e, 0xe57e, + 0xe893, 0xebac, 0xeec7, 0xf1e5, 0xf506, 0xf828, 0xfb4b, 0xfe6f, + 0x7cc3, 0x725e, 0x68d5, 0x6017, 0x5813, 0x50b9, 0x49fb, 0x43cd, + 0x3e22, 0x38ef, 0x342b, 0x2fcc, 0x2bc9, 0x281c, 0x24be, 0x21a6, + 0x1ed1, 0x1c37, 0x19d5, 0x17a6, 0x15a5, 0x13ce, 0x121f, 0x1093, + 0x0f28, 0x0ddc, 0x0cab, 0x0b93, 0x0a92, 0x09a7, 0x08cf, 0x080a, + 0x0754, 0x06ae, 0x0615, 0x0589, 0x0509, 0x0494, 0x0428, 0x03c5, + 0x036a, 0x0317, 0x02cb, 0x0285, 0x0245, 0x020a, 0x01d4, 0x01a2, + 0x0175, 0x014b, 0x0125, 0x0102, 0x00e2, 0x00c5, 0x00aa, 0x0091, + 0x007b, 0x0066, 0x0053, 0x0041, 0x0031, 0x0022, 0x0015, 0x0009, + 0xfffe, 0xfff2, 0xffe5, 0xffd7, 0xffc8, 0xffb7, 0xffa5, 0xff91, + 0xff7b, 0xff64, 0xff4a, 0xff2e, 0xff0f, 0xfeee, 0xfec9, 0xfea1, + 0xfe76, 0xfe46, 0xfe13, 0xfdda, 0xfd9d, 0xfd5a, 0xfd11, 0xfcc1, + 0xfc6b, 0xfc0c, 0xfba5, 0xfb34, 0xfab9, 0xfa33, 0xf9a1, 0xf902, + 0xf854, 0xf797, 0xf6c8, 0xf5e7, 0xf4f1, 0xf3e5, 0xf2c1, 0xf183, + 0xf027, 0xeeac, 0xed0f, 0xeb4d, 0xe961, 0xe74a, 0xe501, 0xe284, + 0xdfcd, 0xdcd8, 0xd99d, 0xd618, 0xd242, 0xce12, 0xc982, 0xc487, + 0xbf1a, 0xb92e, 0xb2ba, 0xabaf, 0xa402, 0x9ba3, 0x9282, 0x888d, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e, 0x0010, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x000a, 0x000e, + 0x0010, 0x0014, 0x0016, 0x0018, 0x001a, 0x001c, 0x001e, 0x0020, + 0x0000, 0x0000, 0x0000, 0x000a, 0x0010, 0x0016, 0x001a, 0x001e, + 0x0020, 0x0024, 0x0026, 0x0028, 0x002a, 0x002c, 0x002e, 0x0030, + 0x0000, 0x0000, 0x0010, 0x001a, 0x0020, 0x0026, 0x002a, 0x002e, + 0x0030, 0x0034, 0x0036, 0x0038, 0x003a, 0x003c, 0x003e, 0x0040, + 0x0000, 0x0010, 0x0020, 0x002a, 0x0030, 0x0036, 0x003a, 0x003e, + 0x0040, 0x0044, 0x0046, 0x0048, 0x004a, 0x004c, 0x004e, 0x0050, + 0x0000, 0x0020, 0x0030, 0x003a, 0x0040, 0x0046, 0x004a, 0x004e, + 0x0050, 0x0054, 0x0056, 0x0058, 0x005a, 0x005c, 0x005e, 0x0060, + 0x0000, 0x0030, 0x0040, 0x004a, 0x0050, 0x0056, 0x005a, 0x005e, + 0x0060, 0x0064, 0x0066, 0x0068, 0x006a, 0x006c, 0x006e, 0x0070, + 0x0008, 0x0021, 0x0042, 0x0064, 0x0086, 0x00a8, 0x00cb, 0x00ee, + 0x0111, 0x0135, 0x0158, 0x017d, 0x01a1, 0x01c6, 0x01eb, 0x0211, + 0x0236, 0x025d, 0x0283, 0x02aa, 0x02d1, 0x02f9, 0x0321, 0x0349, + 0x0372, 0x039b, 0x03c4, 0x03ee, 0x0418, 0x0442, 0x046d, 0x0499, + 0x04c4, 0x04f0, 0x051d, 0x054a, 0x0577, 0x05a5, 0x05d3, 0x0601, + 0x0630, 0x0660, 0x0690, 0x06c0, 0x06f1, 0x0722, 0x0753, 0x0785, + 0x07b8, 0x07eb, 0x081e, 0x0852, 0x0886, 0x08bb, 0x08f0, 0x0926, + 0x095c, 0x0993, 0x09ca, 0x0a02, 0x0a3a, 0x0a73, 0x0aac, 0x0ae6, + 0x0b20, 0x0b5b, 0x0b96, 0x0bd2, 0x0c0e, 0x0c4b, 0x0c89, 0x0cc7, + 0x0d05, 0x0d44, 0x0d84, 0x0dc5, 0x0e05, 0x0e47, 0x0e89, 0x0ecc, + 0x0f0f, 0x0f53, 0x0f97, 0x0fdd, 0x1022, 0x1069, 0x10b0, 0x10f7, + 0x1140, 0x1189, 0x11d2, 0x121c, 0x1267, 0x12b3, 0x12ff, 0x134c, + 0x139a, 0x13e8, 0x1438, 0x1487, 0x14d8, 0x1529, 0x157b, 0x15ce, + 0x1621, 0x1676, 0x16cb, 0x1720, 0x1777, 0x17ce, 0x1826, 0x187f, + 0x18d9, 0x1934, 0x198f, 0x19eb, 0x1a48, 0x1aa6, 0x1b05, 0x1b64, + 0x1bc5, 0x1c26, 0x1c88, 0x1ceb, 0x1d4f, 0x1db4, 0x1e1a, 0x1e80, + 0x1ee8, 0x1f51, 0x1fba, 0x2025, 0x2090, 0x20fc, 0x216a, 0x21d8, + 0x2247, 0x22b8, 0x2329, 0x239b, 0x240f, 0x2483, 0x24f9, 0x256f, + 0x25e7, 0x2660, 0x26da, 0x2755, 0x27d1, 0x284e, 0x28cc, 0x294b, + 0x29cc, 0x2a4e, 0x2ad1, 0x2b55, 0x2bda, 0x2c61, 0x2ce8, 0x2d71, + 0x2dfb, 0x2e87, 0x2f13, 0x2fa1, 0x3031, 0x30c1, 0x3153, 0x31e6, + 0x327b, 0x3310, 0x33a8, 0x3440, 0x34da, 0x3575, 0x3612, 0x36b0, + 0x3750, 0x37f1, 0x3893, 0x3937, 0x39dc, 0x3a83, 0x3b2c, 0x3bd6, + 0x3c81, 0x3d2e, 0x3ddd, 0x3e8d, 0x3f3f, 0x3ff2, 0x40a7, 0x415d, + 0x4216, 0x42d0, 0x438b, 0x4448, 0x4507, 0x45c8, 0x468b, 0x474f, + 0x4815, 0x48dd, 0x49a6, 0x4a72, 0x4b3f, 0x4c0e, 0x4cdf, 0x4db2, + 0x4e87, 0x4f5d, 0x5036, 0x5111, 0x51ed, 0x52cc, 0x53ac, 0x548f, + 0x5573, 0x565a, 0x5743, 0x582e, 0x591b, 0x5a0a, 0x5afb, 0x5bef, + 0x5ce4, 0x5ddc, 0x5ed7, 0x5fd3, 0x60d2, 0x61d3, 0x62d6, 0x63dc, + 0x64e4, 0x65ee, 0x66fb, 0x680a, 0x691c, 0x6a30, 0x6b47, 0x6c60, + 0x6d7c, 0x6e9a, 0x6fbb, 0x70de, 0x7204, 0x732d, 0x7459, 0x7587, + 0x76b8, 0x77eb, 0x7922, 0x7a5b, 0x7b97, 0x7cd6, 0x7e18, 0x7f5d, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0002, 0x0002, 0x0002, 0x0003, + 0x0003, 0x0004, 0x0004, 0x0005, 0x0006, 0x0008, 0x0009, 0x000a, + 0x000c, 0x0010, 0x0012, 0x0015, 0x0019, 0x0022, 0x0024, 0x002a, + 0x0031, 0x003e, 0x0049, 0x0055, 0x0062, 0x007c, 0x0092, 0x00a9, + 0x00c4, 0x00fc, 0x0125, 0x0152, 0x0187, 0x01f2, 0x024a, 0x02a4, + 0x030d, 0x03e3, 0x0492, 0x0547, 0x061b, 0x07c7, 0x0923, 0x0a8d, + 0x0c19, 0x0eb3, 0x1228, 0x14c1, 0x17fb, 0x1d17, 0x22f2, 0x2835, + 0x2dd4, 0x3cd0, 0x4cf5, 0x51cc, 0x7fff, 0x7fff, 0x7fff, 0x7fff, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0002, 0x0002, + 0x0002, 0x0003, 0x0004, 0x0005, 0x0005, 0x0007, 0x0008, 0x000a, + 0x000b, 0x000e, 0x0011, 0x0014, 0x0017, 0x001c, 0x0022, 0x0028, + 0x002e, 0x0039, 0x0045, 0x0050, 0x005c, 0x0073, 0x008a, 0x00a0, + 0x00b9, 0x00e7, 0x0114, 0x0141, 0x0172, 0x01ce, 0x0228, 0x0283, + 0x02e3, 0x039b, 0x0454, 0x0501, 0x05bf, 0x072a, 0x0899, 0x0a18, + 0x0b7e, 0x0e55, 0x10d3, 0x1404, 0x16c3, 0x16c3, 0x16c3, 0x16c3, + 0x0012, 0x0024, 0x0048, 0x006c, 0x0090, 0x00b4, 0x00d8, 0x00fc, + 0x0120, 0x0144, 0x0168, 0x0168, 0x01b0, 0x01b0, 0x021c, 0x021c, + 0x0000, 0x0003, 0x0008, 0x000b, 0x0001, 0x0004, 0x0009, 0x000c, + 0x0002, 0x0005, 0x000a, 0x000d, 0x0010, 0x0013, 0x0011, 0x0014, + 0x0012, 0x0015, 0x0100, 0x0103, 0x0108, 0x010b, 0x0101, 0x0104, + 0x0109, 0x010c, 0x0102, 0x0105, 0x010a, 0x010d, 0x0110, 0x0113, + 0x0111, 0x0114, 0x0112, 0x0115 }; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/mpu401.c linux.ac/drivers/sound/mpu401.c --- linux.vanilla/drivers/sound/mpu401.c Sun Nov 8 15:08:01 1998 +++ linux.ac/drivers/sound/mpu401.c Mon Jun 14 13:56:17 1999 @@ -437,6 +437,15 @@ devc->m_busy = 0; } +int intchk_mpu401(void *dev_id) +{ + struct mpu_config *devc; + int dev = (int) dev_id; + + devc = &dev_conf[dev]; + return input_avail(devc); +} + void mpuintr(int irq, void *dev_id, struct pt_regs *dummy) { struct mpu_config *devc; @@ -1715,6 +1724,7 @@ EXPORT_SYMBOL(probe_mpu401); EXPORT_SYMBOL(attach_mpu401); EXPORT_SYMBOL(unload_mpu401); +EXPORT_SYMBOL(intchk_mpu401); EXPORT_SYMBOL(mpuintr); #ifdef MODULE diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/opl3sa2.c linux.ac/drivers/sound/opl3sa2.c --- linux.vanilla/drivers/sound/opl3sa2.c Sat Jan 9 21:50:45 1999 +++ linux.ac/drivers/sound/opl3sa2.c Sat Jun 12 20:06:07 1999 @@ -467,13 +467,13 @@ } -static int probe_opl3sa2_mss(struct address_info *hw_config) +int probe_opl3sa2_mss(struct address_info *hw_config) { return probe_ms_sound(hw_config); } -static void attach_opl3sa2_mss(struct address_info *hw_config) +void attach_opl3sa2_mss(struct address_info *hw_config) { char mixer_name[64]; @@ -516,7 +516,7 @@ } -static void unload_opl3sa2_mss(struct address_info *hw_config) +void unload_opl3sa2_mss(struct address_info *hw_config) { unload_ms_sound(hw_config); } @@ -592,6 +592,9 @@ { /* Generate a pretty name */ sprintf(chipset_name, "OPL3-SA%c", tag); +#if defined(CONFIG_OPL3SA2_MPU_BASE) && !defined(MODULE) + sound_getconf(SNDCARD_OPL3SA2_MPU)->always_detect = 1; +#endif return 1; } return 0; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/pci_legacy.c linux.ac/drivers/sound/pci_legacy.c --- linux.vanilla/drivers/sound/pci_legacy.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/pci_legacy.c Fri Jun 4 23:52:44 1999 @@ -0,0 +1,273 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include "sound_config.h" +#include "soundmodule.h" +#include "sb_mixer.h" +#include "sb.h" + +/* + * Legacy initialisation tables + */ + +struct pci_legacy +{ + int vendor; + int device; + char *description; + int (*install)(struct pci_dev *, struct pci_legacy *); + int flags; +}; + +#define MAX_CARDS 8 + +static struct address_info pci_cards[MAX_CARDS]; +static int card_count=0; + +static struct address_info pci_mpu_cards[MAX_CARDS]; +static int mpu_count=0; + +static int find_space(int *array, int len) +{ + int i; + for(i=0;array[i]!=0;i++) + { + if(check_region(array[i],len)==0) + return i; + } + return -1; +} + +static int find_dma(int *array) +{ + int i; + for(i=0;array[i]!= -1;i++) + { + if(request_dma(array[i],"pci_legacy")==0) + { + free_dma(array[i]); + return i; + } + } + return -1; +} + +/* + * Setup the Yamaha cards. For now don't do the MPU401/OPL3 ports. + * Does anyone actually use the glorified doorbell mode on an SB ? + * + * For now we only support PC/PCI. If you don't have a PC/PCI sideband + * connector on your board bad luck - you can write the DDMA support. + */ + +static int ymf_init(struct pci_dev *pci_dev, struct pci_legacy *pl) +{ + u16 r; + int slot; + int dma; + int doorbell; + int mpu; + static int ymf_sb[]={0x220, 0x240, 0x260, 0x280, 0}; + static int ymf_opl3[]={0x3A8,0x3A0, 0x398, 0x388, 0}; + static int ymf_dma[]={1,3,0, -1}; + static int ymf_mpu[]={0x330, 0x300, 0x332, 0x334, 0}; + struct address_info *card; + + if((slot=find_space(ymf_sb, 16))==-1) + { + printk(KERN_WARNING "%s: no free soundblaster addresses.\n", + pl->description); + return 0; + } + if((dma=find_dma(ymf_dma))==-1) + { + printk(KERN_WARNING "%s: no free DMA channels.\n", + pl->description); + return 0; + } + + doorbell = find_space(ymf_opl3, 4); + mpu = find_space(ymf_mpu, 4); + + printk(KERN_INFO "Found a %s. Due to lack of documentation this card will\n", + pl->description); + printk(KERN_INFO "be configured as an 8bit soundblaster.\n"); + switch(pl->flags) + { + case 0: + case 1: + pci_read_config_word(pci_dev, 0x42, &r); + /* Mask the fields we will set */ + r&=~0x783F; + /* Set the I/O */ + r|=(slot<<2); + /* Serialized IRQ crap off */ + r|=(1<<15); + /* Set the OPL3 */ + if(doorbell != -1) + { + printk(KERN_INFO "Enabling OPL3 at 0x%03X.\n", + ymf_opl3[doorbell]); + r|=(3-doorbell); + } + if(mpu != -1) + { + r|=(mpu<<4); + printk(KERN_INFO "Enabling MPU at I/O 0x%03X.\n", + ymf_mpu[mpu]); + } + pci_write_config_word(pci_dev, 0x42, r); + pci_read_config_word(pci_dev, 0x40, &r); + /* Set DMA */ + r&=~0x00C0; + r|=(ymf_dma[dma])<<6; + /* SB port only */ + r&=~0xF; + r|=1; + if(doorbell != -1) + r|=2; + if(mpu != -1) + r|=24; + /* SIRQ off, I/O on */ + r&=~(1<<14); + r&=~(1<<15); + pci_write_config_word(pci_dev, 0x40, r); + + + pci_read_config_word(pci_dev, 0x4C, &r); + r&=~1; + pci_write_config_word(pci_dev, 0x4C, r); + + pci_read_config_word(pci_dev, 0x48, &r); + r=1; + pci_write_config_word(pci_dev, 0x48, r); + + + pci_read_config_word(pci_dev, 0x48, &r); + udelay(2000); + r=0; + pci_write_config_word(pci_dev, 0x48, r); + + + pci_read_config_word(pci_dev, 0x48, &r); + r=3; + udelay(2000); + pci_write_config_word(pci_dev, 0x48, r); + + printk(KERN_INFO "%s: set to I/O 0x%03X DMA %d.\n", + pl->description, + ymf_sb[slot], ymf_dma[dma]); + break; + } + + card=&pci_cards[card_count]; + + card->dma = ymf_dma[dma]; + card->irq = pci_dev->irq; + card->io_base = ymf_sb[slot]; + card->dma2 = -1; + + if(sb_dsp_detect(card, SB_PCI_YAMAHA, 0)==-1) + { + printk(KERN_WARNING "pci_legacy: Sound blaster emulation not responding.\n"); + return 0; + } + + attach_sb_card(card); + + if(mpu != -1) + { + card=&pci_mpu_cards[mpu_count]; + card->dma = -1; + card->irq = -1; + card->io_base = ymf_mpu[mpu]; + card->dma2 = -1; + if(probe_sbmpu(card)) + { + attach_sbmpu(card); + mpu_count++; + } + else + printk(KERN_WARNING "pci_legacy: MPU401 emulation not responding.\n"); + + } + + card_count++; + return 1; +} + +/* + * Important; Put the less flexible cards first so that they get + * the SB emulation slots they need. + */ + +struct pci_legacy pci_legacy_table[]={ + { 0x1073, 0x0003, "Yamaha YFM-740C", ymf_init, 0 }, + { 0x1073, 0x000D, "Yamaha YFM-724F", ymf_init, 1 }, + { 0x1073, 0x0004, "Yamaha YFM-724", ymf_init, 1 }, + { 0, 0, NULL, 0, 0} +}; + + +int init_legacy_pci(void) +{ + struct pci_dev *pcidev=NULL; + int count=0; + struct pci_legacy *pt=&pci_legacy_table[0]; + + if(!pci_present()) + return -ENODEV; + + while(pt->vendor) + { + pcidev = NULL; + + printk("Scan for %04X %04X\n", + pt->vendor, pt->device); + while((pcidev = pci_find_device(pt->vendor, pt->device, pcidev))!=NULL) + { + printk("Trying to init %04X %04X\n", + pt->vendor, pt->device); + count+=pt->install(pcidev, pt); + if(count >= MAX_CARDS) + return 0; + } + pt++; + } + + if(count==0) + return -ENODEV; + + printk(KERN_INFO "pci_legacy: %d unsupported PCI card%s placed in legacy 8bit mode.\n", + card_count, + card_count==1?"s":""); + return 0; +} + + +int init_module(void) +{ + if(init_legacy_pci()<0) + { + printk(KERN_ERR "No supported devices found.\n"); + return -ENODEV; + } + return 0; +} + +void cleanup_module(void) +{ + int i; + for(i=0;iirq, devc->midi_irq_cookie, NULL); + if(devc->midi_irq_cookie) + uart401intr(devc->irq, devc->midi_irq_cookie, NULL); #endif if (!(src & 3)) @@ -1191,8 +1192,12 @@ void attach_sbmpu(struct address_info *hw_config) { #if defined(CONFIG_MIDI) && defined(CONFIG_UART401) + hw_config->slots[4] = -1; attach_uart401(hw_config); - last_sb->midi_irq_cookie=midi_devs[hw_config->slots[4]]->devc; + if(hw_config->slots[4] != -1) + last_sb->midi_irq_cookie=midi_devs[hw_config->slots[4]]->devc; + else + last_sb->midi_irq_cookie=NULL; #endif } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sb_ess.c linux.ac/drivers/sound/sb_ess.c --- linux.vanilla/drivers/sound/sb_ess.c Thu May 27 22:11:56 1999 +++ linux.ac/drivers/sound/sb_ess.c Sun Jun 6 01:58:04 1999 @@ -40,6 +40,10 @@ * recording problems for high samplerates. I * fixed this by removing ess_calc_best_speed () * and just doing what the documentation says. + * Andy Sloane (June 4 1999): Stole some code from ALSA to fix the playback + * andy@guildsoftware.com speed on ES1869, ES1879, ES1887, and ES1888. + * 1879's were previously ignored by this driver; + * added (untested) support for those. * * This files contains ESS chip specifics. It's based on the existing ESS * handling as it resided in sb_common.c, sb_mixer.c and sb_audio.c. This @@ -190,15 +194,23 @@ #define ESSTYPE_LIKE20 -1 /* Mimic 2.0 behaviour */ #define ESSTYPE_DETECT 0 /* Mimic 2.0 behaviour */ -int esstype = ESSTYPE_LIKE20; /* module parameter in sb_card.c */ +int esstype = ESSTYPE_DETECT; /* module parameter in sb_card.c */ #define SUBMDL_ES1788 0x10 /* Subtype ES1788 for specific handling */ #define SUBMDL_ES1868 0x11 /* Subtype ES1868 for specific handling */ #define SUBMDL_ES1869 0x12 /* Subtype ES1869 for specific handling */ #define SUBMDL_ES1878 0x13 /* Subtype ES1878 for specific handling */ +#define SUBMDL_ES1879 0x16 /* ES1879 was initially forgotten */ #define SUBMDL_ES1887 0x14 /* Subtype ES1887 for specific handling */ #define SUBMDL_ES1888 0x15 /* Subtype ES1888 for specific handling */ +#define SB_CAP_ES18XX_RATE 0x100 + +#define ES1688_CLOCK1 795444 /* 128 - div */ +#define ES1688_CLOCK2 397722 /* 256 - div */ +#define ES18XX_CLOCK1 793800 /* 128 - div */ +#define ES18XX_CLOCK2 768000 /* 256 - div */ + #ifdef FKS_LOGGING static void ess_show_mixerregs (sb_devc *devc); #endif @@ -323,7 +335,6 @@ return retval; } -#ifdef OBSOLETE static int ess_calc_best_speed (int clock1, int rev1, int clock2, int rev2, int *divp, int *speedp) { @@ -347,7 +358,6 @@ return retval; } -#endif /* * Depending on the audiochannel ESS devices can @@ -366,11 +376,14 @@ * The 0x80 is important for the first audio channel */ div = 0x80 | ess_calc_div (795500, 128, speedp, &diff); + } else if(devc->caps & SB_CAP_ES18XX_RATE) { + ess_calc_best_speed(ES18XX_CLOCK1, 128, ES18XX_CLOCK2, 256, + &div, speedp); } else { if (*speedp > 22000) { - div = 0x80 | ess_calc_div (795500, 256, speedp, &diff); + div = 0x80 | ess_calc_div (ES1688_CLOCK1, 256, speedp, &diff); } else { - div = 0x00 | ess_calc_div (397700, 128, speedp, &diff); + div = 0x00 | ess_calc_div (ES1688_CLOCK2, 128, speedp, &diff); } } *divp = div; @@ -1070,6 +1083,12 @@ case 1788: submodel = SUBMDL_ES1788; break; + case 1878: + submodel = SUBMDL_ES1878; + break; + case 1879: + submodel = SUBMDL_ES1879; + break; case 1887: submodel = SUBMDL_ES1887; break; @@ -1117,6 +1136,10 @@ chip = "ES1878"; devc->submodel = SUBMDL_ES1878; break; + case 0x1879: + chip = "ES1879"; + devc->submodel = SUBMDL_ES1879; + break; default: if ((type & 0x00ff) != ((type >> 8) & 0x00ff)) { printk ("ess_init: Unrecognized %04x\n", type); @@ -1173,6 +1196,15 @@ sprintf(name,"ESS %s AudioDrive (rev %d)", chip, ess_minor & 0x0f); } else { strcpy(name, "Jazz16"); + } + + /* AAS: info stolen from ALSA: these boards have different clocks */ + switch(devc->submodel) { + case SUBMDL_ES1869: + case SUBMDL_ES1887: + case SUBMDL_ES1888: + devc->caps |= SB_CAP_ES18XX_RATE; + break; } hw_config->name = name; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sb_mixer.c linux.ac/drivers/sound/sb_mixer.c --- linux.vanilla/drivers/sound/sb_mixer.c Fri Apr 16 22:10:57 1999 +++ linux.ac/drivers/sound/sb_mixer.c Wed Jun 9 20:07:30 1999 @@ -13,6 +13,7 @@ * * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) * Rolf Fokkens (Dec 20 1998) : Moved ESS stuff into sb_ess.[ch] + * Stanislav Voronyi : Support for AWE 3DSE device (Jun 7 1999) */ #include @@ -550,14 +551,37 @@ int val, ret; /* - * Use ioctl(fd, SOUND_MIXER_PRIVATE1, &mode) to turn AGC off (0) or on (1). + * Use ioctl(fd, SOUND_MIXER_AGC, &mode) to turn AGC off (0) or on (1). + * Use ioctl(fd, SOUND_MIXER_3DSE, &mode) to turn 3DSE off (0) or on (1) + * or mode==2 put 3DSE state to mode. */ - if (cmd == SOUND_MIXER_PRIVATE1 && devc->model == MDL_SB16) - { - if (get_user(val, (int *)arg)) - return -EFAULT; - sb_setmixer(devc, 0x43, (~val) & 0x01); - return 0; + if (devc->model == MDL_SB16) { + if (cmd == SOUND_MIXER_AGC) + { + if (get_user(val, (int *)arg)) + return -EFAULT; + sb_setmixer(devc, 0x43, (~val) & 0x01); + return 0; + } + if (cmd == SOUND_MIXER_3DSE) + { + /* I put here 15, but I don't know the exact version. + At least my 4.13 havn't 3DSE, 4.16 has it. */ + if (devc->minor < 15) + return -EINVAL; + if (get_user(val, (int *)arg)) + return -EFAULT; + if (val == 0 || val == 1) + sb_chgmixer(devc, AWE_3DSE, 0x01, val); + else if (val == 2) + { + ret = sb_getmixer(devc, AWE_3DSE)&0x01; + return put_user(ret, (int *)arg); + } + else + return -EINVAL; + return 0; + } } if (((cmd >> 8) & 0xff) == 'M') { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sb_mixer.h linux.ac/drivers/sound/sb_mixer.h --- linux.vanilla/drivers/sound/sb_mixer.h Sat Jan 9 21:50:45 1999 +++ linux.ac/drivers/sound/sb_mixer.h Wed Jun 9 20:07:30 1999 @@ -78,6 +78,11 @@ #define RIGHT_CHN 1 /* + * 3DSE register of AWE32/64 + */ +#define AWE_3DSE 0x90 + +/* * Mixer registers of ALS007 */ #define ALS007_RECORD_SRC 0x6c diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sgalaxy.c linux.ac/drivers/sound/sgalaxy.c --- linux.vanilla/drivers/sound/sgalaxy.c Fri Nov 13 01:37:15 1998 +++ linux.ac/drivers/sound/sgalaxy.c Sat Jun 12 20:00:29 1999 @@ -2,7 +2,7 @@ * sound/sgalaxy.c * * Low level driver for Aztech Sound Galaxy cards. - * Copyright 1998 Artur Skawina + * Copyright 1998 Artur Skawina * * Supported cards: * Aztech Sound Galaxy Waverider Pro 32 - 3D diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sound_calls.h linux.ac/drivers/sound/sound_calls.h --- linux.vanilla/drivers/sound/sound_calls.h Wed Jan 6 23:02:26 1999 +++ linux.ac/drivers/sound/sound_calls.h Mon Jun 14 13:56:17 1999 @@ -157,6 +157,7 @@ /* From mpu401.c */ void attach_mpu401(struct address_info * hw_config); int probe_mpu401(struct address_info *hw_config); +int intchk_mpu401(void *dev_id); void mpuintr(int irq, void *dev_id, struct pt_regs * dummy); /* From uart6850.c */ @@ -256,21 +257,39 @@ void unload_trix_mpu(struct address_info *hw_info); void unload_cs4232(struct address_info *hw_info); void unload_cs4232_mpu(struct address_info *hw_info); +void unload_opl3sa_wss(struct address_info *hw_info); +void unload_opl3sa_sb(struct address_info *hw_info); +void unload_opl3sa_mpu(struct address_info *hw_info); void unload_opl3sa2(struct address_info *hw_info); void unload_opl3sa2_mpu(struct address_info *hw_info); +void unload_opl3sa2_mss(struct address_info *hw_info); +void unload_softsyn (struct address_info *hw_config); -/* From cs4232.c */ - +/* From cs4232.c */ int probe_cs4232 (struct address_info *hw_config); void attach_cs4232 (struct address_info *hw_config); int probe_cs4232_mpu (struct address_info *hw_config); void attach_cs4232_mpu (struct address_info *hw_config); -/* From opl3sa2.c */ +/* From opl3sa.c */ +void attach_opl3sa_wss (struct address_info *hw_config); +int probe_opl3sa_wss (struct address_info *hw_config); +void attach_opl3sa_sb (struct address_info *hw_config); +int probe_opl3sa_sb (struct address_info *hw_config); +void attach_opl3sa_mpu (struct address_info *hw_config); +int probe_opl3sa_mpu (struct address_info *hw_config); + +/* From opl3sa2.c */ int probe_opl3sa2 (struct address_info *hw_config); void attach_opl3sa2 (struct address_info *hw_config); int probe_opl3sa2_mpu (struct address_info *hw_config); void attach_opl3sa2_mpu (struct address_info *hw_config); +int probe_opl3sa2_mss (struct address_info *hw_config); +void attach_opl3sa2_mss (struct address_info *hw_config); + +/* From softoss.c */ +void attach_softsyn_card (struct address_info *hw_config); +int probe_softsyn (struct address_info *hw_config); /* From maui.c */ void attach_maui(struct address_info * hw_config); @@ -291,12 +310,12 @@ int probe_waveartist(struct address_info *hw_config); void unload_waveartist(struct address_info *hw_config); -/* From wavefront.c */ +/* From wavefront.c */ void attach_wavefront (struct address_info *hw_config); int probe_wavefront (struct address_info *hw_config); void unload_wavefront (struct address_info *hw_config); -/* From wf_midi.c */ +/* From wf_midi.c */ void attach_wf_mpu(struct address_info * hw_config); int probe_wf_mpu(struct address_info *hw_config); void unload_wf_mpu(struct address_info *hw_config); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/waveartist.c linux.ac/drivers/sound/waveartist.c --- linux.vanilla/drivers/sound/waveartist.c Sat Jan 9 21:50:46 1999 +++ linux.ac/drivers/sound/waveartist.c Fri Jun 4 23:52:44 1999 @@ -5,6 +5,7 @@ * codec chip used in the Corel Computer NetWinder. * * Cleaned up and integrated into 2.1 by Russell King (rmk@arm.linux.org.uk) + * Tweaked for X86 by Alan Cox */ /* @@ -40,12 +41,19 @@ #include #include +#ifdef CONFIG_ARCH_NETWINDER #include +#define IS_VNC +#endif #include "soundmodule.h" #include "sound_config.h" #include "waveartist.h" +#ifndef NO_DMA +#define NO_DMA 255 +#endif + #define VNC_TIMER_PERIOD (HZ/4) //check slider 4 times/sec #define MIXER_PRIVATE3_RESET 0x53570000 @@ -203,7 +211,7 @@ } while (timeout--); if (timeout == 0) { - printk("WaveArtist: reset timeout "); + printk(KERN_WARNING "WaveArtist: reset timeout "); if (res != (unsigned int)-1) printk("(res=%04X)", res); printk("\n"); @@ -222,7 +230,7 @@ unsigned int i; if (debug_flg & DEBUG_CMD) { - printk("waveartist_cmd: cmd="); + printk(KERN_DEBUG "waveartist_cmd: cmd="); for (i = 0; i < nr_cmd; i++) printk("%04X ", cmd[i]); @@ -239,7 +247,7 @@ old_data = inw(io_base + CMDR); if (debug_flg & DEBUG_CMD) - printk("flushed %04X...", old_data); + printk(KERN_DEBUG "flushed %04X...", old_data); udelay(10); } @@ -272,14 +280,14 @@ if (debug_flg & DEBUG_CMD) { if (!timed_out) { - printk("waveartist_cmd: resp="); + printk(KERN_DEBUG "waveartist_cmd: resp="); for (i = 0; i < nr_resp; i++) printk("%04X ", resp[i]); printk("\n"); } else - printk("waveartist_cmd: timed out\n"); + printk(KERN_WARNING "waveartist_cmd: timed out\n"); } return timed_out ? 1 : 0; @@ -317,7 +325,7 @@ int count; if (debug_flg & DEBUG_CMD) - printk("waveartist_sendcmd: cmd=0x%04X...", cmd); + printk(KERN_DEBUG "waveartist_sendcmd: cmd=0x%04X...", cmd); udelay(10); @@ -330,7 +338,7 @@ udelay(10); if (debug_flg & DEBUG_CMD) - printk(" flushed %04X...", count); + printk(KERN_DEBUG " flushed %04X...", count); } /* @@ -350,7 +358,7 @@ /* ready BEFORE timeout? */ if (debug_flg & DEBUG_CMD) - printk(" %s\n", count ? "Done OK." : "Error!"); + printk(KERN_DEBUG " %s\n", count ? "Done OK." : "Error!"); udelay(10); @@ -455,7 +463,7 @@ unsigned int count = __count; if (debug_flg & DEBUG_OUT) - printk("waveartist: output block, buf=0x%lx, count=0x%x...\n", + printk(KERN_DEBUG "waveartist: output block, buf=0x%lx, count=0x%x...\n", buf, count); /* * 16 bit data @@ -501,7 +509,7 @@ unsigned int count = __count; if (debug_flg & DEBUG_IN) - printk("waveartist: start input, buf=0x%lx, count=0x%x...\n", + printk(KERN_DEBUG "waveartist: start input, buf=0x%lx, count=0x%x...\n", buf, count); if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ @@ -604,26 +612,26 @@ cli(); if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits)) - printk("waveartist: error setting the record format to %d\n", + printk(KERN_WARNING "waveartist: error setting the record format to %d\n", portc->audio_format); if (waveartist_cmd2(devc, WACMD_INPUTCHANNELS, portc->channels)) - printk("waveartist: error setting record to %d channels\n", + printk(KERN_WARNING "waveartist: error setting record to %d channels\n", portc->channels); /* * write cmd SetSampleSpeedTimeConstant */ if (waveartist_cmd2(devc, WACMD_INPUTSPEED, speed)) - printk("waveartist: error setting the record speed " + printk(KERN_WARNING "waveartist: error setting the record speed " "to %dHz.\n", portc->speed); if (waveartist_cmd2(devc, WACMD_INPUTDMA, 1)) - printk("waveartist: error setting the record data path " + printk(KERN_WARNING "waveartist: error setting the record data path " "to 0x%X\n", 1); if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits)) - printk("waveartist: error setting the record format to %d\n", + printk(KERN_WARNING "waveartist: error setting the record format to %d\n", portc->audio_format); devc->xfer_count = 0; @@ -631,9 +639,9 @@ waveartist_halt_input(dev); if (debug_flg & DEBUG_INTR) { - printk("WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); - printk("WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); - printk("WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); + printk(KERN_DEBUG "WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); + printk(KERN_DEBUG "WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); + printk(KERN_DEBUG "WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); } return 0; @@ -658,19 +666,19 @@ if (waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed) && waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed)) - printk("waveartist: error setting the playback speed " + printk(KERN_WARNING "waveartist: error setting the playback speed " "to %dHz.\n", portc->speed); if (waveartist_cmd2(devc, WACMD_OUTPUTCHANNELS, portc->channels)) - printk("waveartist: error setting the playback to" + printk(KERN_WARNING "waveartist: error setting the playback to" " %d channels\n", portc->channels); if (waveartist_cmd2(devc, WACMD_OUTPUTDMA, 0)) - printk("waveartist: error setting the playback data path " + printk(KERN_WARNING "waveartist: error setting the playback data path " "to 0x%X\n", 0); if (waveartist_cmd2(devc, WACMD_OUTPUTFORMAT, bits)) - printk("waveartist: error setting the playback format to %d\n", + printk(KERN_WARNING "waveartist: error setting the playback format to %d\n", portc->audio_format); devc->xfer_count = 0; @@ -678,9 +686,9 @@ waveartist_halt_output(dev); if (debug_flg & DEBUG_INTR) { - printk("WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); - printk("WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); - printk("WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); + printk(KERN_DEBUG "WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); + printk(KERN_DEBUG "WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); + printk(KERN_DEBUG "WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); } return 0; @@ -775,7 +783,7 @@ unsigned long flags; if (debug_flg & DEBUG_TRIGGER) { - printk("wavnc: audio trigger "); + printk(KERN_DEBUG "wavnc: audio trigger "); if (state & PCM_ENABLE_INPUT) printk("in "); if (state & PCM_ENABLE_OUTPUT) @@ -883,15 +891,14 @@ status = inb(devc->hw.io_base + STATR); if (debug_flg & DEBUG_INTR) - printk("waveartist_intr: stat=%02x, irqstat=%02x\n", + printk(KERN_DEBUG "waveartist_intr: stat=%02x, irqstat=%02x\n", status, irqstatus); if (status & IRQ_REQ) /* Clear interrupt */ waveartist_iack(devc); else - printk("waveartist: unexpected interrupt\n"); + printk(KERN_WARNING "waveartist: unexpected interrupt\n"); -#ifdef CONFIG_AUDIO if (irqstatus & 0x01) { int temp = 1; @@ -906,12 +913,11 @@ temp = 0; } if (temp) //default: - printk("WaveArtist: Unknown interrupt\n"); + printk(KERN_WARNING "WaveArtist: Unknown interrupt\n"); } -#endif if (irqstatus & 0x2) // We do not use SB mode natively... - printk("WaveArtist: Unexpected SB interrupt...\n"); + printk(KERN_WARNING "WaveArtist: Unexpected SB interrupt...\n"); } /* ------------------------------------------------------------------------- @@ -1032,7 +1038,7 @@ waveartist_cmd(devc, 1, vals, 1, vals + 2); if (debug_flg & DEBUG_MIXER) - printk("RECSRC: old left: 0x%04X, old right: 0x%04X.\n", + printk(KERN_DEBUG "RECSRC: old left: 0x%04X, old right: 0x%04X.\n", vals[1] & 0x07, (vals[1] >> 3) & 0x07); vals[1] &= ~0x03F; //kill current left/right mux input select @@ -1106,7 +1112,7 @@ } if (debug_flg & DEBUG_MIXER) - printk("RECSRC %d: left=0x%04X, right=0x%04X.\n", input, + printk(KERN_DEBUG "RECSRC %d: left=0x%04X, right=0x%04X.\n", input, vals[1] & 0x07, (vals[1] >> 3) & 0x07); #else @@ -1127,7 +1133,7 @@ waveartist_cmd(devc, 1, vals, 1, vals + 2); if (debug_flg & DEBUG_MIXER) - printk("RECSRC: old left: 0x%04X, old right: 0x%04X.\n", + printk(KERN_DEBUG "RECSRC: old left: 0x%04X, old right: 0x%04X.\n", vals[1], vals[2]); /* @@ -1197,7 +1203,7 @@ } if (debug_flg & DEBUG_MIXER) - printk("RECSRC %d: left(4) 0x%04X, right(8) 0x%04X.\n", + printk(KERN_DEBUG "RECSRC %d: left(4) 0x%04X, right(8) 0x%04X.\n", level, vals[1], vals[2]); #endif /* @@ -1220,7 +1226,7 @@ right = (level & 0x7f00) >> 8; if (debug_flg & DEBUG_MIXER) - printk("wa_mixer_set(dev=%d, level=%X)\n", + printk(KERN_DEBUG "wa_mixer_set(dev=%d, level=%X)\n", whichDev, level); switch (whichDev) { @@ -1321,7 +1327,7 @@ int i; if (debug_flg & DEBUG_MIXER) - printk("%s: mixer_reset\n", devc->hw.name); + printk(KERN_DEBUG "%s: mixer_reset\n", devc->hw.name); /* * reset mixer cmd @@ -1615,20 +1621,20 @@ waveartist_iack(devc); if (request_irq(devc->hw.irq, waveartist_intr, 0, devc->hw.name, devc) < 0) { - printk("%s: IRQ %d in use\n", + printk(KERN_ERR "%s: IRQ %d in use\n", devc->hw.name, devc->hw.irq); goto uninstall; } if (sound_alloc_dma(devc->hw.dma, devc->hw.name)) { - printk("%s: Can't allocate DMA%d\n", + printk(KERN_ERR "%s: Can't allocate DMA%d\n", devc->hw.name, devc->hw.dma); goto uninstall_irq; } if (devc->hw.dma != devc->hw.dma2 && devc->hw.dma2 != NO_DMA) if (sound_alloc_dma(devc->hw.dma2, devc->hw.name)) { - printk("%s: can't allocate DMA%d\n", + printk(KERN_ERR "%s: can't allocate DMA%d\n", devc->hw.name, devc->hw.dma2); goto uninstall_dma; } @@ -1660,6 +1666,14 @@ return -1; } +#ifndef IS_VNC + +static void vnc_mute(wavnc_info *devc, int mute) +{ +} + +#else + /* * Corel Netwinder specifics... */ @@ -1793,31 +1807,34 @@ mod_timer(&vnc_timer, jiffies + next_timeout); } +#endif + int probe_waveartist(struct address_info *hw_config) { wavnc_info *devc = &adev_info[nr_waveartist_devs]; if (nr_waveartist_devs >= MAX_AUDIO_DEV) { - printk("waveartist: too many audio devices\n"); + printk(KERN_ERR "waveartist: too many audio devices\n"); return 0; } if (check_region(hw_config->io_base, 15)) { - printk("WaveArtist: I/O port conflict\n"); + printk(KERN_ERR "WaveArtist: I/O port conflict\n"); return 0; } +#ifdef IS_NW if (hw_config->irq > 31 || hw_config->irq < 16) { - printk("WaveArtist: Bad IRQ %d\n", hw_config->irq); + printk(KERN_ERR "WaveArtist: Bad IRQ %d\n", hw_config->irq); return 0; } if (hw_config->dma != 3) { - printk("WaveArtist: Bad DMA %d\n", hw_config->dma); + printk(KERN_ERR "WaveArtist: Bad DMA %d\n", hw_config->dma); return 0; } - +#endif hw_config->name = "WaveArtist"; devc->hw = *hw_config; devc->open_mode = 0; @@ -1854,12 +1871,13 @@ if (devc->dev_no < 0) release_region(hw->io_base, 15); else { +#ifdef IS_VNC init_timer(&vnc_timer); vnc_timer.function = vnc_slider_tick; vnc_timer.expires = jiffies; vnc_timer.data = nr_waveartist_devs; add_timer(&vnc_timer); - +#endif nr_waveartist_devs += 1; vnc_mute(devc, 0); @@ -1909,7 +1927,7 @@ for (; i < nr_waveartist_devs; i++) adev_info[i] = adev_info[i + 1]; } else - printk("waveartist: can't find device to unload\n"); + printk(KERN_ERR "waveartist: can't find device to unload\n"); } #ifdef MODULE @@ -1919,10 +1937,10 @@ MODULE_PARM(dma, "i"); /* DMA */ MODULE_PARM(dma2, "i"); /* DMA2 */ -int io = CONFIG_WAVEARTIST_BASE; -int irq = CONFIG_WAVEARTIST_IRQ; -int dma = CONFIG_WAVEARTIST_DMA; -int dma2 = CONFIG_WAVEARTIST_DMA2; +int io = -1; +int irq = -1; +int dma = -1; +int dma2 = NO_DMA; static int attached; @@ -1930,6 +1948,11 @@ int init_module(void) { + if(io == -1 || irq == -1 || dma == -1) + { + printk(KERN_ERR "waveartist:io, irq and dma are mandatory.\n"); + return -EINVAL; + } hw_config.io_base = io; hw_config.irq = irq; hw_config.dma = dma; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/Config.in linux.ac/drivers/usb/Config.in --- linux.vanilla/drivers/usb/Config.in Thu May 27 22:11:56 1999 +++ linux.ac/drivers/usb/Config.in Fri Jun 4 23:52:47 1999 @@ -21,6 +21,7 @@ bool 'OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB fi + bool 'USB hub support (just say yes)' CONFIG_USB_HUB bool 'USB mouse support' CONFIG_USB_MOUSE bool 'USB keyboard support' CONFIG_USB_KBD bool 'USB audio parsing support' CONFIG_USB_AUDIO diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/Makefile linux.ac/drivers/usb/Makefile --- linux.vanilla/drivers/usb/Makefile Thu May 27 22:11:56 1999 +++ linux.ac/drivers/usb/Makefile Fri Jun 4 23:52:47 1999 @@ -18,7 +18,11 @@ M_OBJS := L_OBJS := LX_OBJS := -USBX_OBJS := usb.o hub.o usb-debug.o +USBX_OBJS := usb.o usb-debug.o + +ifeq ($(CONFIG_USB_HUB),y) + USBX_OBJS += hub.o +endif ifeq ($(CONFIG_USB_MOUSE),y) USBX_OBJS += mouse.o diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/README.ohci_hcd linux.ac/drivers/usb/README.ohci_hcd --- linux.vanilla/drivers/usb/README.ohci_hcd Thu May 27 22:11:56 1999 +++ linux.ac/drivers/usb/README.ohci_hcd Thu Jan 1 01:00:00 1970 @@ -1,112 +0,0 @@ - -The OHCI HCD layer is a simple but nearly complete implementation of what the -USB people would call a HCD for the OHCI. - (ISO comming soon, Bulk disabled, INT u. CTRL transfers enabled) -It is based on Linus Torvalds UHCI code and Gregory Smith OHCI fragments (0.03 source tree). -The layer (functions) on top of it, is for interfacing to the alternate-usb device-drivers. - -- Roman Weissgaerber - - - * v2.1 1999/05/09 ep_addr correction, code cleanup - * v0.2.0 1999/05/04 - * everything has been moved into 2 files (ohci-hcd.c, ohci-hub-root.c and headers) - * virtual root hub is now an option, - * memory allocation based on kmalloc and kfree now, simple Bus error handling, - * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion - * - * from Linus Torvalds (uhci.c): APM (not tested); hub, usb_device, bus and related stuff - * from Greg Smith (ohci.c): better reset ohci-controller handling, hub - * - * v0.1.0 1999/04/27 initial release - -to remove the module try: -killall root-hub -: -rmmod usb-ohci-hcd - -Features: -- virtual root hub, all basic hub descriptors and commands (state: complete) - this is an option now (v0.2.0) - #define CONFIG_USB_OHCI_VROOTHUB includes the virtual hub code, (VROOTHUB) - default is without. - (at the moment: the Virtual Root Hub option is not recommended) - - files: ohci-root-hub.c, ohci-root-hub.h - - -- Endpoint Descriptor (ED) handling more static approach - (EDs should be allocated in parallel to the SET CONFIGURATION command and they live - as long as the function (device) is alive or another configuration is choosen. - In the HCD layer the EDs has to be allocated manually either by calling a subroutine - or by sending a USB root hub vendor specific command to the virtual root hub. - At the alternate linux usb stack EDs will be added (allocated) at their first use. - - files: ohci-hcd.c ohci-hcd.h - routines: (do not use for drivers, use the top layer alternate usb commands instead) - - int usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr1, - int interval, int load, f_handler handler, int ep_size, int speed) - adds an endpoint, (if the endpoint already exists some parameters will be updated) - - int usb_ohci_rm_ep(struct usb_ohci_ed *ed, struct ohci * ohci) - removes an endpoint and all pending TDs of that EP - - usb_ohci_rm_function( struct ohci * ohci, union ep_addr_ ep_addr) - removes all Endpoints of a function (device) - -- Transfer Descriptors (TD): handling and allocation of TDs is transparent to the upper layers - The HCD takes care of TDs and EDs memory allocation whereas the upper layers (UBSD ...) has - to take care of buffer allocation. - files: ohci-hcd.c ohci-hcd.h - - There is one basic command for all types of bus transfers (INT, BULK, ISO, CTRL): - - int ohci_trans_req(struct ohci * ohci, int ep_addr, int ctrl_len, void *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1) - - CTRL: ctrl, ctrl_len ... cmd buffer - data, data_len ... data buffer (in or out) - INT, BULK: ctrl = NULL, ctrl_len=0, - data, data_len ... data buffer (in or out) - ISO: tbd - - There is no buffer reinsertion done by the internal HCD function. - (The interface layer does this for a INT-pipe on request.) - If you want a transfer then you have to - provide buffers by sending ohci_trans_req requests. As they are queued as TDs on an ED - you can send as many as you like. They should come back by the callback f_handler in - the same order (for each endpoint, not globally) If an error occurs all - queued transfers of an endpoint will return unsent. They will be marked with an error status. - - e.g double-buffering for int transfers: - - ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0) - ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0) - - and when a data0 packet returns by the callback f_handler requeue it: - ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0) - and when a data1 packet returns by the callback f_handler requeue it: - ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0) - - lw0, lw1 are private fields for upper layers for ids or fine grained handlers. - The alternate usb uses them for dev_id and usb_device_irq handler. - - -- Done list handling: returns the requests (callback f_handler in ED) and does - some error handling, root-hub request dequeuing - (files: ohci-done-list.c in ohci-hcd.c now(v0.2.0)) - -ep_addr union or int is for addressing devices&endpoints: -__u8 ep_addr.bep.ep ... bit 3..0 endpoint address - bit 4 0 - bit 6,5 type: eg. 10 CTRL, 11 BULK, 01 INT, 00 ISO - bit 7 direction 1 IN, 0 OUT - -__u8 ep_addr.bep.fa ... bit 6..0 function address - bit 7 0 - -(__u8 ep_addr.bep.hc ... host controller nr) not used -(__u8 ep_addr.bep.host ... host nr) not used - - - diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/audio.c linux.ac/drivers/usb/audio.c --- linux.vanilla/drivers/usb/audio.c Wed Apr 28 19:14:28 1999 +++ linux.ac/drivers/usb/audio.c Fri Jun 4 23:52:47 1999 @@ -4,6 +4,7 @@ #include #include #include "usb.h" +#include "audio.h" static int usb_audio_probe(struct usb_device *dev); static void usb_audio_disconnect(struct usb_device *dev); @@ -108,6 +109,7 @@ int usb_audio_init(void) { + printk("Registering audio devices.\n"); usb_register(&usb_audio_driver); return 0; } @@ -118,9 +120,95 @@ void usb_audio_interface(struct usb_interface_descriptor *interface, u8 *data) { + if(interface->audio==NULL) + { + interface->audio = (struct usb_audio_if *)kmalloc(sizeof(struct usb_audio_if), GFP_KERNEL); + if(interface->audio==NULL) + { + printk(KERN_WARNING "usb_audio: out of memory.\n"); + return; + } + memset(interface->audio, 0, sizeof(struct usb_audio_if)); + } + printk("audio_if: type %d subtype %d.\n", data[1], data[2]); + switch(data[2]) + { + case 1:printk(" header.\n");break; + case 2:printk(" input.\n");break; + case 3:printk(" output.\n");break; + case 4:printk(" mixer.\n");break; + case 5:printk(" selector.\n");break; + case 6:printk(" feature.\n");break; + case 7:printk(" processor.\n");break; + case 8:printk(" extension.\n");break; + } } -void usb_audio_endpoint(struct usb_endpoint_descriptor *interface, u8 *data) +void usb_audio_endpoint(struct usb_endpoint_descriptor *endpoint, u8 *data) { + if(endpoint->audio==NULL) + { + endpoint->audio = (struct usb_audio_endpoint *)kmalloc(sizeof(struct usb_audio_endpoint), GFP_KERNEL); + if(endpoint->audio==NULL) + { + printk(KERN_WARNING "usb_audio: out of memory.\n"); + return; + } + memset(endpoint->audio, 0, sizeof(struct usb_audio_endpoint)); + } + printk("audio_ep: type %d subtype %d.\n", data[1], data[2]); + switch(data[2]) + { + + case 0x01: + if(data[3]&1) + printk(" ep has frequency control.\n"); + if(data[3]&2) + printk(" ep has pitch control.\n"); + if(data[3]&128) + printk(" ep supports no partial frames.\n"); + printk(" ep lock delay %04X", + data[5]|data[6]<<8); + switch(data[4]) + { + case 1:printk("mS");break; + case 2:printk(" samples");break; + } + printk("\n"); + break; + } } + +/* + * There is duplication of the loops here, but it avoids the core + * code having to know anything about audio. + */ + +void usb_audio_destroy(struct usb_device *dev) +{ + int c, i; + struct usb_config_descriptor *cf; + struct usb_interface_descriptor *ifp; + + if(dev->config==NULL) + return; + + for(c=0;cdescriptor.bNumConfigurations;c++) + { + cf=&dev->config[c]; + if(cf->interface==NULL) + break; + for(i=0;ibNumInterfaces;i++) + { + ifp=&cf->interface[i]; + if(ifp->endpoint==NULL) + break; + if(ifp->endpoint->audio) + kfree(ifp->endpoint->audio); + } + if(cf->interface->audio) + kfree(cf->interface->audio); + } +} + \ No newline at end of file diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/audio.h linux.ac/drivers/usb/audio.h --- linux.vanilla/drivers/usb/audio.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/usb/audio.h Fri Jun 4 23:52:47 1999 @@ -0,0 +1,33 @@ +#define MAX_AUDIO_IFACE 8 +#define MAX_AUDIO_ENDPOINT 8 + +/* + * This isnt a byte valid image of the descriptor. + * The dorks didnt do sensible alignment + */ + +struct usb_audio_if_data +{ + u8 data[MAX_AUDIO_IFACE*2+32]; +}; + +struct usb_audio_ep_data +{ + u8 data[7]; +}; + + +struct usb_audio_if +{ + u16 count; + struct usb_audio_if_data iface[MAX_AUDIO_IFACE]; +}; + +struct usb_audio_endpoint +{ + u16 count; + struct usb_audio_ep_data endpoint[MAX_AUDIO_ENDPOINT]; +}; + + + \ No newline at end of file diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/uhci.c linux.ac/drivers/usb/uhci.c --- linux.vanilla/drivers/usb/uhci.c Thu May 27 22:11:57 1999 +++ linux.ac/drivers/usb/uhci.c Fri Jun 4 23:52:47 1999 @@ -898,6 +898,7 @@ dev = uhci->root_hub = usb_to_uhci(usb); usb->bus = bus; + bus->root_hub = uhci_to_usb(uhci->root_hub); /* Initialize the root hub */ /* UHCI specs says devices must have 2 ports, but goes on to say */ @@ -1191,7 +1192,9 @@ #ifdef CONFIG_USB_KBD usb_kbd_init(); #endif +#ifdef CONFIG_USB_HUB hub_init(); +#endif #ifdef CONFIG_USB_AUDIO usb_audio_init(); #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/usb.c linux.ac/drivers/usb/usb.c --- linux.vanilla/drivers/usb/usb.c Thu May 27 22:11:57 1999 +++ linux.ac/drivers/usb/usb.c Fri Jun 4 23:52:47 1999 @@ -311,6 +311,9 @@ if(dev->config==NULL) return; + + usb_audio_destroy(dev); + for(c=0;cdescriptor.bNumConfigurations;c++) { cf=&dev->config[c]; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/usb.h linux.ac/drivers/usb/usb.h --- linux.vanilla/drivers/usb/usb.h Thu May 27 22:11:57 1999 +++ linux.ac/drivers/usb/usb.h Sat Jun 5 00:12:41 1999 @@ -367,9 +367,11 @@ #ifdef CONFIG_USB_AUDIO void usb_audio_interface(struct usb_interface_descriptor *, u8 *); void usb_audio_endpoint(struct usb_endpoint_descriptor *, u8 *); +void usb_audio_destroy(struct usb_device *); #else extern inline void usb_audio_interface(struct usb_interface_descriptor *interface, u8 *data) {} extern inline void usb_audio_endpoint(struct usb_endpoint_descriptor *interface, u8 *data) {} +extern inline void usb_audio_destroy(struct usb_device *) {} #endif #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/Config.in linux.ac/drivers/video/Config.in --- linux.vanilla/drivers/video/Config.in Fri May 28 00:32:59 1999 +++ linux.ac/drivers/video/Config.in Fri Jun 4 23:52:46 1999 @@ -74,6 +74,7 @@ fi if [ "$ARCH" = "i386" ]; then bool 'VESA VGA graphics console' CONFIG_FB_VESA + bool 'VGA 16-color graphics console' CONFIG_FB_VGA16 define_bool CONFIG_VIDEO_SELECT y fi if [ "$CONFIG_VISWS" = "y" ]; then @@ -141,6 +142,7 @@ 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 + bool 'VGA 16-color planar support' CONFIG_FBCON_VGA_PLANES tristate 'VGA characters/attributes support' CONFIG_FBCON_VGA else # Guess what we need @@ -282,6 +284,9 @@ 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 fi if [ "$CONFIG_FB_MDA" = "y" -o "$CONFIG_FB_VGA" = "y" ]; then define_bool CONFIG_FBCON_VGA y diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/Makefile linux.ac/drivers/video/Makefile --- linux.vanilla/drivers/video/Makefile Fri May 28 00:32:59 1999 +++ linux.ac/drivers/video/Makefile Fri Jun 4 23:52:46 1999 @@ -202,6 +202,10 @@ L_OBJS += vesafb.o endif +ifeq ($(CONFIG_FB_VGA16),y) +L_OBJS += vga16fb.o +endif + ifeq ($(CONFIG_FB_VIRGE),y) L_OBJS += virgefb.o else @@ -459,6 +463,14 @@ else ifeq ($(CONFIG_FBCON_MFB),m) MX_OBJS += fbcon-mfb.o + endif +endif + +ifeq ($(CONFIG_FBCON_VGA_PLANES),y) +OX_OBJS += fbcon-vga-planes.o +else + ifeq ($(CONFIG_FBCON_VGA_PLANES),m) + MX_OBJS += fbcon-vga-planes.o endif endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/fbcon-vga-planes.c linux.ac/drivers/video/fbcon-vga-planes.c --- linux.vanilla/drivers/video/fbcon-vga-planes.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/fbcon-vga-planes.c Fri Jun 4 23:52:46 1999 @@ -0,0 +1,364 @@ +/* + * linux/drivers/video/fbcon-vga-planes.c -- Low level frame buffer operations + * for VGA 4-plane modes + * + * Copyright 1999 Ben Pfaff and Petr Vandrovec + * Based on code by Michael Schmitz + * Based on the old macfb.c 4bpp code by Alan Cox + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. */ + +#include +#include +#include +#include +#include +#include + +#include + +#include